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.

4716 lines
151 KiB

  1. /*++
  2. Copyright (c) 1990-1998 Microsoft Corporation, All Rights Reserved
  3. Module Name:
  4. moudep.c
  5. Abstract:
  6. The initialization and hardware-dependent portions of
  7. the Intel i8042 port driver which are specific to
  8. 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. Revision History:
  16. --*/
  17. #include "stdarg.h"
  18. #include "stdio.h"
  19. #include "string.h"
  20. #include "i8042prt.h"
  21. #include "i8042log.h"
  22. //
  23. // Use the alloc_text pragma to specify the driver initialization routines
  24. // (they can be paged out).
  25. //
  26. #ifdef ALLOC_PRAGMA
  27. #pragma alloc_text(PAGE, I8xMouseConfiguration)
  28. #pragma alloc_text(PAGE, I8xMouseServiceParameters)
  29. #pragma alloc_text(PAGE, I8xInitializeMouse)
  30. #pragma alloc_text(PAGE, I8xGetBytePolledIterated)
  31. #pragma alloc_text(PAGE, I8xTransmitByteSequence)
  32. #pragma alloc_text(PAGE, I8xFindWheelMouse)
  33. #pragma alloc_text(PAGE, I8xQueryNumberOfMouseButtons)
  34. #pragma alloc_text(PAGE, MouseCopyWheelIDs)
  35. //
  36. // These will be locked down right before the mouse interrupt is enabled if a
  37. // mouse is present
  38. //
  39. #pragma alloc_text(PAGEMOUC, I8042MouseInterruptService)
  40. #pragma alloc_text(PAGEMOUC, I8xQueueCurrentMouseInput)
  41. #pragma alloc_text(PAGEMOUC, I8xVerifyMousePnPID)
  42. #endif
  43. #define ONE_PAST_FINAL_SAMPLE ((UCHAR) 0x00)
  44. static const
  45. UCHAR PnpDetectCommands[] = { 20,
  46. 40,
  47. 60,
  48. ONE_PAST_FINAL_SAMPLE
  49. };
  50. static const
  51. UCHAR WheelEnableCommands[] = { 200,
  52. 100,
  53. 80,
  54. ONE_PAST_FINAL_SAMPLE
  55. };
  56. static const
  57. UCHAR FiveButtonEnableCommands[] = { 200,
  58. 200,
  59. 80,
  60. ONE_PAST_FINAL_SAMPLE
  61. };
  62. #if MOUSE_RECORD_ISR
  63. PMOUSE_STATE_RECORD IsrStateHistory = NULL;
  64. PMOUSE_STATE_RECORD CurrentIsrState = NULL;
  65. PMOUSE_STATE_RECORD IsrStateHistoryEnd = NULL;
  66. #endif // MOUSE_RECORD_ISR
  67. #define BUFFER_FULL (OUTPUT_BUFFER_FULL | MOUSE_OUTPUT_BUFFER_FULL)
  68. #define RML_BUTTONS (RIGHT_BUTTON | MIDDLE_BUTTON | LEFT_BUTTON)
  69. #define BUTTONS_4_5 (BUTTON_4 | BUTTON_5)
  70. #define _TRANSITION_DOWN(previous, current, button) \
  71. ((!(previous & button)) && (current & button))
  72. #define _TRANSITION_UP(previous, current, button) \
  73. ((previous & button) && (!(current & button)))
  74. BOOLEAN
  75. I8042MouseInterruptService(
  76. IN PKINTERRUPT Interrupt,
  77. IN PDEVICE_OBJECT DeviceObject
  78. )
  79. /*++
  80. Routine Description:
  81. This routine performs the actual work. It either processes a mouse packet
  82. or the results from a write to the device.
  83. Arguments:
  84. CallIsrContext - Contains the interrupt object and device object.
  85. Return Value:
  86. TRUE if the interrupt was truly ours
  87. --*/
  88. {
  89. PPORT_MOUSE_EXTENSION deviceExtension;
  90. LARGE_INTEGER tickDelta, newTick;
  91. UCHAR previousButtons;
  92. UCHAR previousSignAndOverflow;
  93. UCHAR byte, statusByte, lastByte;
  94. UCHAR resendCommand, nextCommand, altCommand;
  95. BOOLEAN bSendCommand, ret = TRUE;
  96. static PWCHAR currentIdChar;
  97. #define TRANSITION_UP(button) _TRANSITION_UP(previousButtons, byte, button)
  98. #define TRANSITION_DOWN(button) _TRANSITION_DOWN(previousButtons, byte, button)
  99. IsrPrint(DBG_MOUISR_TRACE, ("%s\n", pEnter));
  100. deviceExtension = (PPORT_MOUSE_EXTENSION) DeviceObject->DeviceExtension;
  101. if (deviceExtension->PowerState != PowerDeviceD0) {
  102. return FALSE;
  103. }
  104. //
  105. // Verify that this device really interrupted. Check the status
  106. // register. The Output Buffer Full bit should be set, and the
  107. // Auxiliary Device Output Buffer Full bit should be set.
  108. //
  109. statusByte =
  110. I8X_GET_STATUS_BYTE(Globals.ControllerData->DeviceRegisters[CommandPort]);
  111. if ((statusByte & BUFFER_FULL) != BUFFER_FULL) {
  112. //
  113. // Stall and then try again. The Olivetti MIPS machine
  114. // sometimes gets a mouse interrupt before the status
  115. // register is set.
  116. //
  117. KeStallExecutionProcessor(10);
  118. statusByte = I8X_GET_STATUS_BYTE(Globals.ControllerData->DeviceRegisters[CommandPort]);
  119. if ((statusByte & BUFFER_FULL) != BUFFER_FULL) {
  120. //
  121. // Not our interrupt.
  122. //
  123. IsrPrint(DBG_MOUISR_ERROR | DBG_MOUISR_INFO,
  124. ("not our interrupt!\n"
  125. ));
  126. return FALSE;
  127. }
  128. }
  129. //
  130. // Read the byte from the i8042 data port.
  131. //
  132. I8xGetByteAsynchronous(
  133. (CCHAR) MouseDeviceType,
  134. &byte
  135. );
  136. IsrPrint(DBG_MOUISR_BYTE, ("byte 0x%x\n", byte));
  137. KeQueryTickCount(&newTick);
  138. if (deviceExtension->InputResetSubState == QueueingMouseReset) {
  139. RECORD_ISR_STATE(deviceExtension,
  140. byte,
  141. deviceExtension->LastByteReceived,
  142. newTick);
  143. return TRUE;
  144. }
  145. if (deviceExtension->InputState == MouseResetting && byte == FAILURE) {
  146. RECORD_ISR_STATE(deviceExtension,
  147. byte,
  148. deviceExtension->LastByteReceived,
  149. newTick);
  150. deviceExtension->LastByteReceived = byte;
  151. ret = TRUE;
  152. goto IsrResetMouse;
  153. }
  154. if (deviceExtension->IsrHookCallback) {
  155. BOOLEAN cont= FALSE;
  156. ret = (*deviceExtension->IsrHookCallback)(
  157. deviceExtension->HookContext,
  158. &deviceExtension->CurrentInput,
  159. &deviceExtension->CurrentOutput,
  160. statusByte,
  161. &byte,
  162. &cont,
  163. &deviceExtension->InputState,
  164. &deviceExtension->InputResetSubState
  165. );
  166. if (!cont) {
  167. return ret;
  168. }
  169. }
  170. //
  171. // Watch the data stream for a reset completion (0xaa) followed by the
  172. // device id
  173. //
  174. // this pattern can appear as part of a normal data packet as well. This
  175. // code assumes that sending an enable to an already enabled mouse will:
  176. // * not hang the mouse
  177. // * abort the current packet and return an ACK.
  178. //
  179. if (deviceExtension->LastByteReceived == MOUSE_COMPLETE &&
  180. (byte == 0x00 || byte == 0x03)) {
  181. IsrPrint(DBG_MOUISR_RESETTING, ("received id %2d\n", byte));
  182. RECORD_ISR_STATE(deviceExtension,
  183. byte,
  184. deviceExtension->LastByteReceived,
  185. newTick);
  186. if (InterlockedCompareExchangePointer(&deviceExtension->ResetIrp,
  187. NULL,
  188. NULL) == NULL) {
  189. //
  190. // user unplugged and plugged in the mouse...queue a reset packet
  191. // so the programming of the mouse in the ISR does not conflict with
  192. // any other writes to the i8042prt controller
  193. //
  194. IsrPrint(DBG_MOUISR_RESETTING, ("user initiated reset...queueing\n"));
  195. goto IsrResetMouseOnly;
  196. }
  197. //
  198. // Tell the 8042 port to fetch the device ID of the aux device
  199. // We do this async so that we don't spin at IRQ1!!!
  200. //
  201. I8X_WRITE_CMD_TO_MOUSE();
  202. I8X_MOUSE_COMMAND( GET_DEVICE_ID );
  203. RECORD_ISR_STATE_COMMAND(deviceExtension, GET_DEVICE_ID);
  204. //
  205. // This is part of the substate system for handling a (possible)
  206. // mouse reset.
  207. //
  208. deviceExtension->InputState = MouseResetting;
  209. deviceExtension->InputResetSubState =
  210. ExpectingGetDeviceIdACK;
  211. //
  212. // We don't want to execute any more of the ISR code, so lets just
  213. // do a few things and then return now
  214. //
  215. deviceExtension->LastByteReceived = byte;
  216. deviceExtension->ResendCount = 0;
  217. //
  218. // Done
  219. //
  220. return TRUE;
  221. }
  222. if (deviceExtension->InputState == MouseIdle &&
  223. deviceExtension->CurrentOutput.State != Idle &&
  224. DeviceObject->CurrentIrp != NULL) {
  225. if (byte == RESEND) {
  226. //
  227. // If the timer count is zero, don't process the interrupt
  228. // further. The timeout routine will complete this request.
  229. //
  230. if (Globals.ControllerData->TimerCount == 0) {
  231. return FALSE;
  232. }
  233. //
  234. // Reset the timeout value to indicate no timeout.
  235. //
  236. Globals.ControllerData->TimerCount = I8042_ASYNC_NO_TIMEOUT;
  237. if (deviceExtension->ResendCount <
  238. Globals.ControllerData->Configuration.ResendIterations) {
  239. //
  240. // retard the byte count to resend the last byte
  241. //
  242. deviceExtension->CurrentOutput.CurrentByte -= 1;
  243. deviceExtension->ResendCount += 1;
  244. I8xInitiateIo(DeviceObject);
  245. } else {
  246. deviceExtension->CurrentOutput.State = Idle;
  247. KeInsertQueueDpc(&deviceExtension->RetriesExceededDpc,
  248. DeviceObject,
  249. NULL
  250. );
  251. return TRUE;
  252. }
  253. }
  254. else if (byte == ACKNOWLEDGE) {
  255. //
  256. // The keyboard controller has acknowledged a previous send.
  257. // If there are more bytes to send for the current packet, initiate
  258. // the next send operation. Otherwise, queue the completion DPC.
  259. //
  260. // If the timer count is zero, don't process the interrupt
  261. // further. The timeout routine will complete this request.
  262. //
  263. if (Globals.ControllerData->TimerCount == 0) {
  264. return FALSE;
  265. }
  266. //
  267. // Reset the timeout value to indicate no timeout.
  268. //
  269. Globals.ControllerData->TimerCount = I8042_ASYNC_NO_TIMEOUT;
  270. //
  271. // Reset resend count.
  272. //
  273. deviceExtension->ResendCount = 0;
  274. if (deviceExtension->CurrentOutput.CurrentByte <
  275. deviceExtension->CurrentOutput.ByteCount) {
  276. //
  277. // We've successfully sent the first byte of a 2-byte
  278. // command sequence. Initiate a send of the second byte.
  279. //
  280. IsrPrint(DBG_MOUISR_STATE,
  281. ("now initiate send of byte #%d\n",
  282. deviceExtension->CurrentOutput.CurrentByte
  283. ));
  284. I8xInitiateIo(DeviceObject);
  285. }
  286. else {
  287. //
  288. // We've successfully sent all bytes in the command sequence.
  289. // Reset the current state and queue the completion DPC.
  290. //
  291. IsrPrint(DBG_MOUISR_STATE,
  292. ("all bytes have been sent\n"
  293. ));
  294. deviceExtension->CurrentOutput.State = Idle;
  295. ASSERT(DeviceObject->CurrentIrp != NULL);
  296. IoRequestDpc(
  297. DeviceObject,
  298. DeviceObject->CurrentIrp,
  299. IntToPtr(IsrDpcCauseMouseWriteComplete)
  300. );
  301. }
  302. //
  303. // No matter what, we are done processing for now
  304. //
  305. return TRUE;
  306. }
  307. else {
  308. //
  309. // do what here, eh?
  310. //
  311. }
  312. }
  313. //
  314. // Remember what the last byte we got was
  315. //
  316. lastByte = deviceExtension->LastByteReceived;
  317. deviceExtension->LastByteReceived = byte;
  318. //
  319. // Take the appropriate action, depending on the current state.
  320. // When the state is Idle, we expect to receive mouse button
  321. // data. When the state is XMovement, we expect to receive mouse
  322. // motion in the X direction data. When the state is YMovement,
  323. // we expect to receive mouse motion in the Y direction data. Once
  324. // the Y motion data has been received, the data is queued to the
  325. // mouse InputData queue, the mouse ISR DPC is requested, and the
  326. // state returns to Idle.
  327. //
  328. tickDelta.QuadPart =
  329. newTick.QuadPart -
  330. deviceExtension->PreviousTick.QuadPart;
  331. if ((deviceExtension->InputState != MouseIdle)
  332. && (deviceExtension->InputState != MouseExpectingACK)
  333. && (deviceExtension->InputState != MouseResetting)
  334. && ((tickDelta.LowPart >= deviceExtension->SynchTickCount)
  335. || (tickDelta.HighPart != 0))) {
  336. //
  337. // It has been a long time since we got a byte of
  338. // the data packet. Assume that we are now receiving
  339. // the first byte of a new packet, and discard any
  340. // partially received packet.
  341. //
  342. // N.B. We assume that SynchTickCount is ULONG, and avoid
  343. // a LARGE_INTEGER compare with tickDelta...
  344. //
  345. IsrPrint(DBG_MOUISR_STATE,
  346. ("State was %d, synching\n",
  347. deviceExtension->InputState
  348. ));
  349. //
  350. // The device misbehaved. Lets play it safe and reset the device.
  351. //
  352. // Note: this code is meant to handle cases where some intermediate
  353. // (switch) box resets the mouse and doesn't tell us about it.
  354. // This avoid problems with trying to detect this code since there
  355. // isn't a fool proof way to do it
  356. //
  357. goto IsrResetMouse;
  358. }
  359. deviceExtension->PreviousTick = newTick;
  360. switch(deviceExtension->InputState) {
  361. //
  362. // The mouse interrupted with a status byte. The status byte
  363. // contains information on the mouse button state along with
  364. // the sign and overflow bits for the (yet-to-be-received)
  365. // X and Y motion bytes.
  366. //
  367. case MouseIdle: {
  368. IsrPrint(DBG_MOUISR_STATE, ("mouse status byte\n"));
  369. //
  370. // This is a sanity check test. It is required because some people
  371. // in industry persist in their notion that you can reset a mouse
  372. // device any time you want and not let the OS know anything about
  373. // it. This results in our nice little wheel mouse (which is a
  374. // 4 byte packet engine) suddenly only dumping 3 byte packets.
  375. //
  376. if (WHEEL_PRESENT() && (byte & 0xC8) != 8 ) { // Guaranteed True for Megallan
  377. //
  378. // We are getting a bad packet for the idle state. The best bet
  379. // is to issue a mouse reset request and hope we can recover.
  380. //
  381. goto IsrResetMouse;
  382. }
  383. //
  384. // Update CurrentInput with button transition data.
  385. // I.e., set a button up/down bit in the Buttons field if
  386. // the state of a given button has changed since we
  387. // received the last packet.
  388. //
  389. previousButtons = deviceExtension->PreviousButtons;
  390. // This clears both ButtonFlags and ButtonData
  391. deviceExtension->CurrentInput.Buttons = 0;
  392. deviceExtension->CurrentInput.Flags = 0x0;
  393. if (TRANSITION_DOWN(LEFT_BUTTON)) {
  394. deviceExtension->CurrentInput.ButtonFlags |=
  395. MOUSE_LEFT_BUTTON_DOWN;
  396. } else
  397. if (TRANSITION_UP(LEFT_BUTTON)) {
  398. deviceExtension->CurrentInput.ButtonFlags |=
  399. MOUSE_LEFT_BUTTON_UP;
  400. }
  401. if (TRANSITION_DOWN(RIGHT_BUTTON)) {
  402. deviceExtension->CurrentInput.ButtonFlags |=
  403. MOUSE_RIGHT_BUTTON_DOWN;
  404. } else
  405. if (TRANSITION_UP(RIGHT_BUTTON)) {
  406. deviceExtension->CurrentInput.ButtonFlags |=
  407. MOUSE_RIGHT_BUTTON_UP;
  408. }
  409. if (TRANSITION_DOWN(MIDDLE_BUTTON)) {
  410. deviceExtension->CurrentInput.ButtonFlags |=
  411. MOUSE_MIDDLE_BUTTON_DOWN;
  412. } else
  413. if (TRANSITION_UP(MIDDLE_BUTTON)) {
  414. deviceExtension->CurrentInput.ButtonFlags |=
  415. MOUSE_MIDDLE_BUTTON_UP;
  416. }
  417. //
  418. // Save the button state for comparison the next time around.
  419. // (previousButtons will never have 4/5 set if a 5 button mouse is
  420. // not present, but checking to see if a 5 button mouse is present
  421. // is just as expensive as the additional & and | so just do it with
  422. // out regard to the 5 button mouse's presence
  423. //
  424. deviceExtension->PreviousButtons =
  425. (byte & RML_BUTTONS) | (previousButtons & BUTTONS_4_5);
  426. //
  427. // Save the sign and overflow information from the current byte.
  428. //
  429. deviceExtension->CurrentSignAndOverflow =
  430. (UCHAR) (byte & MOUSE_SIGN_OVERFLOW_MASK);
  431. //
  432. // Update to the next state.
  433. //
  434. deviceExtension->InputState = XMovement;
  435. break;
  436. }
  437. //
  438. // The mouse interrupted with the X motion byte. Apply
  439. // the sign and overflow bits from the mouse status byte received
  440. // previously. Attempt to correct for bogus changes in sign
  441. // that occur with large, rapid mouse movements.
  442. //
  443. case XMovement: {
  444. IsrPrint(DBG_MOUISR_STATE, ("mouse LastX byte\n"));
  445. //
  446. // Update CurrentInput with the X motion data.
  447. //
  448. if (deviceExtension->CurrentSignAndOverflow
  449. & X_OVERFLOW) {
  450. //
  451. // Handle overflow in the X direction. If the previous
  452. // mouse movement overflowed too, ensure that the current
  453. // overflow is in the same direction (i.e., that the sign
  454. // is the same as it was for the previous event). We do this
  455. // to correct for hardware problems -- it should not be possible
  456. // to overflow in one direction and then immediately overflow
  457. // in the opposite direction.
  458. //
  459. previousSignAndOverflow =
  460. deviceExtension->PreviousSignAndOverflow;
  461. if (previousSignAndOverflow & X_OVERFLOW) {
  462. if ((previousSignAndOverflow & X_DATA_SIGN) !=
  463. (deviceExtension->CurrentSignAndOverflow
  464. & X_DATA_SIGN)) {
  465. deviceExtension->CurrentSignAndOverflow
  466. ^= X_DATA_SIGN;
  467. }
  468. }
  469. if (deviceExtension->CurrentSignAndOverflow &
  470. X_DATA_SIGN)
  471. deviceExtension->CurrentInput.LastX =
  472. (LONG) MOUSE_MAXIMUM_NEGATIVE_DELTA;
  473. else
  474. deviceExtension->CurrentInput.LastX =
  475. (LONG) MOUSE_MAXIMUM_POSITIVE_DELTA;
  476. } else {
  477. //
  478. // No overflow. Just store the data, correcting for the
  479. // sign if necessary.
  480. //
  481. deviceExtension->CurrentInput.LastX = (ULONG) byte;
  482. if (deviceExtension->CurrentSignAndOverflow &
  483. X_DATA_SIGN)
  484. deviceExtension->CurrentInput.LastX |=
  485. MOUSE_MAXIMUM_NEGATIVE_DELTA;
  486. }
  487. //
  488. // Update to the next state.
  489. //
  490. deviceExtension->InputState = YMovement;
  491. break;
  492. }
  493. //
  494. // The mouse interrupted with the Y motion byte. Apply
  495. // the sign and overflow bits from the mouse status byte received
  496. // previously. [Attempt to correct for bogus changes in sign
  497. // that occur with large, rapid mouse movements.] Write the
  498. // data to the mouse InputData queue, and queue the mouse ISR DPC
  499. // to complete the interrupt processing.
  500. //
  501. case YMovement: {
  502. IsrPrint(DBG_MOUISR_STATE, ("mouse LastY byte\n"));
  503. //
  504. // Update CurrentInput with the Y motion data.
  505. //
  506. if (deviceExtension->CurrentSignAndOverflow
  507. & Y_OVERFLOW) {
  508. //
  509. // Handle overflow in the Y direction. If the previous
  510. // mouse movement overflowed too, ensure that the current
  511. // overflow is in the same direction (i.e., that the sign
  512. // is the same as it was for the previous event). We do this
  513. // to correct for hardware problems -- it should not be possible
  514. // to overflow in one direction and then immediately overflow
  515. // in the opposite direction.
  516. //
  517. previousSignAndOverflow =
  518. deviceExtension->PreviousSignAndOverflow;
  519. if (previousSignAndOverflow & Y_OVERFLOW) {
  520. if ((previousSignAndOverflow & Y_DATA_SIGN) !=
  521. (deviceExtension->CurrentSignAndOverflow
  522. & Y_DATA_SIGN)) {
  523. deviceExtension->CurrentSignAndOverflow
  524. ^= Y_DATA_SIGN;
  525. }
  526. }
  527. if (deviceExtension->CurrentSignAndOverflow &
  528. Y_DATA_SIGN)
  529. deviceExtension->CurrentInput.LastY =
  530. (LONG) MOUSE_MAXIMUM_POSITIVE_DELTA;
  531. else
  532. deviceExtension->CurrentInput.LastY =
  533. (LONG) MOUSE_MAXIMUM_NEGATIVE_DELTA;
  534. } else {
  535. //
  536. // No overflow. Just store the data, correcting for the
  537. // sign if necessary.
  538. //
  539. deviceExtension->CurrentInput.LastY = (ULONG) byte;
  540. if (deviceExtension->CurrentSignAndOverflow &
  541. Y_DATA_SIGN)
  542. deviceExtension->CurrentInput.LastY |=
  543. MOUSE_MAXIMUM_NEGATIVE_DELTA;
  544. //
  545. // Negate the LastY value (the hardware reports positive
  546. // motion in the direction that we consider negative).
  547. //
  548. deviceExtension->CurrentInput.LastY =
  549. -deviceExtension->CurrentInput.LastY;
  550. }
  551. //
  552. // Update our notion of the previous sign and overflow bits for
  553. // the start of the next mouse input sequence.
  554. //
  555. deviceExtension->PreviousSignAndOverflow =
  556. deviceExtension->CurrentSignAndOverflow;
  557. //
  558. // Choose the next state. The WheelMouse has an extra byte of data
  559. // for us
  560. //
  561. if (WHEEL_PRESENT()) {
  562. deviceExtension->InputState = ZMovement;
  563. }
  564. else {
  565. I8xQueueCurrentMouseInput(DeviceObject);
  566. deviceExtension->InputState = MouseIdle;
  567. }
  568. break;
  569. }
  570. case ZMovement: {
  571. IsrPrint(DBG_MOUISR_STATE, ("mouse LastZ byte\n"));
  572. //
  573. // This code is here to handle the cases were mouse resets were
  574. // not notified to the OS. Uncomment this if you *really* want it,
  575. // but remember that it could possibly reset the mouse when it
  576. // shouldn't have...
  577. //
  578. #if 0
  579. if ( (byte & 0xf8) != 0 && (byte & 0xf8) != 0xf8 ) {
  580. //
  581. // for some reason, the byte was not sign extanded,
  582. // or has a value > 7, which we assume cannot be
  583. // possible giving our equipment. So the packet
  584. // *must* be bogus...
  585. //
  586. // No longer the case with 5 button mice
  587. //
  588. goto IsrResetMouse;
  589. }
  590. #endif
  591. //
  592. // Check to see if we got any z data
  593. // If there were any changes in the button state, ignore the
  594. // z data
  595. //
  596. if (FIVE_PRESENT()) {
  597. //
  598. // Wheel info first, value returned should be
  599. // -120 * the value reported
  600. //
  601. if (byte & 0x0F) {
  602. // sign extend to the upper 4 bits if necessary
  603. if (byte & 0x08) {
  604. deviceExtension->CurrentInput.ButtonData =
  605. (-120) * ((CHAR)((byte & 0xF) | 0xF0));
  606. }
  607. else {
  608. deviceExtension->CurrentInput.ButtonData =
  609. (-120) * ((CHAR) byte & 0xF);
  610. }
  611. deviceExtension->CurrentInput.ButtonFlags |= MOUSE_WHEEL;
  612. }
  613. previousButtons = deviceExtension->PreviousButtons;
  614. // extra buttons
  615. if (TRANSITION_DOWN(BUTTON_4)) {
  616. deviceExtension->CurrentInput.ButtonFlags |=
  617. MOUSE_BUTTON_4_DOWN;
  618. } else
  619. if (TRANSITION_UP(BUTTON_4)) {
  620. deviceExtension->CurrentInput.ButtonFlags |=
  621. MOUSE_BUTTON_4_UP;
  622. }
  623. if (TRANSITION_DOWN(BUTTON_5)) {
  624. deviceExtension->CurrentInput.ButtonFlags |=
  625. MOUSE_BUTTON_5_DOWN;
  626. } else
  627. if (TRANSITION_UP(BUTTON_5)) {
  628. deviceExtension->CurrentInput.ButtonFlags |=
  629. MOUSE_BUTTON_5_UP;
  630. }
  631. // record btns 4 & 5 w/out losing btns 1-3
  632. deviceExtension->PreviousButtons =
  633. (byte & BUTTONS_4_5) | (previousButtons & RML_BUTTONS);
  634. }
  635. else if (byte) {
  636. deviceExtension->CurrentInput.ButtonData =
  637. (-120) * ((CHAR) byte);
  638. deviceExtension->CurrentInput.ButtonFlags |= MOUSE_WHEEL;
  639. }
  640. //
  641. // Pack the data on to the class driver
  642. //
  643. I8xQueueCurrentMouseInput(DeviceObject);
  644. //
  645. // Reset the state
  646. //
  647. deviceExtension->InputState = MouseIdle;
  648. break;
  649. }
  650. case MouseExpectingACK: {
  651. RECORD_ISR_STATE(deviceExtension, byte, lastByte, newTick);
  652. //
  653. // This is a special case. We hit this on one of the very
  654. // first mouse interrupts following the IoConnectInterrupt.
  655. // The interrupt is caused when we enable mouse transmissions
  656. // via I8xMouseEnableTransmission() -- the hardware returns
  657. // an ACK. Just toss this byte away, and set the input state
  658. // to coincide with the start of a new mouse data packet.
  659. //
  660. IsrPrint(DBG_MOUISR_BYTE,
  661. ("...should be from I8xMouseEnableTransmission\n"));
  662. IsrPrint(DBG_MOUISR_BYTE,
  663. (pDumpExpectingAck,
  664. (ULONG) ACKNOWLEDGE,
  665. (ULONG) byte
  666. ));
  667. if (byte == (UCHAR) ACKNOWLEDGE) {
  668. deviceExtension->InputState = MouseIdle;
  669. deviceExtension->EnableMouse.Enabled = FALSE;
  670. } else if (byte == (UCHAR) RESEND) {
  671. //
  672. // Resend the "Enable Mouse Transmission" sequence.
  673. //
  674. // NOTE: This is a workaround for the Olivetti MIPS machine,
  675. // which sends a resend response if a key is held down
  676. // while we're attempting the I8xMouseEnableTransmission.
  677. //
  678. resendCommand = ENABLE_MOUSE_TRANSMISSION;
  679. }
  680. break;
  681. }
  682. case MouseResetting: {
  683. IsrPrint(DBG_MOUISR_RESETTING,
  684. ("state (%d) substate (%2d)\n",
  685. deviceExtension->InputState,
  686. deviceExtension->InputResetSubState
  687. ));
  688. //
  689. // We enter the reset substate machine
  690. //
  691. SwitchOnInputResetSubState:
  692. bSendCommand = TRUE;
  693. altCommand = (UCHAR) 0x00;
  694. RECORD_ISR_STATE(deviceExtension, byte, lastByte, newTick);
  695. switch (deviceExtension->InputResetSubState) {
  696. case StartPnPIdDetection:
  697. ASSERT(byte == (UCHAR) ACKNOWLEDGE);
  698. nextCommand = SET_MOUSE_SAMPLING_RATE;
  699. deviceExtension->InputResetSubState =
  700. ExpectingLoopSetSamplingRateACK;
  701. deviceExtension->SampleRatesIndex = 0;
  702. deviceExtension->SampleRates = (PUCHAR) PnpDetectCommands;
  703. deviceExtension->PostSamplesState = ExpectingPnpId;
  704. break;
  705. case EnableWheel:
  706. bSendCommand = FALSE;
  707. altCommand = SET_MOUSE_SAMPLING_RATE;
  708. deviceExtension->InputResetSubState =
  709. ExpectingLoopSetSamplingRateACK;
  710. deviceExtension->SampleRatesIndex = 0;
  711. deviceExtension->SampleRates = (PUCHAR) WheelEnableCommands;
  712. //
  713. // After enabling the wheel, we shall get the device ID because
  714. // some kinds of wheel mice require the get id right after the
  715. // wheel enabling sequence
  716. //
  717. deviceExtension->PostSamplesState = PostEnableWheelState;
  718. break;
  719. case PostEnableWheelState:
  720. //
  721. // Some wheel mice require a get device ID after turning on the
  722. // wheel for the wheel to be truly turned on
  723. //
  724. bSendCommand = FALSE;
  725. altCommand = GET_DEVICE_ID;
  726. deviceExtension->InputResetSubState =
  727. ExpectingGetDeviceIdDetectACK;
  728. break;
  729. case ExpectingGetDeviceIdDetectACK:
  730. IsrPrint(DBG_MOUISR_ACK,
  731. (pDumpExpectingAck,
  732. (ULONG) ACKNOWLEDGE,
  733. (ULONG) byte
  734. ));
  735. if (byte == (UCHAR) ACKNOWLEDGE) {
  736. bSendCommand = FALSE;
  737. deviceExtension->InputResetSubState =
  738. ExpectingGetDeviceIdDetectValue;
  739. }
  740. else if (byte == (UCHAR) RESEND) {
  741. //
  742. // NOTE: This is a workaround for the Olivetti MIPS machine,
  743. // which sends a resend response if a key is held down
  744. // while we're attempting the I8xMouseEnableTransmission.
  745. //
  746. resendCommand = GET_DEVICE_ID;
  747. }
  748. else {
  749. //
  750. // Log the error
  751. //
  752. KeInsertQueueDpc(&deviceExtension->ErrorLogDpc,
  753. (PIRP) NULL,
  754. LongToPtr(I8042_GET_DEVICE_ID_FAILED)
  755. );
  756. //
  757. // We didn't get an ACK on this? Boggle. Okay, let's
  758. // reset the mouse (probably AGAIN) and try to figure
  759. // things out one more time
  760. //
  761. goto IsrResetMouse;
  762. }
  763. break;
  764. case ExpectingGetDeviceIdDetectValue:
  765. //
  766. // In theory, we can check the mouse ID here and only send the
  767. // 5 button enable sequence if the mouse ID is the wheel mouse
  768. // ID....BUT there are filter drivers which trap the ISR and
  769. // depend on the mouse ID always showing up in the
  770. // ExpectingGetDeviceId2Value state
  771. //
  772. deviceExtension->InputResetSubState = Enable5Buttons;
  773. goto SwitchOnInputResetSubState;
  774. // break;
  775. case Enable5Buttons:
  776. bSendCommand = FALSE;
  777. altCommand = SET_MOUSE_SAMPLING_RATE;
  778. deviceExtension->InputResetSubState =
  779. ExpectingLoopSetSamplingRateACK;
  780. deviceExtension->SampleRatesIndex = 0;
  781. deviceExtension->SampleRates = (PUCHAR) FiveButtonEnableCommands;
  782. deviceExtension->PostSamplesState = PostWheelDetectState;
  783. break;
  784. //
  785. // This state (ExpectingReset) and the next one (Expecting
  786. // ResetId) are only called if we have to issue a reset
  787. // from within the substate machine.
  788. //
  789. case ExpectingReset:
  790. //
  791. // This case handles 3 cases
  792. //
  793. // 1) The ack resulting from writing a MOUSE_RESET (0xFF)
  794. // 2) A resend resulting from writing the reset
  795. // 3) The reset character following the the ack
  796. //
  797. // If the byte is neither of these 3, then just let it go
  798. //
  799. if (byte == ACKNOWLEDGE) {
  800. //
  801. // The ack for the reset, the 0xAA will come immediately
  802. // after this. We can handle it in the same state
  803. //
  804. bSendCommand = FALSE;
  805. break;
  806. }
  807. else if (byte == RESEND) {
  808. bSendCommand = FALSE;
  809. if (deviceExtension->ResendCount++ < MOUSE_RESET_RESENDS_MAX &&
  810. deviceExtension->ResetMouse.IsrResetState
  811. == IsrResetNormal) {
  812. IsrPrint(DBG_MOUISR_RESETTING, ("resending from isr\n"));
  813. //
  814. // Fix for old Digital machines (both x86 and alpha)
  815. // that can't handle resets to close together
  816. //
  817. KeStallExecutionProcessor(
  818. deviceExtension->MouseResetStallTime
  819. );
  820. //
  821. // We send an alt command instead of the normal
  822. // resetCommand so that we can maintain our own count
  823. // here (we want the reset resend max to be larger than
  824. // the std resend max)
  825. //
  826. altCommand = MOUSE_RESET;
  827. }
  828. break;
  829. }
  830. else if (byte != MOUSE_COMPLETE) {
  831. //
  832. // Check to see if we got a reset character (0xAA). If
  833. // not, then we will *ignore* it. Note that this means
  834. // that if we dropped this char, then we could infinite
  835. // loop in this routine.
  836. //
  837. break;
  838. }
  839. //
  840. // Now check to see how many times we have gone
  841. // through this routine without exiting the
  842. // MouseResetting SubState
  843. //
  844. if (deviceExtension->ResetCount >= MOUSE_RESETS_MAX) {
  845. //
  846. // This will queue a reset DPC which will see that too many
  847. // resets have been sent and will clean up the counters and
  848. // and start the next Irp in the StartIO queue
  849. //
  850. goto IsrResetMouse;
  851. }
  852. //
  853. // Because of the test for mouse resets at the start of
  854. // the ISR, the following code should really have no
  855. // effect
  856. //
  857. deviceExtension->InputResetSubState =
  858. ExpectingResetId;
  859. break;
  860. //
  861. // This state is special in that its just here as a place
  862. // holder because we have a detection routine at the start
  863. // of the ISR that automically puts us into
  864. // ExpectingGetDeviceIdACK.
  865. //
  866. // OLD WAY:
  867. // For completeness though, we
  868. // issue a bugcheck here since we can't normally get into
  869. // this state
  870. //
  871. // NEW WAY:
  872. // We ignore this state entirely. As far as I can tell, we get
  873. // into this state when the controller requests a resend (which
  874. // is honored) and then sends the 0xFA, 0xAA in reverse order,
  875. // which the state machine handles, but hits this assert
  876. //
  877. case ExpectingResetId:
  878. //
  879. // Next state
  880. //
  881. deviceExtension->InputResetSubState =
  882. ExpectingGetDeviceIdACK;
  883. if (byte == WHEELMOUSE_ID_BYTE) {
  884. //
  885. // Start a enable command to the device. We *really* don't
  886. // expect to be here.
  887. //
  888. bSendCommand = FALSE;
  889. altCommand = GET_DEVICE_ID;
  890. }
  891. else {
  892. #if 0
  893. //
  894. // Log that we are in a bad state
  895. //
  896. KeInsertQueueDpc(&deviceExtension->ErrorLogDpc,
  897. (PIRP) NULL,
  898. (PVOID) (ULONG) I8042_INVALID_ISR_STATE_MOU
  899. );
  900. ASSERT( byte == WHEELMOUSE_ID_BYTE);
  901. #endif
  902. //
  903. // For sake of completeness
  904. //
  905. deviceExtension->InputResetSubState =
  906. ExpectingReset;
  907. }
  908. break;
  909. case ExpectingGetDeviceIdACK:
  910. IsrPrint(DBG_MOUISR_ACK,
  911. (pDumpExpectingIdAck,
  912. (ULONG) ACKNOWLEDGE,
  913. (ULONG) byte
  914. ));
  915. if (byte == (UCHAR) ACKNOWLEDGE) {
  916. deviceExtension->InputResetSubState =
  917. ExpectingGetDeviceIdValue;
  918. bSendCommand = FALSE;
  919. } else if (byte == (UCHAR) RESEND) {
  920. //
  921. // Resend the "Get Mouse ID Transmission" sequence.
  922. //
  923. // NOTE: This is a workaround for the Olivetti MIPS machine,
  924. // which sends a resend response if a key is held down
  925. // while we're attempting the I8xMouseEnableTransmission.
  926. //
  927. resendCommand = GET_DEVICE_ID;
  928. } else {
  929. //
  930. // If we got here, then we don't know what's going
  931. // on with the device... The best bet is to send down
  932. // a mouse reset command...
  933. //
  934. goto IsrResetMouse;
  935. }
  936. break;
  937. case ExpectingGetDeviceIdValue:
  938. IsrPrint(DBG_MOUISR_RESETTING,
  939. ("id from get device id is %2d\n" ,
  940. (ULONG) byte
  941. ));
  942. //
  943. // Got the device ID from the mouse and compare it with what we
  944. // expect to see. If the ID byte is still wheel or five button
  945. // then we STILL cannot consider this to be data from the mouse
  946. // that has mirrored a reset. There are two reasons why we can't
  947. // consider this real data:
  948. //
  949. // 1) Switch boxes cache the device ID and returned the cached
  950. // ID upon a reset
  951. // 2) Some mice, once put in the 4 byte packet mode, will return
  952. // the wheel or 5 button ID byte even if they have been reset
  953. //
  954. // Furthermore, we cannot check to see if extension->ResetIrp
  955. // exists because this does not cover the case where the mouse
  956. // was unplugged / replugged in.
  957. //
  958. // @@BEGIN_DDKSPLIT
  959. // This is a pit of despair. No matter how crafty we try to be,
  960. // we will never get this right! Perhaps we can turn on this
  961. // check via a reg flag. The MS hardware folks have
  962. // respectfully requested this many, many times and we have
  963. // tried to accomodate them, but we always get bitten by the fix
  964. // in the end.
  965. // @@END_DDKSPLIT
  966. // (byte != WHEELMOUSE_ID_BYTE) && byte != (FIVEBUTTON_ID_BYTE)) {
  967. if (1) {
  968. //
  969. // Log an error/warning message so that we can track these
  970. // problems down in the field
  971. //
  972. #if 0
  973. KeInsertQueueDpc(&deviceExtension->ErrorLogDpc,
  974. (PIRP) NULL,
  975. (PVOID)(ULONG) (WHEEL_PRESENT() ?
  976. I8042_UNEXPECTED_WHEEL_MOUSE_RESET :
  977. I8042_UNEXPECTED_MOUSE_RESET)
  978. );
  979. #endif
  980. bSendCommand = FALSE;
  981. if (deviceExtension->NumberOfButtonsOverride != 0) {
  982. //
  983. // skip button detection and set the res
  984. //
  985. altCommand = POST_BUTTONDETECT_COMMAND;
  986. deviceExtension->InputResetSubState =
  987. POST_BUTTONDETECT_COMMAND_SUBSTATE;
  988. }
  989. else {
  990. altCommand = SET_MOUSE_RESOLUTION;
  991. deviceExtension->InputResetSubState =
  992. ExpectingSetResolutionACK;
  993. }
  994. }
  995. else {
  996. //
  997. // We have a wheel mouse present here... Log something so that
  998. // we know that we got here.
  999. //
  1000. KeInsertQueueDpc(&deviceExtension->ErrorLogDpc,
  1001. (PIRP) NULL,
  1002. LongToPtr(I8042_BOGUS_MOUSE_RESET)
  1003. );
  1004. //
  1005. // Lets go back to the idle state
  1006. //
  1007. deviceExtension->InputState = MouseIdle;
  1008. //
  1009. // Reset the number of possible mouse resets
  1010. //
  1011. deviceExtension->ResetCount = 0;
  1012. }
  1013. break;
  1014. case ExpectingSetResolutionACK:
  1015. IsrPrint(DBG_MOUISR_ACK,
  1016. (pDumpExpectingIdAck,
  1017. (ULONG) ACKNOWLEDGE,
  1018. (ULONG) byte
  1019. ));
  1020. if (byte == (UCHAR) ACKNOWLEDGE) {
  1021. //
  1022. // Set the resolution to 0x00
  1023. //
  1024. nextCommand = 0x00;
  1025. deviceExtension->InputResetSubState =
  1026. ExpectingSetResolutionValueACK;
  1027. } else if (byte == (UCHAR) RESEND) {
  1028. //
  1029. // NOTE: This is a workaround for the Olivetti MIPS machine,
  1030. // which sends a resend response if a key is held down
  1031. // while we're attempting the I8xMouseEnableTransmission.
  1032. //
  1033. resendCommand = SET_MOUSE_RESOLUTION;
  1034. } else {
  1035. //
  1036. // Log the error
  1037. //
  1038. KeInsertQueueDpc(&deviceExtension->ErrorLogDpc,
  1039. (PIRP) NULL,
  1040. LongToPtr(I8042_SET_RESOLUTION_FAILED)
  1041. );
  1042. bSendCommand = FALSE;
  1043. altCommand = GET_DEVICE_ID;
  1044. //
  1045. // Best possible next state
  1046. //
  1047. deviceExtension->InputResetSubState =
  1048. ExpectingGetDeviceId2ACK;
  1049. }
  1050. break;
  1051. case ExpectingSetResolutionValueACK:
  1052. IsrPrint(DBG_MOUISR_ACK,
  1053. (pDumpExpectingIdAck,
  1054. (ULONG) ACKNOWLEDGE,
  1055. (ULONG) byte
  1056. ));
  1057. if (byte == (UCHAR) ACKNOWLEDGE) {
  1058. nextCommand = SET_MOUSE_SCALING_1TO1;
  1059. deviceExtension->InputResetSubState =
  1060. ExpectingSetScaling1to1ACK;
  1061. }
  1062. else if (byte == (UCHAR) RESEND) {
  1063. //
  1064. // NOTE: This is a workaround for the Olivetti MIPS machine,
  1065. // which sends a resend response if a key is held down
  1066. // while we're attempting the I8xMouseEnableTransmission.
  1067. //
  1068. resendCommand = 0x00;
  1069. }
  1070. else {
  1071. //
  1072. // Log the error
  1073. //
  1074. KeInsertQueueDpc(&deviceExtension->ErrorLogDpc,
  1075. (PIRP) NULL,
  1076. LongToPtr(I8042_SET_SAMPLE_RATE_FAILED)
  1077. );
  1078. //
  1079. // Probably not a wheel mouse .. jump to the GetDeviceID2
  1080. // code
  1081. //
  1082. bSendCommand = FALSE;
  1083. altCommand = GET_DEVICE_ID;
  1084. //
  1085. // Best possible next state
  1086. //
  1087. deviceExtension->InputResetSubState =
  1088. ExpectingGetDeviceId2ACK;
  1089. }
  1090. break;
  1091. case ExpectingSetScaling1to1ACK:
  1092. case ExpectingSetScaling1to1ACK2:
  1093. case ExpectingSetScaling1to1ACK3:
  1094. IsrPrint(DBG_MOUISR_ACK,
  1095. (pDumpExpectingIdAck,
  1096. (ULONG) ACKNOWLEDGE,
  1097. (ULONG) byte
  1098. ));
  1099. if (byte == (UCHAR) ACKNOWLEDGE) {
  1100. if (deviceExtension->InputResetSubState ==
  1101. ExpectingSetScaling1to1ACK3) {
  1102. //
  1103. // Read the status of the mouse (a 3 byte stream)
  1104. //
  1105. nextCommand = READ_MOUSE_STATUS;
  1106. deviceExtension->InputResetSubState =
  1107. ExpectingReadMouseStatusACK;
  1108. }
  1109. else {
  1110. deviceExtension->InputResetSubState++;
  1111. nextCommand = SET_MOUSE_SCALING_1TO1;
  1112. }
  1113. } else if (byte == (UCHAR) RESEND) {
  1114. //
  1115. // NOTE: This is a workaround for the Olivetti MIPS machine,
  1116. // which sends a resend response if a key is held down
  1117. // while we're attempting the I8xMouseEnableTransmission.
  1118. //
  1119. resendCommand = SET_MOUSE_SCALING_1TO1;
  1120. } else {
  1121. //
  1122. // Log the error
  1123. //
  1124. KeInsertQueueDpc(&deviceExtension->ErrorLogDpc,
  1125. (PIRP) NULL,
  1126. LongToPtr(I8042_ERROR_DURING_BUTTONS_DETECT)
  1127. );
  1128. bSendCommand = FALSE;
  1129. altCommand = GET_DEVICE_ID;
  1130. //
  1131. // Best possible next state
  1132. //
  1133. deviceExtension->InputResetSubState =
  1134. ExpectingGetDeviceId2ACK;
  1135. }
  1136. break;
  1137. case ExpectingReadMouseStatusACK:
  1138. IsrPrint(DBG_MOUISR_ACK,
  1139. (pDumpExpectingIdAck,
  1140. (ULONG) ACKNOWLEDGE,
  1141. (ULONG) byte
  1142. ));
  1143. if (byte == (UCHAR) ACKNOWLEDGE) {
  1144. //
  1145. // Get ready for the 3 bytes
  1146. //
  1147. deviceExtension->InputResetSubState =
  1148. ExpectingReadMouseStatusByte1;
  1149. bSendCommand = FALSE;
  1150. } else if (byte == (UCHAR) RESEND) {
  1151. //
  1152. // NOTE: This is a workaround for the Olivetti MIPS machine,
  1153. // which sends a resend response if a key is held down
  1154. // while we're attempting the I8xMouseEnableTransmission.
  1155. //
  1156. resendCommand = READ_MOUSE_STATUS;
  1157. } else {
  1158. //
  1159. // Log the error
  1160. //
  1161. KeInsertQueueDpc(&deviceExtension->ErrorLogDpc,
  1162. (PIRP) NULL,
  1163. LongToPtr(I8042_ERROR_DURING_BUTTONS_DETECT)
  1164. );
  1165. //
  1166. // Probably not a wheel mouse .. jump to the GetDeviceID2
  1167. // code
  1168. //
  1169. bSendCommand = FALSE;
  1170. altCommand = GET_DEVICE_ID;
  1171. //
  1172. // Best possible next state
  1173. //
  1174. deviceExtension->InputResetSubState =
  1175. ExpectingGetDeviceId2ACK;
  1176. }
  1177. break;
  1178. case ExpectingReadMouseStatusByte1:
  1179. IsrPrint(DBG_MOUISR_PNPID,
  1180. (pDumpExpecting,
  1181. (ULONG) 0x00,
  1182. (ULONG) byte
  1183. ));
  1184. bSendCommand = FALSE;
  1185. deviceExtension->InputResetSubState =
  1186. ExpectingReadMouseStatusByte2;
  1187. break;
  1188. case ExpectingReadMouseStatusByte2:
  1189. IsrPrint(DBG_MOUISR_PNPID,
  1190. (pDumpExpecting,
  1191. (ULONG) 0x00,
  1192. (ULONG) byte
  1193. ));
  1194. bSendCommand = FALSE;
  1195. deviceExtension->InputResetSubState =
  1196. ExpectingReadMouseStatusByte3;
  1197. //
  1198. // This will be the number of buttons
  1199. //
  1200. if (byte == 2 || byte == 3) {
  1201. deviceExtension->MouseAttributes.NumberOfButtons = byte;
  1202. }
  1203. else {
  1204. deviceExtension->MouseAttributes.NumberOfButtons =
  1205. MOUSE_NUMBER_OF_BUTTONS;
  1206. }
  1207. break;
  1208. case ExpectingReadMouseStatusByte3:
  1209. IsrPrint(DBG_MOUISR_PNPID,
  1210. (pDumpExpecting,
  1211. (ULONG) 0x00,
  1212. (ULONG) byte
  1213. ));
  1214. bSendCommand = FALSE;
  1215. altCommand = POST_BUTTONDETECT_COMMAND;
  1216. deviceExtension->InputResetSubState =
  1217. POST_BUTTONDETECT_COMMAND_SUBSTATE;
  1218. break;
  1219. case ExpectingSetResolutionDefaultACK:
  1220. IsrPrint(DBG_MOUISR_ACK,
  1221. (pDumpExpectingAck,
  1222. (ULONG) ACKNOWLEDGE,
  1223. (ULONG) byte
  1224. ));
  1225. if (byte == (UCHAR) ACKNOWLEDGE) {
  1226. //
  1227. // Set the mouse refresh to the default
  1228. //
  1229. nextCommand = deviceExtension->Resolution;
  1230. deviceExtension->InputResetSubState =
  1231. ExpectingSetResolutionDefaultValueACK;
  1232. }
  1233. else if (byte == (UCHAR) RESEND) {
  1234. //
  1235. // NOTE: This is a workaround for the Olivetti MIPS machine,
  1236. // which sends a resend response if a key is held down
  1237. // while we're attempting the I8xMouseEnableTransmission.
  1238. //
  1239. resendCommand = SET_MOUSE_RESOLUTION;
  1240. }
  1241. else {
  1242. //
  1243. // Log the error
  1244. //
  1245. KeInsertQueueDpc(&deviceExtension->ErrorLogDpc,
  1246. (PIRP) NULL,
  1247. LongToPtr(I8042_SET_RESOLUTION_FAILED)
  1248. );
  1249. //
  1250. // We didn't get an ACK on this? Boggle. Okay, let's
  1251. // reset the mouse (probably AGAIN) and try to figure
  1252. // things out one more time
  1253. //
  1254. goto IsrResetMouse;
  1255. }
  1256. break;
  1257. case ExpectingSetResolutionDefaultValueACK:
  1258. IsrPrint(DBG_MOUISR_ACK,
  1259. (pDumpExpectingAck,
  1260. (ULONG) ACKNOWLEDGE,
  1261. (ULONG) byte
  1262. ));
  1263. if (byte == (UCHAR) ACKNOWLEDGE) {
  1264. //
  1265. // Are we allowed to detect wether or not a wheel mouse
  1266. // is present?
  1267. //
  1268. if (deviceExtension->EnableWheelDetection == 2) {
  1269. //
  1270. // Begin the sequence to activate the mouse wheel
  1271. //
  1272. deviceExtension->InputResetSubState = EnableWheel;
  1273. goto SwitchOnInputResetSubState;
  1274. }
  1275. else if (deviceExtension->EnableWheelDetection == 1) {
  1276. //
  1277. // Begin the PNP id detection sequence
  1278. //
  1279. deviceExtension->InputResetSubState =
  1280. StartPnPIdDetection;
  1281. goto SwitchOnInputResetSubState;
  1282. }
  1283. else {
  1284. //
  1285. // Begin the sequence to set the default refresh
  1286. // rate
  1287. //
  1288. nextCommand = POST_WHEEL_DETECT_COMMAND;
  1289. deviceExtension->InputResetSubState =
  1290. POST_WHEEL_DETECT_COMMAND_SUBSTATE;
  1291. }
  1292. }
  1293. else if (byte == (UCHAR) RESEND) {
  1294. //
  1295. // NOTE: This is a workaround for the Olivetti MIPS machine,
  1296. // which sends a resend response if a key is held down
  1297. // while we're attempting the I8xMouseEnableTransmission.
  1298. //
  1299. deviceExtension->InputResetSubState =
  1300. ExpectingSetResolutionDefaultACK;
  1301. resendCommand = SET_MOUSE_RESOLUTION;
  1302. }
  1303. else {
  1304. //
  1305. // Log the error
  1306. //
  1307. KeInsertQueueDpc(&deviceExtension->ErrorLogDpc,
  1308. (PIRP) NULL,
  1309. LongToPtr(I8042_SET_RESOLUTION_FAILED)
  1310. );
  1311. //
  1312. // We didn't get an ACK on this? Boggle. Okay, let's
  1313. // reset the mouse (probably AGAIN) and try to figure
  1314. // things out one more time
  1315. //
  1316. goto IsrResetMouse;
  1317. }
  1318. break;
  1319. case ExpectingLoopSetSamplingRateACK:
  1320. IsrPrint(DBG_MOUISR_ACK,
  1321. (pDumpExpectingAck,
  1322. (ULONG) ACKNOWLEDGE,
  1323. (ULONG) byte
  1324. ));
  1325. if (byte == (UCHAR) ACKNOWLEDGE) {
  1326. //
  1327. // Set the new sampling rate value
  1328. //
  1329. nextCommand = deviceExtension->SampleRates[
  1330. deviceExtension->SampleRatesIndex];
  1331. deviceExtension->InputResetSubState =
  1332. ExpectingLoopSetSamplingRateValueACK;
  1333. }
  1334. else if (byte == (UCHAR) RESEND) {
  1335. //
  1336. // The state stays the same, just resend the command
  1337. //
  1338. resendCommand = SET_MOUSE_SAMPLING_RATE;
  1339. }
  1340. else {
  1341. //
  1342. // Log the error
  1343. //
  1344. KeInsertQueueDpc(&deviceExtension->ErrorLogDpc,
  1345. (PIRP) NULL,
  1346. LongToPtr(I8042_SET_SAMPLE_RATE_FAILED)
  1347. );
  1348. //
  1349. // Probably not a wheel mouse .. jump to the GetDeviceID2
  1350. // code
  1351. //
  1352. bSendCommand = FALSE;
  1353. altCommand = GET_DEVICE_ID;
  1354. //
  1355. // Best possible next state
  1356. //
  1357. deviceExtension->InputResetSubState =
  1358. ExpectingGetDeviceId2ACK;
  1359. }
  1360. break;
  1361. case ExpectingLoopSetSamplingRateValueACK:
  1362. IsrPrint(DBG_MOUISR_ACK,
  1363. (pDumpExpectingAck,
  1364. (ULONG) ACKNOWLEDGE,
  1365. (ULONG) byte
  1366. ));
  1367. IsrPrint(DBG_MOUISR_ACK,
  1368. ("(%2d)\n",
  1369. deviceExtension->SampleRates[
  1370. deviceExtension->SampleRatesIndex]
  1371. ));
  1372. if (byte == (UCHAR) ACKNOWLEDGE) {
  1373. if (deviceExtension->SampleRates[
  1374. ++deviceExtension->SampleRatesIndex] ==
  1375. ONE_PAST_FINAL_SAMPLE) {
  1376. deviceExtension->InputResetSubState =
  1377. deviceExtension->PostSamplesState;
  1378. goto SwitchOnInputResetSubState;
  1379. }
  1380. else {
  1381. nextCommand = SET_MOUSE_SAMPLING_RATE;
  1382. deviceExtension->InputResetSubState =
  1383. ExpectingLoopSetSamplingRateACK;
  1384. }
  1385. }
  1386. else if (byte == (UCHAR) RESEND) {
  1387. //
  1388. // The state stays the same, just resend the command
  1389. //
  1390. resendCommand = deviceExtension->SampleRates[
  1391. deviceExtension->SampleRatesIndex];
  1392. }
  1393. else {
  1394. //
  1395. // Log the error
  1396. //
  1397. KeInsertQueueDpc(&deviceExtension->ErrorLogDpc,
  1398. (PIRP) NULL,
  1399. LongToPtr(I8042_SET_SAMPLE_RATE_FAILED)
  1400. );
  1401. //
  1402. // Probably not a wheel mouse .. jump to the GetDeviceID2
  1403. // code
  1404. //
  1405. bSendCommand = FALSE;
  1406. altCommand = GET_DEVICE_ID;
  1407. //
  1408. // Best possible next state
  1409. //
  1410. deviceExtension->InputResetSubState =
  1411. ExpectingGetDeviceId2ACK;
  1412. }
  1413. break;
  1414. case ExpectingPnpId:
  1415. //
  1416. // Don't do anything but advance the state, the PnP ID will
  1417. // be "pushed" to the ISR
  1418. //
  1419. deviceExtension->InputResetSubState = ExpectingPnpIdByte1;
  1420. currentIdChar = deviceExtension->PnPID;
  1421. RtlZeroMemory(deviceExtension->PnPID,
  1422. MOUSE_PNPID_LENGTH * sizeof(WCHAR)
  1423. );
  1424. bSendCommand = FALSE;
  1425. break;
  1426. case ExpectingPnpIdByte2:
  1427. //
  1428. // Check to see if this an older MS mouse that gives back its ID
  1429. // in make AND BREAK codes (ugh!). If so, then just eat the
  1430. // remaining 6 (+6) bytes
  1431. //
  1432. if (deviceExtension->PnPID[0] == L'P' && byte == 0x99) {
  1433. deviceExtension->InputResetSubState =
  1434. ExpectingLegacyPnpIdByte2_Make;
  1435. bSendCommand = FALSE;
  1436. break;
  1437. }
  1438. case ExpectingPnpIdByte1:
  1439. case ExpectingPnpIdByte3:
  1440. case ExpectingPnpIdByte4:
  1441. case ExpectingPnpIdByte5:
  1442. case ExpectingPnpIdByte6:
  1443. case ExpectingPnpIdByte7:
  1444. IsrPrint(DBG_MOUISR_PNPID,
  1445. ("ExpectingPnpIdByte%1d (0x%2x)\n",
  1446. (ULONG) deviceExtension->InputResetSubState -
  1447. ExpectingPnpIdByte1 + 1,
  1448. (ULONG) byte
  1449. ));
  1450. if (byte < ScanCodeToUCharCount) {
  1451. *currentIdChar = (WCHAR) ScanCodeToUChar[byte];
  1452. }
  1453. else {
  1454. *currentIdChar = L'?';
  1455. }
  1456. currentIdChar++;
  1457. bSendCommand = FALSE;
  1458. if (deviceExtension->InputResetSubState ==
  1459. ExpectingPnpIdByte7) {
  1460. if (I8xVerifyMousePnPID(deviceExtension,
  1461. deviceExtension->PnPID)) {
  1462. //
  1463. // We are know know for sure that we have a wheel
  1464. // mouse on this system. However, we will update
  1465. // our date structures after the enable has gone
  1466. // through since that simplifies things a great deal
  1467. //
  1468. deviceExtension->InputResetSubState = EnableWheel;
  1469. goto SwitchOnInputResetSubState;
  1470. }
  1471. else {
  1472. //
  1473. // Oops, not our device, so lets stop the sequence
  1474. // now by sending it a GET_DEVICE_ID
  1475. //
  1476. altCommand = GET_DEVICE_ID;
  1477. //
  1478. // Best possible next state
  1479. //
  1480. deviceExtension->InputResetSubState =
  1481. ExpectingGetDeviceId2ACK;
  1482. }
  1483. }
  1484. else {
  1485. ASSERT(deviceExtension->InputResetSubState >=
  1486. ExpectingPnpIdByte1);
  1487. ASSERT(deviceExtension->InputResetSubState <
  1488. ExpectingPnpIdByte7);
  1489. deviceExtension->InputResetSubState++;
  1490. }
  1491. break;
  1492. case ExpectingLegacyPnpIdByte2_Make:
  1493. case ExpectingLegacyPnpIdByte2_Break:
  1494. case ExpectingLegacyPnpIdByte3_Make:
  1495. case ExpectingLegacyPnpIdByte3_Break:
  1496. case ExpectingLegacyPnpIdByte4_Make:
  1497. case ExpectingLegacyPnpIdByte4_Break:
  1498. case ExpectingLegacyPnpIdByte5_Make:
  1499. case ExpectingLegacyPnpIdByte5_Break:
  1500. case ExpectingLegacyPnpIdByte6_Make:
  1501. case ExpectingLegacyPnpIdByte6_Break:
  1502. case ExpectingLegacyPnpIdByte7_Make:
  1503. //
  1504. // Just eat the byte
  1505. //
  1506. deviceExtension->InputResetSubState++;
  1507. bSendCommand = FALSE;
  1508. break;
  1509. case ExpectingLegacyPnpIdByte7_Break:
  1510. //
  1511. // Best possible next state
  1512. //
  1513. bSendCommand = FALSE;
  1514. altCommand = GET_DEVICE_ID;
  1515. deviceExtension->InputResetSubState = ExpectingGetDeviceId2ACK;
  1516. break;
  1517. case PostWheelDetectState:
  1518. bSendCommand = FALSE;
  1519. altCommand = POST_WHEEL_DETECT_COMMAND;
  1520. //
  1521. // Best possible next state
  1522. //
  1523. deviceExtension->InputResetSubState =
  1524. POST_WHEEL_DETECT_COMMAND_SUBSTATE;
  1525. break;
  1526. case ExpectingGetDeviceId2ACK:
  1527. IsrPrint(DBG_MOUISR_ACK,
  1528. (pDumpExpectingAck,
  1529. (ULONG) ACKNOWLEDGE,
  1530. (ULONG) byte
  1531. ));
  1532. if (byte == (UCHAR) ACKNOWLEDGE) {
  1533. deviceExtension->InputResetSubState =
  1534. ExpectingGetDeviceId2Value;
  1535. bSendCommand = FALSE;
  1536. } else if (byte == (UCHAR) RESEND) {
  1537. //
  1538. // NOTE: This is a workaround for the Olivetti MIPS machine,
  1539. // which sends a resend response if a key is held down
  1540. // while we're attempting the I8xMouseEnableTransmission.
  1541. //
  1542. resendCommand = GET_DEVICE_ID;
  1543. } else {
  1544. //
  1545. // Log the error
  1546. //
  1547. KeInsertQueueDpc(&deviceExtension->ErrorLogDpc,
  1548. (PIRP) NULL,
  1549. LongToPtr(I8042_GET_DEVICE_ID_FAILED)
  1550. );
  1551. //
  1552. // We didn't get an ACK on this? Boggle. Okay, let's
  1553. // reset the mouse (probably AGAIN) and try to figure
  1554. // things out one more time
  1555. //
  1556. goto IsrResetMouse;
  1557. }
  1558. break;
  1559. case ExpectingGetDeviceId2Value:
  1560. IsrPrint(DBG_MOUISR_PNPID,
  1561. ("got a device ID of %2d\n",
  1562. (ULONG) byte
  1563. ));
  1564. CLEAR_HW_FLAGS(WHEELMOUSE_HARDWARE_PRESENT | FIVE_BUTTON_HARDWARE_PRESENT);
  1565. SET_HW_FLAGS(MOUSE_HARDWARE_PRESENT);
  1566. switch (byte) {
  1567. case MOUSE_ID_BYTE:
  1568. //
  1569. // Mouse Present, but no wheel
  1570. //
  1571. deviceExtension->MouseAttributes.MouseIdentifier =
  1572. MOUSE_I8042_HARDWARE;
  1573. if (deviceExtension->NumberOfButtonsOverride != 0) {
  1574. deviceExtension->MouseAttributes.NumberOfButtons =
  1575. deviceExtension->NumberOfButtonsOverride;
  1576. }
  1577. else {
  1578. //
  1579. // Number of buttons is determined in the
  1580. // ExpectingReadMouseStatusByte2 case
  1581. //
  1582. // Number of buttons determined in
  1583. ;
  1584. }
  1585. break;
  1586. case WHEELMOUSE_ID_BYTE:
  1587. //
  1588. // Update the HardwarePresent to show a Z mouse is
  1589. // operational and set the appropraite mouse type flags
  1590. //
  1591. SET_HW_FLAGS(WHEELMOUSE_HARDWARE_PRESENT);
  1592. deviceExtension->MouseAttributes.MouseIdentifier =
  1593. WHEELMOUSE_I8042_HARDWARE;
  1594. deviceExtension->MouseAttributes.NumberOfButtons = 3;
  1595. break;
  1596. case FIVEBUTTON_ID_BYTE:
  1597. //
  1598. // Update the HardwarePresent to show a 5 button wheel mouse
  1599. // is operational and set the appropraite mouse type flags
  1600. //
  1601. SET_HW_FLAGS(FIVE_BUTTON_HARDWARE_PRESENT | WHEELMOUSE_HARDWARE_PRESENT);
  1602. deviceExtension->MouseAttributes.MouseIdentifier =
  1603. WHEELMOUSE_I8042_HARDWARE;
  1604. deviceExtension->MouseAttributes.NumberOfButtons = 5;
  1605. break;
  1606. default:
  1607. //
  1608. // Make sure to log the problem
  1609. //
  1610. KeInsertQueueDpc(&deviceExtension->ErrorLogDpc,
  1611. (PIRP) NULL,
  1612. LongToPtr(I8042_MOU_RESET_RESPONSE_FAILED)
  1613. );
  1614. Print(DBG_MOUISR_RESETTING, ("clearing mouse (no response)\n"));
  1615. CLEAR_MOUSE_PRESENT();
  1616. deviceExtension->MouseAttributes.NumberOfButtons = 0;
  1617. deviceExtension->MouseAttributes.MouseIdentifier = 0;
  1618. //
  1619. // Set up the state machine as best we can
  1620. //
  1621. goto IsrResetMouse;
  1622. }
  1623. //
  1624. // Send down the command to set a new sampling rate
  1625. //
  1626. bSendCommand = FALSE;
  1627. altCommand = SET_MOUSE_SAMPLING_RATE;
  1628. //
  1629. // This is our next state
  1630. //
  1631. deviceExtension->InputResetSubState =
  1632. ExpectingSetSamplingRateACK;
  1633. break;
  1634. case ExpectingSetSamplingRateACK:
  1635. IsrPrint(DBG_MOUISR_ACK,
  1636. (pDumpExpectingAck,
  1637. (ULONG) ACKNOWLEDGE,
  1638. (ULONG) byte
  1639. ));
  1640. if (byte == (UCHAR) ACKNOWLEDGE) {
  1641. //
  1642. // Set the mouse refresh rate to its final value
  1643. //
  1644. nextCommand =
  1645. (UCHAR) deviceExtension->MouseAttributes.SampleRate;
  1646. deviceExtension->InputResetSubState =
  1647. ExpectingSetSamplingRateValueACK;
  1648. }
  1649. else if (byte == (UCHAR) RESEND) {
  1650. //
  1651. // NOTE: This is a workaround for the Olivetti MIPS machine,
  1652. // which sends a resend response if a key is held down
  1653. // while we're attempting the I8xMouseEnableTransmission.
  1654. //
  1655. resendCommand = SET_MOUSE_SAMPLING_RATE;
  1656. }
  1657. else {
  1658. //
  1659. // Log the error
  1660. //
  1661. KeInsertQueueDpc(&deviceExtension->ErrorLogDpc,
  1662. (PIRP) NULL,
  1663. LongToPtr(I8042_SET_SAMPLE_RATE_FAILED)
  1664. );
  1665. //
  1666. // We didn't get an ACK on this? Boggle. Okay, let's
  1667. // reset the mouse (probably AGAIN) and try to figure
  1668. // things out one more time
  1669. //
  1670. goto IsrResetMouse;
  1671. }
  1672. break;
  1673. case ExpectingSetSamplingRateValueACK:
  1674. IsrPrint(DBG_MOUISR_ACK,
  1675. (pDumpExpectingAck,
  1676. (ULONG) ACKNOWLEDGE,
  1677. (ULONG) byte
  1678. ));
  1679. if (byte == (UCHAR) ACKNOWLEDGE) {
  1680. //
  1681. // Let's set the resolution once more to be sure.
  1682. //
  1683. nextCommand = SET_MOUSE_RESOLUTION;
  1684. //
  1685. // We go back to expecting an ACK
  1686. //
  1687. deviceExtension->InputResetSubState =
  1688. ExpectingFinalResolutionACK;
  1689. }
  1690. else if (byte == (UCHAR) RESEND) {
  1691. //
  1692. // NOTE: This is a workaround for the Olivetti MIPS machine,
  1693. // which sends a resend response if a key is held down
  1694. // while we're attempting the I8xMouseEnableTransmission.
  1695. //
  1696. resendCommand = SET_MOUSE_SAMPLING_RATE;
  1697. deviceExtension->InputResetSubState =
  1698. ExpectingSetSamplingRateACK;
  1699. }
  1700. else {
  1701. //
  1702. // Log the error
  1703. //
  1704. KeInsertQueueDpc(&deviceExtension->ErrorLogDpc,
  1705. (PIRP) NULL,
  1706. LongToPtr(I8042_SET_SAMPLE_RATE_FAILED)
  1707. );
  1708. //
  1709. // We didn't get an ACK on this? Boggle. Okay, let's
  1710. // reset the mouse (probably AGAIN) and try to figure
  1711. // things out one more time
  1712. //
  1713. goto IsrResetMouse;
  1714. }
  1715. break;
  1716. case ExpectingFinalResolutionACK:
  1717. IsrPrint(DBG_MOUISR_ACK,
  1718. (pDumpExpectingAck,
  1719. (ULONG) ACKNOWLEDGE,
  1720. (ULONG) byte
  1721. ));
  1722. if (byte == (UCHAR) ACKNOWLEDGE) {
  1723. //
  1724. // Set the mouse refresh rate to its final value
  1725. //
  1726. nextCommand =
  1727. (UCHAR) deviceExtension->Resolution;
  1728. deviceExtension->InputResetSubState =
  1729. ExpectingFinalResolutionValueACK;
  1730. }
  1731. else if (byte == (UCHAR) RESEND) {
  1732. //
  1733. // NOTE: This is a workaround for the Olivetti MIPS machine,
  1734. // which sends a resend response if a key is held down
  1735. // while we're attempting the I8xMouseEnableTransmission.
  1736. //
  1737. resendCommand = SET_MOUSE_RESOLUTION;
  1738. }
  1739. else {
  1740. //
  1741. // Log the error
  1742. //
  1743. KeInsertQueueDpc(&deviceExtension->ErrorLogDpc,
  1744. (PIRP) NULL,
  1745. LongToPtr(I8042_SET_RESOLUTION_FAILED)
  1746. );
  1747. //
  1748. // We didn't get an ACK on this? Boggle. Okay, let's
  1749. // reset the mouse (probably AGAIN) and try to figure
  1750. // things out one more time
  1751. //
  1752. goto IsrResetMouse;
  1753. }
  1754. break;
  1755. case ExpectingFinalResolutionValueACK:
  1756. IsrPrint(DBG_MOUISR_ACK,
  1757. (pDumpExpectingAck,
  1758. (ULONG) ACKNOWLEDGE,
  1759. (ULONG) byte
  1760. ));
  1761. if (byte == (UCHAR) ACKNOWLEDGE) {
  1762. //
  1763. // Finally! Enable the mouse and we are done
  1764. //
  1765. nextCommand = ENABLE_MOUSE_TRANSMISSION;
  1766. //
  1767. // We go back to expecting an ACK
  1768. //
  1769. deviceExtension->InputResetSubState =
  1770. ExpectingEnableACK;
  1771. }
  1772. else if (byte == (UCHAR) RESEND) {
  1773. //
  1774. // NOTE: This is a workaround for the Olivetti MIPS machine,
  1775. // which sends a resend response if a key is held down
  1776. // while we're attempting the I8xMouseEnableTransmission.
  1777. //
  1778. resendCommand = SET_MOUSE_RESOLUTION;
  1779. deviceExtension->InputResetSubState =
  1780. ExpectingFinalResolutionACK;
  1781. }
  1782. else {
  1783. //
  1784. // Log the error
  1785. //
  1786. KeInsertQueueDpc(&deviceExtension->ErrorLogDpc,
  1787. (PIRP) NULL,
  1788. LongToPtr(I8042_SET_RESOLUTION_FAILED)
  1789. );
  1790. //
  1791. // We didn't get an ACK on this? Boggle. Okay, let's
  1792. // reset the mouse (probably AGAIN) and try to figure
  1793. // things out one more time
  1794. //
  1795. goto IsrResetMouse;
  1796. }
  1797. break;
  1798. case ExpectingEnableACK:
  1799. IsrPrint(DBG_MOUISR_ACK,
  1800. (pDumpExpectingAck,
  1801. (ULONG) ACKNOWLEDGE,
  1802. (ULONG) byte
  1803. ));
  1804. if (byte == (UCHAR) ACKNOWLEDGE) {
  1805. //
  1806. // Done and reset the number of possible mouse resets
  1807. //
  1808. deviceExtension->InputState = MouseIdle;
  1809. I8X_MOUSE_INIT_COUNTERS(deviceExtension);
  1810. deviceExtension->CurrentInput.Flags |=
  1811. MOUSE_ATTRIBUTES_CHANGED;
  1812. I8xQueueCurrentMouseInput(DeviceObject);
  1813. ASSERT(DeviceObject->CurrentIrp ==
  1814. deviceExtension->ResetIrp);
  1815. ASSERT(deviceExtension->ResetIrp != NULL);
  1816. ASSERT(DeviceObject->CurrentIrp != NULL);
  1817. //
  1818. // CurrentIrp is == deviceExtension->ResetIrp
  1819. //
  1820. IoRequestDpc(DeviceObject,
  1821. // DeviceObject->CurrentIrp,
  1822. deviceExtension->ResetIrp,
  1823. IntToPtr(IsrDpcCauseMouseResetComplete)
  1824. );
  1825. }
  1826. else if (byte == (UCHAR) RESEND) {
  1827. //
  1828. // Resend the "Enable Mouse Transmission" sequence.
  1829. //
  1830. // NOTE: This is a workaround for the Olivetti MIPS machine,
  1831. // which sends a resend response if a key is held down
  1832. // while we're attempting the I8xMouseEnableTransmission.
  1833. //
  1834. resendCommand = ENABLE_MOUSE_TRANSMISSION;
  1835. }
  1836. else {
  1837. //
  1838. // We could not understand if we were able to reenable the
  1839. // mouse... Best bet here is to also reset the mouse.
  1840. //
  1841. // Log the error
  1842. //
  1843. KeInsertQueueDpc(&deviceExtension->ErrorLogDpc,
  1844. (PIRP) NULL,
  1845. LongToPtr(I8042_ENABLE_FAILED)
  1846. );
  1847. goto IsrResetMouse;
  1848. }
  1849. break;
  1850. case MouseResetFailed:
  1851. //
  1852. // We have failed to reset the mouse, just ignore all further
  1853. // data. The ResetSubState will be reset if / when the user
  1854. // tries to reset the mouse via a plug in
  1855. //
  1856. return TRUE;
  1857. default:
  1858. //
  1859. // This is our bad state
  1860. //
  1861. IsrPrint(DBG_MOUISR_ERROR | DBG_MOUISR_STATE,
  1862. (" INVALID RESET SUBSTATE %d\n",
  1863. deviceExtension->InputResetSubState
  1864. ));
  1865. //
  1866. // Queue a DPC to log an internal driver error.
  1867. //
  1868. KeInsertQueueDpc(
  1869. &deviceExtension->ErrorLogDpc,
  1870. (PIRP) NULL,
  1871. LongToPtr(I8042_INVALID_ISR_STATE_MOU)
  1872. );
  1873. ASSERT(FALSE);
  1874. } // switch (deviceExtension->MouseExtension.InputResetSubState)
  1875. break;
  1876. }
  1877. default: {
  1878. //
  1879. // This is our bad state
  1880. //
  1881. IsrPrint(DBG_MOUISR_ERROR | DBG_MOUISR_STATE,
  1882. (" INVALID STATE %d\n",
  1883. deviceExtension->InputState
  1884. ));
  1885. //
  1886. // Queue a DPC to log an internal driver error.
  1887. //
  1888. KeInsertQueueDpc(
  1889. &deviceExtension->ErrorLogDpc,
  1890. (PIRP) NULL,
  1891. LongToPtr(I8042_INVALID_ISR_STATE_MOU)
  1892. );
  1893. ASSERT(FALSE);
  1894. break;
  1895. }
  1896. }
  1897. if (deviceExtension->InputState == MouseResetting) {
  1898. if (bSendCommand) {
  1899. if (byte == (UCHAR) ACKNOWLEDGE) {
  1900. I8X_WRITE_CMD_TO_MOUSE();
  1901. I8X_MOUSE_COMMAND( nextCommand );
  1902. RECORD_ISR_STATE_COMMAND(deviceExtension, nextCommand);
  1903. }
  1904. else if (byte == (UCHAR) RESEND) {
  1905. if (deviceExtension->ResendCount++ < MOUSE_RESENDS_MAX) {
  1906. I8X_WRITE_CMD_TO_MOUSE();
  1907. I8X_MOUSE_COMMAND( resendCommand );
  1908. RECORD_ISR_STATE_COMMAND(deviceExtension, resendCommand);
  1909. }
  1910. else {
  1911. //
  1912. // Got too many resends, try a (possible) reset
  1913. //
  1914. deviceExtension->ResendCount = 0;
  1915. goto IsrResetMouse;
  1916. }
  1917. }
  1918. }
  1919. else if (altCommand) {
  1920. I8X_WRITE_CMD_TO_MOUSE();
  1921. I8X_MOUSE_COMMAND( altCommand );
  1922. RECORD_ISR_STATE_COMMAND(deviceExtension, altCommand);
  1923. }
  1924. if (byte != (UCHAR) RESEND) {
  1925. deviceExtension->ResendCount = 0;
  1926. }
  1927. }
  1928. IsrPrint(DBG_MOUISR_TRACE, ("exit\n"));
  1929. return TRUE;
  1930. IsrResetMouse:
  1931. //
  1932. // About 1/2 of the errors in the resetting state machine are caused by
  1933. // trying to see if the wheel on the mouse exists...just try to enable it
  1934. // from now on....
  1935. //
  1936. if (deviceExtension->EnableWheelDetection == 1) {
  1937. deviceExtension->EnableWheelDetection = 2;
  1938. }
  1939. IsrResetMouseOnly:
  1940. deviceExtension->InputResetSubState = QueueingMouseReset;
  1941. KeInsertQueueDpc(&deviceExtension->MouseIsrResetDpc,
  1942. 0,
  1943. NULL
  1944. );
  1945. return ret;
  1946. #undef TRANSITION_UP
  1947. #undef TRANSITION_DOWN
  1948. }
  1949. NTSTATUS
  1950. I8xInitializeMouse(
  1951. IN PPORT_MOUSE_EXTENSION MouseExtension
  1952. )
  1953. /*++
  1954. Routine Description:
  1955. This routine initializes the i8042 mouse hardware. It is called
  1956. only at initialization, and does not synchronize access to the hardware.
  1957. Arguments:
  1958. DeviceObject - Pointer to the device object.
  1959. Return Value:
  1960. Returns status.
  1961. --*/
  1962. {
  1963. #define DUMP_COUNT 4
  1964. NTSTATUS errorCode = STATUS_SUCCESS;
  1965. NTSTATUS status;
  1966. PPORT_MOUSE_EXTENSION deviceExtension;
  1967. PDEVICE_OBJECT deviceObject;
  1968. PIO_ERROR_LOG_PACKET errorLogEntry;
  1969. UCHAR byte;
  1970. UCHAR numButtons;
  1971. ULONG dumpData[DUMP_COUNT];
  1972. ULONG dumpCount = 0;
  1973. ULONG i;
  1974. ULONG uniqueErrorValue;
  1975. LARGE_INTEGER li,
  1976. startOfSpin,
  1977. nextQuery,
  1978. difference,
  1979. tenSeconds;
  1980. BOOLEAN okToLogError;
  1981. PAGED_CODE();
  1982. Print(DBG_SS_TRACE, ("I8xInitializeMouse enter\n"));
  1983. //
  1984. // Initialize this array
  1985. //
  1986. for (i = 0; i < DUMP_COUNT; i++) {
  1987. dumpData[i] = 0;
  1988. }
  1989. //
  1990. // Get the device extension.
  1991. //
  1992. deviceExtension = MouseExtension;
  1993. deviceObject = deviceExtension->Self;
  1994. okToLogError = TRUE;
  1995. //
  1996. // Reset the mouse. Send a Write To Auxiliary Device command to the
  1997. // 8042 controller. Then send the Reset Mouse command to the mouse
  1998. // through the 8042 data register. Expect to get back an ACK, followed
  1999. // by a completion code and the ID code (0x00).
  2000. //
  2001. status = I8xPutBytePolled(
  2002. (CCHAR) DataPort,
  2003. WAIT_FOR_ACKNOWLEDGE,
  2004. (CCHAR) MouseDeviceType,
  2005. (UCHAR) MOUSE_RESET
  2006. );
  2007. if (!NT_SUCCESS(status)) {
  2008. Print(DBG_SS_ERROR,
  2009. ("%s failed mouse reset, status 0x%x\n",
  2010. pFncInitializeMouse,
  2011. status
  2012. ));
  2013. //
  2014. // Only log this error if the user wants to see it
  2015. //
  2016. okToLogError = Globals.ReportResetErrors;
  2017. //
  2018. // Set up error log info.
  2019. //
  2020. // Use NO_MOU_DEVICE instead of I8042_MOU_RESET_COMMAND_FAILED because
  2021. // it is a clearer message.
  2022. //
  2023. errorCode = I8042_NO_MOU_DEVICE;
  2024. uniqueErrorValue = I8042_ERROR_VALUE_BASE + 415;
  2025. dumpData[0] = KBDMOU_COULD_NOT_SEND_PARAM;
  2026. dumpData[1] = DataPort;
  2027. dumpData[2] = I8042_WRITE_TO_AUXILIARY_DEVICE;
  2028. dumpData[3] = MOUSE_RESET;
  2029. dumpCount = 4;
  2030. status = STATUS_DEVICE_NOT_CONNECTED;
  2031. SET_HW_FLAGS(PHANTOM_MOUSE_HARDWARE_REPORTED);
  2032. goto I8xInitializeMouseExit;
  2033. }
  2034. deviceExtension->ResendCount = 0;
  2035. I8X_MOUSE_INIT_COUNTERS(deviceExtension);
  2036. //
  2037. // Get the mouse reset responses. The first response should be a
  2038. // MOUSE_COMPLETE. The second response should be the mouse ID.
  2039. // Note that it is usually necessary to stall a long time to get the
  2040. // mouse reset/self-test to work.
  2041. //
  2042. li.QuadPart = -100;
  2043. tenSeconds.QuadPart = 10*10*1000*1000;
  2044. KeQueryTickCount(&startOfSpin);
  2045. while (1) {
  2046. status = I8xGetBytePolled(
  2047. (CCHAR) ControllerDeviceType,
  2048. &byte
  2049. );
  2050. if (NT_SUCCESS(status) && (byte == (UCHAR) MOUSE_COMPLETE)) {
  2051. //
  2052. // The reset completed successfully.
  2053. //
  2054. break;
  2055. }
  2056. else {
  2057. //
  2058. // Stall, and then try again to get a response from
  2059. // the reset.
  2060. //
  2061. if (status == STATUS_IO_TIMEOUT) {
  2062. //
  2063. // Stall, and then try again to get a response from
  2064. // the reset.
  2065. //
  2066. KeDelayExecutionThread(KernelMode,
  2067. FALSE,
  2068. &li);
  2069. KeQueryTickCount(&nextQuery);
  2070. difference.QuadPart = nextQuery.QuadPart - startOfSpin.QuadPart;
  2071. ASSERT(KeQueryTimeIncrement() <= MAXLONG);
  2072. if (difference.QuadPart*KeQueryTimeIncrement() >=
  2073. tenSeconds.QuadPart) {
  2074. break;
  2075. }
  2076. }
  2077. else {
  2078. break;
  2079. }
  2080. }
  2081. }
  2082. if (!NT_SUCCESS(status)) {
  2083. Print(DBG_SS_ERROR,
  2084. ("%s failed reset response 1, status 0x%x, byte 0x%x\n",
  2085. pFncInitializeMouse,
  2086. status,
  2087. byte
  2088. ));
  2089. //
  2090. // Set up error log info.
  2091. //
  2092. errorCode = I8042_MOU_RESET_RESPONSE_FAILED;
  2093. uniqueErrorValue = I8042_ERROR_VALUE_BASE + 420;
  2094. dumpData[0] = KBDMOU_INCORRECT_RESPONSE;
  2095. dumpData[1] = ControllerDeviceType;
  2096. dumpData[2] = MOUSE_COMPLETE;
  2097. dumpData[3] = byte;
  2098. dumpCount = 4;
  2099. goto I8xInitializeMouseExit;
  2100. }
  2101. status = I8xGetBytePolled(
  2102. (CCHAR) ControllerDeviceType,
  2103. &byte
  2104. );
  2105. if ((!NT_SUCCESS(status)) || (byte != MOUSE_ID_BYTE)) {
  2106. Print(DBG_SS_ERROR,
  2107. ("%s failed reset response 2, status 0x%x, byte 0x%x\n",
  2108. pFncInitializeMouse,
  2109. status,
  2110. byte
  2111. ));
  2112. //
  2113. // Set up error log info.
  2114. //
  2115. errorCode = I8042_MOU_RESET_RESPONSE_FAILED;
  2116. uniqueErrorValue = I8042_ERROR_VALUE_BASE + 425;
  2117. dumpData[0] = KBDMOU_INCORRECT_RESPONSE;
  2118. dumpData[1] = ControllerDeviceType;
  2119. dumpData[2] = MOUSE_ID_BYTE;
  2120. dumpData[3] = byte;
  2121. dumpCount = 4;
  2122. goto I8xInitializeMouseExit;
  2123. }
  2124. //
  2125. // If we are going to initialize the mouse via the interrupt (the default),
  2126. // then quit here
  2127. //
  2128. if (!deviceExtension->InitializePolled) {
  2129. Print(DBG_SS_NOISE, ("Initializing via the interrupt\n"));
  2130. return STATUS_SUCCESS;
  2131. }
  2132. Print(DBG_SS_NOISE, ("Initializing polled\n"));
  2133. deviceExtension->EnableMouse.FirstTime = TRUE;
  2134. deviceExtension->EnableMouse.Enabled = TRUE;
  2135. deviceExtension->EnableMouse.Count = 0;
  2136. //
  2137. // Check to see if this is a wheel mouse
  2138. //
  2139. I8xFindWheelMouse(deviceExtension);
  2140. //
  2141. // Try to detect the number of mouse buttons.
  2142. //
  2143. status = I8xQueryNumberOfMouseButtons(&numButtons);
  2144. Print(DBG_SS_INFO,
  2145. ("num buttons returned (%d), num butons in attrib (%d)\n"
  2146. "\t(if 0, then no logitech detection support)\n",
  2147. numButtons,
  2148. deviceExtension->MouseAttributes.NumberOfButtons
  2149. ));
  2150. if (!NT_SUCCESS(status)) {
  2151. Print(DBG_SS_ERROR,
  2152. ("%s: failed to get buttons, status 0x%x\n",
  2153. pFncInitializeMouse,
  2154. status
  2155. ));
  2156. //
  2157. // Set up error log info.
  2158. //
  2159. errorCode = I8042_ERROR_DURING_BUTTONS_DETECT;
  2160. uniqueErrorValue = I8042_ERROR_VALUE_BASE + 426;
  2161. dumpData[0] = KBDMOU_COULD_NOT_SEND_PARAM;
  2162. dumpData[1] = DataPort;
  2163. dumpData[2] = I8042_WRITE_TO_AUXILIARY_DEVICE;
  2164. dumpCount = 3;
  2165. goto I8xInitializeMouseExit;
  2166. } else if (numButtons) {
  2167. deviceExtension->MouseAttributes.NumberOfButtons =
  2168. numButtons;
  2169. }
  2170. //
  2171. // If there is a 5 button mouse, report it.
  2172. // If there is a wheel, hardcode the number of buttons to three
  2173. //
  2174. if (FIVE_PRESENT()) {
  2175. deviceExtension->MouseAttributes.NumberOfButtons = 5;
  2176. }
  2177. else if (WHEEL_PRESENT()) {
  2178. deviceExtension->MouseAttributes.NumberOfButtons = 3;
  2179. }
  2180. //
  2181. // Set mouse sampling rate. Send a Write To Auxiliary Device command
  2182. // to the 8042 controller. Then send the Set Mouse Sampling Rate
  2183. // command to the mouse through the 8042 data register,
  2184. // followed by its parameter.
  2185. //
  2186. status = I8xPutBytePolled(
  2187. (CCHAR) DataPort,
  2188. WAIT_FOR_ACKNOWLEDGE,
  2189. (CCHAR) MouseDeviceType,
  2190. (UCHAR) SET_MOUSE_SAMPLING_RATE
  2191. );
  2192. if (!NT_SUCCESS(status)) {
  2193. Print(DBG_SS_ERROR,
  2194. ("%s: failed write set sample rate, status 0x%x\n",
  2195. pFncInitializeMouse,
  2196. status
  2197. ));
  2198. //
  2199. // Set up error log info.
  2200. //
  2201. errorCode = I8042_SET_SAMPLE_RATE_FAILED;
  2202. uniqueErrorValue = I8042_ERROR_VALUE_BASE + 435;
  2203. dumpData[0] = KBDMOU_COULD_NOT_SEND_PARAM;
  2204. dumpData[1] = DataPort;
  2205. dumpData[2] = I8042_WRITE_TO_AUXILIARY_DEVICE;
  2206. dumpData[3] = SET_MOUSE_SAMPLING_RATE;
  2207. dumpCount = 4;
  2208. goto I8xInitializeMouseExit;
  2209. }
  2210. status = I8xPutBytePolled(
  2211. (CCHAR) DataPort,
  2212. WAIT_FOR_ACKNOWLEDGE,
  2213. (CCHAR) MouseDeviceType,
  2214. (UCHAR) deviceExtension->MouseAttributes.SampleRate
  2215. );
  2216. if (!NT_SUCCESS(status)) {
  2217. Print(DBG_SS_ERROR,
  2218. ("%s: failed write sample rate, status 0x%x\n",
  2219. pFncInitializeMouse,
  2220. status
  2221. ));
  2222. //
  2223. // Set up error log info.
  2224. //
  2225. errorCode = I8042_SET_SAMPLE_RATE_FAILED;
  2226. uniqueErrorValue = I8042_ERROR_VALUE_BASE + 445;
  2227. dumpData[0] = KBDMOU_COULD_NOT_SEND_PARAM;
  2228. dumpData[1] = DataPort;
  2229. dumpData[2] = I8042_WRITE_TO_AUXILIARY_DEVICE;
  2230. dumpData[3] = deviceExtension->MouseAttributes.SampleRate;
  2231. dumpCount = 4;
  2232. goto I8xInitializeMouseExit;
  2233. }
  2234. //
  2235. // Set the mouse resolution. Send a Write To Auxiliary Device command
  2236. // to the 8042 controller. Then send the Set Mouse Resolution
  2237. // command to the mouse through the 8042 data register,
  2238. // followed by its parameter.
  2239. //
  2240. status = I8xPutBytePolled(
  2241. (CCHAR) DataPort,
  2242. WAIT_FOR_ACKNOWLEDGE,
  2243. (CCHAR) MouseDeviceType,
  2244. (UCHAR) SET_MOUSE_RESOLUTION
  2245. );
  2246. if (!NT_SUCCESS(status)) {
  2247. Print(DBG_SS_ERROR,
  2248. ("%s: failed write set resolution, status 0x%x\n",
  2249. pFncInitializeMouse,
  2250. status
  2251. ));
  2252. //
  2253. // Set up error log info.
  2254. //
  2255. errorCode = I8042_SET_RESOLUTION_FAILED;
  2256. uniqueErrorValue = I8042_ERROR_VALUE_BASE + 455;
  2257. dumpData[0] = KBDMOU_COULD_NOT_SEND_PARAM;
  2258. dumpData[1] = DataPort;
  2259. dumpData[2] = I8042_WRITE_TO_AUXILIARY_DEVICE;
  2260. dumpData[3] = SET_MOUSE_RESOLUTION;
  2261. dumpCount = 4;
  2262. goto I8xInitializeMouseExit;
  2263. }
  2264. status = I8xPutBytePolled(
  2265. (CCHAR) DataPort,
  2266. WAIT_FOR_ACKNOWLEDGE,
  2267. (CCHAR) MouseDeviceType,
  2268. (UCHAR) deviceExtension->Resolution
  2269. );
  2270. if (!NT_SUCCESS(status)) {
  2271. Print(DBG_SS_ERROR,
  2272. ("%s: failed set mouse resolution, status 0x%x\n",
  2273. pFncInitializeMouse,
  2274. status
  2275. ));
  2276. //
  2277. // Set up error log info.
  2278. //
  2279. errorCode = I8042_SET_RESOLUTION_FAILED;
  2280. uniqueErrorValue = I8042_ERROR_VALUE_BASE + 465;
  2281. dumpData[0] = KBDMOU_COULD_NOT_SEND_PARAM;
  2282. dumpData[1] = DataPort;
  2283. dumpData[2] = I8042_WRITE_TO_AUXILIARY_DEVICE;
  2284. dumpData[3] = deviceExtension->Resolution;
  2285. dumpCount = 4;
  2286. goto I8xInitializeMouseExit;
  2287. }
  2288. I8xInitializeMouseExit:
  2289. if (!NT_SUCCESS(status)) {
  2290. //
  2291. // The mouse initialization failed. Log an error.
  2292. //
  2293. if (errorCode != STATUS_SUCCESS && okToLogError) {
  2294. I8xLogError(deviceObject,
  2295. errorCode,
  2296. uniqueErrorValue,
  2297. status,
  2298. dumpData,
  2299. dumpCount
  2300. );
  2301. }
  2302. }
  2303. //
  2304. // Initialize current mouse input packet state.
  2305. //
  2306. deviceExtension->PreviousSignAndOverflow = 0;
  2307. deviceExtension->InputState = MouseExpectingACK;
  2308. deviceExtension->InputResetSubState = 0;
  2309. deviceExtension->LastByteReceived = 0;
  2310. Print(DBG_SS_TRACE,
  2311. ("%s, %s\n",
  2312. pFncInitializeMouse,
  2313. pExit
  2314. ));
  2315. return status;
  2316. }
  2317. NTSTATUS
  2318. I8xMouseConfiguration(
  2319. IN PPORT_MOUSE_EXTENSION MouseExtension,
  2320. IN PCM_RESOURCE_LIST ResourceList
  2321. )
  2322. /*++
  2323. Routine Description:
  2324. This routine retrieves the configuration information for the mouse.
  2325. Arguments:
  2326. MouseExtension - Mouse extension
  2327. ResourceList - Translated resource list give to us via the start IRP
  2328. Return Value:
  2329. STATUS_SUCCESS if all the resources required are presented
  2330. --*/
  2331. {
  2332. NTSTATUS status = STATUS_SUCCESS;
  2333. PCM_PARTIAL_RESOURCE_LIST partialResList = NULL;
  2334. PCM_PARTIAL_RESOURCE_DESCRIPTOR firstResDesc = NULL,
  2335. currentResDesc = NULL;
  2336. PCM_FULL_RESOURCE_DESCRIPTOR fullResDesc = NULL;
  2337. PI8042_CONFIGURATION_INFORMATION configuration;
  2338. ULONG count,
  2339. i;
  2340. KINTERRUPT_MODE defaultInterruptMode;
  2341. BOOLEAN defaultInterruptShare;
  2342. PAGED_CODE();
  2343. if (!ResourceList) {
  2344. Print(DBG_SS_INFO | DBG_SS_ERROR, ("mouse with no resources\n"));
  2345. return STATUS_INSUFFICIENT_RESOURCES;
  2346. }
  2347. fullResDesc = ResourceList->List;
  2348. if (!fullResDesc) {
  2349. //
  2350. // this should never happen
  2351. //
  2352. ASSERT(fullResDesc != NULL);
  2353. return STATUS_INSUFFICIENT_RESOURCES;
  2354. }
  2355. SET_HW_FLAGS(MOUSE_HARDWARE_PRESENT);
  2356. configuration = &Globals.ControllerData->Configuration;
  2357. partialResList = &fullResDesc->PartialResourceList;
  2358. currentResDesc = firstResDesc = partialResList->PartialDescriptors;
  2359. count = partialResList->Count;
  2360. configuration->FloatingSave = I8042_FLOATING_SAVE;
  2361. configuration->BusNumber = fullResDesc->BusNumber;
  2362. configuration->InterfaceType = fullResDesc->InterfaceType;
  2363. if (configuration->InterfaceType == MicroChannel) {
  2364. defaultInterruptShare = TRUE;
  2365. defaultInterruptMode = LevelSensitive;
  2366. }
  2367. else {
  2368. defaultInterruptShare = I8042_INTERRUPT_SHARE;
  2369. defaultInterruptMode = I8042_INTERRUPT_MODE;
  2370. }
  2371. //
  2372. // NOTE: not all of the resources associated with the i8042 may be given at
  2373. // this time. From empirical tests, the mouse is only associated with its
  2374. // interrupt, while the keyboard will receive the ports along with its
  2375. // interrupt
  2376. //
  2377. for (i = 0; i < count; i++, currentResDesc++) {
  2378. switch (currentResDesc->Type) {
  2379. case CmResourceTypeMemory:
  2380. Globals.RegistersMapped = TRUE;
  2381. case CmResourceTypePort:
  2382. //
  2383. // Copy the port information. We will sort the port list
  2384. // into ascending order based on the starting port address
  2385. // later (note that we *know* there are a max of two port
  2386. // ranges for the i8042).
  2387. //
  2388. #if 0
  2389. if (currentResDesc->Flags == CM_RESOURCE_PORT_MEMORY) {
  2390. Globals.RegistersMapped = TRUE;
  2391. }
  2392. #endif
  2393. Print(DBG_SS_NOISE, ("io flags are 0x%x\n", currentResDesc->Flags));
  2394. if (configuration->PortListCount < MaximumPortCount) {
  2395. configuration->PortList[configuration->PortListCount] =
  2396. *currentResDesc;
  2397. configuration->PortList[configuration->PortListCount].ShareDisposition =
  2398. I8042_REGISTER_SHARE ? CmResourceShareShared:
  2399. CmResourceShareDriverExclusive;
  2400. configuration->PortListCount += 1;
  2401. }
  2402. else {
  2403. Print(DBG_SS_INFO | DBG_SS_ERROR,
  2404. ("Mouse::PortListCount already at max (%d)",
  2405. configuration->PortListCount
  2406. ));
  2407. }
  2408. break;
  2409. case CmResourceTypeInterrupt:
  2410. //
  2411. // Copy the interrupt information.
  2412. //
  2413. MouseExtension->InterruptDescriptor = *currentResDesc;
  2414. MouseExtension->InterruptDescriptor.ShareDisposition =
  2415. defaultInterruptShare ? CmResourceShareShared :
  2416. CmResourceShareDeviceExclusive;
  2417. break;
  2418. default:
  2419. Print(DBG_ALWAYS,
  2420. ("resource type 0x%x unhandled...\n",
  2421. (LONG) currentResDesc->Type
  2422. ));
  2423. break;
  2424. }
  2425. }
  2426. MouseExtension->MouseAttributes.MouseIdentifier = MOUSE_I8042_HARDWARE;
  2427. //
  2428. // If no interrupt configuration information was found, use the
  2429. // mouse driver defaults.
  2430. //
  2431. if (!(MouseExtension->InterruptDescriptor.Type & CmResourceTypeInterrupt)) {
  2432. Print(DBG_SS_INFO | DBG_SS_ERROR,
  2433. ("Using default mouse interrupt config\n"
  2434. ));
  2435. MouseExtension->InterruptDescriptor.Type = CmResourceTypeInterrupt;
  2436. MouseExtension->InterruptDescriptor.ShareDisposition =
  2437. defaultInterruptShare ? CmResourceShareShared :
  2438. CmResourceShareDeviceExclusive;
  2439. MouseExtension->InterruptDescriptor.Flags =
  2440. (defaultInterruptMode == Latched) ? CM_RESOURCE_INTERRUPT_LATCHED :
  2441. CM_RESOURCE_INTERRUPT_LEVEL_SENSITIVE;
  2442. MouseExtension->InterruptDescriptor.u.Interrupt.Level = MOUSE_IRQL;
  2443. MouseExtension->InterruptDescriptor.u.Interrupt.Vector = MOUSE_VECTOR;
  2444. // MouseExtension->ReportInterrupt = TRUE;
  2445. }
  2446. Print(DBG_SS_INFO,
  2447. ("Mouse interrupt config --\n"
  2448. "%s, %s, Irq = 0x%x\n",
  2449. MouseExtension->InterruptDescriptor.ShareDisposition == CmResourceShareShared?
  2450. "Sharable" : "NonSharable",
  2451. MouseExtension->InterruptDescriptor.Flags == CM_RESOURCE_INTERRUPT_LATCHED?
  2452. "Latched" : "Level Sensitive",
  2453. MouseExtension->InterruptDescriptor.u.Interrupt.Vector
  2454. ));
  2455. if (NT_SUCCESS(status)) {
  2456. SET_HW_FLAGS(MOUSE_HARDWARE_INITIALIZED);
  2457. }
  2458. return status;
  2459. }
  2460. NTSTATUS
  2461. I8xQueryNumberOfMouseButtons(
  2462. OUT PUCHAR NumberOfMouseButtons
  2463. )
  2464. /*++
  2465. Routine Description:
  2466. This implements logitech's method for detecting the number of
  2467. mouse buttons. If anything doesn't go as expected then 0
  2468. is returned.
  2469. Calling this routine will set the mouse resolution to something
  2470. really low. The mouse resolution should be reset after this
  2471. call.
  2472. Arguments:
  2473. DeviceObject - Supplies the device object.
  2474. NumberOfMouseButtons - Returns the number of mouse buttons or 0 if
  2475. the device did not support this type of
  2476. mouse button detection.
  2477. Return Value:
  2478. An NTSTATUS code indicating success or failure.
  2479. --*/
  2480. {
  2481. NTSTATUS status;
  2482. UCHAR byte;
  2483. UCHAR buttons;
  2484. ULONG i;
  2485. PAGED_CODE();
  2486. //
  2487. // First we need to send down a set resolution command
  2488. //
  2489. status = I8xPutBytePolled(
  2490. (CCHAR) DataPort,
  2491. WAIT_FOR_ACKNOWLEDGE,
  2492. (CCHAR) MouseDeviceType,
  2493. (UCHAR) SET_MOUSE_RESOLUTION
  2494. );
  2495. if (!NT_SUCCESS(status)) {
  2496. return status;
  2497. }
  2498. //
  2499. // This is another part of the data packet to get the info we want
  2500. //
  2501. status = I8xPutBytePolled(
  2502. (CCHAR) DataPort,
  2503. WAIT_FOR_ACKNOWLEDGE,
  2504. (CCHAR) MouseDeviceType,
  2505. (UCHAR) 0x00
  2506. );
  2507. if (!NT_SUCCESS(status)) {
  2508. return status;
  2509. }
  2510. for (i = 0; i < 3; i++) {
  2511. status = I8xPutBytePolled(
  2512. (CCHAR) DataPort,
  2513. WAIT_FOR_ACKNOWLEDGE,
  2514. (CCHAR) MouseDeviceType,
  2515. (UCHAR) SET_MOUSE_SCALING_1TO1
  2516. );
  2517. if (!NT_SUCCESS(status)) {
  2518. return status;
  2519. }
  2520. }
  2521. status = I8xPutBytePolled(
  2522. (CCHAR) DataPort,
  2523. WAIT_FOR_ACKNOWLEDGE,
  2524. (CCHAR) MouseDeviceType,
  2525. (UCHAR) READ_MOUSE_STATUS
  2526. );
  2527. if (!NT_SUCCESS(status)) {
  2528. return status;
  2529. }
  2530. status = I8xGetBytePolled((CCHAR) ControllerDeviceType, &byte);
  2531. if (!NT_SUCCESS(status)) {
  2532. return status;
  2533. }
  2534. Print(DBG_SS_NOISE, ("Query Buttons, 1st byte: 0x%2x\n", byte));
  2535. status = I8xGetBytePolled((CCHAR) ControllerDeviceType, &buttons);
  2536. if (!NT_SUCCESS(status)) {
  2537. return status;
  2538. }
  2539. Print(DBG_SS_NOISE, ("Query Buttons, 2nd byte: 0x%2x\n", buttons));
  2540. status = I8xGetBytePolled((CCHAR) ControllerDeviceType, &byte);
  2541. if (!NT_SUCCESS(status)) {
  2542. return status;
  2543. }
  2544. Print(DBG_SS_NOISE, ("Query Buttons, 3rd byte: 0x%2x\n", byte));
  2545. if (buttons == 2 || buttons == 3) {
  2546. *NumberOfMouseButtons = buttons;
  2547. Print(DBG_SS_NOISE, ("Query Buttons found %2x", *NumberOfMouseButtons));
  2548. }
  2549. else {
  2550. *NumberOfMouseButtons = 0;
  2551. Print(DBG_SS_NOISE, ("Query Buttons -- not supported\n"));
  2552. }
  2553. return status;
  2554. }
  2555. NTSTATUS
  2556. I8xMouseEnableTransmission(
  2557. IN PPORT_MOUSE_EXTENSION MouseExtension
  2558. )
  2559. /*++
  2560. Routine Description:
  2561. This routine sends an Enable command to the mouse hardware, causing
  2562. the mouse to begin transmissions. It is called at initialization
  2563. time, but only after the interrupt has been connected. This is
  2564. necessary so the driver can keep its notion of the mouse input data
  2565. state in sync with the hardware (i.e., for this type of mouse there is no
  2566. way to differentiate the first byte of a packet; if the user is randomly
  2567. moving the mouse during boot/initialization, the first mouse interrupt we
  2568. receive following IoConnectInterrupt could be for a byte that is not the
  2569. start of a packet, and we have no way to know that).
  2570. Arguments:
  2571. DeviceObject - Pointer to the device object.
  2572. Return Value:
  2573. Returns status.
  2574. --*/
  2575. {
  2576. #define DUMP_COUNT 4
  2577. NTSTATUS errorCode = STATUS_SUCCESS;
  2578. NTSTATUS status;
  2579. PIO_ERROR_LOG_PACKET errorLogEntry;
  2580. ULONG dumpCount = 0;
  2581. ULONG dumpData[DUMP_COUNT];
  2582. ULONG i;
  2583. ULONG uniqueErrorValue;
  2584. LARGE_INTEGER li;
  2585. PPORT_MOUSE_EXTENSION mouseExtension;
  2586. Print(DBG_SS_TRACE,
  2587. ("%s: %s\n",
  2588. pFncMouseEnable,
  2589. pEnter
  2590. ));
  2591. //
  2592. // Initialize the dump structure
  2593. //
  2594. for (i = 0; i < DUMP_COUNT; i++) {
  2595. dumpData[i] = 0;
  2596. }
  2597. if (MouseExtension->EnableMouse.FirstTime) {
  2598. // 5 seconds
  2599. li.QuadPart = -5 * 10 // from 100 ns to us
  2600. * 1000 // us to ms
  2601. * 1000; // ms to s
  2602. MouseExtension->EnableMouse.FirstTime = FALSE;
  2603. KeSetTimerEx(
  2604. &MouseExtension->EnableMouse.Timer,
  2605. li,
  2606. 5 * 1000, // ms to s
  2607. &MouseExtension->EnableMouse.Dpc
  2608. );
  2609. }
  2610. //
  2611. // Re-enable the mouse at the mouse hardware, so that it can transmit
  2612. // data packets in continuous mode. Note that this is not the same
  2613. // as enabling the mouse device at the 8042 controller. The mouse
  2614. // hardware is sent an Enable command here, because it was
  2615. // Disabled as a result of the mouse reset command performed
  2616. // in I8xInitializeMouse().
  2617. //
  2618. // Note that we don't wait for an ACKNOWLEDGE back. The
  2619. // ACKNOWLEDGE back will actually cause a mouse interrupt, which
  2620. // then gets handled in the mouse ISR.
  2621. //
  2622. status = I8xPutBytePolled(
  2623. (CCHAR) DataPort,
  2624. NO_WAIT_FOR_ACKNOWLEDGE,
  2625. (CCHAR) MouseDeviceType,
  2626. (UCHAR) ENABLE_MOUSE_TRANSMISSION
  2627. );
  2628. if (!NT_SUCCESS(status)) {
  2629. Print(DBG_SS_ERROR,
  2630. ("%s: "
  2631. "failed write enable transmission, status 0x%x\n",
  2632. pFncMouseEnable,
  2633. status
  2634. ));
  2635. //
  2636. // Set up error log info.
  2637. //
  2638. errorCode = I8042_MOU_ENABLE_XMIT;
  2639. uniqueErrorValue = I8042_ERROR_VALUE_BASE + 475;
  2640. dumpData[0] = KBDMOU_COULD_NOT_SEND_PARAM;
  2641. dumpData[1] = DataPort;
  2642. dumpData[2] = I8042_WRITE_TO_AUXILIARY_DEVICE;
  2643. dumpData[3] = ENABLE_MOUSE_TRANSMISSION;
  2644. dumpCount = 4;
  2645. goto I8xEnableMouseTransmissionExit;
  2646. }
  2647. I8xEnableMouseTransmissionExit:
  2648. if (!NT_SUCCESS(status)) {
  2649. //
  2650. // The mouse initialization failed. Log an error.
  2651. //
  2652. if (errorCode != STATUS_SUCCESS) {
  2653. errorLogEntry = (PIO_ERROR_LOG_PACKET)
  2654. IoAllocateErrorLogEntry(
  2655. MouseExtension->Self, (UCHAR)
  2656. (sizeof(IO_ERROR_LOG_PACKET) + (dumpCount * sizeof(ULONG)))
  2657. );
  2658. if (errorLogEntry != NULL) {
  2659. errorLogEntry->ErrorCode = errorCode;
  2660. errorLogEntry->DumpDataSize = (USHORT) dumpCount * sizeof(ULONG);
  2661. errorLogEntry->SequenceNumber = 0;
  2662. errorLogEntry->MajorFunctionCode = 0;
  2663. errorLogEntry->IoControlCode = 0;
  2664. errorLogEntry->RetryCount = 0;
  2665. errorLogEntry->UniqueErrorValue = uniqueErrorValue;
  2666. errorLogEntry->FinalStatus = status;
  2667. for (i = 0; i < dumpCount; i++) {
  2668. errorLogEntry->DumpData[i] = dumpData[i];
  2669. }
  2670. IoWriteErrorLogEntry(errorLogEntry);
  2671. }
  2672. }
  2673. }
  2674. //
  2675. // Initialize current mouse input packet state
  2676. //
  2677. MouseExtension->PreviousSignAndOverflow = 0;
  2678. MouseExtension->InputState = MouseExpectingACK;
  2679. Print(DBG_SS_TRACE, ("I8xMouseEnableTransmission (0x%x)\n", status));
  2680. return status;
  2681. }
  2682. NTSTATUS
  2683. I8xTransmitByteSequence(
  2684. PUCHAR Bytes,
  2685. ULONG* UniqueErrorValue,
  2686. ULONG* ErrorCode,
  2687. ULONG* DumpData,
  2688. ULONG* DumpCount
  2689. )
  2690. {
  2691. NTSTATUS status;
  2692. ULONG byteCount;
  2693. PAGED_CODE();
  2694. status = STATUS_SUCCESS;
  2695. byteCount = 0;
  2696. //
  2697. // Begin sending commands to the mouse
  2698. //
  2699. while (Bytes[byteCount] != 0) {
  2700. status = I8xPutBytePolled(
  2701. (CCHAR) DataPort,
  2702. WAIT_FOR_ACKNOWLEDGE,
  2703. (CCHAR) MouseDeviceType,
  2704. Bytes[byteCount]
  2705. );
  2706. if (!NT_SUCCESS(status)) {
  2707. Print(DBG_SS_ERROR,
  2708. ("%s, failed write set sample rate #%d, status 0x%x\n",
  2709. pFncFindWheelMouse,
  2710. byteCount,
  2711. status
  2712. ));
  2713. //
  2714. // Set up error log info
  2715. //
  2716. *ErrorCode = I8042_SET_SAMPLE_RATE_FAILED;
  2717. *DumpCount = 4;
  2718. DumpData[0] = KBDMOU_COULD_NOT_SEND_PARAM;
  2719. DumpData[1] = DataPort;
  2720. DumpData[2] = I8042_WRITE_TO_AUXILIARY_DEVICE;
  2721. DumpData[3] = Bytes[byteCount];
  2722. break;
  2723. }
  2724. //
  2725. // Next command
  2726. //
  2727. byteCount++;
  2728. (*UniqueErrorValue) += 5;
  2729. KeStallExecutionProcessor(50);
  2730. } // while
  2731. return status;
  2732. }
  2733. NTSTATUS
  2734. I8xGetBytePolledIterated(
  2735. IN CCHAR DeviceType,
  2736. OUT PUCHAR Byte,
  2737. ULONG Attempts
  2738. )
  2739. {
  2740. NTSTATUS status = STATUS_UNSUCCESSFUL;
  2741. ULONG i;
  2742. PAGED_CODE();
  2743. //
  2744. // Try to get a single character
  2745. //
  2746. for(i = 0; i < Attempts; i++) {
  2747. status = I8xGetBytePolled(
  2748. (CCHAR) ControllerDeviceType,
  2749. Byte
  2750. );
  2751. if (NT_SUCCESS(status)) {
  2752. //
  2753. // Read was successfull. We got a byte.
  2754. //
  2755. break;
  2756. }
  2757. //
  2758. // If the read timed out, stall and retry.
  2759. // If some other error occured handle it outside the loop
  2760. //
  2761. if (status == STATUS_IO_TIMEOUT) {
  2762. KeStallExecutionProcessor(50);
  2763. }
  2764. else {
  2765. break;
  2766. }
  2767. }
  2768. return status;
  2769. }
  2770. NTSTATUS
  2771. I8xFindWheelMouse(
  2772. IN PPORT_MOUSE_EXTENSION MouseExtension
  2773. )
  2774. /*++
  2775. Routine Description:
  2776. There are two methods of finding a wheel mouse on a system. The first
  2777. method, is to send down the request to get the PNP id of the device
  2778. and compare it with the known id for a wheel mouse. The method is
  2779. useful since some machines hang on the second detection mechanism,
  2780. even if no mouse is present on the system.
  2781. The second method, which also enables a wheel mouse is set the sampling
  2782. rate to 200hz, then 100hz, then 80hz, and then read the device id. An
  2783. ID of 3 indicates a zoom mouse.
  2784. If the registry entry "EnableWheelDetection" is 0 then this
  2785. routine will just return STATUS_NO_SUCH_DEVICE. If the registry entry
  2786. is 1 (the default), then the first and second detection mechanisms will
  2787. be used. If the registry entry is 2, then only the second detection
  2788. mechanism will be used.
  2789. Arguments:
  2790. DeviceObject - Pointer to the device object
  2791. Return Value:
  2792. Returns status
  2793. Remarks:
  2794. As a side effect the sample rate is left at 80Hz and if a wheelmouse is
  2795. attached it is in the wheel mode where packets are different.
  2796. --*/
  2797. {
  2798. #define DUMP_COUNT 4
  2799. NTSTATUS errorCode = STATUS_SUCCESS;
  2800. NTSTATUS status;
  2801. PIO_ERROR_LOG_PACKET errorLogEntry;
  2802. UCHAR byte;
  2803. UCHAR enableCommands[] = {
  2804. SET_MOUSE_SAMPLING_RATE, 200,
  2805. SET_MOUSE_SAMPLING_RATE, 100,
  2806. SET_MOUSE_SAMPLING_RATE, 80,
  2807. GET_DEVICE_ID, 0 // NULL terminate
  2808. };
  2809. UCHAR enable5Commands[] = {
  2810. SET_MOUSE_SAMPLING_RATE, 200,
  2811. SET_MOUSE_SAMPLING_RATE, 200,
  2812. SET_MOUSE_SAMPLING_RATE, 80,
  2813. GET_DEVICE_ID, 0 // NULL terminate
  2814. };
  2815. UCHAR pnpCommands[] = {
  2816. SET_MOUSE_SAMPLING_RATE, 20,
  2817. SET_MOUSE_SAMPLING_RATE, 40,
  2818. SET_MOUSE_SAMPLING_RATE, 60,
  2819. 0 // NULL terminates
  2820. };
  2821. ULONG dumpCount = 0;
  2822. ULONG dumpData[DUMP_COUNT];
  2823. ULONG i;
  2824. ULONG idCount;
  2825. ULONG uniqueErrorValue = I8042_ERROR_VALUE_BASE + 480;
  2826. WCHAR mouseID[MOUSE_PNPID_LENGTH];
  2827. PWCHAR currentChar;
  2828. PAGED_CODE();
  2829. //
  2830. // Let the world know that we have entered this routine
  2831. //
  2832. Print(DBG_SS_TRACE,
  2833. ("%s, %s\n",
  2834. pFncFindWheelMouse,
  2835. pEnter
  2836. ));
  2837. if (MouseExtension->EnableWheelDetection == 0) {
  2838. Print(DBG_SS_INFO | DBG_SS_NOISE,
  2839. ("%s: Detection disabled in registry\n",
  2840. pFncFindWheelMouse
  2841. ));
  2842. return STATUS_NO_SUCH_DEVICE;
  2843. }
  2844. //
  2845. // Initialize some variables
  2846. //
  2847. for(i = 0; i < DUMP_COUNT; i++) {
  2848. dumpData[i] = 0;
  2849. }
  2850. //
  2851. // If the MouseInterruptObject exists, then we have gone through initialization
  2852. // at least once and know about the mouse attached
  2853. //
  2854. if (MouseExtension->InterruptObject) {
  2855. if (WHEEL_PRESENT()) {
  2856. //
  2857. // Skip detection and go straight to turning on the wheel
  2858. //
  2859. goto InitializeWheel;
  2860. }
  2861. else {
  2862. //
  2863. // No wheel mouse present, no need to detect it a second time
  2864. //
  2865. return STATUS_NO_SUCH_DEVICE;
  2866. }
  2867. }
  2868. //
  2869. // What is the point of this here???
  2870. //
  2871. KeStallExecutionProcessor(50);
  2872. //
  2873. // First check to see if we will try the 'better' method of detection
  2874. //
  2875. if (MouseExtension->EnableWheelDetection == 1) {
  2876. status = I8xTransmitByteSequence(
  2877. pnpCommands,
  2878. &uniqueErrorValue,
  2879. &errorCode,
  2880. dumpData,
  2881. &dumpCount
  2882. );
  2883. if (!NT_SUCCESS(status)) {
  2884. goto I8xFindWheelMouseExit;
  2885. }
  2886. //
  2887. // Zero out the string that will ID the mouse
  2888. //
  2889. RtlZeroMemory(mouseID,
  2890. MOUSE_PNPID_LENGTH * sizeof(WCHAR)
  2891. );
  2892. currentChar = mouseID;
  2893. //
  2894. // We should start to see the PNP string come back our way
  2895. // (MOUSE_PNPID_LENGTH includes the NULL in its length)
  2896. //
  2897. for (idCount = 0; idCount < MOUSE_PNPID_LENGTH-1; idCount++) {
  2898. status = I8xGetBytePolledIterated(
  2899. (CCHAR) ControllerDeviceType,
  2900. &byte,
  2901. 5
  2902. );
  2903. //
  2904. // if the operation wasn't successful or the characters don't
  2905. // match, than try to flush the buffers
  2906. //
  2907. if (byte < ScanCodeToUCharCount) {
  2908. *currentChar = ScanCodeToUChar[byte];
  2909. if (*currentChar) {
  2910. currentChar++;
  2911. }
  2912. }
  2913. if (!NT_SUCCESS(status)) { // || byte != pnpID[idCount]) {
  2914. //
  2915. // Couldn't get a byte
  2916. //
  2917. do {
  2918. //
  2919. // Wait a little bit
  2920. //
  2921. KeStallExecutionProcessor( 50 );
  2922. //
  2923. // Get a byte if there is one
  2924. //
  2925. status = I8xGetBytePolled(
  2926. (CCHAR) ControllerDeviceType,
  2927. &byte
  2928. );
  2929. } while (status != STATUS_IO_TIMEOUT);
  2930. //
  2931. // We are done here
  2932. //
  2933. return STATUS_NO_SUCH_DEVICE;
  2934. } // if
  2935. } // for
  2936. Print(DBG_SS_INFO, ("found a pnp id of %ws\n", mouseID));
  2937. if (!I8xVerifyMousePnPID(MouseExtension, mouseID)) {
  2938. return STATUS_NO_SUCH_DEVICE;
  2939. }
  2940. }
  2941. else if (MouseExtension->EnableWheelDetection != 2) {
  2942. //
  2943. // We got a bogus id. Let's just assume that they meant to disable
  2944. // the little detection routine
  2945. //
  2946. Print(DBG_SS_INFO | DBG_SS_NOISE,
  2947. ("%s: Detection disabled in registry\n",
  2948. pFncFindWheelMouse
  2949. ));
  2950. //
  2951. // Done
  2952. //
  2953. return STATUS_NO_SUCH_DEVICE;
  2954. } // if
  2955. //
  2956. // Start the second detection routine, which will also enable the
  2957. // device if present
  2958. //
  2959. InitializeWheel:
  2960. status = I8xTransmitByteSequence(
  2961. enableCommands,
  2962. &uniqueErrorValue,
  2963. &errorCode,
  2964. dumpData,
  2965. &dumpCount
  2966. );
  2967. if (!NT_SUCCESS(status)) {
  2968. goto I8xFindWheelMouseExit;
  2969. }
  2970. //
  2971. // Get the mouse ID
  2972. //
  2973. status = I8xGetBytePolledIterated(
  2974. (CCHAR) ControllerDeviceType,
  2975. &byte,
  2976. 5
  2977. );
  2978. //
  2979. // Check to see what we got
  2980. //
  2981. if ((!NT_SUCCESS(status)) ||
  2982. ((byte != MOUSE_ID_BYTE) && (byte != WHEELMOUSE_ID_BYTE))) {
  2983. Print(DBG_SS_ERROR,
  2984. ("%s, failed ID, status 0x%x, byte 0x%x\n",
  2985. pFncFindWheelMouse,
  2986. status,
  2987. byte
  2988. ));
  2989. //
  2990. // Set up error log info
  2991. //
  2992. errorCode = I8042_MOU_RESET_RESPONSE_FAILED;
  2993. dumpData[0] = KBDMOU_INCORRECT_RESPONSE;
  2994. dumpData[1] = ControllerDeviceType;
  2995. dumpData[2] = MOUSE_ID_BYTE;
  2996. dumpData[3] = byte;
  2997. dumpCount = 4;
  2998. goto I8xFindWheelMouseExit;
  2999. }
  3000. else if (byte == WHEELMOUSE_ID_BYTE) {
  3001. //
  3002. // Update the HardwarePresent to show a Z mouse is operational,
  3003. // and set the appropriate mouse type flags
  3004. //
  3005. SET_HW_FLAGS(WHEELMOUSE_HARDWARE_PRESENT);
  3006. MouseExtension->MouseAttributes.MouseIdentifier =
  3007. WHEELMOUSE_I8042_HARDWARE;
  3008. status = I8xTransmitByteSequence(
  3009. enable5Commands,
  3010. &uniqueErrorValue,
  3011. &errorCode,
  3012. dumpData,
  3013. &dumpCount
  3014. );
  3015. if (NT_SUCCESS(status)) {
  3016. status = I8xGetBytePolledIterated(
  3017. (CCHAR) ControllerDeviceType,
  3018. &byte,
  3019. 5
  3020. );
  3021. if (NT_SUCCESS(status) && byte == FIVEBUTTON_ID_BYTE) {
  3022. //
  3023. // Update the HardwarePresent to show a Z mouse with 2 extra buttons is operational,
  3024. // and set the appropriate mouse type flags
  3025. //
  3026. SET_HW_FLAGS(FIVE_BUTTON_HARDWARE_PRESENT | WHEELMOUSE_HARDWARE_PRESENT);
  3027. MouseExtension->MouseAttributes.MouseIdentifier =
  3028. WHEELMOUSE_I8042_HARDWARE;
  3029. }
  3030. }
  3031. }
  3032. else {
  3033. SET_HW_FLAGS(MOUSE_HARDWARE_PRESENT);
  3034. Print(DBG_SS_INFO,
  3035. ("%s, Mouse attached - running in mouse mode.\n",
  3036. pFncFindWheelMouse
  3037. ));
  3038. }
  3039. I8xFindWheelMouseExit:
  3040. if (!NT_SUCCESS(status)) {
  3041. //
  3042. // The mouse initialization failed. Log an error.
  3043. //
  3044. if(errorCode != STATUS_SUCCESS) {
  3045. errorLogEntry = (PIO_ERROR_LOG_PACKET)
  3046. IoAllocateErrorLogEntry(
  3047. MouseExtension->Self,
  3048. (UCHAR) (sizeof(IO_ERROR_LOG_PACKET) +
  3049. (dumpCount * sizeof(ULONG)))
  3050. );
  3051. if(errorLogEntry != NULL) {
  3052. errorLogEntry->ErrorCode = errorCode;
  3053. errorLogEntry->DumpDataSize = (USHORT) dumpCount * sizeof(ULONG);
  3054. errorLogEntry->SequenceNumber = 0;
  3055. errorLogEntry->MajorFunctionCode = 0;
  3056. errorLogEntry->IoControlCode = 0;
  3057. errorLogEntry->RetryCount = 0;
  3058. errorLogEntry->UniqueErrorValue = uniqueErrorValue;
  3059. errorLogEntry->FinalStatus = status;
  3060. for(i = 0; i < dumpCount; i++) {
  3061. errorLogEntry->DumpData[i] = dumpData[i];
  3062. }
  3063. IoWriteErrorLogEntry(errorLogEntry);
  3064. }
  3065. }
  3066. }
  3067. Print(DBG_SS_TRACE, ("FindWheel mouse (0x%x)\n", status));
  3068. return status;
  3069. }
  3070. VOID
  3071. I8xFinishResetRequest(
  3072. PPORT_MOUSE_EXTENSION MouseExtension,
  3073. BOOLEAN Failed,
  3074. BOOLEAN RaiseIrql,
  3075. BOOLEAN CancelTimer
  3076. )
  3077. {
  3078. PIRP irp;
  3079. KIRQL oldIrql;
  3080. irp = (PIRP) InterlockedExchangePointer(&MouseExtension->ResetIrp,
  3081. NULL
  3082. );
  3083. if (CancelTimer) {
  3084. //
  3085. // We must cancel our watchdog timer so that it doesn't try to reset the
  3086. // mouse at a later time
  3087. //
  3088. KeCancelTimer(&MouseExtension->ResetMouse.Timer);
  3089. }
  3090. Print(DBG_IOCTL_INFO | DBG_SS_INFO,
  3091. ("Finished with mouse reset irp %p\n", irp));
  3092. //
  3093. // Raise to dispatch because KeInsertQueueDpc, IoFreeController, and
  3094. // IoStartNextPacket all require to be at this irql.
  3095. //
  3096. if (RaiseIrql) {
  3097. KeRaiseIrql(DISPATCH_LEVEL, &oldIrql);
  3098. }
  3099. //
  3100. // Let people know that the reset failed
  3101. //
  3102. if (Failed && Globals.ReportResetErrors) {
  3103. KeInsertQueueDpc(&MouseExtension->ErrorLogDpc,
  3104. (PIRP) NULL,
  3105. LongToPtr(I8042_MOU_RESET_RESPONSE_FAILED)
  3106. );
  3107. }
  3108. CLEAR_RECORD_STATE(MouseExtension);
  3109. //
  3110. // NOTE: To prevent the reset detection code from
  3111. // restarting us all over again (which don't want
  3112. // otherwise we would not be here, we need to fool
  3113. // the detection into thinking that the last character
  3114. // wasn't MOUSE_COMPLETE
  3115. //
  3116. MouseExtension->LastByteReceived = 0;
  3117. //
  3118. // Oops. Oh well, the mouse hasn't been able to reset
  3119. // in all these tries, so lets consider it dead.
  3120. //
  3121. // However, just in case the user yanks it out and
  3122. // plugs in a new one, we should reset our count
  3123. // back down to zero so that we will actually try to
  3124. // activate the thing when he plugs it back in there....but we don't do
  3125. // this here. If we see the reset sequence in the ISR, we will reset
  3126. // the counts there.
  3127. //
  3128. //MouseExtension->ResendCount = 0;
  3129. // I8X_MOUSE_INIT_COUNTERS(MouseExtension);
  3130. //
  3131. // Make sure the next packet is started, regardless if the reset IRP
  3132. // was present or not
  3133. //
  3134. IoFreeController(Globals.ControllerData->ControllerObject);
  3135. IoStartNextPacket(MouseExtension->Self, FALSE);
  3136. if (RaiseIrql) {
  3137. KeLowerIrql(oldIrql);
  3138. }
  3139. if (irp != NULL) {
  3140. IoFreeIrp(irp);
  3141. IoReleaseRemoveLock(&MouseExtension->RemoveLock, irp);
  3142. }
  3143. }
  3144. VOID
  3145. I8xResetMouseFailed(
  3146. PPORT_MOUSE_EXTENSION MouseExtension
  3147. )
  3148. /*++
  3149. Routine Description:
  3150. The resetting of the mouse failed after repeated tries to get it working.
  3151. Free the irp and start the next packet in our start io reoutine.
  3152. Arguments:
  3153. MouseExtension - Mouse extension
  3154. Return Value:
  3155. None.
  3156. --*/
  3157. {
  3158. PIRP irp;
  3159. KIRQL oldIrql;
  3160. Print(DBG_SS_ERROR | DBG_SS_INFO, ("mouse reset failed\n"));
  3161. //
  3162. // Mark the failed reset in the device extension
  3163. //
  3164. MouseExtension->ResetMouse.IsrResetState = MouseResetFailed;
  3165. I8xFinishResetRequest(MouseExtension, TRUE, TRUE, TRUE);
  3166. }
  3167. NTSTATUS
  3168. I8xResetMouse(
  3169. PPORT_MOUSE_EXTENSION MouseExtension
  3170. )
  3171. /*++
  3172. Routine Description:
  3173. Sends the reset command to the mouse (through the start i/o routine if it
  3174. doesn't exist yet) if we haven't reached our reset limit. Otherwise, gives
  3175. up and calls I8xResetMouseFailed.
  3176. Arguments:
  3177. MouseExtension - Mouse extension
  3178. Return Value:
  3179. STATUS_SUCCESS if successful
  3180. --*/
  3181. {
  3182. PDEVICE_OBJECT self;
  3183. PIO_STACK_LOCATION stack;
  3184. PIRP pResetIrp, pIrp;
  3185. NTSTATUS status;
  3186. Print(DBG_SS_NOISE, ("reset count = %d\n", (LONG) MouseExtension->ResetCount));
  3187. self = MouseExtension->Self;
  3188. status = STATUS_SUCCESS;
  3189. MouseExtension->ResetCount++;
  3190. MouseExtension->FailedCompleteResetCount++;
  3191. if (MouseExtension->ResetCount >= MOUSE_RESETS_MAX ||
  3192. MouseExtension->FailedCompleteResetCount >= MOUSE_RESETS_MAX) {
  3193. Print(DBG_SS_ERROR, ("Resetting mouse failed!\n"));
  3194. I8xResetMouseFailed(MouseExtension);
  3195. return STATUS_DEVICE_NOT_CONNECTED;
  3196. }
  3197. #if 0
  3198. if (MouseExtension->LastByteReceived == 0xFC &&
  3199. MouseExtension->InputState == MouseResetting) {
  3200. I8xDrainOutputBuffer(
  3201. Globals.ControllerData->DeviceRegisters[DataPort],
  3202. Globals.ControllerData->DeviceRegisters[CommandPort]
  3203. );
  3204. }
  3205. #endif
  3206. //
  3207. // Insert a "fake" request into the StartIO queue for the reset. This way,
  3208. // the reset of the mouse can be serialized with all of the other kb IOCTLS
  3209. // that come down during start or return from a low power state
  3210. //
  3211. pResetIrp = IoAllocateIrp(self->StackSize, FALSE);
  3212. if (pResetIrp == NULL) {
  3213. return STATUS_INSUFFICIENT_RESOURCES;
  3214. }
  3215. pIrp = (PIRP) InterlockedCompareExchangePointer(&MouseExtension->ResetIrp,
  3216. pResetIrp,
  3217. NULL);
  3218. //
  3219. // Check to see if we had a pending reset request. If there was,
  3220. // pIrp != NULL and we should just write the reset to the device now.
  3221. //
  3222. if (pIrp == NULL) {
  3223. stack = IoGetNextIrpStackLocation(pResetIrp);
  3224. stack->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
  3225. stack->Parameters.DeviceIoControl.IoControlCode = IOCTL_INTERNAL_MOUSE_RESET;
  3226. IoSetNextIrpStackLocation(pResetIrp);
  3227. status = IoAcquireRemoveLock(&MouseExtension->RemoveLock, pResetIrp);
  3228. if (NT_SUCCESS(status)) {
  3229. Print(DBG_SS_INFO, ("IoStarting reset irp %p\n", pResetIrp));
  3230. IoStartPacket(self, pResetIrp, (PULONG) NULL, NULL);
  3231. }
  3232. else {
  3233. pIrp = (PIRP) InterlockedExchangePointer(&MouseExtension->ResetIrp,
  3234. NULL);
  3235. Print(DBG_SS_INFO, ("Failed acquire on reset irp %p\n", pIrp));
  3236. if (pIrp != NULL) {
  3237. ASSERT(pIrp == pResetIrp);
  3238. IoFreeIrp(pIrp);
  3239. pIrp = NULL;
  3240. }
  3241. }
  3242. }
  3243. else {
  3244. //
  3245. // Free the irp we just allocated
  3246. //
  3247. IoFreeIrp(pResetIrp);
  3248. pResetIrp = NULL;
  3249. //
  3250. // The Reset Irp exists, just send another reset
  3251. //
  3252. I8xSendResetCommand(MouseExtension);
  3253. }
  3254. return status;
  3255. }
  3256. VOID
  3257. I8xSendResetCommand (
  3258. PPORT_MOUSE_EXTENSION MouseExtension
  3259. )
  3260. /*++
  3261. Routine Description:
  3262. Writes the actual reset to the mouse and kicks off the watch dog timer.
  3263. Arguments:
  3264. MouseExtension - Mouse extension
  3265. Return Value:
  3266. None.
  3267. --*/
  3268. {
  3269. LARGE_INTEGER li = RtlConvertLongToLargeInteger(-MOUSE_RESET_TIMEOUT);
  3270. MouseExtension->ResetMouse.IsrResetState = IsrResetNormal;
  3271. //
  3272. // Delay for 1 second
  3273. //
  3274. KeSetTimer(&MouseExtension->ResetMouse.Timer,
  3275. li,
  3276. &MouseExtension->ResetMouse.Dpc
  3277. );
  3278. MouseExtension->PreviousSignAndOverflow = 0;
  3279. MouseExtension->InputState = MouseResetting;
  3280. MouseExtension->InputResetSubState = ExpectingReset;
  3281. MouseExtension->LastByteReceived = 0;
  3282. //
  3283. // The watch dog timer bases its time computations on this value, set it to
  3284. // now so that all the times computed are relative to the last time we sent
  3285. // a reset and not x seconds ago when we last received an interrupt from the
  3286. // mouse
  3287. //
  3288. KeQueryTickCount(&MouseExtension->PreviousTick);
  3289. I8xPutBytePolled((CCHAR) DataPort,
  3290. NO_WAIT_FOR_ACKNOWLEDGE,
  3291. (CCHAR) MouseDeviceType,
  3292. (UCHAR) MOUSE_RESET
  3293. );
  3294. }
  3295. VOID
  3296. I8xQueueCurrentMouseInput(
  3297. IN PDEVICE_OBJECT DeviceObject
  3298. )
  3299. /*++
  3300. Routine Description:
  3301. This routine queues the current input data to be processed by a
  3302. DPC outside the ISR
  3303. Arguments:
  3304. DeviceObject - Pointer to the device object
  3305. Return Value:
  3306. None
  3307. --*/
  3308. {
  3309. PPORT_MOUSE_EXTENSION deviceExtension;
  3310. UCHAR buttonsDelta;
  3311. UCHAR previousButtons;
  3312. deviceExtension = (PPORT_MOUSE_EXTENSION) DeviceObject->DeviceExtension;
  3313. //
  3314. // If the mouse is enabled, add the data to the InputData queue
  3315. // and queue the ISR DPC. One might wonder why we bother to
  3316. // do all this processing of the mouse packet, only to toss it
  3317. // away (i.e., not queue it) at this point. The answer is that
  3318. // this mouse provides no data to allow the driver to determine
  3319. // when the first byte of a packet is received -- if the driver
  3320. // doesn't process all interrupts from the start, there is no
  3321. // way to keep MouseExtension.InputState in synch with hardware
  3322. // reality.
  3323. //
  3324. if (deviceExtension->EnableCount) {
  3325. if (!I8xWriteDataToMouseQueue(
  3326. deviceExtension,
  3327. &deviceExtension->CurrentInput
  3328. )) {
  3329. //
  3330. // InputData queue overflowed.
  3331. //
  3332. // Queue a DPC to log an overrun error.
  3333. //
  3334. IsrPrint(DBG_MOUISR_ERROR,
  3335. ("I8042MouseInterruptService: queue overflow\n"
  3336. ));
  3337. if (deviceExtension->OkayToLogOverflow) {
  3338. KeInsertQueueDpc(
  3339. &deviceExtension->ErrorLogDpc,
  3340. (PIRP) NULL,
  3341. LongToPtr(I8042_MOU_BUFFER_OVERFLOW)
  3342. );
  3343. deviceExtension->OkayToLogOverflow =
  3344. FALSE;
  3345. }
  3346. } else if (deviceExtension->DpcInterlockMouse >= 0) {
  3347. //
  3348. // The ISR DPC is already executing. Tell the ISR DPC it has
  3349. // more work to do by incrementing DpcInterlockMouse.
  3350. //
  3351. deviceExtension->DpcInterlockMouse += 1;
  3352. } else {
  3353. //
  3354. // Queue the ISR DPC.
  3355. //
  3356. KeInsertQueueDpc(
  3357. &deviceExtension->MouseIsrDpc,
  3358. (PIRP) NULL, // DeviceObject->CurrentIrp,
  3359. NULL
  3360. );
  3361. }
  3362. }
  3363. return;
  3364. }
  3365. VOID
  3366. MouseCopyWheelIDs(
  3367. OUT PUNICODE_STRING Destination,
  3368. IN PUNICODE_STRING Source
  3369. )
  3370. /*++
  3371. Routine Description:
  3372. Copies the multisz specified in Source into Destinatio along with the default
  3373. IDs already known. Destination is in non paged pool while Source is paged.
  3374. Argument:
  3375. Destination - Will receive new copied string
  3376. Source - String read from the registry
  3377. Return Value:
  3378. None.
  3379. --*/
  3380. {
  3381. PWSTR str = NULL;
  3382. ULONG length;
  3383. PAGED_CODE();
  3384. ASSERT(Destination->Buffer == NULL);
  3385. RtlZeroMemory(Destination, sizeof(*Destination));
  3386. //
  3387. // Check to see the Source string is not just an empty multi SZ
  3388. //
  3389. if (Source->MaximumLength > (sizeof(L'\0') * 2)) {
  3390. Destination->Buffer = (WCHAR*)
  3391. ExAllocatePool(NonPagedPool, Source->MaximumLength * sizeof(WCHAR));
  3392. if (Destination->Buffer != NULL) {
  3393. RtlCopyMemory(Destination->Buffer,
  3394. Source->Buffer,
  3395. Source->MaximumLength * sizeof(WCHAR));
  3396. Destination->Length = Destination->MaximumLength =
  3397. Source->MaximumLength;
  3398. //
  3399. // Make sure each string is in upper case
  3400. //
  3401. str = Destination->Buffer;
  3402. while (*str != L'\0') {
  3403. Print(DBG_SS_NOISE, ("wheel id: %ws\n", str));
  3404. _wcsupr(str);
  3405. str += wcslen(str) + 1;
  3406. }
  3407. }
  3408. }
  3409. }
  3410. VOID
  3411. I8xMouseServiceParameters(
  3412. IN PUNICODE_STRING RegistryPath,
  3413. IN PPORT_MOUSE_EXTENSION MouseExtension
  3414. )
  3415. /*++
  3416. Routine Description:
  3417. This routine retrieves this driver's service parameters information
  3418. from the registry. Overrides these values if they are present in the
  3419. devnode.
  3420. Arguments:
  3421. RegistryPath - Pointer to the null-terminated Unicode name of the
  3422. registry path for this driver.
  3423. MouseExtension - Mouse extension
  3424. Return Value:
  3425. None.
  3426. --*/
  3427. {
  3428. NTSTATUS status = STATUS_SUCCESS;
  3429. PRTL_QUERY_REGISTRY_TABLE parameters = NULL;
  3430. HANDLE keyHandle;
  3431. UNICODE_STRING parametersPath;
  3432. PWSTR path = NULL;
  3433. ULONG defaultDataQueueSize = DATA_QUEUE_SIZE,
  3434. defaultSynchPacket100ns = MOUSE_SYNCH_PACKET_100NS,
  3435. defaultEnableWheelDetection = 1,
  3436. defaultMouseResolution = MOUSE_RESOLUTION,
  3437. defaultNumberOfButtons = 0,
  3438. defaultSampleRate = MOUSE_SAMPLE_RATE,
  3439. defaultWheelDetectionTimeout = WHEEL_DETECTION_TIMEOUT,
  3440. defaultInitializePolled = I8X_INIT_POLLED_DEFAULT,
  3441. enableWheelDetection = 1,
  3442. mouseResolution = MOUSE_RESOLUTION,
  3443. numberOfButtons = MOUSE_NUMBER_OF_BUTTONS,
  3444. sampleRate = MOUSE_SAMPLE_RATE,
  3445. initializePolled = I8X_INIT_POLLED_DEFAULT,
  3446. i = 0;
  3447. ULONG defaultStallTime = 1000;
  3448. LARGE_INTEGER largeDetectionTimeout;
  3449. USHORT queries = 10;
  3450. WCHAR szDefaultIDs[] = { L"\0" };
  3451. UNICODE_STRING IDs;
  3452. #if MOUSE_RECORD_ISR
  3453. ULONG defaultHistoryLength = 100,
  3454. defaultRecordHistoryFlags = 0x0;
  3455. queries += 2;
  3456. #endif
  3457. PAGED_CODE();
  3458. parametersPath.Buffer = NULL;
  3459. //
  3460. // Registry path is already null-terminated, so just use it.
  3461. //
  3462. path = RegistryPath->Buffer;
  3463. if (NT_SUCCESS(status)) {
  3464. //
  3465. // Allocate the Rtl query table.
  3466. //
  3467. parameters = ExAllocatePool(
  3468. PagedPool,
  3469. sizeof(RTL_QUERY_REGISTRY_TABLE) * (queries + 1)
  3470. );
  3471. if (!parameters) {
  3472. Print(DBG_SS_ERROR,
  3473. ("%s: couldn't allocate table for Rtl query to %ws for %ws\n",
  3474. pFncServiceParameters,
  3475. pwParameters,
  3476. path
  3477. ));
  3478. status = STATUS_UNSUCCESSFUL;
  3479. } else {
  3480. RtlZeroMemory(
  3481. parameters,
  3482. sizeof(RTL_QUERY_REGISTRY_TABLE) * (queries + 1)
  3483. );
  3484. //
  3485. // Form a path to this driver's Parameters subkey.
  3486. //
  3487. RtlInitUnicodeString( &parametersPath, NULL );
  3488. parametersPath.MaximumLength = RegistryPath->Length +
  3489. (wcslen(pwParameters) * sizeof(WCHAR) ) + sizeof(UNICODE_NULL);
  3490. parametersPath.Buffer = ExAllocatePool(
  3491. PagedPool,
  3492. parametersPath.MaximumLength
  3493. );
  3494. if (!parametersPath.Buffer) {
  3495. Print(DBG_SS_ERROR,
  3496. ("%s: Couldn't allocate string for path to %ws for %ws\n",
  3497. pFncServiceParameters,
  3498. pwParameters,
  3499. path
  3500. ));
  3501. status = STATUS_UNSUCCESSFUL;
  3502. }
  3503. }
  3504. }
  3505. if (NT_SUCCESS(status)) {
  3506. //
  3507. // Form the parameters path.
  3508. //
  3509. RtlZeroMemory(
  3510. parametersPath.Buffer,
  3511. parametersPath.MaximumLength
  3512. );
  3513. RtlAppendUnicodeToString(
  3514. &parametersPath,
  3515. path
  3516. );
  3517. RtlAppendUnicodeToString(
  3518. &parametersPath,
  3519. pwParameters
  3520. );
  3521. //
  3522. // Gather all of the "user specified" information from
  3523. // the registry.
  3524. //
  3525. parameters[i].Flags = RTL_QUERY_REGISTRY_DIRECT;
  3526. parameters[i].Name = pwMouseDataQueueSize;
  3527. parameters[i].EntryContext =
  3528. &MouseExtension->MouseAttributes.InputDataQueueLength;
  3529. parameters[i].DefaultType = REG_DWORD;
  3530. parameters[i].DefaultData = &defaultDataQueueSize;
  3531. parameters[i].DefaultLength = sizeof(ULONG);
  3532. parameters[++i].Flags = RTL_QUERY_REGISTRY_DIRECT;
  3533. parameters[i].Name = pwNumberOfButtons;
  3534. parameters[i].EntryContext = &numberOfButtons;
  3535. parameters[i].DefaultType = REG_DWORD;
  3536. parameters[i].DefaultData = &defaultNumberOfButtons;
  3537. parameters[i].DefaultLength = sizeof(ULONG);
  3538. parameters[++i].Flags = RTL_QUERY_REGISTRY_DIRECT;
  3539. parameters[i].Name = pwSampleRate;
  3540. parameters[i].EntryContext = &sampleRate;
  3541. parameters[i].DefaultType = REG_DWORD;
  3542. parameters[i].DefaultData = &defaultSampleRate;
  3543. parameters[i].DefaultLength = sizeof(ULONG);
  3544. parameters[++i].Flags = RTL_QUERY_REGISTRY_DIRECT;
  3545. parameters[i].Name = pwMouseResolution;
  3546. parameters[i].EntryContext = &mouseResolution;
  3547. parameters[i].DefaultType = REG_DWORD;
  3548. parameters[i].DefaultData = &defaultMouseResolution;
  3549. parameters[i].DefaultLength = sizeof(ULONG);
  3550. parameters[++i].Flags = RTL_QUERY_REGISTRY_DIRECT;
  3551. parameters[i].Name = pwMouseSynchIn100ns;
  3552. parameters[i].EntryContext = &MouseExtension->SynchTickCount;
  3553. parameters[i].DefaultType = REG_DWORD;
  3554. parameters[i].DefaultData = &defaultSynchPacket100ns;
  3555. parameters[i].DefaultLength = sizeof(ULONG);
  3556. parameters[++i].Flags = RTL_QUERY_REGISTRY_DIRECT;
  3557. parameters[i].Name = pwEnableWheelDetection;
  3558. parameters[i].EntryContext = &enableWheelDetection;
  3559. parameters[i].DefaultType = REG_DWORD;
  3560. parameters[i].DefaultData = &defaultEnableWheelDetection;
  3561. parameters[i].DefaultLength = sizeof(ULONG);
  3562. parameters[++i].Flags = RTL_QUERY_REGISTRY_DIRECT;
  3563. parameters[i].Name = L"MouseInitializePolled";
  3564. parameters[i].EntryContext = &initializePolled;
  3565. parameters[i].DefaultType = REG_DWORD;
  3566. parameters[i].DefaultData = &defaultInitializePolled;
  3567. parameters[i].DefaultLength = sizeof(ULONG);
  3568. parameters[++i].Flags = RTL_QUERY_REGISTRY_DIRECT;
  3569. parameters[i].Name = L"MouseResendStallTime";
  3570. parameters[i].EntryContext = &MouseExtension->MouseResetStallTime;
  3571. parameters[i].DefaultType = REG_DWORD;
  3572. parameters[i].DefaultData = &defaultStallTime;
  3573. parameters[i].DefaultLength = sizeof(ULONG);
  3574. #if MOUSE_RECORD_ISR
  3575. parameters[++i].Flags = RTL_QUERY_REGISTRY_DIRECT;
  3576. parameters[i].Name = L"RecordMouseIsrFlags";
  3577. parameters[i].EntryContext = &MouseExtension->RecordHistoryFlags;
  3578. parameters[i].DefaultType = REG_DWORD;
  3579. parameters[i].DefaultData = &defaultRecordHistoryFlags;
  3580. parameters[i].DefaultLength = sizeof(ULONG);
  3581. parameters[++i].Flags = RTL_QUERY_REGISTRY_DIRECT;
  3582. parameters[i].Name = L"RecordMouseIsrLength";
  3583. parameters[i].EntryContext = &MouseExtension->RecordHistoryCount;
  3584. parameters[i].DefaultType = REG_DWORD;
  3585. parameters[i].DefaultData = &defaultHistoryLength;
  3586. parameters[i].DefaultLength = sizeof(ULONG);
  3587. #endif
  3588. status = RtlQueryRegistryValues(
  3589. RTL_REGISTRY_ABSOLUTE | RTL_REGISTRY_OPTIONAL,
  3590. parametersPath.Buffer,
  3591. parameters,
  3592. NULL,
  3593. NULL
  3594. );
  3595. if (!NT_SUCCESS(status)) {
  3596. Print(DBG_SS_INFO,
  3597. ("mou RtlQueryRegistryValues failed (0x%x)\n",
  3598. status
  3599. ));
  3600. }
  3601. }
  3602. if (!NT_SUCCESS(status)) {
  3603. //
  3604. // Go ahead and assign driver defaults.
  3605. //
  3606. MouseExtension->MouseAttributes.InputDataQueueLength =
  3607. defaultDataQueueSize;
  3608. MouseExtension->EnableWheelDetection = (UCHAR)
  3609. defaultEnableWheelDetection;
  3610. MouseExtension->SynchTickCount = defaultSynchPacket100ns;
  3611. }
  3612. Print(DBG_SS_NOISE,
  3613. ("results from services key:\n"
  3614. "\tmouse queue length = %d\n"
  3615. "\tnumber of buttons = %d\n"
  3616. "\tsample rate = %d\n"
  3617. "\tresolution = %d\n"
  3618. "\tsynch tick count = %d\n"
  3619. "\twheel detection = %d\n"
  3620. "\tdetection timeout = %d\n"
  3621. "\tintiailize polled = %d\n"
  3622. "\treset stall time = %d\n",
  3623. MouseExtension->MouseAttributes.InputDataQueueLength,
  3624. numberOfButtons,
  3625. sampleRate,
  3626. mouseResolution,
  3627. MouseExtension->SynchTickCount,
  3628. enableWheelDetection,
  3629. MouseExtension->WheelDetectionTimeout,
  3630. initializePolled,
  3631. MouseExtension->MouseResetStallTime
  3632. ));
  3633. status = IoOpenDeviceRegistryKey(MouseExtension->PDO,
  3634. PLUGPLAY_REGKEY_DEVICE,
  3635. STANDARD_RIGHTS_READ,
  3636. &keyHandle
  3637. );
  3638. if (NT_SUCCESS(status)) {
  3639. ULONG prevInputDataQueueLength,
  3640. prevNumberOfButtons,
  3641. prevSampleRate,
  3642. prevMouseResolution,
  3643. prevSynchPacket100ns,
  3644. prevEnableWheelDetection,
  3645. prevWheelDetectionTimeout,
  3646. prevInitializePolled;
  3647. RtlInitUnicodeString(&IDs,
  3648. NULL);
  3649. //
  3650. // If the value is not present in devnode, then the default is the value
  3651. // read in from the Services\i8042prt\Parameters key
  3652. //
  3653. prevInputDataQueueLength =
  3654. MouseExtension->MouseAttributes.InputDataQueueLength;
  3655. prevNumberOfButtons = numberOfButtons;
  3656. prevSampleRate = sampleRate;
  3657. prevMouseResolution = mouseResolution;
  3658. prevSynchPacket100ns = MouseExtension->SynchTickCount;
  3659. prevEnableWheelDetection = enableWheelDetection;
  3660. prevWheelDetectionTimeout = MouseExtension->WheelDetectionTimeout;
  3661. prevInitializePolled = initializePolled;
  3662. i = 0;
  3663. //
  3664. // Gather all of the "user specified" information from
  3665. // the registry (this time from the devnode)
  3666. //
  3667. parameters[i].Flags = RTL_QUERY_REGISTRY_DIRECT;
  3668. parameters[i].Name = pwMouseDataQueueSize;
  3669. parameters[i].EntryContext =
  3670. &MouseExtension->MouseAttributes.InputDataQueueLength;
  3671. parameters[i].DefaultType = REG_DWORD;
  3672. parameters[i].DefaultData = &prevInputDataQueueLength;
  3673. parameters[i].DefaultLength = sizeof(ULONG);
  3674. parameters[++i].Flags = RTL_QUERY_REGISTRY_DIRECT;
  3675. parameters[i].Name = pwNumberOfButtons;
  3676. parameters[i].EntryContext = &numberOfButtons;
  3677. parameters[i].DefaultType = REG_DWORD;
  3678. parameters[i].DefaultData = &prevNumberOfButtons;
  3679. parameters[i].DefaultLength = sizeof(ULONG);
  3680. parameters[++i].Flags = RTL_QUERY_REGISTRY_DIRECT;
  3681. parameters[i].Name = pwSampleRate;
  3682. parameters[i].EntryContext = &sampleRate;
  3683. parameters[i].DefaultType = REG_DWORD;
  3684. parameters[i].DefaultData = &prevSampleRate;
  3685. parameters[i].DefaultLength = sizeof(ULONG);
  3686. parameters[++i].Flags = RTL_QUERY_REGISTRY_DIRECT;
  3687. parameters[i].Name = pwMouseResolution;
  3688. parameters[i].EntryContext = &mouseResolution;
  3689. parameters[i].DefaultType = REG_DWORD;
  3690. parameters[i].DefaultData = &prevMouseResolution;
  3691. parameters[i].DefaultLength = sizeof(ULONG);
  3692. parameters[++i].Flags = RTL_QUERY_REGISTRY_DIRECT;
  3693. parameters[i].Name = pwMouseSynchIn100ns;
  3694. parameters[i].EntryContext = &MouseExtension->SynchTickCount;
  3695. parameters[i].DefaultType = REG_DWORD;
  3696. parameters[i].DefaultData = &prevSynchPacket100ns;
  3697. parameters[i].DefaultLength = sizeof(ULONG);
  3698. parameters[++i].Flags = RTL_QUERY_REGISTRY_DIRECT;
  3699. parameters[i].Name = pwEnableWheelDetection;
  3700. parameters[i].EntryContext = &enableWheelDetection;
  3701. parameters[i].DefaultType = REG_DWORD;
  3702. parameters[i].DefaultData = &prevEnableWheelDetection;
  3703. parameters[i].DefaultLength = sizeof(ULONG);
  3704. parameters[++i].Flags = RTL_QUERY_REGISTRY_DIRECT;
  3705. parameters[i].Name = L"MouseInitializePolled";
  3706. parameters[i].EntryContext = &initializePolled;
  3707. parameters[i].DefaultType = REG_DWORD;
  3708. parameters[i].DefaultData = &prevInitializePolled;
  3709. parameters[i].DefaultLength = sizeof(ULONG);
  3710. parameters[++i].Flags = RTL_QUERY_REGISTRY_DIRECT | RTL_QUERY_REGISTRY_NOEXPAND;
  3711. parameters[i].Name = L"WheelDetectIDs";
  3712. parameters[i].EntryContext = &IDs;
  3713. parameters[i].DefaultType = REG_MULTI_SZ;
  3714. parameters[i].DefaultData = szDefaultIDs;
  3715. parameters[i].DefaultLength = sizeof(szDefaultIDs);
  3716. parameters[++i].Flags = RTL_QUERY_REGISTRY_DIRECT;
  3717. parameters[i].Name = L"WheelDetectionTimeout";
  3718. parameters[i].EntryContext = &MouseExtension->WheelDetectionTimeout;
  3719. parameters[i].DefaultType = REG_DWORD;
  3720. parameters[i].DefaultData = &defaultWheelDetectionTimeout;
  3721. parameters[i].DefaultLength = sizeof(ULONG);
  3722. status = RtlQueryRegistryValues(
  3723. RTL_REGISTRY_HANDLE,
  3724. (PWSTR) keyHandle,
  3725. parameters,
  3726. NULL,
  3727. NULL
  3728. );
  3729. if (NT_SUCCESS(status)) {
  3730. Print(DBG_SS_NOISE,
  3731. ("results from devnode key:\n"
  3732. "\tmouse queue length = %d\n"
  3733. "\tnumber of buttons = %d\n"
  3734. "\tsample rate = %d\n"
  3735. "\tresolution = %d\n"
  3736. "\tsynch tick count = %d\n"
  3737. "\twheel detection = %d\n"
  3738. "\tinitialize polled = %d\n"
  3739. "\tdetection timeout = %d\n",
  3740. MouseExtension->MouseAttributes.InputDataQueueLength,
  3741. numberOfButtons,
  3742. sampleRate,
  3743. mouseResolution,
  3744. MouseExtension->SynchTickCount,
  3745. enableWheelDetection,
  3746. initializePolled,
  3747. MouseExtension->WheelDetectionTimeout
  3748. ));
  3749. }
  3750. else {
  3751. Print(DBG_SS_INFO | DBG_SS_ERROR,
  3752. ("mou RtlQueryRegistryValues (via handle) failed with (0x%x)\n",
  3753. status
  3754. ));
  3755. }
  3756. ZwClose(keyHandle);
  3757. }
  3758. else {
  3759. Print(DBG_SS_INFO | DBG_SS_ERROR,
  3760. ("mou, opening devnode handle failed (0x%x)\n",
  3761. status
  3762. ));
  3763. }
  3764. //
  3765. // Needs to be in NonPagedPool so it can be access during the ISR
  3766. //
  3767. MouseCopyWheelIDs(&MouseExtension->WheelDetectionIDs,
  3768. &IDs);
  3769. RtlFreeUnicodeString(&IDs);
  3770. Print(DBG_SS_NOISE, ("I8xMouseServiceParameters results..\n"));
  3771. if (MouseExtension->MouseAttributes.InputDataQueueLength == 0) {
  3772. Print(DBG_SS_INFO | DBG_SS_ERROR,
  3773. ("\toverriding %ws = 0x%x\n",
  3774. pwMouseDataQueueSize,
  3775. MouseExtension->MouseAttributes.InputDataQueueLength
  3776. ));
  3777. MouseExtension->MouseAttributes.InputDataQueueLength =
  3778. defaultDataQueueSize;
  3779. }
  3780. MouseExtension->MouseAttributes.InputDataQueueLength *=
  3781. sizeof(MOUSE_INPUT_DATA);
  3782. MouseExtension->InitializePolled = (UCHAR) initializePolled;
  3783. switch (enableWheelDetection) {
  3784. case 2:
  3785. case 1:
  3786. MouseExtension->EnableWheelDetection = (UCHAR) enableWheelDetection;
  3787. break;
  3788. default:
  3789. MouseExtension->EnableWheelDetection = 0;
  3790. }
  3791. Print(DBG_SS_NOISE,
  3792. (pDumpHex,
  3793. pwEnableWheelDetection,
  3794. MouseExtension->EnableWheelDetection
  3795. ));
  3796. Print(DBG_SS_NOISE,
  3797. (pDumpHex,
  3798. pwMouseDataQueueSize,
  3799. MouseExtension->MouseAttributes.InputDataQueueLength
  3800. ));
  3801. if (numberOfButtons == 0) {
  3802. MouseExtension->NumberOfButtonsOverride = 0;
  3803. MouseExtension->MouseAttributes.NumberOfButtons = MOUSE_NUMBER_OF_BUTTONS;
  3804. }
  3805. else {
  3806. MouseExtension->NumberOfButtonsOverride = (UCHAR) numberOfButtons;
  3807. MouseExtension->MouseAttributes.NumberOfButtons = (USHORT) numberOfButtons;
  3808. }
  3809. Print(DBG_SS_NOISE,
  3810. (pDumpDecimal,
  3811. pwNumberOfButtons,
  3812. MouseExtension->MouseAttributes.NumberOfButtons
  3813. ));
  3814. MouseExtension->MouseAttributes.SampleRate = (USHORT) sampleRate;
  3815. Print(DBG_SS_NOISE,
  3816. (pDumpDecimal,
  3817. pwSampleRate,
  3818. MouseExtension->MouseAttributes.SampleRate
  3819. ));
  3820. MouseExtension->Resolution = (UCHAR) mouseResolution;
  3821. Print(DBG_SS_NOISE,
  3822. (pDumpDecimal,
  3823. pwMouseResolution,
  3824. mouseResolution
  3825. ));
  3826. Print(DBG_SS_NOISE,
  3827. (pDumpDecimal,
  3828. L"MouseResetStallTime",
  3829. MouseExtension->MouseResetStallTime
  3830. ));
  3831. if (MouseExtension->WheelDetectionTimeout > 4000) {
  3832. MouseExtension->WheelDetectionTimeout = WHEEL_DETECTION_TIMEOUT;
  3833. }
  3834. //
  3835. // Convert ms to 100 ns units
  3836. // 1000 => ms to us
  3837. // 10 => us to 100 ns
  3838. //
  3839. largeDetectionTimeout.QuadPart = MouseExtension->WheelDetectionTimeout *
  3840. 1000 * 10;
  3841. largeDetectionTimeout.QuadPart /= KeQueryTimeIncrement();
  3842. MouseExtension->WheelDetectionTimeout = largeDetectionTimeout.LowPart;
  3843. Print(DBG_SS_NOISE,
  3844. (pDumpDecimal,
  3845. L"WheelDetectionTimeout",
  3846. MouseExtension->WheelDetectionTimeout
  3847. ));
  3848. if (MouseExtension->SynchTickCount == 0) {
  3849. Print(DBG_SS_ERROR | DBG_SS_INFO,
  3850. ("\toverriding %ws\n",
  3851. pwMouseSynchIn100ns
  3852. ));
  3853. MouseExtension->SynchTickCount = defaultSynchPacket100ns;
  3854. }
  3855. //
  3856. // Convert SynchTickCount to be the number of interval timer
  3857. // interrupts that occur during the time specified by MouseSynchIn100ns.
  3858. // Note that KeQueryTimeIncrement returns the number of 100ns units that
  3859. // are added to the system time each time the interval clock interrupts.
  3860. //
  3861. MouseExtension->SynchTickCount /= KeQueryTimeIncrement();
  3862. Print(DBG_SS_NOISE,
  3863. (pDumpHex,
  3864. pwMouseSynchIn100ns,
  3865. MouseExtension->SynchTickCount
  3866. ));
  3867. //
  3868. // Free the allocated memory before returning.
  3869. //
  3870. if (parametersPath.Buffer)
  3871. ExFreePool(parametersPath.Buffer);
  3872. if (parameters)
  3873. ExFreePool(parameters);
  3874. }