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.

688 lines
14 KiB

  1. /*++
  2. Copyright (c) 1993 Microsoft Corporation
  3. Copyright (c) 1993 Logitech Inc.
  4. Module Name:
  5. cseries.c
  6. Abstract:
  7. Environment:
  8. Kernel mode only.
  9. Notes:
  10. Revision History:
  11. --*/
  12. //
  13. // Includes.
  14. //
  15. #include "ntddk.h"
  16. #include "sermouse.h"
  17. #include "cseries.h"
  18. #include "debug.h"
  19. //
  20. // Use the alloc_text pragma to specify the driver initialization routines
  21. // (they can be paged out).
  22. //
  23. #ifdef ALLOC_PRAGMA
  24. #pragma alloc_text(INIT,CSerPowerUp)
  25. #pragma alloc_text(INIT,CSerSetReportRate)
  26. #pragma alloc_text(INIT,CSerSetBaudRate)
  27. #pragma alloc_text(INIT,CSerSetProtocol)
  28. #pragma alloc_text(INIT,CSerDetect)
  29. #endif // ALLOC_PRAGMA
  30. //
  31. // Constants.
  32. //
  33. //
  34. // The status command sent to the mouse.
  35. //
  36. #define CSER_STATUS_COMMAND 's'
  37. //
  38. // The query number of mouse buttons command sent to the mouse.
  39. //
  40. #define CSER_QUERY_BUTTONS_COMMAND 'k'
  41. //
  42. // Status report from a CSeries mouse.
  43. //
  44. #define CSER_STATUS 0x4F
  45. //
  46. // Timeout value for the status returned by a CSeries mouse.
  47. //
  48. #define CSER_STATUS_DELAY 50
  49. //
  50. // Time (in milliseconds) needed by the mouse to adapt to a new baud rate.
  51. //
  52. #define CSER_BAUDRATE_DELAY 2
  53. //
  54. // Default baud rate and report rate.
  55. //
  56. #define CSER_DEFAULT_BAUDRATE 1200
  57. #define CSER_DEFAULT_REPORTRATE 150
  58. //
  59. // Button/status definitions.
  60. //
  61. #define CSER_SYNCH_BIT 0x80
  62. #define CSER_BUTTON_LEFT 0x04
  63. #define CSER_BUTTON_RIGHT 0x01
  64. #define CSER_BUTTON_MIDDLE 0x02
  65. #define CSER_BUTTON_LEFT_SR 2
  66. #define CSER_BUTTON_RIGHT_SL 1
  67. #define CSER_BUTTON_MIDDLE_SL 1
  68. #define SIGN_X 0x10
  69. #define SIGN_Y 0x08
  70. //
  71. // Macros.
  72. //
  73. #define sizeofel(x) (sizeof(x)/sizeof(*x))
  74. //
  75. // Type definitions.
  76. //
  77. typedef struct _REPORT_RATE {
  78. CHAR Command;
  79. UCHAR ReportRate;
  80. } REPORT_RATE;
  81. typedef struct _PROTOCOL {
  82. CHAR Command;
  83. UCHAR LineCtrl;
  84. PPROTOCOL_HANDLER Handler;
  85. } PROTOCOL;
  86. typedef struct _CSER_BAUDRATE {
  87. CHAR *Command;
  88. ULONG BaudRate;
  89. } CSER_BAUDRATE;
  90. //
  91. // Globals.
  92. //
  93. //
  94. // The baud rate at which we try to detect a mouse.
  95. //
  96. static ULONG BaudRateDetect[] = { 1200, 2400, 4800, 9600 };
  97. //
  98. // This list is indexed by protocol values PROTOCOL_*.
  99. //
  100. PROTOCOL Protocol[] = {
  101. {'S',
  102. ACE_8BW | ACE_PEN | ACE_1SB,
  103. CSerHandlerMM
  104. },
  105. {'T',
  106. ACE_8BW | ACE_1SB,
  107. NULL
  108. },
  109. {'U',
  110. ACE_8BW | ACE_1SB,
  111. NULL
  112. },
  113. {'V',
  114. ACE_7BW | ACE_1SB,
  115. NULL
  116. },
  117. {'B',
  118. ACE_7BW | ACE_PEN | ACE_EPS | ACE_1SB,
  119. NULL
  120. },
  121. {'A',
  122. ACE_7BW | ACE_PEN | ACE_EPS | ACE_1SB,
  123. NULL
  124. }
  125. };
  126. static REPORT_RATE ReportRateTable[] = {
  127. {'D', 0 },
  128. {'J', 10},
  129. {'K', 20},
  130. {'L', 35},
  131. {'R', 50},
  132. {'M', 70},
  133. {'Q', 100},
  134. {'N', 150},
  135. {'O', 151} // Continuous
  136. };
  137. static CSER_BAUDRATE CserBaudRateTable[] = {
  138. { "*n", 1200 },
  139. { "*o", 2400 },
  140. { "*p", 4800 },
  141. { "*q", 9600 }
  142. };
  143. BOOLEAN
  144. CSerPowerUp(
  145. PUCHAR Port
  146. )
  147. /*++
  148. Routine Description:
  149. Powers up the mouse by making the RTS and DTR active.
  150. Arguments:
  151. Port - Pointer to the serial port.
  152. Return Value:
  153. TRUE.
  154. --*/
  155. {
  156. UCHAR lineCtrl;
  157. SerMouPrint((2, "SERMOUSE-PowerUp: Enter\n"));
  158. //
  159. // Set both RTS and DTR lines to an active state.
  160. //
  161. lineCtrl = UARTSetModemCtrl(Port, ACE_DTR | ACE_RTS);
  162. SerMouPrint((1, "SERMOUSE-Initial line control: %#x\n", lineCtrl));
  163. //
  164. // If the lines are high, the power is on for at least 500 ms due to the
  165. // MSeries detection.
  166. //
  167. if ((lineCtrl & (ACE_DTR | ACE_RTS)) != (ACE_DTR | ACE_RTS)) {
  168. SerMouPrint((1, "SERMOUSE-Powering up\n"));
  169. //
  170. // Wait CSER_POWER_UP milliseconds for the mouse to power up
  171. // correctly.
  172. //
  173. KeStallExecutionProcessor(CSER_POWER_UP * MS_TO_MICROSECONDS);
  174. }
  175. SerMouPrint((2, "SERMOUSE-PowerUp: Exit\n"));
  176. return TRUE;
  177. }
  178. VOID
  179. CSerSetReportRate(
  180. PUCHAR Port,
  181. UCHAR ReportRate
  182. )
  183. /*++
  184. Routine Description:
  185. Set the mouse report rate. This can range from 0 (prompt mode) to
  186. continuous report rate.
  187. Arguments:
  188. Port - Pointer to serial port.
  189. ReportRate - The desired report rate.
  190. Return Value:
  191. None.
  192. --*/
  193. {
  194. LONG count;
  195. SerMouPrint((2, "SERMOUSE-CSerSetReportRate: Enter\n"));
  196. for (count = sizeofel(ReportRateTable) - 1; count >= 0; count--) {
  197. //
  198. // Get the character to send from the table.
  199. //
  200. if (ReportRate >= ReportRateTable[count].ReportRate) {
  201. //
  202. // Set the baud rate.
  203. //
  204. SerMouPrint((
  205. 3,
  206. "SERMOUSE-New ReportRate: %u\n", ReportRateTable[count].ReportRate
  207. ));
  208. UARTWriteChar(Port, ReportRateTable[count].Command);
  209. break;
  210. }
  211. }
  212. SerMouPrint((2, "SERMOUSE-CSerSetReportRate: Exit\n"));
  213. return;
  214. }
  215. VOID
  216. CSerSetBaudRate(
  217. PUCHAR Port,
  218. ULONG BaudRate,
  219. ULONG BaudClock
  220. )
  221. /*++
  222. Routine Description:
  223. Set the new mouse baud rate. This will change the serial port baud rate.
  224. Arguments:
  225. Port - Pointer to the serial port.
  226. BaudRate - Desired baud rate.
  227. BaudClock - The external frequency driving the serial chip.
  228. Return Value:
  229. None.
  230. --*/
  231. {
  232. LONG count;
  233. SerMouPrint((2, "SERMOUSE-CSerSetBaudRate: Enter\n"));
  234. //
  235. // Before we mess with the baud rate, put the mouse in prompt mode.
  236. //
  237. CSerSetReportRate(Port, 0);
  238. for (count = sizeofel(CserBaudRateTable) - 1; count >= 0; count--) {
  239. if (BaudRate >= CserBaudRateTable[count].BaudRate) {
  240. //
  241. // Set the baud rate.
  242. //
  243. UARTWriteString(Port, CserBaudRateTable[count].Command);
  244. while(!UARTIsTransmitEmpty(Port)) /* Do nothing */;
  245. UARTSetBaudRate(Port, CserBaudRateTable[count].BaudRate, BaudClock);
  246. //
  247. // Delay to allow the UART and the mouse to synchronize
  248. // correctly.
  249. //
  250. KeStallExecutionProcessor(CSER_BAUDRATE_DELAY * MS_TO_MICROSECONDS);
  251. break;
  252. }
  253. }
  254. SerMouPrint((2, "SERMOUSE-CSerSetBaudRate: Exit\n"));
  255. return;
  256. }
  257. PPROTOCOL_HANDLER
  258. CSerSetProtocol(
  259. PUCHAR Port,
  260. UCHAR NewProtocol
  261. )
  262. /*++
  263. Routine Description:
  264. Change the mouse protocol.
  265. Note: Not all the protocols are implemented in this driver.
  266. Arguments:
  267. Port - Pointer to the serial port.
  268. Return Value:
  269. Address of the protocol handler function. See the interrupt service
  270. routine.
  271. --*/
  272. {
  273. SerMouPrint((2, "SERMOUSE-CSerSetProtocol: Enter\n"));
  274. ASSERT(NewProtocol < CSER_PROTOCOL_MAX);
  275. //
  276. // Set the protocol.
  277. //
  278. UARTWriteChar(Port, Protocol[NewProtocol].Command);
  279. UARTSetLineCtrl(Port, Protocol[NewProtocol].LineCtrl);
  280. SerMouPrint((2, "SERMOUSE-NewProtocol: %u\n", NewProtocol & 0xFF));
  281. SerMouPrint((2, "SERMOUSE-CSerSetProtocol: Exit\n"));
  282. return Protocol[NewProtocol].Handler;
  283. }
  284. BOOLEAN
  285. CSerDetect(
  286. PUCHAR Port,
  287. ULONG BaudClock,
  288. PULONG HardwareButtons
  289. )
  290. /*++
  291. Routine Description:
  292. Detection of a CSeries type mouse. The main steps are:
  293. - Power up the mouse.
  294. - Cycle through the available baud rates and try to get an answer
  295. from the mouse.
  296. At the end of the routine, a default baud rate and report rate are set.
  297. Arguments:
  298. Port - Pointer to the serial port.
  299. BaudClock - The external frequency driving the serial chip.
  300. HardwareButtons - Returns the number of hardware buttons detected.
  301. Return Value:
  302. TRUE if a CSeries type mouse is detected, otherwise FALSE.
  303. --*/
  304. {
  305. UCHAR status, numButtons;
  306. ULONG count;
  307. BOOLEAN detected = FALSE;
  308. SerMouSetDebugOutput(DBG_COLOR);
  309. SerMouPrint((2, "SERMOUSE-CSerDetect: Start\n"));
  310. //
  311. // Power up the mouse if necessary.
  312. //
  313. CSerPowerUp(Port);
  314. //
  315. // Set the line control register to a format that the mouse can
  316. // understand (see below: the line is set after the report rate).
  317. //
  318. UARTSetLineCtrl(Port, Protocol[CSER_PROTOCOL_MM].LineCtrl);
  319. //
  320. // Cycle through the different baud rates to detect the mouse.
  321. //
  322. for (count = 0; count < sizeofel(BaudRateDetect); count++) {
  323. UARTSetBaudRate(Port, BaudRateDetect[count], BaudClock);
  324. //
  325. // Put the mouse in prompt mode.
  326. //
  327. CSerSetReportRate(Port, 0);
  328. //
  329. // Set the MM protocol. This way we get the mouse to talk to us in a
  330. // specific format. This avoids receiving errors from the line
  331. // register.
  332. //
  333. CSerSetProtocol(Port, CSER_PROTOCOL_MM);
  334. //
  335. // Try to get the status byte.
  336. //
  337. UARTWriteChar(Port, CSER_STATUS_COMMAND);
  338. while (!UARTIsTransmitEmpty(Port)) {
  339. // Nothing
  340. }
  341. //
  342. // In case something is already there...
  343. //
  344. UARTFlushReadBuffer(Port);
  345. //
  346. // Read back the status character.
  347. //
  348. if (UARTReadChar(Port, &status, CSER_STATUS_DELAY) &&
  349. (status == CSER_STATUS)) {
  350. detected = TRUE;
  351. SerMouPrint((
  352. 1,
  353. "SERMOUSE-Detected mouse at %u bauds\n",
  354. BaudRateDetect[count]
  355. ));
  356. break;
  357. }
  358. }
  359. if (detected) {
  360. //
  361. // Get the number of buttons back from the mouse.
  362. //
  363. UARTWriteChar(Port, CSER_QUERY_BUTTONS_COMMAND);
  364. while (!UARTIsTransmitEmpty(Port)) {
  365. // Nothing
  366. }
  367. //
  368. // In case something is already there...
  369. //
  370. UARTFlushReadBuffer(Port);
  371. //
  372. // Read back the number of buttons.
  373. //
  374. if (UARTReadChar(Port, &numButtons, CSER_STATUS_DELAY)) {
  375. numButtons &= 0x0F;
  376. if (numButtons == 2 || numButtons == 3) {
  377. *HardwareButtons = numButtons;
  378. } else {
  379. *HardwareButtons = MOUSE_NUMBER_OF_BUTTONS;
  380. }
  381. } else {
  382. *HardwareButtons = MOUSE_NUMBER_OF_BUTTONS;
  383. }
  384. }
  385. //
  386. // Put the mouse back in a default mode. The protocol is already set.
  387. //
  388. CSerSetBaudRate(Port, CSER_DEFAULT_BAUDRATE, BaudClock);
  389. CSerSetReportRate(Port, CSER_DEFAULT_REPORTRATE);
  390. SerMouPrint((3, "SERMOUSE-Detected: %s\n", detected ? "TRUE" : "FALSE"));
  391. SerMouPrint((3, "SERMOUSE-Status byte: %#x\n", status));
  392. SerMouPrint((2, "SERMOUSE-CSerDetect: End\n"));
  393. SerMouSetDebugOutput(DBG_SERIAL);
  394. return detected;
  395. }
  396. BOOLEAN
  397. CSerHandlerMM(
  398. IN PMOUSE_INPUT_DATA CurrentInput,
  399. IN PHANDLER_DATA HandlerData,
  400. IN UCHAR Value,
  401. IN UCHAR LineState)
  402. /*++
  403. Routine Description:
  404. This is the protocol handler routine for the MM protocol.
  405. Arguments:
  406. CurrentInput - Pointer to the report packet.
  407. Value - The input buffer value.
  408. LineState - The serial port line state.
  409. Return Value:
  410. Returns TRUE if the handler has a completed report.
  411. --*/
  412. {
  413. BOOLEAN retval = FALSE;
  414. SerMouPrint((2, "SERMOUSE-MMHandler: enter\n"));
  415. if ((Value & CSER_SYNCH_BIT) && (HandlerData->State != STATE0)) {
  416. HandlerData->Error++;
  417. SerMouPrint((
  418. 1,
  419. "SERMOUSE-Synch error. State: %u\n", HandlerData->State
  420. ));
  421. HandlerData->State = STATE0;
  422. }
  423. else if (!(Value & CSER_SYNCH_BIT) && (HandlerData->State == STATE0)) {
  424. HandlerData->Error++;
  425. SerMouPrint((
  426. 1,
  427. "SERMOUSE-Synch error. State: %u\n", HandlerData->State
  428. ));
  429. goto LExit;
  430. }
  431. //
  432. // Check for a line state error.
  433. //
  434. if (LineState & ACE_LERR) {
  435. //
  436. // Reset the handler state.
  437. //
  438. HandlerData->State = STATE0;
  439. HandlerData->Error++;
  440. SerMouPrint((1, "SERMOUSE-Line status error: %#x\n", LineState));
  441. }
  442. else {
  443. SerMouPrint((2, "SERMOUSE-State%u\n", HandlerData->State));
  444. HandlerData->Raw[HandlerData->State] = Value;
  445. switch (HandlerData->State) {
  446. case STATE0:
  447. case STATE1:
  448. HandlerData->State++;
  449. break;
  450. case STATE2:
  451. HandlerData->State = STATE0;
  452. //
  453. // Buttons formatting.
  454. //
  455. CurrentInput->RawButtons =
  456. (HandlerData->Raw[STATE0] & CSER_BUTTON_LEFT) >> CSER_BUTTON_LEFT_SR;
  457. CurrentInput->RawButtons |=
  458. (HandlerData->Raw[STATE0] & CSER_BUTTON_RIGHT) << CSER_BUTTON_RIGHT_SL;
  459. CurrentInput->RawButtons |=
  460. (HandlerData->Raw[STATE0] & CSER_BUTTON_MIDDLE) << CSER_BUTTON_MIDDLE_SL;
  461. //
  462. // Displacement formatting.
  463. //
  464. CurrentInput->LastX = (HandlerData->Raw[STATE0] & SIGN_X) ?
  465. HandlerData->Raw[STATE1] :
  466. -(LONG)HandlerData->Raw[STATE1];
  467. //
  468. // Note: The Y displacement is positive to the south.
  469. //
  470. CurrentInput->LastY = (HandlerData->Raw[STATE0] & SIGN_Y) ?
  471. -(LONG)HandlerData->Raw[STATE2] :
  472. HandlerData->Raw[STATE2];
  473. SerMouPrint((1, "SERMOUSE-Displacement X: %ld\n", CurrentInput->LastX));
  474. SerMouPrint((1, "SERMOUSE-Displacement Y: %ld\n", CurrentInput->LastY));
  475. SerMouPrint((1, "SERMOUSE-Raw Buttons: %0lx\n", CurrentInput->RawButtons));
  476. //
  477. // The report is complete. Tell the interrupt handler to send it.
  478. //
  479. retval = TRUE;
  480. break;
  481. default:
  482. SerMouPrint((
  483. 0,
  484. "SERMOUSE-MM Handler failure: incorrect state value.\n"
  485. ));
  486. ASSERT(FALSE);
  487. }
  488. }
  489. LExit:
  490. SerMouPrint((2, "SERMOUSE-MMHandler: exit\n"));
  491. return retval;
  492. }