Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

2264 lines
70 KiB

  1. /*++
  2. Copyright (c) 1990-1998 Microsoft Corporation, All Rights Reserved
  3. Module Name:
  4. i8042dep.c
  5. Abstract:
  6. The initialization and hardware-dependent portions of
  7. the Intel i8042 port driver which are common to both
  8. the keyboard and the auxiliary (PS/2 mouse) device.
  9. Environment:
  10. Kernel mode only.
  11. Notes:
  12. NOTES: (Future/outstanding issues)
  13. - Powerfail not implemented.
  14. - Consolidate duplicate code, where possible and appropriate.
  15. - There is code ifdef'ed out (#if 0). This code was intended to
  16. disable the device by setting the correct disable bit in the CCB.
  17. It is supposedly correct to disable the device prior to sending a
  18. command that will cause output to end up in the 8042 output buffer
  19. (thereby possibly trashing something that was already in the output
  20. buffer). Unfortunately, on rev K8 of the AMI 8042, disabling the
  21. device where we do caused some commands to timeout, because
  22. the keyboard was unable to return the expected bytes. Interestingly,
  23. AMI claim that the device is only really disabled until the next ACK
  24. comes back.
  25. Revision History:
  26. --*/
  27. #include "stdarg.h"
  28. #include "stdio.h"
  29. #include "string.h"
  30. #include "i8042prt.h"
  31. #include "i8042log.h"
  32. //
  33. // Use the alloc_text pragma to specify the driver initialization routines
  34. // (they can be paged out).
  35. //
  36. #ifdef ALLOC_PRAGMA
  37. #pragma alloc_text(INIT, DriverEntry)
  38. #pragma alloc_text(INIT, I8xDetermineSharedInterrupts)
  39. #pragma alloc_text(INIT, I8xServiceParameters)
  40. #pragma alloc_text(PAGE, I8xInitializeHardwareAtBoot)
  41. #pragma alloc_text(PAGE, I8xInitializeHardware)
  42. #pragma alloc_text(PAGE, I8xReinitializeHardware)
  43. #pragma alloc_text(PAGE, I8xUnload)
  44. #pragma alloc_text(PAGE, I8xToggleInterrupts)
  45. #endif
  46. GLOBALS Globals;
  47. NTSTATUS
  48. DriverEntry(
  49. IN PDRIVER_OBJECT DriverObject,
  50. IN PUNICODE_STRING RegistryPath
  51. )
  52. {
  53. NTSTATUS status = STATUS_SUCCESS;
  54. UNICODE_STRING parametersPath;
  55. PWSTR path;
  56. RtlZeroMemory(&Globals,
  57. sizeof(GLOBALS)
  58. );
  59. Globals.ControllerData = (PCONTROLLER_DATA) ExAllocatePool(
  60. NonPagedPool,
  61. sizeof(CONTROLLER_DATA)
  62. );
  63. if (!Globals.ControllerData) {
  64. status = STATUS_INSUFFICIENT_RESOURCES;
  65. goto DriverEntryError;
  66. }
  67. RtlZeroMemory(Globals.ControllerData,
  68. sizeof(CONTROLLER_DATA)
  69. );
  70. Globals.ControllerData->ControllerObject = IoCreateController(0);
  71. if (!Globals.ControllerData->ControllerObject) {
  72. status = STATUS_INSUFFICIENT_RESOURCES;
  73. goto DriverEntryError;
  74. }
  75. Globals.RegistryPath.MaximumLength = RegistryPath->Length +
  76. sizeof(UNICODE_NULL);
  77. Globals.RegistryPath.Length = RegistryPath->Length;
  78. Globals.RegistryPath.Buffer = ExAllocatePool(
  79. NonPagedPool,
  80. Globals.RegistryPath.MaximumLength
  81. );
  82. if (!Globals.RegistryPath.Buffer) {
  83. Print (DBG_SS_ERROR,
  84. ("Initialize: Couldn't allocate pool for registry path."));
  85. status = STATUS_INSUFFICIENT_RESOURCES;
  86. goto DriverEntryError;
  87. }
  88. RtlZeroMemory (Globals.RegistryPath.Buffer,
  89. Globals.RegistryPath.MaximumLength);
  90. RtlMoveMemory (Globals.RegistryPath.Buffer,
  91. RegistryPath->Buffer,
  92. RegistryPath->Length);
  93. I8xServiceParameters(RegistryPath);
  94. ExInitializeFastMutex(&Globals.DispatchMutex);
  95. KeInitializeSpinLock(&Globals.ControllerData->BytesSpinLock);
  96. KeInitializeSpinLock(&Globals.ControllerData->PowerSpinLock);
  97. KeInitializeTimer(&Globals.ControllerData->CommandTimer);
  98. Globals.ControllerData->TimerCount = I8042_ASYNC_NO_TIMEOUT;
  99. DriverObject->DriverStartIo = I8xStartIo;
  100. DriverObject->DriverUnload = I8xUnload;
  101. DriverObject->DriverExtension->AddDevice = I8xAddDevice;
  102. DriverObject->MajorFunction[IRP_MJ_CREATE] = I8xCreate;
  103. DriverObject->MajorFunction[IRP_MJ_CLOSE] = I8xClose;
  104. DriverObject->MajorFunction[IRP_MJ_INTERNAL_DEVICE_CONTROL] =
  105. I8xInternalDeviceControl;
  106. DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = I8xDeviceControl;
  107. DriverObject->MajorFunction[IRP_MJ_FLUSH_BUFFERS] = I8xFlush;
  108. DriverObject->MajorFunction[IRP_MJ_PNP] = I8xPnP;
  109. DriverObject->MajorFunction[IRP_MJ_POWER] = I8xPower;
  110. DriverObject->MajorFunction[IRP_MJ_SYSTEM_CONTROL] = I8xSystemControl;
  111. //
  112. // Initialize the i8042 command timer.
  113. //
  114. Print(DBG_SS_TRACE, ("DriverEntry (0x%x) \n", status));
  115. return status;
  116. DriverEntryError:
  117. //
  118. // Clean after something has gone wrong
  119. //
  120. if (Globals.ControllerData) {
  121. if (Globals.ControllerData->ControllerObject) {
  122. IoDeleteController(Globals.ControllerData->ControllerObject);
  123. }
  124. ExFreePool(Globals.ControllerData);
  125. }
  126. if (Globals.RegistryPath.Buffer) {
  127. ExFreePool(Globals.RegistryPath.Buffer);
  128. }
  129. return status;
  130. }
  131. VOID
  132. I8xUnload(
  133. IN PDRIVER_OBJECT Driver
  134. )
  135. /*++
  136. Routine Description:
  137. Free all the allocated resources associated with this driver.
  138. Arguments:
  139. DriverObject - Pointer to the driver object.
  140. Return Value:
  141. None.
  142. --*/
  143. {
  144. ULONG i;
  145. PAGED_CODE();
  146. ASSERT(NULL == Driver->DeviceObject);
  147. Print(DBG_SS_TRACE, ("Unload \n"));
  148. if (Globals.RegistersMapped) {
  149. for (i = 0;
  150. i < Globals.ControllerData->Configuration.PortListCount;
  151. i++) {
  152. MmUnmapIoSpace(
  153. Globals.ControllerData->DeviceRegisters[i],
  154. Globals.ControllerData->Configuration.PortList[i].u.Memory.Length
  155. );
  156. }
  157. }
  158. //
  159. // Free resources in Globals
  160. //
  161. ExFreePool(Globals.RegistryPath.Buffer);
  162. if (Globals.ControllerData->ControllerObject) {
  163. IoDeleteController(Globals.ControllerData->ControllerObject);
  164. }
  165. ExFreePool(Globals.ControllerData);
  166. return;
  167. }
  168. VOID
  169. I8xDrainOutputBuffer(
  170. IN PUCHAR DataAddress,
  171. IN PUCHAR CommandAddress
  172. )
  173. /*++
  174. Routine Description:
  175. This routine drains the i8042 controller's output buffer. This gets
  176. rid of stale data that may have resulted from the user hitting a key
  177. or moving the mouse, prior to the execution of I8042Initialize.
  178. Arguments:
  179. DataAddress - Pointer to the data address to read/write from/to.
  180. CommandAddress - Pointer to the command/status address to
  181. read/write from/to.
  182. Return Value:
  183. None.
  184. --*/
  185. {
  186. UCHAR byte;
  187. ULONG i, limit;
  188. LARGE_INTEGER li;
  189. Print(DBG_BUFIO_TRACE, ("I8xDrainOutputBuffer: enter\n"));
  190. //
  191. // Wait till the input buffer is processed by keyboard
  192. // then go and read the data from keyboard. Don't wait longer
  193. // than 1 second in case hardware is broken. This fix is
  194. // necessary for some DEC hardware so that the keyboard doesn't
  195. // lock up.
  196. //
  197. limit = 1000;
  198. li.QuadPart = -10000;
  199. for (i = 0; i < limit; i++) {
  200. if (!(I8X_GET_STATUS_BYTE(CommandAddress)&INPUT_BUFFER_FULL)) {
  201. break;
  202. }
  203. KeDelayExecutionThread(KernelMode, // Mode
  204. FALSE, // Alertable
  205. &li); // Delay in (micro s)
  206. }
  207. while (I8X_GET_STATUS_BYTE(CommandAddress) & OUTPUT_BUFFER_FULL) {
  208. //
  209. // Eat the output buffer byte.
  210. //
  211. byte = I8X_GET_DATA_BYTE(DataAddress);
  212. }
  213. Print(DBG_BUFIO_TRACE, ("I8xDrainOutputBuffer: exit\n"));
  214. }
  215. VOID
  216. I8xGetByteAsynchronous(
  217. IN CCHAR DeviceType,
  218. OUT PUCHAR Byte
  219. )
  220. /*++
  221. Routine Description:
  222. This routine reads a data byte from the controller or keyboard
  223. or mouse, asynchronously.
  224. Arguments:
  225. DeviceType - Specifies which device (i8042 controller, keyboard, or
  226. mouse) to read the byte from.
  227. Byte - Pointer to the location to store the byte read from the hardware.
  228. Return Value:
  229. None.
  230. As a side-effect, the byte value read is stored. If the hardware was not
  231. ready for output or did not respond, the byte value is not stored.
  232. --*/
  233. {
  234. ULONG i;
  235. UCHAR response;
  236. UCHAR desiredMask;
  237. Print(DBG_BUFIO_TRACE,
  238. ("I8xGetByteAsynchronous: enter\n"
  239. ));
  240. Print(DBG_BUFIO_INFO,
  241. ("I8xGetByteAsynchronous: %s\n",
  242. DeviceType == KeyboardDeviceType ? "keyboard" :
  243. (DeviceType == MouseDeviceType ? "mouse" :
  244. "8042 controller")
  245. ));
  246. i = 0;
  247. desiredMask = (DeviceType == MouseDeviceType)?
  248. (UCHAR) (OUTPUT_BUFFER_FULL | MOUSE_OUTPUT_BUFFER_FULL):
  249. (UCHAR) OUTPUT_BUFFER_FULL;
  250. //
  251. // Poll until we get back a controller status value that indicates
  252. // the output buffer is full. If we want to read a byte from the mouse,
  253. // further ensure that the auxiliary device output buffer full bit is
  254. // set.
  255. //
  256. while ((i < (ULONG)Globals.ControllerData->Configuration.PollingIterations) &&
  257. ((UCHAR)((response =
  258. I8X_GET_STATUS_BYTE(Globals.ControllerData->DeviceRegisters[CommandPort]))
  259. & desiredMask) != desiredMask)) {
  260. if (response & OUTPUT_BUFFER_FULL) {
  261. //
  262. // There is something in the i8042 output buffer, but it
  263. // isn't from the device we want to get a byte from. Eat
  264. // the byte and try again.
  265. //
  266. *Byte = I8X_GET_DATA_BYTE(Globals.ControllerData->DeviceRegisters[DataPort]);
  267. Print(DBG_BUFIO_INFO, ("I8xGetByteAsynchronous: ate 0x%x\n",*Byte));
  268. } else {
  269. //
  270. // Try again.
  271. //
  272. i += 1;
  273. Print(DBG_BUFIO_NOISE,
  274. ("I8xGetByteAsynchronous: wait for correct status\n"
  275. ));
  276. }
  277. }
  278. if (i >= (ULONG)Globals.ControllerData->Configuration.PollingIterations) {
  279. Print(DBG_BUFIO_INFO | DBG_BUFIO_ERROR,
  280. ("I8xGetByteAsynchronous: timing out\n"
  281. ));
  282. return;
  283. }
  284. //
  285. // Grab the byte from the hardware.
  286. //
  287. *Byte = I8X_GET_DATA_BYTE(Globals.ControllerData->DeviceRegisters[DataPort]);
  288. Print(DBG_BUFIO_TRACE,
  289. ("I8xGetByteAsynchronous: exit with Byte 0x%x\n", *Byte
  290. ));
  291. }
  292. NTSTATUS
  293. I8xGetBytePolled(
  294. IN CCHAR DeviceType,
  295. OUT PUCHAR Byte
  296. )
  297. /*++
  298. Routine Description:
  299. This routine reads a data byte from the controller or keyboard
  300. or mouse, in polling mode.
  301. Arguments:
  302. DeviceType - Specifies which device (i8042 controller, keyboard, or
  303. mouse) to read the byte from.
  304. Byte - Pointer to the location to store the byte read from the hardware.
  305. Return Value:
  306. STATUS_IO_TIMEOUT - The hardware was not ready for output or did not
  307. respond.
  308. STATUS_SUCCESS - The byte was successfully read from the hardware.
  309. As a side-effect, the byte value read is stored.
  310. --*/
  311. {
  312. ULONG i;
  313. UCHAR response;
  314. UCHAR desiredMask;
  315. PSTR device;
  316. Print(DBG_BUFIO_TRACE,
  317. ("I8xGetBytePolled: enter\n"
  318. ));
  319. if (DeviceType == KeyboardDeviceType) {
  320. device = "keyboard";
  321. } else if (DeviceType == MouseDeviceType) {
  322. device = "mouse";
  323. } else {
  324. device = "8042 controller";
  325. }
  326. Print(DBG_BUFIO_INFO, ("I8xGetBytePolled: %s\n", device));
  327. i = 0;
  328. desiredMask = (DeviceType == MouseDeviceType)?
  329. (UCHAR) (OUTPUT_BUFFER_FULL | MOUSE_OUTPUT_BUFFER_FULL):
  330. (UCHAR) OUTPUT_BUFFER_FULL;
  331. //
  332. // Poll until we get back a controller status value that indicates
  333. // the output buffer is full. If we want to read a byte from the mouse,
  334. // further ensure that the auxiliary device output buffer full bit is
  335. // set.
  336. //
  337. while ((i < (ULONG)Globals.ControllerData->Configuration.PollingIterations) &&
  338. ((UCHAR)((response =
  339. I8X_GET_STATUS_BYTE(Globals.ControllerData->DeviceRegisters[CommandPort]))
  340. & desiredMask) != desiredMask)) {
  341. if (response & OUTPUT_BUFFER_FULL) {
  342. //
  343. // There is something in the i8042 output buffer, but it
  344. // isn't from the device we want to get a byte from. Eat
  345. // the byte and try again.
  346. //
  347. *Byte = I8X_GET_DATA_BYTE(Globals.ControllerData->DeviceRegisters[DataPort]);
  348. Print(DBG_BUFIO_INFO, ("I8xGetBytePolled: ate 0x%x\n", *Byte));
  349. } else {
  350. Print(DBG_BUFIO_NOISE, ("I8xGetBytePolled: stalling\n"));
  351. KeStallExecutionProcessor(
  352. Globals.ControllerData->Configuration.StallMicroseconds
  353. );
  354. i += 1;
  355. }
  356. }
  357. if (i >= (ULONG)Globals.ControllerData->Configuration.PollingIterations) {
  358. Print(DBG_BUFIO_INFO | DBG_BUFIO_NOISE,
  359. ("I8xGetBytePolled: timing out\n"
  360. ));
  361. return(STATUS_IO_TIMEOUT);
  362. }
  363. //
  364. // Grab the byte from the hardware, and return success.
  365. //
  366. *Byte = I8X_GET_DATA_BYTE(Globals.ControllerData->DeviceRegisters[DataPort]);
  367. Print(DBG_BUFIO_TRACE, ("I8xGetBytePolled: exit with Byte 0x%x\n", *Byte));
  368. return(STATUS_SUCCESS);
  369. }
  370. NTSTATUS
  371. I8xGetControllerCommand(
  372. IN ULONG HardwareDisableEnableMask,
  373. OUT PUCHAR Byte
  374. )
  375. /*++
  376. Routine Description:
  377. This routine reads the 8042 Controller Command Byte.
  378. Arguments:
  379. HardwareDisableEnableMask - Specifies which hardware devices, if any,
  380. need to be disabled/enable around the operation.
  381. Byte - Pointer to the location into which the Controller Command Byte is
  382. read.
  383. Return Value:
  384. Status is returned.
  385. --*/
  386. {
  387. NTSTATUS status;
  388. NTSTATUS secondStatus;
  389. ULONG retryCount;
  390. Print(DBG_BUFIO_TRACE, ("I8xGetControllerCommand: enter\n"));
  391. //
  392. // Disable the specified devices before sending the command to
  393. // read the Controller Command Byte (otherwise data in the output
  394. // buffer might get trashed).
  395. //
  396. if (HardwareDisableEnableMask & KEYBOARD_HARDWARE_PRESENT) {
  397. status = I8xPutBytePolled(
  398. (CCHAR) CommandPort,
  399. NO_WAIT_FOR_ACKNOWLEDGE,
  400. (CCHAR) UndefinedDeviceType,
  401. (UCHAR) I8042_DISABLE_KEYBOARD_DEVICE
  402. );
  403. if (!NT_SUCCESS(status)) {
  404. return(status);
  405. }
  406. }
  407. if (HardwareDisableEnableMask & MOUSE_HARDWARE_PRESENT) {
  408. status = I8xPutBytePolled(
  409. (CCHAR) CommandPort,
  410. NO_WAIT_FOR_ACKNOWLEDGE,
  411. (CCHAR) UndefinedDeviceType,
  412. (UCHAR) I8042_DISABLE_MOUSE_DEVICE
  413. );
  414. if (!NT_SUCCESS(status)) {
  415. //
  416. // Re-enable the keyboard device, if necessary, before returning.
  417. //
  418. if (HardwareDisableEnableMask & KEYBOARD_HARDWARE_PRESENT) {
  419. secondStatus = I8xPutBytePolled(
  420. (CCHAR) CommandPort,
  421. NO_WAIT_FOR_ACKNOWLEDGE,
  422. (CCHAR) UndefinedDeviceType,
  423. (UCHAR) I8042_ENABLE_KEYBOARD_DEVICE
  424. );
  425. }
  426. return(status);
  427. }
  428. }
  429. //
  430. // Send a command to the i8042 controller to read the Controller
  431. // Command Byte.
  432. //
  433. status = I8xPutBytePolled(
  434. (CCHAR) CommandPort,
  435. NO_WAIT_FOR_ACKNOWLEDGE,
  436. (CCHAR) UndefinedDeviceType,
  437. (UCHAR) I8042_READ_CONTROLLER_COMMAND_BYTE
  438. );
  439. //
  440. // Read the byte from the i8042 data port.
  441. //
  442. if (NT_SUCCESS(status)) {
  443. for (retryCount = 0; retryCount < 5; retryCount++) {
  444. status = I8xGetBytePolled(
  445. (CCHAR) ControllerDeviceType,
  446. Byte
  447. );
  448. if (NT_SUCCESS(status)) {
  449. break;
  450. }
  451. if (status == STATUS_IO_TIMEOUT) {
  452. KeStallExecutionProcessor(50);
  453. } else {
  454. break;
  455. }
  456. }
  457. }
  458. //
  459. // Re-enable the specified devices. Clear the device disable
  460. // bits in the Controller Command Byte by hand (they got set when
  461. // we disabled the devices, so the CCB we read lacked the real
  462. // device disable bit information).
  463. //
  464. if (HardwareDisableEnableMask & KEYBOARD_HARDWARE_PRESENT) {
  465. secondStatus = I8xPutBytePolled(
  466. (CCHAR) CommandPort,
  467. NO_WAIT_FOR_ACKNOWLEDGE,
  468. (CCHAR) UndefinedDeviceType,
  469. (UCHAR) I8042_ENABLE_KEYBOARD_DEVICE
  470. );
  471. if (!NT_SUCCESS(secondStatus)) {
  472. if (NT_SUCCESS(status))
  473. status = secondStatus;
  474. } else if (status == STATUS_SUCCESS) {
  475. *Byte &= (UCHAR) ~CCB_DISABLE_KEYBOARD_DEVICE;
  476. }
  477. }
  478. if (HardwareDisableEnableMask & MOUSE_HARDWARE_PRESENT) {
  479. secondStatus = I8xPutBytePolled(
  480. (CCHAR) CommandPort,
  481. NO_WAIT_FOR_ACKNOWLEDGE,
  482. (CCHAR) UndefinedDeviceType,
  483. (UCHAR) I8042_ENABLE_MOUSE_DEVICE
  484. );
  485. if (!NT_SUCCESS(secondStatus)) {
  486. if (NT_SUCCESS(status))
  487. status = secondStatus;
  488. } else if (NT_SUCCESS(status)) {
  489. *Byte &= (UCHAR) ~CCB_DISABLE_MOUSE_DEVICE;
  490. }
  491. }
  492. Print(DBG_BUFIO_TRACE, ("I8xGetControllerCommand: exit\n"));
  493. return(status);
  494. }
  495. NTSTATUS
  496. I8xToggleInterrupts(
  497. BOOLEAN State
  498. )
  499. /*++
  500. Routine Description:
  501. This routine is called by KeSynchronizeExecution to turn toggle the
  502. interrupt(s).
  503. Arguments:
  504. ToggleContext - indicates whether to turn the interrupts on or off plus it
  505. stores the results of the operation
  506. Return Value:
  507. success of the toggle
  508. --*/
  509. {
  510. I8042_TRANSMIT_CCB_CONTEXT transmitCCBContext;
  511. PAGED_CODE();
  512. Print(DBG_SS_TRACE,
  513. ("I8xToggleInterrupts(%s), enter\n",
  514. State ? "TRUE" : "FALSE"
  515. ));
  516. if (State) {
  517. transmitCCBContext.HardwareDisableEnableMask =
  518. Globals.ControllerData->HardwarePresent;
  519. transmitCCBContext.AndOperation = OR_OPERATION;
  520. transmitCCBContext.ByteMask =
  521. (KEYBOARD_PRESENT()) ? CCB_ENABLE_KEYBOARD_INTERRUPT : 0;
  522. transmitCCBContext.ByteMask |= (UCHAR)
  523. (MOUSE_PRESENT()) ? CCB_ENABLE_MOUSE_INTERRUPT : 0;
  524. }
  525. else {
  526. transmitCCBContext.HardwareDisableEnableMask = 0;
  527. transmitCCBContext.AndOperation = AND_OPERATION;
  528. transmitCCBContext.ByteMask = (UCHAR)
  529. ~((UCHAR) CCB_ENABLE_KEYBOARD_INTERRUPT |
  530. (UCHAR) CCB_ENABLE_MOUSE_INTERRUPT);
  531. }
  532. I8xTransmitControllerCommand((PVOID) &transmitCCBContext);
  533. if (!NT_SUCCESS(transmitCCBContext.Status)) {
  534. Print(DBG_SS_INFO | DBG_SS_ERROR,
  535. ("I8xToggleInterrupts: failed to %sable the interrupts, status 0x%x\n",
  536. State ? "en" : "dis",
  537. transmitCCBContext.Status
  538. ));
  539. }
  540. return transmitCCBContext.Status;
  541. }
  542. NTSTATUS
  543. I8xInitializeHardwareAtBoot(
  544. NTSTATUS *KeyboardStatus,
  545. NTSTATUS *MouseStatus
  546. )
  547. /*++
  548. Routine Description:
  549. First initialization of the hardware
  550. Arguments:
  551. KeyboardStatus - Stores result of keyboard init
  552. MouseStatus - Stores result of mouse init
  553. Return Value:
  554. success if any of the devices are found and initialized
  555. --*/
  556. {
  557. NTSTATUS status = STATUS_SUCCESS;
  558. PAGED_CODE();
  559. //
  560. // It is OK to try to initialize the keyboard if the mouse has already started,
  561. // BUT we don't want to take the chance of disabling the keyboard if it has
  562. // already started and a start for the mouse arrives.
  563. //
  564. if (Globals.KeyboardExtension &&
  565. Globals.KeyboardExtension->InterruptObject) {
  566. return STATUS_INVALID_DEVICE_REQUEST;
  567. }
  568. if (!I8xSanityCheckResources()) {
  569. return STATUS_INSUFFICIENT_RESOURCES;
  570. }
  571. //
  572. // NEC machine can not toggle interrupts
  573. //
  574. status = I8xToggleInterrupts(FALSE);
  575. if (!NT_SUCCESS(status)) {
  576. return status;
  577. }
  578. I8xInitializeHardware(KeyboardStatus, MouseStatus, INIT_FIRST_TIME);
  579. if ((NT_SUCCESS(*KeyboardStatus) ||
  580. (DEVICE_START_SUCCESS(*KeyboardStatus) && Globals.Headless) ||
  581. NT_SUCCESS(*MouseStatus) ||
  582. (DEVICE_START_SUCCESS(*MouseStatus) && Globals.Headless)) &&
  583. (MOUSE_PRESENT() || KEYBOARD_PRESENT())) {
  584. status = I8xToggleInterrupts(TRUE);
  585. }
  586. return status;
  587. }
  588. VOID
  589. I8xReinitializeHardware (
  590. PPOWER_UP_WORK_ITEM Item
  591. )
  592. /*++
  593. Routine Description:
  594. Initializes the hardware after returning from a low power state. The
  595. routine is called from a worker item thread.
  596. Arguments:
  597. Item - Work queue item
  598. Return Value:
  599. success if any of the devices are found and initialized
  600. --*/
  601. {
  602. NTSTATUS keyboardStatus = STATUS_UNSUCCESSFUL,
  603. mouseStatus = STATUS_UNSUCCESSFUL;
  604. BOOLEAN result;
  605. PIRP mouOutstandingPowerIrp = NULL,
  606. kbOutstandingPowerIrp = NULL;
  607. PIO_STACK_LOCATION stack;
  608. NTSTATUS status;
  609. ULONG initFlags = 0;
  610. PPORT_MOUSE_EXTENSION mouseExtension = Globals.MouseExtension;
  611. PPORT_KEYBOARD_EXTENSION keyboardExtension = Globals.KeyboardExtension;
  612. PAGED_CODE();
  613. kbOutstandingPowerIrp = Item->KeyboardPowerIrp;
  614. mouOutstandingPowerIrp = Item->MousePowerIrp;
  615. //
  616. // Initialize the device if it is returning from a low power state (denoted
  617. // by an outstanding power irp) or if it is already in D0 (and the other
  618. // device has been power cycled)
  619. //
  620. if (kbOutstandingPowerIrp ||
  621. (KEYBOARD_PRESENT() &&
  622. Globals.KeyboardExtension &&
  623. Globals.KeyboardExtension->PowerState == PowerDeviceD0 ) ) {
  624. initFlags |= INIT_KEYBOARD;
  625. }
  626. //
  627. // if the keyboard is in D0, then the other device has to have power cycled
  628. // for us to get into this code path
  629. //
  630. if (KEYBOARD_PRESENT() &&
  631. Globals.KeyboardExtension &&
  632. Globals.KeyboardExtension->PowerState == PowerDeviceD0) {
  633. ASSERT(mouOutstandingPowerIrp);
  634. }
  635. if (mouOutstandingPowerIrp ||
  636. (MOUSE_PRESENT() &&
  637. Globals.MouseExtension &&
  638. Globals.MouseExtension->PowerState == PowerDeviceD0 ) ) {
  639. initFlags |= INIT_MOUSE;
  640. }
  641. //
  642. // if the mouse is in D0, then the other device has to have power cycled
  643. // for us to get into this code path
  644. //
  645. if (MOUSE_PRESENT() &&
  646. Globals.MouseExtension &&
  647. Globals.MouseExtension->PowerState == PowerDeviceD0) {
  648. ASSERT(kbOutstandingPowerIrp);
  649. }
  650. ASSERT(initFlags != 0x0);
  651. //
  652. // Check resources
  653. //
  654. if( Globals.I8xReadXxxUchar == NULL &&
  655. I8xSanityCheckResources() == FALSE )
  656. {
  657. //
  658. // Resource check failed, manually remove device
  659. //
  660. if( initFlags & INIT_KEYBOARD ){
  661. I8xManuallyRemoveDevice(GET_COMMON_DATA(keyboardExtension));
  662. }
  663. if( initFlags & INIT_MOUSE ){
  664. I8xManuallyRemoveDevice(GET_COMMON_DATA(mouseExtension));
  665. }
  666. }else{
  667. //
  668. // Disable the interrupts on the i8042
  669. //
  670. I8xToggleInterrupts(FALSE);
  671. Print(DBG_POWER_NOISE, ("item ... starting init\n"));
  672. I8xInitializeHardware(&keyboardStatus, &mouseStatus, initFlags);
  673. }
  674. //
  675. // Reset PoweredDevices so that we can keep track of the powered device
  676. // the next time the machine is power managed off.
  677. //
  678. if (!DEVICE_START_SUCCESS(keyboardStatus)) {
  679. Print(DBG_SS_ERROR,
  680. ("I8xReinitializeHardware for kb failed, 0x%x\n",
  681. keyboardStatus
  682. ));
  683. }
  684. if (!DEVICE_START_SUCCESS(mouseStatus)) {
  685. Print(DBG_SS_ERROR,
  686. ("I8xReinitializeHardware for mou failed, 0x%x\n",
  687. mouseStatus
  688. ));
  689. }
  690. if (DEVICE_START_SUCCESS(keyboardStatus) || DEVICE_START_SUCCESS(mouseStatus)) {
  691. //
  692. // Enable the interrupts on the i8042
  693. //
  694. I8xToggleInterrupts(TRUE);
  695. }
  696. if (DEVICE_START_SUCCESS(mouseStatus) || mouseStatus == STATUS_IO_TIMEOUT) {
  697. Print(DBG_SS_NOISE, ("reinit, mouse status == 0x%x\n", mouseStatus));
  698. if (mouOutstandingPowerIrp) {
  699. stack = IoGetCurrentIrpStackLocation(mouOutstandingPowerIrp);
  700. ASSERT(stack->Parameters.Power.State.DeviceState == PowerDeviceD0);
  701. mouseExtension->PowerState = stack->Parameters.Power.State.DeviceState;
  702. mouseExtension->ShutdownType = PowerActionNone;
  703. PoSetPowerState(mouseExtension->Self,
  704. stack->Parameters.Power.Type,
  705. stack->Parameters.Power.State
  706. );
  707. }
  708. if (IS_LEVEL_TRIGGERED(mouseExtension)) {
  709. Print(DBG_SS_NOISE,
  710. ("mouse is level triggered, reconnecting INT\n"));
  711. ASSERT(mouseExtension->InterruptObject == NULL);
  712. I8xMouseConnectInterruptAndEnable(mouseExtension, FALSE);
  713. ASSERT(mouseExtension->InterruptObject != NULL);
  714. }
  715. if (mouseStatus != STATUS_IO_TIMEOUT &&
  716. mouseStatus != STATUS_DEVICE_NOT_CONNECTED) {
  717. if (mouseExtension->InitializePolled) {
  718. I8xMouseEnableTransmission(mouseExtension);
  719. }
  720. else {
  721. I8X_MOUSE_INIT_COUNTERS(mouseExtension);
  722. I8xResetMouse(mouseExtension);
  723. }
  724. }
  725. else {
  726. //
  727. // Came back from low power and device didn't respond, pretend that
  728. // it is there, so that if the user plugs in a mouse later on, we
  729. // will be able to init it and make it usable
  730. //
  731. ;
  732. }
  733. mouseStatus = STATUS_SUCCESS;
  734. }
  735. //
  736. // Complete the irp no matter how the device came back
  737. //
  738. if (mouOutstandingPowerIrp) {
  739. mouOutstandingPowerIrp->IoStatus.Status = mouseStatus;
  740. mouOutstandingPowerIrp->IoStatus.Information = 0;
  741. PoStartNextPowerIrp(mouOutstandingPowerIrp);
  742. IoCompleteRequest(mouOutstandingPowerIrp, IO_NO_INCREMENT);
  743. IoReleaseRemoveLock(&mouseExtension->RemoveLock,
  744. mouOutstandingPowerIrp);
  745. }
  746. if (DEVICE_START_SUCCESS(keyboardStatus)) {
  747. if (kbOutstandingPowerIrp) {
  748. stack = IoGetCurrentIrpStackLocation(kbOutstandingPowerIrp);
  749. ASSERT(stack->Parameters.Power.State.DeviceState == PowerDeviceD0);
  750. keyboardExtension->PowerState = stack->Parameters.Power.State.DeviceState;
  751. keyboardExtension->ShutdownType = PowerActionNone;
  752. PoSetPowerState(keyboardExtension->Self,
  753. stack->Parameters.Power.Type,
  754. stack->Parameters.Power.State
  755. );
  756. }
  757. keyboardStatus = STATUS_SUCCESS;
  758. }
  759. //
  760. // Complete the irp no matter how the device came back
  761. //
  762. if (kbOutstandingPowerIrp) {
  763. kbOutstandingPowerIrp->IoStatus.Status = keyboardStatus;
  764. kbOutstandingPowerIrp->IoStatus.Information = 0;
  765. PoStartNextPowerIrp(kbOutstandingPowerIrp);
  766. IoCompleteRequest(kbOutstandingPowerIrp, IO_NO_INCREMENT);
  767. IoReleaseRemoveLock(&keyboardExtension->RemoveLock,
  768. kbOutstandingPowerIrp);
  769. }
  770. I8xSetPowerFlag(WORK_ITEM_QUEUED, FALSE);
  771. ExFreePool(Item);
  772. }
  773. VOID
  774. I8xInitializeHardware(
  775. NTSTATUS *KeyboardStatus,
  776. NTSTATUS *MouseStatus,
  777. ULONG InitFlags
  778. )
  779. /*++
  780. Routine Description:
  781. This routine initializes the i8042 controller, keyboard, and mouse.
  782. Note that it is only called at initialization time. This routine
  783. does not need to synchronize access to the hardware, or synchronize
  784. with the ISRs (they aren't connected yet).
  785. Arguments:
  786. DeviceObject - Pointer to the device object.
  787. Return Value:
  788. None. As a side-effect, however, DeviceExtension->HardwarePresent is set.
  789. --*/
  790. {
  791. NTSTATUS altStatus;
  792. PUCHAR dataAddress, commandAddress;
  793. BOOLEAN canTouchKeyboard, canTouchMouse, firstInit;
  794. PPORT_MOUSE_EXTENSION mouseExtension = Globals.MouseExtension;
  795. PPORT_KEYBOARD_EXTENSION keyboardExtension = Globals.KeyboardExtension;
  796. PAGED_CODE();
  797. Print(DBG_SS_TRACE, ("I8xInitializeHardware: enter\n"));
  798. //
  799. // Grab useful configuration parameters from global data
  800. //
  801. dataAddress = Globals.ControllerData->DeviceRegisters[DataPort];
  802. commandAddress = Globals.ControllerData->DeviceRegisters[CommandPort];
  803. //
  804. // Drain the i8042 output buffer to get rid of stale data.
  805. //
  806. I8xDrainOutputBuffer(dataAddress, commandAddress);
  807. if (!MOUSE_PRESENT()) {
  808. Print(DBG_SS_INFO, ("I8xInitializeHardware: no mouse present\n"));
  809. }
  810. if (!KEYBOARD_PRESENT()) {
  811. Print(DBG_SS_INFO, ("I8xInitializeHardware: no keyboard present\n" ));
  812. }
  813. firstInit = (InitFlags & INIT_FIRST_TIME) ? TRUE : FALSE;
  814. if (firstInit) {
  815. canTouchKeyboard = canTouchMouse = TRUE;
  816. }
  817. else {
  818. canTouchKeyboard = (InitFlags & INIT_KEYBOARD) ? TRUE : FALSE;
  819. canTouchMouse = (InitFlags & INIT_MOUSE) ? TRUE : FALSE;
  820. }
  821. //
  822. // Disable the keyboard and mouse devices.
  823. //
  824. #if 0
  825. //
  826. // NOTE: This is supposedly the "correct" thing to do. However,
  827. // disabling the keyboard device here causes the AMI rev K8 machines
  828. // (e.g., some Northgates) to fail some commands (e.g., the READID
  829. // command).
  830. //
  831. *KeyboardStatus =
  832. I8xPutBytePolled(
  833. (CCHAR) CommandPort,
  834. NO_WAIT_FOR_ACKNOWLEDGE,
  835. (CCHAR) UndefinedDeviceType,
  836. (UCHAR) I8042_DISABLE_KEYBOARD_DEVICE
  837. );
  838. if (!NT_SUCCESS(*KeyboardStatus)) {
  839. Print(DBG_SS_ERROR,
  840. ("I8xInitializeHardware: failed kbd disable, status 0x%x\n",
  841. *KeyboardStatus
  842. ));
  843. I8xManuallyRemoveDevice(GET_COMMON_DATA(keyboardExtension));
  844. }
  845. #endif
  846. //
  847. // We will only run this piece of code when we are coming out of sleep. We
  848. // do this b/c the user might moved the mouse or keyboard and that can lead
  849. // to errors during init.
  850. //
  851. if (KEYBOARD_PRESENT() && firstInit == FALSE && canTouchKeyboard &&
  852. keyboardExtension->ShutdownType == PowerActionSleep) {
  853. I8xPutBytePolled((CCHAR) CommandPort,
  854. NO_WAIT_FOR_ACKNOWLEDGE,
  855. (CCHAR) UndefinedDeviceType,
  856. (UCHAR) I8042_DISABLE_KEYBOARD_DEVICE
  857. );
  858. }
  859. #if 0
  860. //
  861. // NOTE: This is supposedly the "correct thing to do. However,
  862. // disabling the mouse on RadiSys EPC-24 which uses VLSI part number
  863. // VL82C144 (3751E) causes the part to shut down keyboard interrupts.
  864. //
  865. *MouseStatus =
  866. I8xPutBytePolled(
  867. (CCHAR) CommandPort,
  868. NO_WAIT_FOR_ACKNOWLEDGE,
  869. (CCHAR) UndefinedDeviceType,
  870. (UCHAR) I8042_DISABLE_MOUSE_DEVICE
  871. );
  872. if (!NT_SUCCESS(*MouseStatus)) {
  873. Print(DBG_SS_ERROR,
  874. ("I8xInitializeHardware: failed mou disable, status 0x%x\n",
  875. *MouseStatus
  876. ));
  877. I8xManuallyRemoveDevice(GET_COMMON_DATA(mouseExtension));
  878. }
  879. #endif
  880. //
  881. // We will only run this piece of code when we are coming out of sleep. We
  882. // do this b/c the user might moved the mouse or keyboard and that can lead
  883. // to errors during init.
  884. //
  885. if (MOUSE_PRESENT() && firstInit == FALSE && canTouchMouse &&
  886. mouseExtension->ShutdownType == PowerActionSleep) {
  887. I8xPutBytePolled((CCHAR) CommandPort,
  888. NO_WAIT_FOR_ACKNOWLEDGE,
  889. (CCHAR) UndefinedDeviceType,
  890. (UCHAR) I8042_DISABLE_MOUSE_DEVICE
  891. );
  892. }
  893. //
  894. // Drain the i8042 output buffer to get rid of stale data that could
  895. // come in sometime between the previous drain and the time the devices
  896. // are disabled.
  897. //
  898. I8xDrainOutputBuffer(dataAddress, commandAddress);
  899. //
  900. // Setup the keyboard hardware.
  901. //
  902. if (KEYBOARD_PRESENT() && canTouchKeyboard) {
  903. ASSERT(keyboardExtension);
  904. *KeyboardStatus = I8xInitializeKeyboard(keyboardExtension);
  905. if (DEVICE_START_SUCCESS(*KeyboardStatus)) {
  906. //
  907. // If we are not headless and there is no device, we want to
  908. // successfully start the device, but then remove it in
  909. // IRP_MN_QUERY_PNP_DEVICE_STATE. If we fail the start now, we will
  910. // never get the query device state irp.
  911. //
  912. // If we are headless, then do not remove the device. This has the
  913. // side effect of the keyboard being listed when the user enumerates
  914. // all of the keyboards on the machine.
  915. //
  916. if (*KeyboardStatus == STATUS_DEVICE_NOT_CONNECTED) {
  917. if (Globals.Headless == FALSE) {
  918. Print(DBG_SS_INFO, ("kb not connected, removing\n"));
  919. I8xManuallyRemoveDevice(GET_COMMON_DATA(keyboardExtension));
  920. }
  921. else if (firstInit) {
  922. Print(DBG_SS_INFO, ("hiding the kb in the UI\n"));
  923. keyboardExtension->PnpDeviceState |= PNP_DEVICE_DONT_DISPLAY_IN_UI;
  924. IoInvalidateDeviceState(keyboardExtension->PDO);
  925. }
  926. }
  927. }
  928. else {
  929. Print(DBG_SS_ERROR,
  930. ("I8xInitializeHardware: failed kbd init, status 0x%x\n",
  931. *KeyboardStatus
  932. ));
  933. I8xManuallyRemoveDevice(GET_COMMON_DATA(keyboardExtension));
  934. }
  935. }
  936. else {
  937. *KeyboardStatus = STATUS_NO_SUCH_DEVICE;
  938. }
  939. //
  940. // Setup the mouse hardware.
  941. //
  942. if (MOUSE_PRESENT() && canTouchMouse) {
  943. ASSERT(mouseExtension);
  944. *MouseStatus = I8xInitializeMouse(mouseExtension);
  945. if (DEVICE_START_SUCCESS(*MouseStatus)) {
  946. //
  947. // If we are not headless and there is no device, we want to
  948. // successfully start the device, but then remove it in
  949. // IRP_MN_QUERY_PNP_DEVICE_STATE. If we fail the start now, we will
  950. // never get the query device state irp.
  951. //
  952. // If we are headless, then do not remove the device. This has the
  953. // side effect of keeping a mouse pointer on the screen even if
  954. // there is no mouse plugged in and will be listed when a user
  955. // enumerates all of the mice on the machine.
  956. //
  957. // If this is not the initial boot, then do not remove the device
  958. // if it is not responsive no matter what mode we are in.
  959. //
  960. if (*MouseStatus == STATUS_DEVICE_NOT_CONNECTED) {
  961. if (firstInit) {
  962. if (Globals.Headless == FALSE) {
  963. Print(DBG_SS_INFO, ("mouse not connected, removing\n"));
  964. I8xManuallyRemoveDevice(GET_COMMON_DATA(mouseExtension));
  965. }
  966. else {
  967. Print(DBG_SS_INFO, ("hiding mouse in the UI\n"));
  968. mouseExtension->PnpDeviceState |=
  969. PNP_DEVICE_DONT_DISPLAY_IN_UI;
  970. IoInvalidateDeviceState(mouseExtension->PDO);
  971. }
  972. }
  973. else {
  974. //
  975. // Mouse was previously present, but is now unresponsive.
  976. // Hope that it comes back at a later point in time.
  977. //
  978. // FYI: Mouse can be unresponsive because of the PC's BIOS
  979. // password security.
  980. //
  981. /* do nothing */;
  982. }
  983. }
  984. }
  985. else if (firstInit) {
  986. Print(DBG_SS_ERROR,
  987. ("I8xInitializeHardware: failed mou init, status 0x%x\n" ,
  988. *MouseStatus
  989. ));
  990. I8xManuallyRemoveDevice(GET_COMMON_DATA(mouseExtension));
  991. }
  992. }
  993. else {
  994. *MouseStatus = STATUS_NO_SUCH_DEVICE;
  995. }
  996. //
  997. // Enable the keyboard and mouse devices and their interrupts. Note
  998. // that it is required that this operation happen during intialization
  999. // time, because the i8042 Output Buffer Full bit gets set in the
  1000. // Controller Command Byte when the keyboard/mouse is used, even if
  1001. // the device is disabled. Hence, we cannot successfully perform
  1002. // the enable operation later (e.g., when processing
  1003. // IOCTL_INTERNAL_*_ENABLE), because we can't guarantee that
  1004. // I8xPutBytePolled() won't time out waiting for the Output Buffer Full
  1005. // bit to clear, even if we drain the output buffer (because the user
  1006. // could be playing with the mouse/keyboard, and continuing to set the
  1007. // OBF bit). KeyboardEnableCount and MouseEnableCount remain zero until
  1008. // their respective IOCTL_INTERNAL_*_ENABLE call succeeds, so the ISR
  1009. // ignores the unexpected interrupts.
  1010. //
  1011. if (KEYBOARD_PRESENT() && NT_SUCCESS(*KeyboardStatus) && canTouchKeyboard) {
  1012. NTSTATUS status;
  1013. Print(DBG_SS_INFO, ("resetting the LEDs\n"));
  1014. if ((status = I8xPutBytePolled(
  1015. (CCHAR) DataPort,
  1016. WAIT_FOR_ACKNOWLEDGE,
  1017. (CCHAR) KeyboardDeviceType,
  1018. (UCHAR) SET_KEYBOARD_INDICATORS
  1019. )) == STATUS_SUCCESS) {
  1020. status = I8xPutBytePolled(
  1021. (CCHAR) DataPort,
  1022. WAIT_FOR_ACKNOWLEDGE,
  1023. (CCHAR) KeyboardDeviceType,
  1024. (UCHAR) keyboardExtension->KeyboardIndicators.LedFlags
  1025. );
  1026. if (status != STATUS_SUCCESS) {
  1027. Print(DBG_SS_INFO, ("setting LEDs value at mou failure failed 0x%x\n", status));
  1028. }
  1029. }
  1030. else {
  1031. Print(DBG_SS_INFO, ("setting LEDs at mou failure failed 0x%x\n", status));
  1032. }
  1033. }
  1034. //
  1035. // Re-enable the keyboard device in the Controller Command Byte.
  1036. // Note that some of the keyboards will send an ACK back, while
  1037. // others don't. Don't wait for an ACK, but do drain the output
  1038. // buffer afterwards so that an unexpected ACK doesn't mess up
  1039. // successive PutByte operations.
  1040. if (KEYBOARD_PRESENT() && canTouchKeyboard) {
  1041. altStatus = I8xPutBytePolled(
  1042. (CCHAR) CommandPort,
  1043. NO_WAIT_FOR_ACKNOWLEDGE,
  1044. (CCHAR) UndefinedDeviceType,
  1045. (UCHAR) I8042_ENABLE_KEYBOARD_DEVICE
  1046. );
  1047. if (!NT_SUCCESS(altStatus) && firstInit) {
  1048. *KeyboardStatus = altStatus;
  1049. Print(DBG_SS_ERROR,
  1050. ("I8xInitializeHardware: failed kbd re-enable, status 0x%x\n",
  1051. *KeyboardStatus
  1052. ));
  1053. I8xManuallyRemoveDevice(GET_COMMON_DATA(keyboardExtension));
  1054. }
  1055. I8xDrainOutputBuffer(dataAddress, commandAddress);
  1056. }
  1057. //
  1058. // Re-enable the mouse device in the Controller Command Byte.
  1059. //
  1060. if (MOUSE_PRESENT() && canTouchMouse) {
  1061. altStatus = I8xPutBytePolled(
  1062. (CCHAR) CommandPort,
  1063. NO_WAIT_FOR_ACKNOWLEDGE,
  1064. (CCHAR) UndefinedDeviceType,
  1065. (UCHAR) I8042_ENABLE_MOUSE_DEVICE
  1066. );
  1067. //
  1068. // If the mouse or the controller is still unresponsive when coming out
  1069. // of low power, just leave it be and hope it comes out of its confused
  1070. // state later.
  1071. //
  1072. if (!NT_SUCCESS(altStatus) && firstInit) {
  1073. *MouseStatus = altStatus;
  1074. Print(DBG_SS_ERROR,
  1075. ("I8xInitializeHardware: failed mou re-enable, status 0x%x\n",
  1076. altStatus
  1077. ));
  1078. I8xManuallyRemoveDevice(GET_COMMON_DATA(mouseExtension));
  1079. }
  1080. I8xDrainOutputBuffer(dataAddress, commandAddress);
  1081. }
  1082. Print(DBG_SS_TRACE,
  1083. ("I8xInitializeHardware (k 0x%x, m 0x%x)\n",
  1084. *KeyboardStatus,
  1085. *MouseStatus
  1086. ));
  1087. }
  1088. VOID
  1089. I8xPutByteAsynchronous(
  1090. IN CCHAR PortType,
  1091. IN UCHAR Byte
  1092. )
  1093. /*++
  1094. Routine Description:
  1095. This routine sends a command or data byte to the controller or keyboard
  1096. or mouse, asynchronously. It does not wait for acknowledgment.
  1097. If the hardware was not ready for input, the byte is not sent.
  1098. Arguments:
  1099. PortType - If CommandPort, send the byte to the command register,
  1100. otherwise send it to the data register.
  1101. Byte - The byte to send to the hardware.
  1102. Return Value:
  1103. None.
  1104. --*/
  1105. {
  1106. ULONG i;
  1107. Print(DBG_BUFIO_TRACE, ("I8xPutByteAsynchronous: enter\n" ));
  1108. //
  1109. // Make sure the Input Buffer Full controller status bit is clear.
  1110. // Time out if necessary.
  1111. //
  1112. i = 0;
  1113. while ((i++ < (ULONG)Globals.ControllerData->Configuration.PollingIterations) &&
  1114. (I8X_GET_STATUS_BYTE(Globals.ControllerData->DeviceRegisters[CommandPort])
  1115. & INPUT_BUFFER_FULL)) {
  1116. //
  1117. // Do nothing.
  1118. //
  1119. Print(DBG_BUFIO_NOISE,
  1120. ("I8xPutByteAsynchronous: wait for IBF and OBF to clear\n"
  1121. ));
  1122. }
  1123. if (i >= (ULONG)Globals.ControllerData->Configuration.PollingIterations) {
  1124. Print(DBG_BUFIO_ERROR,
  1125. ("I8xPutByteAsynchronous: exceeded number of retries\n"
  1126. ));
  1127. return;
  1128. }
  1129. //
  1130. // Send the byte to the appropriate (command/data) hardware register.
  1131. //
  1132. if (PortType == CommandPort) {
  1133. Print(DBG_BUFIO_INFO,
  1134. ("I8xPutByteAsynchronous: sending 0x%x to command port\n",
  1135. Byte
  1136. ));
  1137. I8X_PUT_COMMAND_BYTE(Globals.ControllerData->DeviceRegisters[CommandPort], Byte);
  1138. } else {
  1139. Print(DBG_BUFIO_INFO,
  1140. ("I8xPutByteAsynchronous: sending 0x%x to data port\n",
  1141. Byte
  1142. ));
  1143. I8X_PUT_DATA_BYTE(Globals.ControllerData->DeviceRegisters[DataPort], Byte);
  1144. }
  1145. Print(DBG_BUFIO_TRACE, ("I8xPutByteAsynchronous: exit\n"));
  1146. }
  1147. NTSTATUS
  1148. I8xPutBytePolled(
  1149. IN CCHAR PortType,
  1150. IN BOOLEAN WaitForAcknowledge,
  1151. IN CCHAR AckDeviceType,
  1152. IN UCHAR Byte
  1153. )
  1154. /*++
  1155. Routine Description:
  1156. This routine sends a command or data byte to the controller or keyboard
  1157. or mouse, in polling mode. It waits for acknowledgment and resends
  1158. the command/data if necessary.
  1159. Arguments:
  1160. PortType - If CommandPort, send the byte to the command register,
  1161. otherwise send it to the data register.
  1162. WaitForAcknowledge - If true, wait for an ACK back from the hardware.
  1163. AckDeviceType - Indicates which device we expect to get the ACK back
  1164. from.
  1165. Byte - The byte to send to the hardware.
  1166. Return Value:
  1167. STATUS_IO_TIMEOUT - The hardware was not ready for input or did not
  1168. respond.
  1169. STATUS_SUCCESS - The byte was successfully sent to the hardware.
  1170. --*/
  1171. {
  1172. ULONG i,j;
  1173. UCHAR response;
  1174. NTSTATUS status;
  1175. BOOLEAN keepTrying;
  1176. PUCHAR dataAddress, commandAddress;
  1177. Print(DBG_BUFIO_TRACE, ("I8xPutBytePolled: enter\n"));
  1178. if (AckDeviceType == MouseDeviceType) {
  1179. //
  1180. // We need to precede a PutByte for the mouse device with
  1181. // a PutByte that tells the controller that the next byte
  1182. // sent to the controller should go to the auxiliary device
  1183. // (by default it would go to the keyboard device). We
  1184. // do this by calling I8xPutBytePolled recursively to send
  1185. // the "send next byte to auxiliary device" command
  1186. // before sending the intended byte to the mouse. Note that
  1187. // there is only one level of recursion, since the AckDeviceType
  1188. // for the recursive call is guaranteed to be UndefinedDeviceType,
  1189. // and hence this IF statement will evaluate to FALSE.
  1190. //
  1191. I8xPutBytePolled(
  1192. (CCHAR) CommandPort,
  1193. NO_WAIT_FOR_ACKNOWLEDGE,
  1194. (CCHAR) UndefinedDeviceType,
  1195. (UCHAR) I8042_WRITE_TO_AUXILIARY_DEVICE
  1196. );
  1197. }
  1198. dataAddress = Globals.ControllerData->DeviceRegisters[DataPort];
  1199. commandAddress = Globals.ControllerData->DeviceRegisters[CommandPort];
  1200. for (j=0;j < (ULONG)Globals.ControllerData->Configuration.ResendIterations;j++) {
  1201. //
  1202. // Make sure the Input Buffer Full controller status bit is clear.
  1203. // Time out if necessary.
  1204. //
  1205. i = 0;
  1206. while ((i++ < (ULONG)Globals.ControllerData->Configuration.PollingIterations)
  1207. && (I8X_GET_STATUS_BYTE(commandAddress) & INPUT_BUFFER_FULL)) {
  1208. Print(DBG_BUFIO_NOISE, ("I8xPutBytePolled: stalling\n"));
  1209. KeStallExecutionProcessor(
  1210. Globals.ControllerData->Configuration.StallMicroseconds
  1211. );
  1212. }
  1213. if (i >= (ULONG)Globals.ControllerData->Configuration.PollingIterations) {
  1214. Print((DBG_BUFIO_MASK & ~DBG_BUFIO_INFO),
  1215. ("I8xPutBytePolled: timing out\n"
  1216. ));
  1217. status = STATUS_IO_TIMEOUT;
  1218. break;
  1219. }
  1220. //
  1221. // Drain the i8042 output buffer to get rid of stale data.
  1222. //
  1223. I8xDrainOutputBuffer(dataAddress, commandAddress);
  1224. //
  1225. // Send the byte to the appropriate (command/data) hardware register.
  1226. //
  1227. if (PortType == CommandPort) {
  1228. Print(DBG_BUFIO_INFO,
  1229. ("I8xPutBytePolled: sending 0x%x to command port\n",
  1230. Byte
  1231. ));
  1232. I8X_PUT_COMMAND_BYTE(commandAddress, Byte);
  1233. } else {
  1234. Print(DBG_BUFIO_INFO,
  1235. ("I8xPutBytePolled: sending 0x%x to data port\n",
  1236. Byte
  1237. ));
  1238. I8X_PUT_DATA_BYTE(dataAddress, Byte);
  1239. }
  1240. //
  1241. // If we don't need to wait for an ACK back from the controller,
  1242. // set the status and break out of the for loop.
  1243. //
  1244. //
  1245. if (WaitForAcknowledge == NO_WAIT_FOR_ACKNOWLEDGE) {
  1246. status = STATUS_SUCCESS;
  1247. break;
  1248. }
  1249. //
  1250. // Wait for an ACK back from the controller. If we get an ACK,
  1251. // the operation was successful. If we get a RESEND, break out to
  1252. // the for loop and try the operation again. Ignore anything other
  1253. // than ACK or RESEND.
  1254. //
  1255. Print(DBG_BUFIO_NOISE,
  1256. ("I8xPutBytePolled: waiting for ACK\n"
  1257. ));
  1258. keepTrying = FALSE;
  1259. while ((status = I8xGetBytePolled(
  1260. AckDeviceType,
  1261. &response
  1262. )
  1263. ) == STATUS_SUCCESS) {
  1264. if (response == ACKNOWLEDGE) {
  1265. Print(DBG_BUFIO_NOISE, ("I8xPutBytePolled: got ACK\n"));
  1266. break;
  1267. } else if (response == RESEND) {
  1268. Print(DBG_BUFIO_NOISE, ("I8xPutBytePolled: got RESEND\n"));
  1269. if (AckDeviceType == MouseDeviceType) {
  1270. //
  1271. // We need to precede the "resent" PutByte for the
  1272. // mouse device with a PutByte that tells the controller
  1273. // that the next byte sent to the controller should go
  1274. // to the auxiliary device (by default it would go to
  1275. // the keyboard device). We do this by calling
  1276. // I8xPutBytePolled recursively to send the "send next
  1277. // byte to auxiliary device" command before resending
  1278. // the byte to the mouse. Note that there is only one
  1279. // level of recursion, since the AckDeviceType for the
  1280. // recursive call is guaranteed to be UndefinedDeviceType.
  1281. //
  1282. I8xPutBytePolled(
  1283. (CCHAR) CommandPort,
  1284. NO_WAIT_FOR_ACKNOWLEDGE,
  1285. (CCHAR) UndefinedDeviceType,
  1286. (UCHAR) I8042_WRITE_TO_AUXILIARY_DEVICE
  1287. );
  1288. }
  1289. keepTrying = TRUE;
  1290. break;
  1291. }
  1292. //
  1293. // Ignore any other response, and keep trying.
  1294. //
  1295. }
  1296. if (!keepTrying)
  1297. break;
  1298. }
  1299. //
  1300. // Check to see if the number of allowable retries was exceeded.
  1301. //
  1302. if (j >= (ULONG)Globals.ControllerData->Configuration.ResendIterations) {
  1303. Print(DBG_BUFIO_ERROR,
  1304. ("I8xPutBytePolled: exceeded number of retries\n"
  1305. ));
  1306. status = STATUS_IO_TIMEOUT;
  1307. }
  1308. Print(DBG_BUFIO_TRACE, ("I8xPutBytePolled: exit\n"));
  1309. return(status);
  1310. }
  1311. NTSTATUS
  1312. I8xPutControllerCommand(
  1313. IN UCHAR Byte
  1314. )
  1315. /*++
  1316. Routine Description:
  1317. This routine writes the 8042 Controller Command Byte.
  1318. Arguments:
  1319. Byte - The byte to store in the Controller Command Byte.
  1320. Return Value:
  1321. Status is returned.
  1322. --*/
  1323. {
  1324. NTSTATUS status;
  1325. Print(DBG_BUFIO_TRACE, ("I8xPutControllerCommand: enter\n"));
  1326. //
  1327. // Send a command to the i8042 controller to write the Controller
  1328. // Command Byte.
  1329. //
  1330. status = I8xPutBytePolled(
  1331. (CCHAR) CommandPort,
  1332. NO_WAIT_FOR_ACKNOWLEDGE,
  1333. (CCHAR) UndefinedDeviceType,
  1334. (UCHAR) I8042_WRITE_CONTROLLER_COMMAND_BYTE
  1335. );
  1336. if (!NT_SUCCESS(status)) {
  1337. return(status);
  1338. }
  1339. //
  1340. // Write the byte through the i8042 data port.
  1341. //
  1342. Print(DBG_BUFIO_TRACE, ("I8xPutControllerCommand: exit\n"));
  1343. return(I8xPutBytePolled(
  1344. (CCHAR) DataPort,
  1345. NO_WAIT_FOR_ACKNOWLEDGE,
  1346. (CCHAR) UndefinedDeviceType,
  1347. (UCHAR) Byte
  1348. )
  1349. );
  1350. }
  1351. BOOLEAN
  1352. I8xDetermineSharedInterrupts(VOID)
  1353. {
  1354. //
  1355. // This was a specific fix for Jensen Alphas. Since we do not support them
  1356. // anymore, ifdef this code away.
  1357. //
  1358. #ifdef JENSEN
  1359. RTL_QUERY_REGISTRY_TABLE jensenTable[2] = {0};
  1360. UNICODE_STRING jensenData;
  1361. UNICODE_STRING jensenValue;
  1362. WCHAR jensenBuffer[256];
  1363. BOOLEAN shareInterrupts = FALSE;
  1364. //
  1365. // Check to see if this is a Jensen alpha. If it is, then
  1366. // we'll have to change the way we enable and disable interrupts
  1367. //
  1368. jensenData.Length = 0;
  1369. jensenData.MaximumLength = 512;
  1370. jensenData.Buffer = (PWCHAR)&jensenBuffer[0];
  1371. RtlInitUnicodeString(&jensenValue,
  1372. L"Jensen"
  1373. );
  1374. RtlZeroMemory(jensenTable, sizeof(RTL_QUERY_REGISTRY_TABLE)*2);
  1375. jensenTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT
  1376. | RTL_QUERY_REGISTRY_REQUIRED;
  1377. jensenTable[0].Name = L"Identifier";
  1378. jensenTable[0].EntryContext = &jensenData;
  1379. if (NT_SUCCESS(RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE
  1380. | RTL_REGISTRY_OPTIONAL,
  1381. L"\\REGISTRY\\MACHINE\\HARDWARE"
  1382. L"\\DESCRIPTION\\SYSTEM",
  1383. &jensenTable[0],
  1384. NULL,
  1385. NULL))) {
  1386. //
  1387. // Skip past the DEC-XX Portion of the name string.
  1388. // Be carful and make sure we have at least that much data.
  1389. //
  1390. if (jensenData.Length <= (sizeof(WCHAR)*6)) {
  1391. return FALSE;
  1392. }
  1393. else {
  1394. jensenData.Length -= (sizeof(WCHAR)*6);
  1395. jensenData.MaximumLength -= (sizeof(WCHAR)*6);
  1396. jensenData.Buffer = (PWCHAR)&jensenBuffer[sizeof(WCHAR)*6];
  1397. Print(DBG_SS_NOISE, ("Machine name is %ws\n", jensenData.Buffer));
  1398. shareInterrupts = RtlEqualUnicodeString(&jensenData,
  1399. &jensenValue,
  1400. FALSE
  1401. );
  1402. }
  1403. }
  1404. return shareInterrupts;
  1405. #else
  1406. return FALSE;
  1407. #endif
  1408. }
  1409. VOID
  1410. I8xServiceParameters(
  1411. IN PUNICODE_STRING RegistryPath
  1412. )
  1413. /*++
  1414. Routine Description:
  1415. This routine retrieves this driver's service parameters information
  1416. from the registry.
  1417. Arguments:
  1418. RegistryPath - Pointer to the null-terminated Unicode name of the
  1419. registry path for this driver.
  1420. KeyboardDeviceName - Pointer to the Unicode string that will receive
  1421. the keyboard port device name.
  1422. PointerDeviceName - Pointer to the Unicode string that will receive
  1423. the pointer port device name.
  1424. Return Value:
  1425. None. As a side-effect, sets fields in DeviceExtension->Configuration.
  1426. --*/
  1427. {
  1428. NTSTATUS status = STATUS_SUCCESS;
  1429. PI8042_CONFIGURATION_INFORMATION configuration;
  1430. PRTL_QUERY_REGISTRY_TABLE parameters = NULL;
  1431. PWSTR path = NULL;
  1432. ULONG defaultDataQueueSize = DATA_QUEUE_SIZE;
  1433. ULONG defaultDebugFlags = DEFAULT_DEBUG_FLAGS;
  1434. ULONG defaultIsrDebugFlags = 0L;
  1435. ULONG defaultBreakOnSysRq = 1;
  1436. ULONG defaultHeadless = 0;
  1437. ULONG defaultReportResetErrors = 0;
  1438. ULONG pollingIterations = 0;
  1439. ULONG pollingIterationsMaximum = 0;
  1440. ULONG resendIterations = 0;
  1441. ULONG breakOnSysRq = 1;
  1442. ULONG headless = 0;
  1443. ULONG reportResetErrors = 0;
  1444. ULONG i = 0;
  1445. UNICODE_STRING parametersPath;
  1446. USHORT defaultPollingIterations = I8042_POLLING_DEFAULT;
  1447. USHORT defaultPollingIterationsMaximum = I8042_POLLING_MAXIMUM;
  1448. USHORT defaultResendIterations = I8042_RESEND_DEFAULT;
  1449. USHORT queries = 7;
  1450. #if I8042_VERBOSE
  1451. queries += 2;
  1452. #endif
  1453. configuration = &(Globals.ControllerData->Configuration);
  1454. configuration->StallMicroseconds = I8042_STALL_DEFAULT;
  1455. parametersPath.Buffer = NULL;
  1456. configuration->SharedInterrupts = I8xDetermineSharedInterrupts();
  1457. //
  1458. // Registry path is already null-terminated, so just use it.
  1459. //
  1460. path = RegistryPath->Buffer;
  1461. if (NT_SUCCESS(status)) {
  1462. //
  1463. // Allocate the Rtl query table.
  1464. //
  1465. parameters = ExAllocatePool(
  1466. PagedPool,
  1467. sizeof(RTL_QUERY_REGISTRY_TABLE) * (queries + 1)
  1468. );
  1469. if (!parameters) {
  1470. Print(DBG_SS_ERROR,
  1471. ("%s: couldn't allocate table for Rtl query to %ws for %ws\n",
  1472. pFncServiceParameters,
  1473. pwParameters,
  1474. path
  1475. ));
  1476. status = STATUS_UNSUCCESSFUL;
  1477. } else {
  1478. RtlZeroMemory(
  1479. parameters,
  1480. sizeof(RTL_QUERY_REGISTRY_TABLE) * (queries + 1)
  1481. );
  1482. //
  1483. // Form a path to this driver's Parameters subkey.
  1484. //
  1485. RtlInitUnicodeString( &parametersPath, NULL );
  1486. parametersPath.MaximumLength = RegistryPath->Length +
  1487. (wcslen(pwParameters) * sizeof(WCHAR) ) + sizeof(UNICODE_NULL);
  1488. parametersPath.Buffer = ExAllocatePool(
  1489. PagedPool,
  1490. parametersPath.MaximumLength
  1491. );
  1492. if (!parametersPath.Buffer) {
  1493. Print(DBG_SS_ERROR,
  1494. ("%s: Couldn't allocate string for path to %ws for %ws\n",
  1495. pFncServiceParameters,
  1496. pwParameters,
  1497. path
  1498. ));
  1499. status = STATUS_UNSUCCESSFUL;
  1500. }
  1501. }
  1502. }
  1503. if (NT_SUCCESS(status)) {
  1504. //
  1505. // Form the parameters path.
  1506. //
  1507. RtlZeroMemory(
  1508. parametersPath.Buffer,
  1509. parametersPath.MaximumLength
  1510. );
  1511. RtlAppendUnicodeToString(
  1512. &parametersPath,
  1513. path
  1514. );
  1515. RtlAppendUnicodeToString(
  1516. &parametersPath,
  1517. pwParameters
  1518. );
  1519. Print(DBG_SS_INFO,
  1520. ("%s: %ws path is %ws\n",
  1521. pFncServiceParameters,
  1522. pwParameters,
  1523. parametersPath.Buffer
  1524. ));
  1525. //
  1526. // Gather all of the "user specified" information from
  1527. // the registry.
  1528. //
  1529. parameters[i].Flags = RTL_QUERY_REGISTRY_DIRECT;
  1530. parameters[i].Name = pwResendIterations;
  1531. parameters[i].EntryContext = &resendIterations;
  1532. parameters[i].DefaultType = REG_DWORD;
  1533. parameters[i].DefaultData = &defaultResendIterations;
  1534. parameters[i].DefaultLength = sizeof(USHORT);
  1535. parameters[++i].Flags = RTL_QUERY_REGISTRY_DIRECT;
  1536. parameters[i].Name = pwPollingIterations;
  1537. parameters[i].EntryContext = &pollingIterations;
  1538. parameters[i].DefaultType = REG_DWORD;
  1539. parameters[i].DefaultData = &defaultPollingIterations;
  1540. parameters[i].DefaultLength = sizeof(USHORT);
  1541. parameters[++i].Flags = RTL_QUERY_REGISTRY_DIRECT;
  1542. parameters[i].Name = pwPollingIterationsMaximum;
  1543. parameters[i].EntryContext = &pollingIterationsMaximum;
  1544. parameters[i].DefaultType = REG_DWORD;
  1545. parameters[i].DefaultData = &defaultPollingIterationsMaximum;
  1546. parameters[i].DefaultLength = sizeof(USHORT);
  1547. parameters[++i].Flags = RTL_QUERY_REGISTRY_DIRECT;
  1548. parameters[i].Name = L"BreakOnSysRq";
  1549. parameters[i].EntryContext = &breakOnSysRq;
  1550. parameters[i].DefaultType = REG_DWORD;
  1551. parameters[i].DefaultData = &defaultBreakOnSysRq;
  1552. parameters[i].DefaultLength = sizeof(ULONG);
  1553. parameters[++i].Flags = RTL_QUERY_REGISTRY_DIRECT;
  1554. parameters[i].Name = L"Headless";
  1555. parameters[i].EntryContext = &headless;
  1556. parameters[i].DefaultType = REG_DWORD;
  1557. parameters[i].DefaultData = &defaultHeadless;
  1558. parameters[i].DefaultLength = sizeof(ULONG);
  1559. parameters[++i].Flags = RTL_QUERY_REGISTRY_DIRECT;
  1560. parameters[i].Name = L"ReportResetErrors";
  1561. parameters[i].EntryContext = &reportResetErrors;
  1562. parameters[i].DefaultType = REG_DWORD;
  1563. parameters[i].DefaultData = &defaultReportResetErrors;
  1564. parameters[i].DefaultLength = sizeof(ULONG);
  1565. #if I8042_VERBOSE
  1566. parameters[++i].Flags = RTL_QUERY_REGISTRY_DIRECT;
  1567. parameters[i].Name = pwDebugFlags;
  1568. parameters[i].EntryContext = &Globals.DebugFlags;
  1569. parameters[i].DefaultType = REG_DWORD;
  1570. parameters[i].DefaultData = &defaultDebugFlags;
  1571. parameters[i].DefaultLength = sizeof(ULONG);
  1572. parameters[++i].Flags = RTL_QUERY_REGISTRY_DIRECT;
  1573. parameters[i].Name = pwIsrDebugFlags;
  1574. parameters[i].EntryContext = &Globals.IsrDebugFlags;
  1575. parameters[i].DefaultType = REG_DWORD;
  1576. parameters[i].DefaultData = &defaultIsrDebugFlags;
  1577. parameters[i].DefaultLength = sizeof(ULONG);
  1578. // 16
  1579. #endif // I8042_VERBOSE
  1580. // ASSERT( ((LONG) i) == (queries-1) );
  1581. status = RtlQueryRegistryValues(
  1582. RTL_REGISTRY_ABSOLUTE | RTL_REGISTRY_OPTIONAL,
  1583. parametersPath.Buffer,
  1584. parameters,
  1585. NULL,
  1586. NULL
  1587. );
  1588. if (!NT_SUCCESS(status)) {
  1589. Print(DBG_SS_INFO,
  1590. ("%s: RtlQueryRegistryValues failed with 0x%x\n",
  1591. pFncServiceParameters,
  1592. status
  1593. ));
  1594. }
  1595. }
  1596. if (!NT_SUCCESS(status)) {
  1597. //
  1598. // Go ahead and assign driver defaults.
  1599. //
  1600. configuration->ResendIterations = defaultResendIterations;
  1601. configuration->PollingIterations = defaultPollingIterations;
  1602. configuration->PollingIterationsMaximum =
  1603. defaultPollingIterationsMaximum;
  1604. }
  1605. else {
  1606. configuration->ResendIterations = (USHORT) resendIterations;
  1607. configuration->PollingIterations = (USHORT) pollingIterations;
  1608. configuration->PollingIterationsMaximum =
  1609. (USHORT) pollingIterationsMaximum;
  1610. if (breakOnSysRq) {
  1611. Globals.BreakOnSysRq = TRUE;
  1612. Print(DBG_SS_NOISE, ("breaking on SysRq\n"));
  1613. }
  1614. else {
  1615. Print(DBG_SS_NOISE, ("NOT breaking on SysRq\n"));
  1616. }
  1617. if (headless) {
  1618. Globals.Headless = TRUE;
  1619. Print(DBG_SS_NOISE, ("headless\n"));
  1620. }
  1621. else {
  1622. Globals.Headless = FALSE;
  1623. Print(DBG_SS_NOISE, ("NOT headless\n"));
  1624. }
  1625. if (reportResetErrors) {
  1626. Globals.ReportResetErrors = TRUE;
  1627. Print(DBG_SS_NOISE,
  1628. ("reporting reset errors to system event log\n"));
  1629. }
  1630. else {
  1631. Globals.ReportResetErrors = FALSE;
  1632. Print(DBG_SS_NOISE,
  1633. ("NOT reporting reset errors to system event log\n"));
  1634. }
  1635. }
  1636. Print(DBG_SS_NOISE, ("I8xServiceParameters results..\n"));
  1637. Print(DBG_SS_NOISE,
  1638. ("\tDebug flags are 0x%x, Isr Debug flags are 0x%x\n",
  1639. Globals.DebugFlags,
  1640. Globals.IsrDebugFlags
  1641. ));
  1642. Print(DBG_SS_NOISE,
  1643. ("\tInterrupts are %s shared\n",
  1644. configuration->SharedInterrupts ? "" : "not"
  1645. ));
  1646. Print(DBG_SS_NOISE,
  1647. ("\tStallMicroseconds = %d\n",
  1648. configuration->StallMicroseconds
  1649. ));
  1650. Print(DBG_SS_NOISE,
  1651. (pDumpDecimal,
  1652. pwResendIterations,
  1653. configuration->ResendIterations
  1654. ));
  1655. Print(DBG_SS_NOISE,
  1656. (pDumpDecimal,
  1657. pwPollingIterations,
  1658. configuration->PollingIterations
  1659. ));
  1660. Print(DBG_SS_NOISE,
  1661. (pDumpDecimal,
  1662. pwPollingIterationsMaximum,
  1663. configuration->PollingIterationsMaximum
  1664. ));
  1665. //
  1666. // Free the allocated memory before returning.
  1667. //
  1668. if (parametersPath.Buffer)
  1669. ExFreePool(parametersPath.Buffer);
  1670. if (parameters)
  1671. ExFreePool(parameters);
  1672. }
  1673. VOID
  1674. I8xTransmitControllerCommand(
  1675. IN PI8042_TRANSMIT_CCB_CONTEXT TransmitCCBContext
  1676. )
  1677. /*++
  1678. Routine Description:
  1679. This routine reads the 8042 Controller Command Byte, performs an AND
  1680. or OR operation using the specified ByteMask, and writes the resulting
  1681. ControllerCommandByte.
  1682. Arguments:
  1683. Context - Pointer to a structure containing the HardwareDisableEnableMask,
  1684. the AndOperation boolean, and the ByteMask to apply to the Controller
  1685. Command Byte before it is rewritten.
  1686. Return Value:
  1687. None. Status is returned in the Context structure.
  1688. --*/
  1689. {
  1690. UCHAR controllerCommandByte;
  1691. UCHAR verifyCommandByte;
  1692. PIO_ERROR_LOG_PACKET errorLogEntry;
  1693. LARGE_INTEGER endTime, curTime;
  1694. Print(DBG_BUFIO_TRACE, ("I8xTransmitControllerCommand: enter\n"));
  1695. //
  1696. // Get the current Controller Command Byte.
  1697. //
  1698. TransmitCCBContext->Status =
  1699. I8xGetControllerCommand(
  1700. TransmitCCBContext->HardwareDisableEnableMask,
  1701. &controllerCommandByte
  1702. );
  1703. if (!NT_SUCCESS(TransmitCCBContext->Status)) {
  1704. return;
  1705. }
  1706. Print(DBG_BUFIO_INFO,
  1707. ("I8xTransmitControllerCommand: current CCB 0x%x\n",
  1708. controllerCommandByte
  1709. ));
  1710. //
  1711. // Diddle the desired bits in the Controller Command Byte.
  1712. //
  1713. if (TransmitCCBContext->AndOperation) {
  1714. controllerCommandByte &= TransmitCCBContext->ByteMask;
  1715. }
  1716. else {
  1717. controllerCommandByte |= TransmitCCBContext->ByteMask;
  1718. }
  1719. KeQueryTickCount(&curTime);
  1720. endTime.QuadPart = curTime.QuadPart +
  1721. (LONGLONG)( 2 * // Try for 2 seconds
  1722. KeQueryTimeIncrement() *
  1723. 1000 * 10000 );
  1724. // SECOND_TO_MILLISEC * MILLISEC_TO_100NS
  1725. //
  1726. // Write the new Controller Command Byte.
  1727. //
  1728. do{
  1729. TransmitCCBContext->Status =
  1730. I8xPutControllerCommand(controllerCommandByte);
  1731. Print(DBG_BUFIO_INFO,
  1732. ("I8xTransmitControllerCommand: new CCB 0x%x\n",
  1733. controllerCommandByte
  1734. ));
  1735. //
  1736. // Verify that the new Controller Command Byte really got written.
  1737. //
  1738. TransmitCCBContext->Status =
  1739. I8xGetControllerCommand(
  1740. TransmitCCBContext->HardwareDisableEnableMask,
  1741. &verifyCommandByte
  1742. );
  1743. if (verifyCommandByte == 0xff) {
  1744. //
  1745. // Stall for 50 microseconds and retry
  1746. //
  1747. KeStallExecutionProcessor(50);
  1748. }
  1749. else {
  1750. break;
  1751. }
  1752. KeQueryTickCount(&curTime);
  1753. } while( endTime.QuadPart > curTime.QuadPart );
  1754. if (NT_SUCCESS(TransmitCCBContext->Status)
  1755. && (verifyCommandByte != controllerCommandByte)
  1756. && (verifyCommandByte != ACKNOWLEDGE)
  1757. // && (verifyCommandByte != KEYBOARD_RESET)
  1758. ) {
  1759. TransmitCCBContext->Status = STATUS_DEVICE_DATA_ERROR;
  1760. Print(DBG_BUFIO_ERROR,
  1761. ("I8xTransmitControllerCommand: wrote 0x%x, failed verification (0x%x)\n",
  1762. (int) controllerCommandByte,
  1763. (int) verifyCommandByte
  1764. ));
  1765. if (KeGetCurrentIrql() <= DISPATCH_LEVEL) {
  1766. //
  1767. // Log an error only if we are running at dispatch or below
  1768. //
  1769. errorLogEntry = (PIO_ERROR_LOG_PACKET)
  1770. IoAllocateErrorLogEntry((Globals.KeyboardExtension ?
  1771. Globals.KeyboardExtension->Self :
  1772. Globals.MouseExtension->Self),
  1773. sizeof(IO_ERROR_LOG_PACKET)
  1774. + (4 * sizeof(ULONG))
  1775. );
  1776. if (errorLogEntry != NULL) {
  1777. errorLogEntry->ErrorCode = I8042_CCB_WRITE_FAILED;
  1778. errorLogEntry->DumpDataSize = 4 * sizeof(ULONG);
  1779. errorLogEntry->SequenceNumber = 0;
  1780. errorLogEntry->MajorFunctionCode = 0;
  1781. errorLogEntry->IoControlCode = 0;
  1782. errorLogEntry->RetryCount = 0;
  1783. errorLogEntry->UniqueErrorValue = 80;
  1784. errorLogEntry->FinalStatus = TransmitCCBContext->Status;
  1785. errorLogEntry->DumpData[0] = KBDMOU_COULD_NOT_SEND_PARAM;
  1786. errorLogEntry->DumpData[1] = DataPort;
  1787. errorLogEntry->DumpData[2] = I8042_WRITE_CONTROLLER_COMMAND_BYTE;
  1788. errorLogEntry->DumpData[3] = controllerCommandByte;
  1789. IoWriteErrorLogEntry(errorLogEntry);
  1790. }
  1791. }
  1792. }
  1793. Print(DBG_BUFIO_TRACE, ("I8xTransmitControllerCommand: exit\n"));
  1794. return;
  1795. }