Source code of Windows XP (NT5)
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.

2224 lines
67 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. // Disable the interrupts on the i8042
  653. //
  654. I8xToggleInterrupts(FALSE);
  655. Print(DBG_POWER_NOISE, ("item ... starting init\n"));
  656. I8xInitializeHardware(&keyboardStatus, &mouseStatus, initFlags);
  657. //
  658. // Reset PoweredDevices so that we can keep track of the powered device
  659. // the next time the machine is power managed off.
  660. //
  661. if (!DEVICE_START_SUCCESS(keyboardStatus)) {
  662. Print(DBG_SS_ERROR,
  663. ("I8xReinitializeHardware for kb failed, 0x%x\n",
  664. keyboardStatus
  665. ));
  666. }
  667. if (!DEVICE_START_SUCCESS(mouseStatus)) {
  668. Print(DBG_SS_ERROR,
  669. ("I8xReinitializeHardware for mou failed, 0x%x\n",
  670. mouseStatus
  671. ));
  672. }
  673. if (DEVICE_START_SUCCESS(keyboardStatus) || DEVICE_START_SUCCESS(mouseStatus)) {
  674. //
  675. // Enable the interrupts on the i8042
  676. //
  677. I8xToggleInterrupts(TRUE);
  678. }
  679. if (DEVICE_START_SUCCESS(mouseStatus) || mouseStatus == STATUS_IO_TIMEOUT) {
  680. Print(DBG_SS_NOISE, ("reinit, mouse status == 0x%x\n", mouseStatus));
  681. if (mouOutstandingPowerIrp) {
  682. stack = IoGetCurrentIrpStackLocation(mouOutstandingPowerIrp);
  683. ASSERT(stack->Parameters.Power.State.DeviceState == PowerDeviceD0);
  684. mouseExtension->PowerState = stack->Parameters.Power.State.DeviceState;
  685. mouseExtension->ShutdownType = PowerActionNone;
  686. PoSetPowerState(mouseExtension->Self,
  687. stack->Parameters.Power.Type,
  688. stack->Parameters.Power.State
  689. );
  690. }
  691. if (IS_LEVEL_TRIGGERED(mouseExtension)) {
  692. Print(DBG_SS_NOISE,
  693. ("mouse is level triggered, reconnecting INT\n"));
  694. ASSERT(mouseExtension->InterruptObject == NULL);
  695. I8xMouseConnectInterruptAndEnable(mouseExtension, FALSE);
  696. ASSERT(mouseExtension->InterruptObject != NULL);
  697. }
  698. if (mouseStatus != STATUS_IO_TIMEOUT &&
  699. mouseStatus != STATUS_DEVICE_NOT_CONNECTED) {
  700. if (mouseExtension->InitializePolled) {
  701. I8xMouseEnableTransmission(mouseExtension);
  702. }
  703. else {
  704. I8X_MOUSE_INIT_COUNTERS(mouseExtension);
  705. I8xResetMouse(mouseExtension);
  706. }
  707. }
  708. else {
  709. //
  710. // Came back from low power and device didn't respond, pretend that
  711. // it is there, so that if the user plugs in a mouse later on, we
  712. // will be able to init it and make it usable
  713. //
  714. ;
  715. }
  716. mouseStatus = STATUS_SUCCESS;
  717. }
  718. //
  719. // Complete the irp no matter how the device came back
  720. //
  721. if (mouOutstandingPowerIrp) {
  722. mouOutstandingPowerIrp->IoStatus.Status = mouseStatus;
  723. mouOutstandingPowerIrp->IoStatus.Information = 0;
  724. PoStartNextPowerIrp(mouOutstandingPowerIrp);
  725. IoCompleteRequest(mouOutstandingPowerIrp, IO_NO_INCREMENT);
  726. IoReleaseRemoveLock(&mouseExtension->RemoveLock,
  727. mouOutstandingPowerIrp);
  728. }
  729. if (DEVICE_START_SUCCESS(keyboardStatus)) {
  730. if (kbOutstandingPowerIrp) {
  731. stack = IoGetCurrentIrpStackLocation(kbOutstandingPowerIrp);
  732. ASSERT(stack->Parameters.Power.State.DeviceState == PowerDeviceD0);
  733. keyboardExtension->PowerState = stack->Parameters.Power.State.DeviceState;
  734. keyboardExtension->ShutdownType = PowerActionNone;
  735. PoSetPowerState(keyboardExtension->Self,
  736. stack->Parameters.Power.Type,
  737. stack->Parameters.Power.State
  738. );
  739. }
  740. keyboardStatus = STATUS_SUCCESS;
  741. }
  742. //
  743. // Complete the irp no matter how the device came back
  744. //
  745. if (kbOutstandingPowerIrp) {
  746. kbOutstandingPowerIrp->IoStatus.Status = keyboardStatus;
  747. kbOutstandingPowerIrp->IoStatus.Information = 0;
  748. PoStartNextPowerIrp(kbOutstandingPowerIrp);
  749. IoCompleteRequest(kbOutstandingPowerIrp, IO_NO_INCREMENT);
  750. IoReleaseRemoveLock(&keyboardExtension->RemoveLock,
  751. kbOutstandingPowerIrp);
  752. }
  753. I8xSetPowerFlag(WORK_ITEM_QUEUED, FALSE);
  754. ExFreePool(Item);
  755. }
  756. VOID
  757. I8xInitializeHardware(
  758. NTSTATUS *KeyboardStatus,
  759. NTSTATUS *MouseStatus,
  760. ULONG InitFlags
  761. )
  762. /*++
  763. Routine Description:
  764. This routine initializes the i8042 controller, keyboard, and mouse.
  765. Note that it is only called at initialization time. This routine
  766. does not need to synchronize access to the hardware, or synchronize
  767. with the ISRs (they aren't connected yet).
  768. Arguments:
  769. DeviceObject - Pointer to the device object.
  770. Return Value:
  771. None. As a side-effect, however, DeviceExtension->HardwarePresent is set.
  772. --*/
  773. {
  774. NTSTATUS altStatus;
  775. PUCHAR dataAddress, commandAddress;
  776. BOOLEAN canTouchKeyboard, canTouchMouse, firstInit;
  777. PPORT_MOUSE_EXTENSION mouseExtension = Globals.MouseExtension;
  778. PPORT_KEYBOARD_EXTENSION keyboardExtension = Globals.KeyboardExtension;
  779. PAGED_CODE();
  780. Print(DBG_SS_TRACE, ("I8xInitializeHardware: enter\n"));
  781. //
  782. // Grab useful configuration parameters from global data
  783. //
  784. dataAddress = Globals.ControllerData->DeviceRegisters[DataPort];
  785. commandAddress = Globals.ControllerData->DeviceRegisters[CommandPort];
  786. //
  787. // Drain the i8042 output buffer to get rid of stale data.
  788. //
  789. I8xDrainOutputBuffer(dataAddress, commandAddress);
  790. if (!MOUSE_PRESENT()) {
  791. Print(DBG_SS_INFO, ("I8xInitializeHardware: no mouse present\n"));
  792. }
  793. if (!KEYBOARD_PRESENT()) {
  794. Print(DBG_SS_INFO, ("I8xInitializeHardware: no keyboard present\n" ));
  795. }
  796. firstInit = (InitFlags & INIT_FIRST_TIME) ? TRUE : FALSE;
  797. if (firstInit) {
  798. canTouchKeyboard = canTouchMouse = TRUE;
  799. }
  800. else {
  801. canTouchKeyboard = (InitFlags & INIT_KEYBOARD) ? TRUE : FALSE;
  802. canTouchMouse = (InitFlags & INIT_MOUSE) ? TRUE : FALSE;
  803. }
  804. //
  805. // Disable the keyboard and mouse devices.
  806. //
  807. #if 0
  808. //
  809. // NOTE: This is supposedly the "correct" thing to do. However,
  810. // disabling the keyboard device here causes the AMI rev K8 machines
  811. // (e.g., some Northgates) to fail some commands (e.g., the READID
  812. // command).
  813. //
  814. *KeyboardStatus =
  815. I8xPutBytePolled(
  816. (CCHAR) CommandPort,
  817. NO_WAIT_FOR_ACKNOWLEDGE,
  818. (CCHAR) UndefinedDeviceType,
  819. (UCHAR) I8042_DISABLE_KEYBOARD_DEVICE
  820. );
  821. if (!NT_SUCCESS(*KeyboardStatus)) {
  822. Print(DBG_SS_ERROR,
  823. ("I8xInitializeHardware: failed kbd disable, status 0x%x\n",
  824. *KeyboardStatus
  825. ));
  826. I8xManuallyRemoveDevice(GET_COMMON_DATA(keyboardExtension));
  827. }
  828. #endif
  829. //
  830. // We will only run this piece of code when we are coming out of sleep. We
  831. // do this b/c the user might moved the mouse or keyboard and that can lead
  832. // to errors during init.
  833. //
  834. if (KEYBOARD_PRESENT() && firstInit == FALSE && canTouchKeyboard &&
  835. keyboardExtension->ShutdownType == PowerActionSleep) {
  836. I8xPutBytePolled((CCHAR) CommandPort,
  837. NO_WAIT_FOR_ACKNOWLEDGE,
  838. (CCHAR) UndefinedDeviceType,
  839. (UCHAR) I8042_DISABLE_KEYBOARD_DEVICE
  840. );
  841. }
  842. #if 0
  843. //
  844. // NOTE: This is supposedly the "correct thing to do. However,
  845. // disabling the mouse on RadiSys EPC-24 which uses VLSI part number
  846. // VL82C144 (3751E) causes the part to shut down keyboard interrupts.
  847. //
  848. *MouseStatus =
  849. I8xPutBytePolled(
  850. (CCHAR) CommandPort,
  851. NO_WAIT_FOR_ACKNOWLEDGE,
  852. (CCHAR) UndefinedDeviceType,
  853. (UCHAR) I8042_DISABLE_MOUSE_DEVICE
  854. );
  855. if (!NT_SUCCESS(*MouseStatus)) {
  856. Print(DBG_SS_ERROR,
  857. ("I8xInitializeHardware: failed mou disable, status 0x%x\n",
  858. *MouseStatus
  859. ));
  860. I8xManuallyRemoveDevice(GET_COMMON_DATA(mouseExtension));
  861. }
  862. #endif
  863. //
  864. // We will only run this piece of code when we are coming out of sleep. We
  865. // do this b/c the user might moved the mouse or keyboard and that can lead
  866. // to errors during init.
  867. //
  868. if (MOUSE_PRESENT() && firstInit == FALSE && canTouchMouse &&
  869. mouseExtension->ShutdownType == PowerActionSleep) {
  870. I8xPutBytePolled((CCHAR) CommandPort,
  871. NO_WAIT_FOR_ACKNOWLEDGE,
  872. (CCHAR) UndefinedDeviceType,
  873. (UCHAR) I8042_DISABLE_MOUSE_DEVICE
  874. );
  875. }
  876. //
  877. // Drain the i8042 output buffer to get rid of stale data that could
  878. // come in sometime between the previous drain and the time the devices
  879. // are disabled.
  880. //
  881. I8xDrainOutputBuffer(dataAddress, commandAddress);
  882. //
  883. // Setup the keyboard hardware.
  884. //
  885. if (KEYBOARD_PRESENT() && canTouchKeyboard) {
  886. ASSERT(keyboardExtension);
  887. *KeyboardStatus = I8xInitializeKeyboard(keyboardExtension);
  888. if (DEVICE_START_SUCCESS(*KeyboardStatus)) {
  889. //
  890. // If we are not headless and there is no device, we want to
  891. // successfully start the device, but then remove it in
  892. // IRP_MN_QUERY_PNP_DEVICE_STATE. If we fail the start now, we will
  893. // never get the query device state irp.
  894. //
  895. // If we are headless, then do not remove the device. This has the
  896. // side effect of the keyboard being listed when the user enumerates
  897. // all of the keyboards on the machine.
  898. //
  899. if (*KeyboardStatus == STATUS_DEVICE_NOT_CONNECTED) {
  900. if (Globals.Headless == FALSE) {
  901. Print(DBG_SS_INFO, ("kb not connected, removing\n"));
  902. I8xManuallyRemoveDevice(GET_COMMON_DATA(keyboardExtension));
  903. }
  904. else if (firstInit) {
  905. Print(DBG_SS_INFO, ("hiding the kb in the UI\n"));
  906. keyboardExtension->PnpDeviceState |= PNP_DEVICE_DONT_DISPLAY_IN_UI;
  907. IoInvalidateDeviceState(keyboardExtension->PDO);
  908. }
  909. }
  910. }
  911. else {
  912. Print(DBG_SS_ERROR,
  913. ("I8xInitializeHardware: failed kbd init, status 0x%x\n",
  914. *KeyboardStatus
  915. ));
  916. I8xManuallyRemoveDevice(GET_COMMON_DATA(keyboardExtension));
  917. }
  918. }
  919. else {
  920. *KeyboardStatus = STATUS_NO_SUCH_DEVICE;
  921. }
  922. //
  923. // Setup the mouse hardware.
  924. //
  925. if (MOUSE_PRESENT() && canTouchMouse) {
  926. ASSERT(mouseExtension);
  927. *MouseStatus = I8xInitializeMouse(mouseExtension);
  928. if (DEVICE_START_SUCCESS(*MouseStatus)) {
  929. //
  930. // If we are not headless and there is no device, we want to
  931. // successfully start the device, but then remove it in
  932. // IRP_MN_QUERY_PNP_DEVICE_STATE. If we fail the start now, we will
  933. // never get the query device state irp.
  934. //
  935. // If we are headless, then do not remove the device. This has the
  936. // side effect of keeping a mouse pointer on the screen even if
  937. // there is no mouse plugged in and will be listed when a user
  938. // enumerates all of the mice on the machine.
  939. //
  940. // If this is not the initial boot, then do not remove the device
  941. // if it is not responsive no matter what mode we are in.
  942. //
  943. if (*MouseStatus == STATUS_DEVICE_NOT_CONNECTED) {
  944. if (firstInit) {
  945. if (Globals.Headless == FALSE) {
  946. Print(DBG_SS_INFO, ("mouse not connected, removing\n"));
  947. I8xManuallyRemoveDevice(GET_COMMON_DATA(mouseExtension));
  948. }
  949. else {
  950. Print(DBG_SS_INFO, ("hiding mouse in the UI\n"));
  951. mouseExtension->PnpDeviceState |=
  952. PNP_DEVICE_DONT_DISPLAY_IN_UI;
  953. IoInvalidateDeviceState(mouseExtension->PDO);
  954. }
  955. }
  956. else {
  957. //
  958. // Mouse was previously present, but is now unresponsive.
  959. // Hope that it comes back at a later point in time.
  960. //
  961. // FYI: Mouse can be unresponsive because of the PC's BIOS
  962. // password security.
  963. //
  964. /* do nothing */;
  965. }
  966. }
  967. }
  968. else if (firstInit) {
  969. Print(DBG_SS_ERROR,
  970. ("I8xInitializeHardware: failed mou init, status 0x%x\n" ,
  971. *MouseStatus
  972. ));
  973. I8xManuallyRemoveDevice(GET_COMMON_DATA(mouseExtension));
  974. }
  975. }
  976. else {
  977. *MouseStatus = STATUS_NO_SUCH_DEVICE;
  978. }
  979. //
  980. // Enable the keyboard and mouse devices and their interrupts. Note
  981. // that it is required that this operation happen during intialization
  982. // time, because the i8042 Output Buffer Full bit gets set in the
  983. // Controller Command Byte when the keyboard/mouse is used, even if
  984. // the device is disabled. Hence, we cannot successfully perform
  985. // the enable operation later (e.g., when processing
  986. // IOCTL_INTERNAL_*_ENABLE), because we can't guarantee that
  987. // I8xPutBytePolled() won't time out waiting for the Output Buffer Full
  988. // bit to clear, even if we drain the output buffer (because the user
  989. // could be playing with the mouse/keyboard, and continuing to set the
  990. // OBF bit). KeyboardEnableCount and MouseEnableCount remain zero until
  991. // their respective IOCTL_INTERNAL_*_ENABLE call succeeds, so the ISR
  992. // ignores the unexpected interrupts.
  993. //
  994. if (KEYBOARD_PRESENT() && NT_SUCCESS(*KeyboardStatus) && canTouchKeyboard) {
  995. NTSTATUS status;
  996. Print(DBG_SS_INFO, ("resetting the LEDs\n"));
  997. if ((status = I8xPutBytePolled(
  998. (CCHAR) DataPort,
  999. WAIT_FOR_ACKNOWLEDGE,
  1000. (CCHAR) KeyboardDeviceType,
  1001. (UCHAR) SET_KEYBOARD_INDICATORS
  1002. )) == STATUS_SUCCESS) {
  1003. status = I8xPutBytePolled(
  1004. (CCHAR) DataPort,
  1005. WAIT_FOR_ACKNOWLEDGE,
  1006. (CCHAR) KeyboardDeviceType,
  1007. (UCHAR) keyboardExtension->KeyboardIndicators.LedFlags
  1008. );
  1009. if (status != STATUS_SUCCESS) {
  1010. Print(DBG_SS_INFO, ("setting LEDs value at mou failure failed 0x%x\n", status));
  1011. }
  1012. }
  1013. else {
  1014. Print(DBG_SS_INFO, ("setting LEDs at mou failure failed 0x%x\n", status));
  1015. }
  1016. }
  1017. //
  1018. // Re-enable the keyboard device in the Controller Command Byte.
  1019. // Note that some of the keyboards will send an ACK back, while
  1020. // others don't. Don't wait for an ACK, but do drain the output
  1021. // buffer afterwards so that an unexpected ACK doesn't mess up
  1022. // successive PutByte operations.
  1023. if (KEYBOARD_PRESENT() && canTouchKeyboard) {
  1024. altStatus = I8xPutBytePolled(
  1025. (CCHAR) CommandPort,
  1026. NO_WAIT_FOR_ACKNOWLEDGE,
  1027. (CCHAR) UndefinedDeviceType,
  1028. (UCHAR) I8042_ENABLE_KEYBOARD_DEVICE
  1029. );
  1030. if (!NT_SUCCESS(altStatus) && firstInit) {
  1031. *KeyboardStatus = altStatus;
  1032. Print(DBG_SS_ERROR,
  1033. ("I8xInitializeHardware: failed kbd re-enable, status 0x%x\n",
  1034. *KeyboardStatus
  1035. ));
  1036. I8xManuallyRemoveDevice(GET_COMMON_DATA(keyboardExtension));
  1037. }
  1038. I8xDrainOutputBuffer(dataAddress, commandAddress);
  1039. }
  1040. //
  1041. // Re-enable the mouse device in the Controller Command Byte.
  1042. //
  1043. if (MOUSE_PRESENT() && canTouchMouse) {
  1044. altStatus = I8xPutBytePolled(
  1045. (CCHAR) CommandPort,
  1046. NO_WAIT_FOR_ACKNOWLEDGE,
  1047. (CCHAR) UndefinedDeviceType,
  1048. (UCHAR) I8042_ENABLE_MOUSE_DEVICE
  1049. );
  1050. //
  1051. // If the mouse or the controller is still unresponsive when coming out
  1052. // of low power, just leave it be and hope it comes out of its confused
  1053. // state later.
  1054. //
  1055. if (!NT_SUCCESS(altStatus) && firstInit) {
  1056. *MouseStatus = altStatus;
  1057. Print(DBG_SS_ERROR,
  1058. ("I8xInitializeHardware: failed mou re-enable, status 0x%x\n",
  1059. altStatus
  1060. ));
  1061. I8xManuallyRemoveDevice(GET_COMMON_DATA(mouseExtension));
  1062. }
  1063. I8xDrainOutputBuffer(dataAddress, commandAddress);
  1064. }
  1065. Print(DBG_SS_TRACE,
  1066. ("I8xInitializeHardware (k 0x%x, m 0x%x)\n",
  1067. *KeyboardStatus,
  1068. *MouseStatus
  1069. ));
  1070. }
  1071. VOID
  1072. I8xPutByteAsynchronous(
  1073. IN CCHAR PortType,
  1074. IN UCHAR Byte
  1075. )
  1076. /*++
  1077. Routine Description:
  1078. This routine sends a command or data byte to the controller or keyboard
  1079. or mouse, asynchronously. It does not wait for acknowledgment.
  1080. If the hardware was not ready for input, the byte is not sent.
  1081. Arguments:
  1082. PortType - If CommandPort, send the byte to the command register,
  1083. otherwise send it to the data register.
  1084. Byte - The byte to send to the hardware.
  1085. Return Value:
  1086. None.
  1087. --*/
  1088. {
  1089. ULONG i;
  1090. Print(DBG_BUFIO_TRACE, ("I8xPutByteAsynchronous: enter\n" ));
  1091. //
  1092. // Make sure the Input Buffer Full controller status bit is clear.
  1093. // Time out if necessary.
  1094. //
  1095. i = 0;
  1096. while ((i++ < (ULONG)Globals.ControllerData->Configuration.PollingIterations) &&
  1097. (I8X_GET_STATUS_BYTE(Globals.ControllerData->DeviceRegisters[CommandPort])
  1098. & INPUT_BUFFER_FULL)) {
  1099. //
  1100. // Do nothing.
  1101. //
  1102. Print(DBG_BUFIO_NOISE,
  1103. ("I8xPutByteAsynchronous: wait for IBF and OBF to clear\n"
  1104. ));
  1105. }
  1106. if (i >= (ULONG)Globals.ControllerData->Configuration.PollingIterations) {
  1107. Print(DBG_BUFIO_ERROR,
  1108. ("I8xPutByteAsynchronous: exceeded number of retries\n"
  1109. ));
  1110. return;
  1111. }
  1112. //
  1113. // Send the byte to the appropriate (command/data) hardware register.
  1114. //
  1115. if (PortType == CommandPort) {
  1116. Print(DBG_BUFIO_INFO,
  1117. ("I8xPutByteAsynchronous: sending 0x%x to command port\n",
  1118. Byte
  1119. ));
  1120. I8X_PUT_COMMAND_BYTE(Globals.ControllerData->DeviceRegisters[CommandPort], Byte);
  1121. } else {
  1122. Print(DBG_BUFIO_INFO,
  1123. ("I8xPutByteAsynchronous: sending 0x%x to data port\n",
  1124. Byte
  1125. ));
  1126. I8X_PUT_DATA_BYTE(Globals.ControllerData->DeviceRegisters[DataPort], Byte);
  1127. }
  1128. Print(DBG_BUFIO_TRACE, ("I8xPutByteAsynchronous: exit\n"));
  1129. }
  1130. NTSTATUS
  1131. I8xPutBytePolled(
  1132. IN CCHAR PortType,
  1133. IN BOOLEAN WaitForAcknowledge,
  1134. IN CCHAR AckDeviceType,
  1135. IN UCHAR Byte
  1136. )
  1137. /*++
  1138. Routine Description:
  1139. This routine sends a command or data byte to the controller or keyboard
  1140. or mouse, in polling mode. It waits for acknowledgment and resends
  1141. the command/data if necessary.
  1142. Arguments:
  1143. PortType - If CommandPort, send the byte to the command register,
  1144. otherwise send it to the data register.
  1145. WaitForAcknowledge - If true, wait for an ACK back from the hardware.
  1146. AckDeviceType - Indicates which device we expect to get the ACK back
  1147. from.
  1148. Byte - The byte to send to the hardware.
  1149. Return Value:
  1150. STATUS_IO_TIMEOUT - The hardware was not ready for input or did not
  1151. respond.
  1152. STATUS_SUCCESS - The byte was successfully sent to the hardware.
  1153. --*/
  1154. {
  1155. ULONG i,j;
  1156. UCHAR response;
  1157. NTSTATUS status;
  1158. BOOLEAN keepTrying;
  1159. PUCHAR dataAddress, commandAddress;
  1160. Print(DBG_BUFIO_TRACE, ("I8xPutBytePolled: enter\n"));
  1161. if (AckDeviceType == MouseDeviceType) {
  1162. //
  1163. // We need to precede a PutByte for the mouse device with
  1164. // a PutByte that tells the controller that the next byte
  1165. // sent to the controller should go to the auxiliary device
  1166. // (by default it would go to the keyboard device). We
  1167. // do this by calling I8xPutBytePolled recursively to send
  1168. // the "send next byte to auxiliary device" command
  1169. // before sending the intended byte to the mouse. Note that
  1170. // there is only one level of recursion, since the AckDeviceType
  1171. // for the recursive call is guaranteed to be UndefinedDeviceType,
  1172. // and hence this IF statement will evaluate to FALSE.
  1173. //
  1174. I8xPutBytePolled(
  1175. (CCHAR) CommandPort,
  1176. NO_WAIT_FOR_ACKNOWLEDGE,
  1177. (CCHAR) UndefinedDeviceType,
  1178. (UCHAR) I8042_WRITE_TO_AUXILIARY_DEVICE
  1179. );
  1180. }
  1181. dataAddress = Globals.ControllerData->DeviceRegisters[DataPort];
  1182. commandAddress = Globals.ControllerData->DeviceRegisters[CommandPort];
  1183. for (j=0;j < (ULONG)Globals.ControllerData->Configuration.ResendIterations;j++) {
  1184. //
  1185. // Make sure the Input Buffer Full controller status bit is clear.
  1186. // Time out if necessary.
  1187. //
  1188. i = 0;
  1189. while ((i++ < (ULONG)Globals.ControllerData->Configuration.PollingIterations)
  1190. && (I8X_GET_STATUS_BYTE(commandAddress) & INPUT_BUFFER_FULL)) {
  1191. Print(DBG_BUFIO_NOISE, ("I8xPutBytePolled: stalling\n"));
  1192. KeStallExecutionProcessor(
  1193. Globals.ControllerData->Configuration.StallMicroseconds
  1194. );
  1195. }
  1196. if (i >= (ULONG)Globals.ControllerData->Configuration.PollingIterations) {
  1197. Print((DBG_BUFIO_MASK & ~DBG_BUFIO_INFO),
  1198. ("I8xPutBytePolled: timing out\n"
  1199. ));
  1200. status = STATUS_IO_TIMEOUT;
  1201. break;
  1202. }
  1203. //
  1204. // Drain the i8042 output buffer to get rid of stale data.
  1205. //
  1206. I8xDrainOutputBuffer(dataAddress, commandAddress);
  1207. //
  1208. // Send the byte to the appropriate (command/data) hardware register.
  1209. //
  1210. if (PortType == CommandPort) {
  1211. Print(DBG_BUFIO_INFO,
  1212. ("I8xPutBytePolled: sending 0x%x to command port\n",
  1213. Byte
  1214. ));
  1215. I8X_PUT_COMMAND_BYTE(commandAddress, Byte);
  1216. } else {
  1217. Print(DBG_BUFIO_INFO,
  1218. ("I8xPutBytePolled: sending 0x%x to data port\n",
  1219. Byte
  1220. ));
  1221. I8X_PUT_DATA_BYTE(dataAddress, Byte);
  1222. }
  1223. //
  1224. // If we don't need to wait for an ACK back from the controller,
  1225. // set the status and break out of the for loop.
  1226. //
  1227. //
  1228. if (WaitForAcknowledge == NO_WAIT_FOR_ACKNOWLEDGE) {
  1229. status = STATUS_SUCCESS;
  1230. break;
  1231. }
  1232. //
  1233. // Wait for an ACK back from the controller. If we get an ACK,
  1234. // the operation was successful. If we get a RESEND, break out to
  1235. // the for loop and try the operation again. Ignore anything other
  1236. // than ACK or RESEND.
  1237. //
  1238. Print(DBG_BUFIO_NOISE,
  1239. ("I8xPutBytePolled: waiting for ACK\n"
  1240. ));
  1241. keepTrying = FALSE;
  1242. while ((status = I8xGetBytePolled(
  1243. AckDeviceType,
  1244. &response
  1245. )
  1246. ) == STATUS_SUCCESS) {
  1247. if (response == ACKNOWLEDGE) {
  1248. Print(DBG_BUFIO_NOISE, ("I8xPutBytePolled: got ACK\n"));
  1249. break;
  1250. } else if (response == RESEND) {
  1251. Print(DBG_BUFIO_NOISE, ("I8xPutBytePolled: got RESEND\n"));
  1252. if (AckDeviceType == MouseDeviceType) {
  1253. //
  1254. // We need to precede the "resent" PutByte for the
  1255. // mouse device with a PutByte that tells the controller
  1256. // that the next byte sent to the controller should go
  1257. // to the auxiliary device (by default it would go to
  1258. // the keyboard device). We do this by calling
  1259. // I8xPutBytePolled recursively to send the "send next
  1260. // byte to auxiliary device" command before resending
  1261. // the byte to the mouse. Note that there is only one
  1262. // level of recursion, since the AckDeviceType for the
  1263. // recursive call is guaranteed to be UndefinedDeviceType.
  1264. //
  1265. I8xPutBytePolled(
  1266. (CCHAR) CommandPort,
  1267. NO_WAIT_FOR_ACKNOWLEDGE,
  1268. (CCHAR) UndefinedDeviceType,
  1269. (UCHAR) I8042_WRITE_TO_AUXILIARY_DEVICE
  1270. );
  1271. }
  1272. keepTrying = TRUE;
  1273. break;
  1274. }
  1275. //
  1276. // Ignore any other response, and keep trying.
  1277. //
  1278. }
  1279. if (!keepTrying)
  1280. break;
  1281. }
  1282. //
  1283. // Check to see if the number of allowable retries was exceeded.
  1284. //
  1285. if (j >= (ULONG)Globals.ControllerData->Configuration.ResendIterations) {
  1286. Print(DBG_BUFIO_ERROR,
  1287. ("I8xPutBytePolled: exceeded number of retries\n"
  1288. ));
  1289. status = STATUS_IO_TIMEOUT;
  1290. }
  1291. Print(DBG_BUFIO_TRACE, ("I8xPutBytePolled: exit\n"));
  1292. return(status);
  1293. }
  1294. NTSTATUS
  1295. I8xPutControllerCommand(
  1296. IN UCHAR Byte
  1297. )
  1298. /*++
  1299. Routine Description:
  1300. This routine writes the 8042 Controller Command Byte.
  1301. Arguments:
  1302. Byte - The byte to store in the Controller Command Byte.
  1303. Return Value:
  1304. Status is returned.
  1305. --*/
  1306. {
  1307. NTSTATUS status;
  1308. Print(DBG_BUFIO_TRACE, ("I8xPutControllerCommand: enter\n"));
  1309. //
  1310. // Send a command to the i8042 controller to write the Controller
  1311. // Command Byte.
  1312. //
  1313. status = I8xPutBytePolled(
  1314. (CCHAR) CommandPort,
  1315. NO_WAIT_FOR_ACKNOWLEDGE,
  1316. (CCHAR) UndefinedDeviceType,
  1317. (UCHAR) I8042_WRITE_CONTROLLER_COMMAND_BYTE
  1318. );
  1319. if (!NT_SUCCESS(status)) {
  1320. return(status);
  1321. }
  1322. //
  1323. // Write the byte through the i8042 data port.
  1324. //
  1325. Print(DBG_BUFIO_TRACE, ("I8xPutControllerCommand: exit\n"));
  1326. return(I8xPutBytePolled(
  1327. (CCHAR) DataPort,
  1328. NO_WAIT_FOR_ACKNOWLEDGE,
  1329. (CCHAR) UndefinedDeviceType,
  1330. (UCHAR) Byte
  1331. )
  1332. );
  1333. }
  1334. BOOLEAN
  1335. I8xDetermineSharedInterrupts(VOID)
  1336. {
  1337. //
  1338. // This was a specific fix for Jensen Alphas. Since we do not support them
  1339. // anymore, ifdef this code away.
  1340. //
  1341. #ifdef JENSEN
  1342. RTL_QUERY_REGISTRY_TABLE jensenTable[2] = {0};
  1343. UNICODE_STRING jensenData;
  1344. UNICODE_STRING jensenValue;
  1345. WCHAR jensenBuffer[256];
  1346. BOOLEAN shareInterrupts = FALSE;
  1347. //
  1348. // Check to see if this is a Jensen alpha. If it is, then
  1349. // we'll have to change the way we enable and disable interrupts
  1350. //
  1351. jensenData.Length = 0;
  1352. jensenData.MaximumLength = 512;
  1353. jensenData.Buffer = (PWCHAR)&jensenBuffer[0];
  1354. RtlInitUnicodeString(&jensenValue,
  1355. L"Jensen"
  1356. );
  1357. RtlZeroMemory(jensenTable, sizeof(RTL_QUERY_REGISTRY_TABLE)*2);
  1358. jensenTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT
  1359. | RTL_QUERY_REGISTRY_REQUIRED;
  1360. jensenTable[0].Name = L"Identifier";
  1361. jensenTable[0].EntryContext = &jensenData;
  1362. if (NT_SUCCESS(RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE
  1363. | RTL_REGISTRY_OPTIONAL,
  1364. L"\\REGISTRY\\MACHINE\\HARDWARE"
  1365. L"\\DESCRIPTION\\SYSTEM",
  1366. &jensenTable[0],
  1367. NULL,
  1368. NULL))) {
  1369. //
  1370. // Skip past the DEC-XX Portion of the name string.
  1371. // Be carful and make sure we have at least that much data.
  1372. //
  1373. if (jensenData.Length <= (sizeof(WCHAR)*6)) {
  1374. return FALSE;
  1375. }
  1376. else {
  1377. jensenData.Length -= (sizeof(WCHAR)*6);
  1378. jensenData.MaximumLength -= (sizeof(WCHAR)*6);
  1379. jensenData.Buffer = (PWCHAR)&jensenBuffer[sizeof(WCHAR)*6];
  1380. Print(DBG_SS_NOISE, ("Machine name is %ws\n", jensenData.Buffer));
  1381. shareInterrupts = RtlEqualUnicodeString(&jensenData,
  1382. &jensenValue,
  1383. FALSE
  1384. );
  1385. }
  1386. }
  1387. return shareInterrupts;
  1388. #else
  1389. return FALSE;
  1390. #endif
  1391. }
  1392. VOID
  1393. I8xServiceParameters(
  1394. IN PUNICODE_STRING RegistryPath
  1395. )
  1396. /*++
  1397. Routine Description:
  1398. This routine retrieves this driver's service parameters information
  1399. from the registry.
  1400. Arguments:
  1401. RegistryPath - Pointer to the null-terminated Unicode name of the
  1402. registry path for this driver.
  1403. KeyboardDeviceName - Pointer to the Unicode string that will receive
  1404. the keyboard port device name.
  1405. PointerDeviceName - Pointer to the Unicode string that will receive
  1406. the pointer port device name.
  1407. Return Value:
  1408. None. As a side-effect, sets fields in DeviceExtension->Configuration.
  1409. --*/
  1410. {
  1411. NTSTATUS status = STATUS_SUCCESS;
  1412. PI8042_CONFIGURATION_INFORMATION configuration;
  1413. PRTL_QUERY_REGISTRY_TABLE parameters = NULL;
  1414. PWSTR path = NULL;
  1415. ULONG defaultDataQueueSize = DATA_QUEUE_SIZE;
  1416. ULONG defaultDebugFlags = DEFAULT_DEBUG_FLAGS;
  1417. ULONG defaultIsrDebugFlags = 0L;
  1418. ULONG defaultBreakOnSysRq = 1;
  1419. ULONG defaultHeadless = 0;
  1420. ULONG defaultReportResetErrors = 0;
  1421. ULONG pollingIterations = 0;
  1422. ULONG pollingIterationsMaximum = 0;
  1423. ULONG resendIterations = 0;
  1424. ULONG breakOnSysRq = 1;
  1425. ULONG headless = 0;
  1426. ULONG reportResetErrors = 0;
  1427. ULONG i = 0;
  1428. UNICODE_STRING parametersPath;
  1429. USHORT defaultPollingIterations = I8042_POLLING_DEFAULT;
  1430. USHORT defaultPollingIterationsMaximum = I8042_POLLING_MAXIMUM;
  1431. USHORT defaultResendIterations = I8042_RESEND_DEFAULT;
  1432. USHORT queries = 7;
  1433. #if I8042_VERBOSE
  1434. queries += 2;
  1435. #endif
  1436. configuration = &(Globals.ControllerData->Configuration);
  1437. configuration->StallMicroseconds = I8042_STALL_DEFAULT;
  1438. parametersPath.Buffer = NULL;
  1439. configuration->SharedInterrupts = I8xDetermineSharedInterrupts();
  1440. //
  1441. // Registry path is already null-terminated, so just use it.
  1442. //
  1443. path = RegistryPath->Buffer;
  1444. if (NT_SUCCESS(status)) {
  1445. //
  1446. // Allocate the Rtl query table.
  1447. //
  1448. parameters = ExAllocatePool(
  1449. PagedPool,
  1450. sizeof(RTL_QUERY_REGISTRY_TABLE) * (queries + 1)
  1451. );
  1452. if (!parameters) {
  1453. Print(DBG_SS_ERROR,
  1454. ("%s: couldn't allocate table for Rtl query to %ws for %ws\n",
  1455. pFncServiceParameters,
  1456. pwParameters,
  1457. path
  1458. ));
  1459. status = STATUS_UNSUCCESSFUL;
  1460. } else {
  1461. RtlZeroMemory(
  1462. parameters,
  1463. sizeof(RTL_QUERY_REGISTRY_TABLE) * (queries + 1)
  1464. );
  1465. //
  1466. // Form a path to this driver's Parameters subkey.
  1467. //
  1468. RtlInitUnicodeString( &parametersPath, NULL );
  1469. parametersPath.MaximumLength = RegistryPath->Length +
  1470. (wcslen(pwParameters) * sizeof(WCHAR) ) + sizeof(UNICODE_NULL);
  1471. parametersPath.Buffer = ExAllocatePool(
  1472. PagedPool,
  1473. parametersPath.MaximumLength
  1474. );
  1475. if (!parametersPath.Buffer) {
  1476. Print(DBG_SS_ERROR,
  1477. ("%s: Couldn't allocate string for path to %ws for %ws\n",
  1478. pFncServiceParameters,
  1479. pwParameters,
  1480. path
  1481. ));
  1482. status = STATUS_UNSUCCESSFUL;
  1483. }
  1484. }
  1485. }
  1486. if (NT_SUCCESS(status)) {
  1487. //
  1488. // Form the parameters path.
  1489. //
  1490. RtlZeroMemory(
  1491. parametersPath.Buffer,
  1492. parametersPath.MaximumLength
  1493. );
  1494. RtlAppendUnicodeToString(
  1495. &parametersPath,
  1496. path
  1497. );
  1498. RtlAppendUnicodeToString(
  1499. &parametersPath,
  1500. pwParameters
  1501. );
  1502. Print(DBG_SS_INFO,
  1503. ("%s: %ws path is %ws\n",
  1504. pFncServiceParameters,
  1505. pwParameters,
  1506. parametersPath.Buffer
  1507. ));
  1508. //
  1509. // Gather all of the "user specified" information from
  1510. // the registry.
  1511. //
  1512. parameters[i].Flags = RTL_QUERY_REGISTRY_DIRECT;
  1513. parameters[i].Name = pwResendIterations;
  1514. parameters[i].EntryContext = &resendIterations;
  1515. parameters[i].DefaultType = REG_DWORD;
  1516. parameters[i].DefaultData = &defaultResendIterations;
  1517. parameters[i].DefaultLength = sizeof(USHORT);
  1518. parameters[++i].Flags = RTL_QUERY_REGISTRY_DIRECT;
  1519. parameters[i].Name = pwPollingIterations;
  1520. parameters[i].EntryContext = &pollingIterations;
  1521. parameters[i].DefaultType = REG_DWORD;
  1522. parameters[i].DefaultData = &defaultPollingIterations;
  1523. parameters[i].DefaultLength = sizeof(USHORT);
  1524. parameters[++i].Flags = RTL_QUERY_REGISTRY_DIRECT;
  1525. parameters[i].Name = pwPollingIterationsMaximum;
  1526. parameters[i].EntryContext = &pollingIterationsMaximum;
  1527. parameters[i].DefaultType = REG_DWORD;
  1528. parameters[i].DefaultData = &defaultPollingIterationsMaximum;
  1529. parameters[i].DefaultLength = sizeof(USHORT);
  1530. parameters[++i].Flags = RTL_QUERY_REGISTRY_DIRECT;
  1531. parameters[i].Name = L"BreakOnSysRq";
  1532. parameters[i].EntryContext = &breakOnSysRq;
  1533. parameters[i].DefaultType = REG_DWORD;
  1534. parameters[i].DefaultData = &defaultBreakOnSysRq;
  1535. parameters[i].DefaultLength = sizeof(ULONG);
  1536. parameters[++i].Flags = RTL_QUERY_REGISTRY_DIRECT;
  1537. parameters[i].Name = L"Headless";
  1538. parameters[i].EntryContext = &headless;
  1539. parameters[i].DefaultType = REG_DWORD;
  1540. parameters[i].DefaultData = &defaultHeadless;
  1541. parameters[i].DefaultLength = sizeof(ULONG);
  1542. parameters[++i].Flags = RTL_QUERY_REGISTRY_DIRECT;
  1543. parameters[i].Name = L"ReportResetErrors";
  1544. parameters[i].EntryContext = &reportResetErrors;
  1545. parameters[i].DefaultType = REG_DWORD;
  1546. parameters[i].DefaultData = &defaultReportResetErrors;
  1547. parameters[i].DefaultLength = sizeof(ULONG);
  1548. #if I8042_VERBOSE
  1549. parameters[++i].Flags = RTL_QUERY_REGISTRY_DIRECT;
  1550. parameters[i].Name = pwDebugFlags;
  1551. parameters[i].EntryContext = &Globals.DebugFlags;
  1552. parameters[i].DefaultType = REG_DWORD;
  1553. parameters[i].DefaultData = &defaultDebugFlags;
  1554. parameters[i].DefaultLength = sizeof(ULONG);
  1555. parameters[++i].Flags = RTL_QUERY_REGISTRY_DIRECT;
  1556. parameters[i].Name = pwIsrDebugFlags;
  1557. parameters[i].EntryContext = &Globals.IsrDebugFlags;
  1558. parameters[i].DefaultType = REG_DWORD;
  1559. parameters[i].DefaultData = &defaultIsrDebugFlags;
  1560. parameters[i].DefaultLength = sizeof(ULONG);
  1561. // 16
  1562. #endif // I8042_VERBOSE
  1563. // ASSERT( ((LONG) i) == (queries-1) );
  1564. status = RtlQueryRegistryValues(
  1565. RTL_REGISTRY_ABSOLUTE | RTL_REGISTRY_OPTIONAL,
  1566. parametersPath.Buffer,
  1567. parameters,
  1568. NULL,
  1569. NULL
  1570. );
  1571. if (!NT_SUCCESS(status)) {
  1572. Print(DBG_SS_INFO,
  1573. ("%s: RtlQueryRegistryValues failed with 0x%x\n",
  1574. pFncServiceParameters,
  1575. status
  1576. ));
  1577. }
  1578. }
  1579. if (!NT_SUCCESS(status)) {
  1580. //
  1581. // Go ahead and assign driver defaults.
  1582. //
  1583. configuration->ResendIterations = defaultResendIterations;
  1584. configuration->PollingIterations = defaultPollingIterations;
  1585. configuration->PollingIterationsMaximum =
  1586. defaultPollingIterationsMaximum;
  1587. }
  1588. else {
  1589. configuration->ResendIterations = (USHORT) resendIterations;
  1590. configuration->PollingIterations = (USHORT) pollingIterations;
  1591. configuration->PollingIterationsMaximum =
  1592. (USHORT) pollingIterationsMaximum;
  1593. if (breakOnSysRq) {
  1594. Globals.BreakOnSysRq = TRUE;
  1595. Print(DBG_SS_NOISE, ("breaking on SysRq\n"));
  1596. }
  1597. else {
  1598. Print(DBG_SS_NOISE, ("NOT breaking on SysRq\n"));
  1599. }
  1600. if (headless) {
  1601. Globals.Headless = TRUE;
  1602. Print(DBG_SS_NOISE, ("headless\n"));
  1603. }
  1604. else {
  1605. Globals.Headless = FALSE;
  1606. Print(DBG_SS_NOISE, ("NOT headless\n"));
  1607. }
  1608. if (reportResetErrors) {
  1609. Globals.ReportResetErrors = TRUE;
  1610. Print(DBG_SS_NOISE,
  1611. ("reporting reset errors to system event log\n"));
  1612. }
  1613. else {
  1614. Globals.ReportResetErrors = FALSE;
  1615. Print(DBG_SS_NOISE,
  1616. ("NOT reporting reset errors to system event log\n"));
  1617. }
  1618. }
  1619. Print(DBG_SS_NOISE, ("I8xServiceParameters results..\n"));
  1620. Print(DBG_SS_NOISE,
  1621. ("\tDebug flags are 0x%x, Isr Debug flags are 0x%x\n",
  1622. Globals.DebugFlags,
  1623. Globals.IsrDebugFlags
  1624. ));
  1625. Print(DBG_SS_NOISE,
  1626. ("\tInterrupts are %s shared\n",
  1627. configuration->SharedInterrupts ? "" : "not"
  1628. ));
  1629. Print(DBG_SS_NOISE,
  1630. ("\tStallMicroseconds = %d\n",
  1631. configuration->StallMicroseconds
  1632. ));
  1633. Print(DBG_SS_NOISE,
  1634. (pDumpDecimal,
  1635. pwResendIterations,
  1636. configuration->ResendIterations
  1637. ));
  1638. Print(DBG_SS_NOISE,
  1639. (pDumpDecimal,
  1640. pwPollingIterations,
  1641. configuration->PollingIterations
  1642. ));
  1643. Print(DBG_SS_NOISE,
  1644. (pDumpDecimal,
  1645. pwPollingIterationsMaximum,
  1646. configuration->PollingIterationsMaximum
  1647. ));
  1648. //
  1649. // Free the allocated memory before returning.
  1650. //
  1651. if (parametersPath.Buffer)
  1652. ExFreePool(parametersPath.Buffer);
  1653. if (parameters)
  1654. ExFreePool(parameters);
  1655. }
  1656. VOID
  1657. I8xTransmitControllerCommand(
  1658. IN PI8042_TRANSMIT_CCB_CONTEXT TransmitCCBContext
  1659. )
  1660. /*++
  1661. Routine Description:
  1662. This routine reads the 8042 Controller Command Byte, performs an AND
  1663. or OR operation using the specified ByteMask, and writes the resulting
  1664. ControllerCommandByte.
  1665. Arguments:
  1666. Context - Pointer to a structure containing the HardwareDisableEnableMask,
  1667. the AndOperation boolean, and the ByteMask to apply to the Controller
  1668. Command Byte before it is rewritten.
  1669. Return Value:
  1670. None. Status is returned in the Context structure.
  1671. --*/
  1672. {
  1673. UCHAR controllerCommandByte;
  1674. UCHAR verifyCommandByte;
  1675. PIO_ERROR_LOG_PACKET errorLogEntry;
  1676. Print(DBG_BUFIO_TRACE, ("I8xTransmitControllerCommand: enter\n"));
  1677. //
  1678. // Get the current Controller Command Byte.
  1679. //
  1680. TransmitCCBContext->Status =
  1681. I8xGetControllerCommand(
  1682. TransmitCCBContext->HardwareDisableEnableMask,
  1683. &controllerCommandByte
  1684. );
  1685. if (!NT_SUCCESS(TransmitCCBContext->Status)) {
  1686. return;
  1687. }
  1688. Print(DBG_BUFIO_INFO,
  1689. ("I8xTransmitControllerCommand: current CCB 0x%x\n",
  1690. controllerCommandByte
  1691. ));
  1692. //
  1693. // Diddle the desired bits in the Controller Command Byte.
  1694. //
  1695. if (TransmitCCBContext->AndOperation) {
  1696. controllerCommandByte &= TransmitCCBContext->ByteMask;
  1697. }
  1698. else {
  1699. controllerCommandByte |= TransmitCCBContext->ByteMask;
  1700. }
  1701. //
  1702. // Write the new Controller Command Byte.
  1703. //
  1704. PutControllerCommand:
  1705. TransmitCCBContext->Status =
  1706. I8xPutControllerCommand(controllerCommandByte);
  1707. Print(DBG_BUFIO_INFO,
  1708. ("I8xTransmitControllerCommand: new CCB 0x%x\n",
  1709. controllerCommandByte
  1710. ));
  1711. //
  1712. // Verify that the new Controller Command Byte really got written.
  1713. //
  1714. TransmitCCBContext->Status =
  1715. I8xGetControllerCommand(
  1716. TransmitCCBContext->HardwareDisableEnableMask,
  1717. &verifyCommandByte
  1718. );
  1719. if (verifyCommandByte == 0xff) {
  1720. KeStallExecutionProcessor(50);
  1721. //
  1722. // Stall for about a second
  1723. //
  1724. goto PutControllerCommand;
  1725. }
  1726. if (NT_SUCCESS(TransmitCCBContext->Status)
  1727. && (verifyCommandByte != controllerCommandByte)
  1728. && (verifyCommandByte != ACKNOWLEDGE)
  1729. // && (verifyCommandByte != KEYBOARD_RESET)
  1730. ) {
  1731. TransmitCCBContext->Status = STATUS_DEVICE_DATA_ERROR;
  1732. Print(DBG_BUFIO_ERROR,
  1733. ("I8xTransmitControllerCommand: wrote 0x%x, failed verification (0x%x)\n",
  1734. (int) controllerCommandByte,
  1735. (int) verifyCommandByte
  1736. ));
  1737. if (KeGetCurrentIrql() <= DISPATCH_LEVEL) {
  1738. //
  1739. // Log an error only if we are running at dispatch or below
  1740. //
  1741. errorLogEntry = (PIO_ERROR_LOG_PACKET)
  1742. IoAllocateErrorLogEntry((Globals.KeyboardExtension ?
  1743. Globals.KeyboardExtension->Self :
  1744. Globals.MouseExtension->Self),
  1745. sizeof(IO_ERROR_LOG_PACKET)
  1746. + (4 * sizeof(ULONG))
  1747. );
  1748. if (errorLogEntry != NULL) {
  1749. errorLogEntry->ErrorCode = I8042_CCB_WRITE_FAILED;
  1750. errorLogEntry->DumpDataSize = 4 * sizeof(ULONG);
  1751. errorLogEntry->SequenceNumber = 0;
  1752. errorLogEntry->MajorFunctionCode = 0;
  1753. errorLogEntry->IoControlCode = 0;
  1754. errorLogEntry->RetryCount = 0;
  1755. errorLogEntry->UniqueErrorValue = 80;
  1756. errorLogEntry->FinalStatus = TransmitCCBContext->Status;
  1757. errorLogEntry->DumpData[0] = KBDMOU_COULD_NOT_SEND_PARAM;
  1758. errorLogEntry->DumpData[1] = DataPort;
  1759. errorLogEntry->DumpData[2] = I8042_WRITE_CONTROLLER_COMMAND_BYTE;
  1760. errorLogEntry->DumpData[3] = controllerCommandByte;
  1761. IoWriteErrorLogEntry(errorLogEntry);
  1762. }
  1763. }
  1764. }
  1765. Print(DBG_BUFIO_TRACE, ("I8xTransmitControllerCommand: exit\n"));
  1766. return;
  1767. }