pl050.c 35 KB

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