i8042.c 36 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642
  1. /*++
  2. Copyright (c) 2012 Minoca Corp. All Rights Reserved
  3. Module Name:
  4. i8042.c
  5. Abstract:
  6. This module implements the Intel 8042 keyboard/mouse controller driver.
  7. Author:
  8. Evan Green 20-Dec-2012
  9. Environment:
  10. Kernel
  11. --*/
  12. //
  13. // ------------------------------------------------------------------- Includes
  14. //
  15. #include <minoca/kernel/driver.h>
  16. #include "i8042.h"
  17. //
  18. // --------------------------------------------------------------------- Macros
  19. //
  20. //
  21. // These macros read from and write to the control, status, and data registers.
  22. //
  23. #define WRITE_CONTROL_REGISTER(_Device, _Value) \
  24. HlIoPortOutByte(_Device->ControlPort, _Value)
  25. #define READ_STATUS_REGISTER(_Device) HlIoPortInByte(_Device->ControlPort)
  26. #define WRITE_DATA_REGISTER(_Device, _Value) \
  27. HlIoPortOutByte(_Device->DataPort, _Value)
  28. #define READ_DATA_REGISTER(_Device) HlIoPortInByte(_Device->DataPort)
  29. //
  30. // This macro spins waiting for the last keyboard command to finish.
  31. //
  32. #define WAIT_FOR_INPUT_BUFFER(_Device) \
  33. while ((READ_STATUS_REGISTER(_Device) & \
  34. I8042_STATUS_INPUT_BUFFER_FULL) != 0) { \
  35. \
  36. NOTHING; \
  37. }
  38. //
  39. // This macro determines if data is available to be received from the device.
  40. //
  41. #define IS_DATA_AVAILABLE(_Device) \
  42. ((READ_STATUS_REGISTER(_Device) & I8042_STATUS_OUTPUT_BUFFER_FULL) != 0)
  43. //
  44. // ---------------------------------------------------------------- Definitions
  45. //
  46. //
  47. // Define the size of the device keyboard buffer size.
  48. //
  49. #define I8042_BUFFER_SIZE 256
  50. //
  51. // Define the bits in the 8042 status register.
  52. //
  53. #define I8042_STATUS_OUTPUT_BUFFER_FULL 0x01
  54. #define I8042_STATUS_INPUT_BUFFER_FULL 0x02
  55. #define I8042_STATUS_SELF_TEST_COMPLETE 0x04
  56. #define I8042_STATUS_LAST_WRITE_COMMAND 0x08
  57. #define I8042_STATUS_KEYBOARD_UNLOCK 0x10
  58. #define I8042_STATUS_DATA_FROM_MOUSE 0x20
  59. #define I8042_STATUS_TIMEOUT 0x40
  60. #define I8042_STATUS_PARITY_ERROR 0x80
  61. //
  62. // Define bits in the 8042 command byte register.
  63. //
  64. #define I8042_COMMAND_BYTE_KEYBOARD_INTERRUPT_ENABLED 0x01
  65. #define I8042_COMMAND_BYTE_MOUSE_INTERRUPT_ENABLED 0x02
  66. #define I8042_COMMAND_BYTE_SYSTEM_FLAG 0x04
  67. #define I8042_COMMAND_BYTE_PCAT_INHIBIT 0x08
  68. #define I8042_COMMAND_BYTE_KEYBOARD_DISABLED 0x10
  69. #define I8042_COMMAND_BYTE_MOUSE_DISABLED 0x20
  70. #define I8042_COMMAND_BYTE_TRANSLATION_ENABLED 0x40
  71. //
  72. // Define the known device identifiers that this driver responds to.
  73. //
  74. #define KEYBOARD_HARDWARE_IDENTIFIER "PNP0303"
  75. #define MOUSE_HARDWARE_IDENTIFIER "PNP0F13"
  76. //
  77. // Define the allocation tag used by this driver.
  78. //
  79. #define I8042_ALLOCATION_TAG 0x32343869 // '248i'
  80. //
  81. // Define the amount of time to allow the keyboard to reset, in microseconds.
  82. //
  83. #define I8042_RESET_DELAY 10000
  84. //
  85. // ------------------------------------------------------ Data Type Definitions
  86. //
  87. /*++
  88. Structure Description:
  89. This structure stores context about a device driven by the i8042 driver.
  90. Members:
  91. IsMouse - Stores a boolean indicating whether the device is a mouse (TRUE)
  92. or a keyboard (FALSE).
  93. ControlPort - Stores the I/O port number of the 8042 control port.
  94. DataPort - Stores the I/O port number of the 8042 data port.
  95. InterruptVector - Stores the interrupt vector that this interrupt comes in
  96. on.
  97. InterruptLine - Stores the interrupt line that the interrupt comes in on.
  98. InterruptResourcesFound - Stores a boolean indicating whether or not the
  99. interrupt vector and interrupt line fields are valid.
  100. InterruptHandle - Stores the handle for the connected interrupt.
  101. UserInputDeviceHandle - Stores the handle returned by the User Input
  102. library.
  103. InterruptLock - Stores a spinlock synchronizing access to the device with
  104. the interrupt service routine.
  105. ReadLock - Stores a pointer to a queued lock that serializes read access
  106. to the data buffer.
  107. ReadIndex - Stores the index of the next byte to read out of the data
  108. buffer.
  109. WriteIndex - Stores the index of the next byte to write to the data buffer.
  110. DataBuffer - Stores the buffer of keys coming out of the controller.
  111. --*/
  112. typedef struct _I8042_DEVICE {
  113. BOOL IsMouse;
  114. USHORT ControlPort;
  115. USHORT DataPort;
  116. ULONGLONG InterruptVector;
  117. ULONGLONG InterruptLine;
  118. BOOL InterruptResourcesFound;
  119. HANDLE InterruptHandle;
  120. HANDLE UserInputDeviceHandle;
  121. KSPIN_LOCK InterruptLock;
  122. PQUEUED_LOCK ReadLock;
  123. volatile ULONG ReadIndex;
  124. volatile ULONG WriteIndex;
  125. volatile UCHAR DataBuffer[I8042_BUFFER_SIZE];
  126. } I8042_DEVICE, *PI8042_DEVICE;
  127. //
  128. // ----------------------------------------------- Internal Function Prototypes
  129. //
  130. KSTATUS
  131. I8042AddDevice (
  132. PVOID Driver,
  133. PSTR DeviceId,
  134. PSTR ClassId,
  135. PSTR CompatibleIds,
  136. PVOID DeviceToken
  137. );
  138. VOID
  139. I8042DispatchStateChange (
  140. PIRP Irp,
  141. PVOID DeviceContext,
  142. PVOID IrpContext
  143. );
  144. VOID
  145. I8042DispatchOpen (
  146. PIRP Irp,
  147. PVOID DeviceContext,
  148. PVOID IrpContext
  149. );
  150. VOID
  151. I8042DispatchClose (
  152. PIRP Irp,
  153. PVOID DeviceContext,
  154. PVOID IrpContext
  155. );
  156. VOID
  157. I8042DispatchIo (
  158. PIRP Irp,
  159. PVOID DeviceContext,
  160. PVOID IrpContext
  161. );
  162. VOID
  163. I8042DispatchSystemControl (
  164. PIRP Irp,
  165. PVOID DeviceContext,
  166. PVOID IrpContext
  167. );
  168. INTERRUPT_STATUS
  169. I8042InterruptService (
  170. PVOID Context
  171. );
  172. INTERRUPT_STATUS
  173. I8042InterruptServiceWorker (
  174. PVOID Parameter
  175. );
  176. KSTATUS
  177. I8042pProcessResourceRequirements (
  178. PIRP Irp,
  179. PI8042_DEVICE Device
  180. );
  181. KSTATUS
  182. I8042pStartDevice (
  183. PIRP Irp,
  184. PI8042_DEVICE Device
  185. );
  186. KSTATUS
  187. I8042pEnableDevice (
  188. PVOID OsDevice,
  189. PI8042_DEVICE Device
  190. );
  191. KSTATUS
  192. I8042pSetLedState (
  193. PVOID Device,
  194. PVOID DeviceContext,
  195. ULONG LedState
  196. );
  197. UCHAR
  198. I8042pReadCommandByte (
  199. PI8042_DEVICE Device
  200. );
  201. VOID
  202. I8042pWriteCommandByte (
  203. PI8042_DEVICE Device,
  204. UCHAR Value
  205. );
  206. KSTATUS
  207. I8042pSendKeyboardCommand (
  208. PI8042_DEVICE Device,
  209. UCHAR Command,
  210. UCHAR Parameter
  211. );
  212. KSTATUS
  213. I8042pSendCommand (
  214. PI8042_DEVICE Device,
  215. UCHAR Command
  216. );
  217. KSTATUS
  218. I8042pReceiveResponse (
  219. PI8042_DEVICE Device,
  220. PUCHAR Data
  221. );
  222. //
  223. // -------------------------------------------------------------------- Globals
  224. //
  225. PDRIVER I8042Driver = NULL;
  226. //
  227. // ------------------------------------------------------------------ Functions
  228. //
  229. KSTATUS
  230. DriverEntry (
  231. PDRIVER Driver
  232. )
  233. /*++
  234. Routine Description:
  235. This routine is the entry point for the i8042 driver. It registers its other
  236. dispatch functions, and performs driver-wide initialization.
  237. Arguments:
  238. Driver - Supplies a pointer to the driver object.
  239. Return Value:
  240. STATUS_SUCCESS on success.
  241. Failure code on error.
  242. --*/
  243. {
  244. DRIVER_FUNCTION_TABLE FunctionTable;
  245. KSTATUS Status;
  246. I8042Driver = Driver;
  247. RtlZeroMemory(&FunctionTable, sizeof(DRIVER_FUNCTION_TABLE));
  248. FunctionTable.Version = DRIVER_FUNCTION_TABLE_VERSION;
  249. FunctionTable.AddDevice = I8042AddDevice;
  250. FunctionTable.DispatchStateChange = I8042DispatchStateChange;
  251. FunctionTable.DispatchOpen = I8042DispatchOpen;
  252. FunctionTable.DispatchClose = I8042DispatchClose;
  253. FunctionTable.DispatchIo = I8042DispatchIo;
  254. FunctionTable.DispatchSystemControl = I8042DispatchSystemControl;
  255. Status = IoRegisterDriverFunctions(Driver, &FunctionTable);
  256. return Status;
  257. }
  258. //
  259. // --------------------------------------------------------- Internal Functions
  260. //
  261. KSTATUS
  262. I8042AddDevice (
  263. PVOID Driver,
  264. PSTR DeviceId,
  265. PSTR ClassId,
  266. PSTR CompatibleIds,
  267. PVOID DeviceToken
  268. )
  269. /*++
  270. Routine Description:
  271. This routine is called when a device is detected for which the i8042 driver
  272. acts as the function driver. The driver will attach itself to the stack.
  273. Arguments:
  274. Driver - Supplies a pointer to the driver being called.
  275. DeviceId - Supplies a pointer to a string with the device ID.
  276. ClassId - Supplies a pointer to a string containing the device's class ID.
  277. CompatibleIds - Supplies a pointer to a string containing device IDs
  278. that would be compatible with this device.
  279. DeviceToken - Supplies an opaque token that the driver can use to identify
  280. the device in the system. This token should be used when attaching to
  281. the stack.
  282. Return Value:
  283. STATUS_SUCCESS on success.
  284. Failure code if the driver was unsuccessful in attaching itself.
  285. --*/
  286. {
  287. BOOL DeviceIdsAreEqual;
  288. BOOL DeviceIsMouse;
  289. BOOL MatchesCompatibleId;
  290. BOOL MatchFound;
  291. PI8042_DEVICE NewDevice;
  292. KSTATUS Status;
  293. DeviceIsMouse = FALSE;
  294. MatchFound = FALSE;
  295. DeviceIdsAreEqual = IoAreDeviceIdsEqual(DeviceId,
  296. KEYBOARD_HARDWARE_IDENTIFIER);
  297. MatchesCompatibleId =
  298. IoIsDeviceIdInCompatibleIdList(KEYBOARD_HARDWARE_IDENTIFIER,
  299. DeviceToken);
  300. if ((DeviceIdsAreEqual != FALSE) || (MatchesCompatibleId != FALSE)) {
  301. MatchFound = TRUE;
  302. } else {
  303. //
  304. // Attempt to match against the mouse ID.
  305. //
  306. DeviceIdsAreEqual = IoAreDeviceIdsEqual(DeviceId,
  307. MOUSE_HARDWARE_IDENTIFIER);
  308. MatchesCompatibleId =
  309. IoIsDeviceIdInCompatibleIdList(MOUSE_HARDWARE_IDENTIFIER,
  310. DeviceToken);
  311. if ((DeviceIdsAreEqual != FALSE) || (MatchesCompatibleId != FALSE)) {
  312. MatchFound = TRUE;
  313. DeviceIsMouse = TRUE;
  314. }
  315. }
  316. //
  317. // If there is no match, return now.
  318. //
  319. if (MatchFound == FALSE) {
  320. return STATUS_SUCCESS;
  321. }
  322. //
  323. // there is a match, create the device context and attach to the device.
  324. //
  325. NewDevice = MmAllocateNonPagedPool(sizeof(I8042_DEVICE),
  326. I8042_ALLOCATION_TAG);
  327. if (NewDevice == NULL) {
  328. return STATUS_INSUFFICIENT_RESOURCES;
  329. }
  330. RtlZeroMemory(NewDevice, sizeof(I8042_DEVICE));
  331. KeInitializeSpinLock(&(NewDevice->InterruptLock));
  332. NewDevice->InterruptHandle = INVALID_HANDLE;
  333. NewDevice->UserInputDeviceHandle = INVALID_HANDLE;
  334. NewDevice->IsMouse = DeviceIsMouse;
  335. NewDevice->ReadLock = KeCreateQueuedLock();
  336. if (NewDevice->ReadLock == NULL) {
  337. Status = STATUS_INSUFFICIENT_RESOURCES;
  338. goto AddDeviceEnd;
  339. }
  340. Status = IoAttachDriverToDevice(Driver, DeviceToken, NewDevice);
  341. if (!KSUCCESS(Status)) {
  342. goto AddDeviceEnd;
  343. }
  344. AddDeviceEnd:
  345. if (!KSUCCESS(Status)) {
  346. if (NewDevice != NULL) {
  347. if (NewDevice->ReadLock != NULL) {
  348. KeDestroyQueuedLock(NewDevice->ReadLock);
  349. }
  350. MmFreeNonPagedPool(NewDevice);
  351. }
  352. }
  353. return Status;
  354. }
  355. VOID
  356. I8042DispatchStateChange (
  357. PIRP Irp,
  358. PVOID DeviceContext,
  359. PVOID IrpContext
  360. )
  361. /*++
  362. Routine Description:
  363. This routine handles State Change IRPs.
  364. Arguments:
  365. Irp - Supplies a pointer to the I/O request packet.
  366. DeviceContext - Supplies the context pointer supplied by the driver when it
  367. attached itself to the driver stack. Presumably this pointer contains
  368. driver-specific device context.
  369. IrpContext - Supplies the context pointer supplied by the driver when
  370. the IRP was created.
  371. Return Value:
  372. None.
  373. --*/
  374. {
  375. PI8042_DEVICE Device;
  376. KSTATUS Status;
  377. ASSERT(Irp->MajorCode == IrpMajorStateChange);
  378. Device = (PI8042_DEVICE)DeviceContext;
  379. switch (Irp->MinorCode) {
  380. case IrpMinorQueryResources:
  381. //
  382. // On the way up, filter the resource requirements to add interrupt
  383. // vectors to any lines.
  384. //
  385. if (Irp->Direction == IrpUp) {
  386. Status = I8042pProcessResourceRequirements(Irp, Device);
  387. if (!KSUCCESS(Status)) {
  388. IoCompleteIrp(I8042Driver, Irp, Status);
  389. }
  390. }
  391. break;
  392. case IrpMinorStartDevice:
  393. //
  394. // Attempt to fire the thing up if the bus has already started it.
  395. //
  396. if (Irp->Direction == IrpUp) {
  397. Status = I8042pStartDevice(Irp, Device);
  398. if (!KSUCCESS(Status)) {
  399. IoCompleteIrp(I8042Driver, Irp, Status);
  400. }
  401. }
  402. break;
  403. //
  404. // For all other IRPs, do nothing.
  405. //
  406. default:
  407. break;
  408. }
  409. return;
  410. }
  411. VOID
  412. I8042DispatchOpen (
  413. PIRP Irp,
  414. PVOID DeviceContext,
  415. PVOID IrpContext
  416. )
  417. /*++
  418. Routine Description:
  419. This routine handles Open IRPs.
  420. Arguments:
  421. Irp - Supplies a pointer to the I/O request packet.
  422. DeviceContext - Supplies the context pointer supplied by the driver when it
  423. attached itself to the driver stack. Presumably this pointer contains
  424. driver-specific device context.
  425. IrpContext - Supplies the context pointer supplied by the driver when
  426. the IRP was created.
  427. Return Value:
  428. None.
  429. --*/
  430. {
  431. return;
  432. }
  433. VOID
  434. I8042DispatchClose (
  435. PIRP Irp,
  436. PVOID DeviceContext,
  437. PVOID IrpContext
  438. )
  439. /*++
  440. Routine Description:
  441. This routine handles Close IRPs.
  442. Arguments:
  443. Irp - Supplies a pointer to the I/O request packet.
  444. DeviceContext - Supplies the context pointer supplied by the driver when it
  445. attached itself to the driver stack. Presumably this pointer contains
  446. driver-specific device context.
  447. IrpContext - Supplies the context pointer supplied by the driver when
  448. the IRP was created.
  449. Return Value:
  450. None.
  451. --*/
  452. {
  453. return;
  454. }
  455. VOID
  456. I8042DispatchIo (
  457. PIRP Irp,
  458. PVOID DeviceContext,
  459. PVOID IrpContext
  460. )
  461. /*++
  462. Routine Description:
  463. This routine handles I/O IRPs.
  464. Arguments:
  465. Irp - Supplies a pointer to the I/O request packet.
  466. DeviceContext - Supplies the context pointer supplied by the driver when it
  467. attached itself to the driver stack. Presumably this pointer contains
  468. driver-specific device context.
  469. IrpContext - Supplies the context pointer supplied by the driver when
  470. the IRP was created.
  471. Return Value:
  472. None.
  473. --*/
  474. {
  475. return;
  476. }
  477. VOID
  478. I8042DispatchSystemControl (
  479. PIRP Irp,
  480. PVOID DeviceContext,
  481. PVOID IrpContext
  482. )
  483. /*++
  484. Routine Description:
  485. This routine handles System Control IRPs.
  486. Arguments:
  487. Irp - Supplies a pointer to the I/O request packet.
  488. DeviceContext - Supplies the context pointer supplied by the driver when it
  489. attached itself to the driver stack. Presumably this pointer contains
  490. driver-specific device context.
  491. IrpContext - Supplies the context pointer supplied by the driver when
  492. the IRP was created.
  493. Return Value:
  494. None.
  495. --*/
  496. {
  497. ASSERT(Irp->MajorCode == IrpMajorSystemControl);
  498. //
  499. // Do no processing on any IRPs. Let them flow.
  500. //
  501. return;
  502. }
  503. INTERRUPT_STATUS
  504. I8042InterruptService (
  505. PVOID Context
  506. )
  507. /*++
  508. Routine Description:
  509. This routine implements the 8042 keyboard controller interrupt service
  510. routine.
  511. Arguments:
  512. Context - Supplies the context pointer given to the system when the
  513. interrupt was connected. In this case, this points to the 8042 device
  514. context.
  515. Return Value:
  516. Interrupt status.
  517. --*/
  518. {
  519. UCHAR Byte;
  520. PI8042_DEVICE Device;
  521. INTERRUPT_STATUS InterruptStatus;
  522. ULONG WriteIndex;
  523. Device = (PI8042_DEVICE)Context;
  524. InterruptStatus = InterruptStatusNotClaimed;
  525. //
  526. // Check to see if there is data waiting.
  527. //
  528. if ((READ_STATUS_REGISTER(Device) & I8042_STATUS_OUTPUT_BUFFER_FULL) != 0) {
  529. //
  530. // There was data here, so most likely it was this device interrupting.
  531. //
  532. InterruptStatus = InterruptStatusClaimed;
  533. //
  534. // Read the bytes out of the controller.
  535. //
  536. KeAcquireSpinLock(&(Device->InterruptLock));
  537. WriteIndex = Device->WriteIndex;
  538. while ((READ_STATUS_REGISTER(Device) &
  539. I8042_STATUS_OUTPUT_BUFFER_FULL) != 0) {
  540. Byte = READ_DATA_REGISTER(Device);
  541. if (((WriteIndex + 1) % I8042_BUFFER_SIZE) != Device->ReadIndex) {
  542. Device->DataBuffer[WriteIndex] = Byte;
  543. //
  544. // Advance the write index.
  545. //
  546. if ((WriteIndex + 1) == I8042_BUFFER_SIZE) {
  547. WriteIndex = 0;
  548. } else {
  549. WriteIndex += 1;
  550. }
  551. } else {
  552. RtlDebugPrint("I8042: Buffer overflow, losing byte %02X\n",
  553. Byte);
  554. }
  555. }
  556. //
  557. // Save the new write index now that everything's out.
  558. //
  559. Device->WriteIndex = WriteIndex;
  560. KeReleaseSpinLock(&(Device->InterruptLock));
  561. }
  562. return InterruptStatus;
  563. }
  564. INTERRUPT_STATUS
  565. I8042InterruptServiceWorker (
  566. PVOID Parameter
  567. )
  568. /*++
  569. Routine Description:
  570. This routine processes interrupts for the e100 controller at low level.
  571. Arguments:
  572. Parameter - Supplies an optional parameter passed in by the creator of the
  573. work item.
  574. Return Value:
  575. Interrupt status.
  576. --*/
  577. {
  578. UCHAR Byte;
  579. UCHAR Code1;
  580. UCHAR Code2;
  581. UCHAR Code3;
  582. PI8042_DEVICE Device;
  583. USER_INPUT_EVENT Event;
  584. BOOL KeyUp;
  585. ULONG ReadIndex;
  586. Code1 = 0;
  587. Code2 = 0;
  588. Code3 = 0;
  589. Device = (PI8042_DEVICE)Parameter;
  590. ASSERT(KeGetRunLevel() == RunLevelLow);
  591. RtlZeroMemory(&Event, sizeof(USER_INPUT_EVENT));
  592. //
  593. // Pull as much data out of the buffer as there is.
  594. //
  595. KeAcquireQueuedLock(Device->ReadLock);
  596. ReadIndex = Device->ReadIndex;
  597. while (ReadIndex != Device->WriteIndex) {
  598. Byte = Device->DataBuffer[ReadIndex];
  599. ReadIndex += 1;
  600. if (ReadIndex == I8042_BUFFER_SIZE) {
  601. ReadIndex = 0;
  602. }
  603. //
  604. // If the first byte read was the extended 2 code, then another 2 bytes
  605. // should be coming in. Get those bytes.
  606. //
  607. if (Code1 == SCAN_CODE_1_EXTENDED_2_CODE) {
  608. if (Code2 == 0) {
  609. Code2 = Byte;
  610. continue;
  611. }
  612. Code3 = Byte;
  613. //
  614. // If the first byte read was the extended (1) code, then another byte
  615. // should be coming in. Get that byte.
  616. //
  617. } else if (Code1 == SCAN_CODE_1_EXTENDED_CODE) {
  618. Code2 = Byte;
  619. } else {
  620. Code1 = Byte;
  621. if ((Code1 == SCAN_CODE_1_EXTENDED_CODE) ||
  622. (Code1 == SCAN_CODE_1_EXTENDED_2_CODE)) {
  623. continue;
  624. }
  625. }
  626. //
  627. // Get the specifics of the event.
  628. //
  629. Event.U.Key = I8042ConvertScanCodeToKey(Code1, Code2, Code3, &KeyUp);
  630. if (Event.U.Key != KeyboardKeyInvalid) {
  631. if (KeyUp != FALSE) {
  632. Event.EventType = UserInputEventKeyUp;
  633. } else {
  634. Event.EventType = UserInputEventKeyDown;
  635. }
  636. //
  637. // Log the event.
  638. //
  639. InReportInputEvent(Device->UserInputDeviceHandle, &Event);
  640. }
  641. //
  642. // A full key combination was read, move the read index forward.
  643. //
  644. Device->ReadIndex = ReadIndex;
  645. Code1 = 0;
  646. Code2 = 0;
  647. }
  648. KeReleaseQueuedLock(Device->ReadLock);
  649. return InterruptStatusClaimed;
  650. }
  651. KSTATUS
  652. I8042pProcessResourceRequirements (
  653. PIRP Irp,
  654. PI8042_DEVICE Device
  655. )
  656. /*++
  657. Routine Description:
  658. This routine filters through the resource requirements presented by the
  659. bus. It adds an interrupt vector requirement for any interrupt line
  660. requested.
  661. Arguments:
  662. Irp - Supplies a pointer to the I/O request packet.
  663. Device - Supplies a pointer to this 8042 controller device.
  664. Return Value:
  665. Status code.
  666. --*/
  667. {
  668. PRESOURCE_CONFIGURATION_LIST Requirements;
  669. KSTATUS Status;
  670. RESOURCE_REQUIREMENT VectorRequirement;
  671. ASSERT((Irp->MajorCode == IrpMajorStateChange) &&
  672. (Irp->MinorCode == IrpMinorQueryResources));
  673. //
  674. // Initialize a nice interrupt vector requirement in preparation.
  675. //
  676. RtlZeroMemory(&VectorRequirement, sizeof(RESOURCE_REQUIREMENT));
  677. VectorRequirement.Type = ResourceTypeInterruptVector;
  678. VectorRequirement.Minimum = 0;
  679. VectorRequirement.Maximum = -1;
  680. VectorRequirement.Length = 1;
  681. //
  682. // Loop through all configuration lists, creating a vector for each line.
  683. //
  684. Requirements = Irp->U.QueryResources.ResourceRequirements;
  685. Status = IoCreateAndAddInterruptVectorsForLines(Requirements,
  686. &VectorRequirement);
  687. if (!KSUCCESS(Status)) {
  688. goto ProcessResourceRequirementsEnd;
  689. }
  690. ProcessResourceRequirementsEnd:
  691. return Status;
  692. }
  693. KSTATUS
  694. I8042pStartDevice (
  695. PIRP Irp,
  696. PI8042_DEVICE Device
  697. )
  698. /*++
  699. Routine Description:
  700. This routine starts up the 8042 controller.
  701. Arguments:
  702. Irp - Supplies a pointer to the I/O request packet.
  703. Device - Supplies a pointer to this 8042 controller device.
  704. Return Value:
  705. Status code.
  706. --*/
  707. {
  708. PRESOURCE_ALLOCATION Allocation;
  709. PRESOURCE_ALLOCATION_LIST AllocationList;
  710. IO_CONNECT_INTERRUPT_PARAMETERS Connect;
  711. BOOL ControlFound;
  712. BOOL DataFound;
  713. PRESOURCE_ALLOCATION LineAllocation;
  714. KSTATUS Status;
  715. ControlFound = FALSE;
  716. DataFound = FALSE;
  717. //
  718. // If there are no resources, then return success but don't start anything.
  719. //
  720. AllocationList = Irp->U.StartDevice.ProcessorLocalResources;
  721. if (AllocationList == NULL) {
  722. Status = STATUS_SUCCESS;
  723. goto StartDeviceEnd;
  724. }
  725. //
  726. // Loop through the allocated resources to get the control and data ports,
  727. // and the interrupt.
  728. //
  729. Allocation = IoGetNextResourceAllocation(AllocationList, NULL);
  730. while (Allocation != NULL) {
  731. if (Allocation->Type == ResourceTypeIoPort) {
  732. ASSERT(Allocation->Length == 1);
  733. ASSERT(Allocation->Allocation <= 0xFFFF);
  734. //
  735. // Assume the first resource is the data port.
  736. //
  737. if (DataFound == FALSE) {
  738. Device->DataPort = (USHORT)Allocation->Allocation;
  739. DataFound = TRUE;
  740. //
  741. // The second resource must be the control port.
  742. //
  743. } else if (ControlFound == FALSE) {
  744. Device->ControlPort = (USHORT)Allocation->Allocation;
  745. ControlFound = TRUE;
  746. }
  747. //
  748. // If the resource is an interrupt vector, then it should have an
  749. // owning interrupt line allocation.
  750. //
  751. } else if (Allocation->Type == ResourceTypeInterruptVector) {
  752. //
  753. // Currently only one interrupt resource is expected.
  754. //
  755. ASSERT(Device->InterruptResourcesFound == FALSE);
  756. ASSERT(Allocation->OwningAllocation != NULL);
  757. //
  758. // Save the line and vector number.
  759. //
  760. LineAllocation = Allocation->OwningAllocation;
  761. Device->InterruptLine = LineAllocation->Allocation;
  762. Device->InterruptVector = Allocation->Allocation;
  763. Device->InterruptResourcesFound = TRUE;
  764. }
  765. //
  766. // Get the next allocation in the list.
  767. //
  768. Allocation = IoGetNextResourceAllocation(AllocationList, Allocation);
  769. }
  770. //
  771. // Fail if both ports were not found.
  772. //
  773. if ((DataFound == FALSE) || (ControlFound == FALSE)) {
  774. Status = STATUS_INVALID_CONFIGURATION;
  775. goto StartDeviceEnd;
  776. }
  777. //
  778. // Fire up the device.
  779. //
  780. Status = I8042pEnableDevice(Irp->Device, Device);
  781. if (!KSUCCESS(Status)) {
  782. goto StartDeviceEnd;
  783. }
  784. //
  785. // Attempt to connect the interrupt.
  786. //
  787. ASSERT(Device->InterruptHandle == INVALID_HANDLE);
  788. RtlZeroMemory(&Connect, sizeof(IO_CONNECT_INTERRUPT_PARAMETERS));
  789. Connect.Version = IO_CONNECT_INTERRUPT_PARAMETERS_VERSION;
  790. Connect.Device = Irp->Device;
  791. Connect.LineNumber = Device->InterruptLine;
  792. Connect.Vector = Device->InterruptVector;
  793. Connect.InterruptServiceRoutine = I8042InterruptService;
  794. Connect.LowLevelServiceRoutine = I8042InterruptServiceWorker;
  795. Connect.Context = Device;
  796. Connect.Interrupt = &(Device->InterruptHandle);
  797. Status = IoConnectInterrupt(&Connect);
  798. if (!KSUCCESS(Status)) {
  799. goto StartDeviceEnd;
  800. }
  801. StartDeviceEnd:
  802. if (!KSUCCESS(Status)) {
  803. Device->InterruptResourcesFound = FALSE;
  804. if (Device->InterruptHandle != INVALID_HANDLE) {
  805. IoDisconnectInterrupt(Device->InterruptHandle);
  806. Device->InterruptHandle = INVALID_HANDLE;
  807. }
  808. if (Device->UserInputDeviceHandle != INVALID_HANDLE) {
  809. InDestroyInputDevice(Device->UserInputDeviceHandle);
  810. Device->UserInputDeviceHandle = INVALID_HANDLE;
  811. }
  812. }
  813. return Status;
  814. }
  815. KSTATUS
  816. I8042pEnableDevice (
  817. PVOID OsDevice,
  818. PI8042_DEVICE Device
  819. )
  820. /*++
  821. Routine Description:
  822. This routine enables the given 8042 device.
  823. Arguments:
  824. OsDevice - Supplies a pointer to the OS device token.
  825. Device - Supplies a pointer to this 8042 controller device.
  826. Return Value:
  827. Status code.
  828. --*/
  829. {
  830. UCHAR CommandByte;
  831. USER_INPUT_DEVICE_DESCRIPTION Description;
  832. UCHAR Response;
  833. KSTATUS Status;
  834. BOOL TwoPorts;
  835. if (Device->IsMouse != FALSE) {
  836. //
  837. // Mice are not currently supported.
  838. //
  839. return STATUS_NOT_IMPLEMENTED;
  840. } else {
  841. //
  842. // Disable both ports.
  843. //
  844. I8042pSendCommand(Device, I8042_COMMAND_DISABLE_KEYBOARD);
  845. I8042pSendCommand(Device, I8042_COMMAND_DISABLE_MOUSE_PORT);
  846. //
  847. // Flush any leftover data out.
  848. //
  849. while ((READ_STATUS_REGISTER(Device) &
  850. I8042_STATUS_OUTPUT_BUFFER_FULL) != 0) {
  851. READ_DATA_REGISTER(Device);
  852. }
  853. //
  854. // Enable the keyboard in the command byte. Disable the interrupt
  855. // for now during setup.
  856. //
  857. CommandByte = I8042pReadCommandByte(Device);
  858. CommandByte &= ~(I8042_COMMAND_BYTE_KEYBOARD_DISABLED |
  859. I8042_COMMAND_BYTE_PCAT_INHIBIT |
  860. I8042_COMMAND_BYTE_KEYBOARD_INTERRUPT_ENABLED |
  861. I8042_COMMAND_BYTE_MOUSE_INTERRUPT_ENABLED);
  862. I8042pWriteCommandByte(Device, CommandByte);
  863. //
  864. // Send a self test to the controller itself, and verify that it
  865. // passes.
  866. //
  867. I8042pSendCommand(Device, I8042_COMMAND_SELF_TEST);
  868. HlBusySpin(I8042_RESET_DELAY);
  869. Status = I8042pReceiveResponse(Device, &Response);
  870. if (!KSUCCESS(Status)) {
  871. goto EnableDeviceEnd;
  872. }
  873. if (Response != I8042_SELF_TEST_SUCCESS) {
  874. RtlDebugPrint("i8042: Received %x to keyboard reset instead of "
  875. "expected %x.\n",
  876. Response,
  877. I8042_SELF_TEST_SUCCESS);
  878. Status = STATUS_DEVICE_IO_ERROR;
  879. goto EnableDeviceEnd;
  880. }
  881. //
  882. // Determine if there are two ports. Enable the mouse port, and the
  883. // "data from mouse" bit in the status should clear.
  884. //
  885. TwoPorts = FALSE;
  886. I8042pSendCommand(Device, I8042_COMMAND_ENABLE_MOUSE_PORT);
  887. if ((READ_STATUS_REGISTER(Device) &
  888. I8042_STATUS_DATA_FROM_MOUSE) == 0) {
  889. TwoPorts = TRUE;
  890. }
  891. I8042pSendCommand(Device, I8042_COMMAND_DISABLE_MOUSE_PORT);
  892. //
  893. // Test the ports.
  894. //
  895. I8042pSendCommand(Device, I8042_COMMAND_INTERFACE_TEST);
  896. Status = I8042pReceiveResponse(Device, &Response);
  897. if (!KSUCCESS(Status)) {
  898. goto EnableDeviceEnd;
  899. }
  900. if (Response != I8042_PORT_TEST_SUCCESS) {
  901. Status = STATUS_DEVICE_IO_ERROR;
  902. goto EnableDeviceEnd;
  903. }
  904. if (TwoPorts != FALSE) {
  905. I8042pSendCommand(Device, I8042_COMMAND_TEST_MOUSE_PORT);
  906. Status = I8042pReceiveResponse(Device, &Response);
  907. if (!KSUCCESS(Status)) {
  908. goto EnableDeviceEnd;
  909. }
  910. if (Response != I8042_PORT_TEST_SUCCESS) {
  911. Status = STATUS_DEVICE_IO_ERROR;
  912. goto EnableDeviceEnd;
  913. }
  914. }
  915. //
  916. // Enable the ports.
  917. //
  918. I8042pSendCommand(Device, I8042_COMMAND_ENABLE_KEYBOARD);
  919. if (TwoPorts != FALSE) {
  920. I8042pSendCommand(Device, I8042_COMMAND_ENABLE_MOUSE_PORT);
  921. }
  922. //
  923. // Reset the keyboard.
  924. //
  925. Status = I8042pSendKeyboardCommand(Device,
  926. KEYBOARD_COMMAND_RESET,
  927. KEYBOARD_COMMAND_NO_PARAMETER);
  928. if (!KSUCCESS(Status)) {
  929. goto EnableDeviceEnd;
  930. }
  931. //
  932. // Read the BAT (Basic Assurance Test) code that the keyboard sends
  933. // when it finishes resetting.
  934. //
  935. Status = I8042pReceiveResponse(Device, &Response);
  936. if (!KSUCCESS(Status)) {
  937. goto EnableDeviceEnd;
  938. }
  939. if (Response != KEYBOARD_BAT_PASS) {
  940. goto EnableDeviceEnd;
  941. }
  942. //
  943. // Set the typematic rate/delay on the keyboard. Start by sending the
  944. // command.
  945. //
  946. Status = I8042pSendKeyboardCommand(Device,
  947. KEYBOARD_COMMAND_SET_TYPEMATIC,
  948. DEFAULT_TYPEMATIC_VALUE);
  949. if (!KSUCCESS(Status)) {
  950. goto EnableDeviceEnd;
  951. }
  952. //
  953. // Enable the keyboard.
  954. //
  955. Status = I8042pSendKeyboardCommand(Device,
  956. KEYBOARD_COMMAND_ENABLE,
  957. KEYBOARD_COMMAND_NO_PARAMETER);
  958. if (!KSUCCESS(Status)) {
  959. goto EnableDeviceEnd;
  960. }
  961. //
  962. // Create the user input handle if not already done.
  963. //
  964. if (Device->UserInputDeviceHandle == INVALID_HANDLE) {
  965. Description.Device = OsDevice;
  966. Description.DeviceContext = Device;
  967. Description.Type = UserInputDeviceKeyboard;
  968. Description.InterfaceVersion =
  969. USER_INPUT_KEYBOARD_DEVICE_INTERFACE_VERSION;
  970. Description.U.KeyboardInterface.SetLedState = I8042pSetLedState;
  971. Device->UserInputDeviceHandle = InRegisterInputDevice(&Description);
  972. if (Device->UserInputDeviceHandle == INVALID_HANDLE) {
  973. Status = STATUS_UNSUCCESSFUL;
  974. goto EnableDeviceEnd;
  975. }
  976. }
  977. //
  978. // Enable the keyboard interrupt.
  979. //
  980. CommandByte |= I8042_COMMAND_BYTE_KEYBOARD_INTERRUPT_ENABLED;
  981. I8042pWriteCommandByte(Device, CommandByte);
  982. }
  983. EnableDeviceEnd:
  984. return Status;
  985. }
  986. KSTATUS
  987. I8042pSetLedState (
  988. PVOID Device,
  989. PVOID DeviceContext,
  990. ULONG LedState
  991. )
  992. /*++
  993. Routine Description:
  994. This routine sets a keyboard's LED state (e.g. Number lock, Caps lock and
  995. scroll lock). The state is absolute; the desired state for each LED must be
  996. supplied.
  997. Arguments:
  998. Device - Supplies a pointer to the OS device representing the user input
  999. device.
  1000. DeviceContext - Supplies the opaque device context supplied in the device
  1001. description upon registration with the user input library.
  1002. LedState - Supplies a bitmask of flags describing the desired LED state.
  1003. See USER_INPUT_KEYBOARD_LED_* for definition.
  1004. Return Value:
  1005. Status code.
  1006. --*/
  1007. {
  1008. PI8042_DEVICE I8042Device;
  1009. UCHAR KeyboardLedState;
  1010. KSTATUS Status;
  1011. I8042Device = (PI8042_DEVICE)DeviceContext;
  1012. //
  1013. // Convert the LED state to the proper format.
  1014. //
  1015. KeyboardLedState = 0;
  1016. if ((LedState & USER_INPUT_KEYBOARD_LED_SCROLL_LOCK) != 0) {
  1017. KeyboardLedState |= KEYBOARD_LED_SCROLL_LOCK;
  1018. }
  1019. if ((LedState & USER_INPUT_KEYBOARD_LED_NUM_LOCK) != 0) {
  1020. KeyboardLedState |= KEYBOARD_LED_NUM_LOCK;
  1021. }
  1022. if ((LedState & USER_INPUT_KEYBOARD_LED_CAPS_LOCK) != 0) {
  1023. KeyboardLedState |= KEYBOARD_LED_CAPS_LOCK;
  1024. }
  1025. Status = I8042pSendKeyboardCommand(I8042Device,
  1026. KEYBOARD_COMMAND_SET_LEDS,
  1027. KeyboardLedState);
  1028. return Status;
  1029. }
  1030. UCHAR
  1031. I8042pReadCommandByte (
  1032. PI8042_DEVICE Device
  1033. )
  1034. /*++
  1035. Routine Description:
  1036. This routine reads the contents of the command byte in the 8042 keyboard
  1037. controller.
  1038. Arguments:
  1039. Device - Supplies a pointer to this 8042 controller device.
  1040. Return Value:
  1041. Status code.
  1042. --*/
  1043. {
  1044. I8042pSendCommand(Device, I8042_COMMAND_READ_COMMAND_BYTE);
  1045. return READ_DATA_REGISTER(Device);
  1046. }
  1047. VOID
  1048. I8042pWriteCommandByte (
  1049. PI8042_DEVICE Device,
  1050. UCHAR Value
  1051. )
  1052. /*++
  1053. Routine Description:
  1054. This routine reads the contents of the command byte in the 8042 keyboard
  1055. controller.
  1056. Arguments:
  1057. Device - Supplies a pointer to this 8042 controller device.
  1058. Value - Supplies the value to write to the command register.
  1059. Return Value:
  1060. Status code.
  1061. --*/
  1062. {
  1063. KSTATUS Status;
  1064. Status = I8042pSendCommand(Device, I8042_COMMAND_WRITE_COMMAND_BYTE);
  1065. if (KSUCCESS(Status)) {
  1066. WRITE_DATA_REGISTER(Device, Value);
  1067. }
  1068. return;
  1069. }
  1070. KSTATUS
  1071. I8042pSendKeyboardCommand (
  1072. PI8042_DEVICE Device,
  1073. UCHAR Command,
  1074. UCHAR Parameter
  1075. )
  1076. /*++
  1077. Routine Description:
  1078. This routine sends a command byte to the keyboard itself (not the
  1079. keyboard controller) and checks the return status byte.
  1080. Arguments:
  1081. Device - Supplies a pointer to this 8042 controller device.
  1082. Command - Supplies the command to write to the keyboard.
  1083. Parameter - Supplies an additional byte to send. Set this to 0xFF to
  1084. skip sending this byte.
  1085. Return Value:
  1086. Status code indicating whether the keyboard succeeded or failed the
  1087. command.
  1088. --*/
  1089. {
  1090. UCHAR KeyboardResult;
  1091. KSTATUS Status;
  1092. WAIT_FOR_INPUT_BUFFER(Device);
  1093. WRITE_DATA_REGISTER(Device, Command);
  1094. if (Parameter != KEYBOARD_COMMAND_NO_PARAMETER) {
  1095. WAIT_FOR_INPUT_BUFFER(Device);
  1096. WRITE_DATA_REGISTER(Device, Parameter);
  1097. }
  1098. Status = I8042pReceiveResponse(Device, &KeyboardResult);
  1099. if (!KSUCCESS(Status)) {
  1100. return Status;
  1101. }
  1102. if (KeyboardResult == KEYBOARD_STATUS_ACKNOWLEDGE) {
  1103. return STATUS_SUCCESS;
  1104. }
  1105. if (KeyboardResult == KEYBOARD_STATUS_RESEND) {
  1106. return STATUS_NOT_READY;
  1107. }
  1108. if (KeyboardResult == KEYBOARD_STATUS_OVERRUN) {
  1109. return STATUS_BUFFER_OVERRUN;
  1110. }
  1111. return STATUS_DEVICE_IO_ERROR;
  1112. }
  1113. KSTATUS
  1114. I8042pSendCommand (
  1115. PI8042_DEVICE Device,
  1116. UCHAR Command
  1117. )
  1118. /*++
  1119. Routine Description:
  1120. This routine sends a command to the PS/2 controller (not the device
  1121. connected to it).
  1122. Arguments:
  1123. Device - Supplies a pointer to this 8042 controller device.
  1124. Command - Supplies the command to write to the controller.
  1125. Return Value:
  1126. Status code indicating whether the keyboard succeeded or failed the
  1127. command.
  1128. --*/
  1129. {
  1130. WAIT_FOR_INPUT_BUFFER(Device);
  1131. WRITE_CONTROL_REGISTER(Device, Command);
  1132. WAIT_FOR_INPUT_BUFFER(Device);
  1133. return STATUS_SUCCESS;
  1134. }
  1135. KSTATUS
  1136. I8042pReceiveResponse (
  1137. PI8042_DEVICE Device,
  1138. PUCHAR Data
  1139. )
  1140. /*++
  1141. Routine Description:
  1142. This routine receives a byte from the data port, with a timeout.
  1143. Arguments:
  1144. Device - Supplies a pointer to this 8042 controller device.
  1145. Data - Supplies a pointer where the data will be returned on success.
  1146. Return Value:
  1147. Status code.
  1148. --*/
  1149. {
  1150. KSTATUS StatusCode;
  1151. UCHAR StatusRegister;
  1152. ULONGLONG Timeout;
  1153. Timeout = KeGetRecentTimeCounter() +
  1154. ((HlQueryTimeCounterFrequency() * I8042_COMMAND_TIMEOUT) /
  1155. MILLISECONDS_PER_SECOND);
  1156. StatusCode = STATUS_TIMEOUT;
  1157. do {
  1158. StatusRegister = READ_STATUS_REGISTER(Device);
  1159. if ((StatusRegister & I8042_STATUS_TIMEOUT) != 0) {
  1160. StatusCode = STATUS_TIMEOUT;
  1161. break;
  1162. } else if ((StatusRegister & I8042_STATUS_PARITY_ERROR) != 0) {
  1163. StatusCode = STATUS_PARITY_ERROR;
  1164. break;
  1165. } else if ((StatusRegister & I8042_STATUS_OUTPUT_BUFFER_FULL) != 0) {
  1166. *Data = READ_DATA_REGISTER(Device);
  1167. StatusCode = STATUS_SUCCESS;
  1168. break;
  1169. }
  1170. } while (KeGetRecentTimeCounter() <= Timeout);
  1171. return StatusCode;
  1172. }