Leaked source code of windows server 2003
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.

706 lines
16 KiB

  1. /*++
  2. Copyright (c) 1990-1998 Microsoft Corporation, All Rights Reserved
  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 "mouser.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(PAGE,CSerPowerUp)
  25. #pragma alloc_text(PAGE,CSerSetReportRate)
  26. #pragma alloc_text(PAGE,CSerSetBaudRate)
  27. #pragma alloc_text(PAGE,CSerSetProtocol)
  28. #pragma alloc_text(PAGE,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 * MS_TO_100_NS)
  49. #define CSER_STATUS_DELAY 50
  50. //
  51. // Time (in microconds) needed by the mouse to adapt to a new baud rate.
  52. //
  53. #define CSER_BAUDRATE_DELAY (2 * MS_TO_100_NS)
  54. //
  55. // Default baud rate and report rate.
  56. //
  57. #define CSER_DEFAULT_BAUDRATE 1200
  58. #define CSER_DEFAULT_REPORTRATE 150
  59. //
  60. // Button/status definitions.
  61. //
  62. #define CSER_SYNCH_BIT 0x80
  63. #define CSER_BUTTON_LEFT 0x04
  64. #define CSER_BUTTON_RIGHT 0x01
  65. #define CSER_BUTTON_MIDDLE 0x02
  66. #define CSER_BUTTON_LEFT_SR 2
  67. #define CSER_BUTTON_RIGHT_SL 1
  68. #define CSER_BUTTON_MIDDLE_SL 1
  69. #define SIGN_X 0x10
  70. #define SIGN_Y 0x08
  71. //
  72. // Macros.
  73. //
  74. #define sizeofel(x) (sizeof(x)/sizeof(*x))
  75. //
  76. // Type definitions.
  77. //
  78. typedef struct _REPORT_RATE {
  79. CHAR Command;
  80. UCHAR ReportRate;
  81. } REPORT_RATE;
  82. typedef struct _PROTOCOL {
  83. CHAR Command;
  84. SERIAL_LINE_CONTROL LineCtrl;
  85. PPROTOCOL_HANDLER Handler;
  86. } PROTOCOL;
  87. typedef struct _CSER_BAUDRATE {
  88. CHAR *Command;
  89. ULONG BaudRate;
  90. } CSER_BAUDRATE;
  91. //
  92. // Globals.
  93. //
  94. //
  95. // The baud rate at which we try to detect a mouse.
  96. //
  97. static ULONG BaudRateDetect[] = { 1200, 2400, 4800, 9600 };
  98. //
  99. // This list is indexed by protocol values PROTOCOL_*.
  100. //
  101. PROTOCOL Protocol[] = {
  102. {'S',
  103. // ACE_8BW | ACE_PEN | ACE_1SB,
  104. { STOP_BIT_1, 0, 8 },
  105. CSerHandlerMM
  106. },
  107. {'T',
  108. // ACE_8BW | ACE_1SB,
  109. { STOP_BIT_1, NO_PARITY, 8 },
  110. NULL
  111. },
  112. {'U',
  113. // ACE_8BW | ACE_1SB,
  114. { STOP_BIT_1, NO_PARITY, 8 },
  115. NULL
  116. },
  117. {'V',
  118. // ACE_7BW | ACE_1SB,
  119. { STOP_BIT_1, NO_PARITY, 7 },
  120. NULL
  121. },
  122. {'B',
  123. // ACE_7BW | ACE_PEN | ACE_EPS | ACE_1SB,
  124. { STOP_BIT_1, EVEN_PARITY, 7 },
  125. NULL
  126. },
  127. {'A',
  128. // ACE_7BW | ACE_PEN | ACE_EPS | ACE_1SB,
  129. { STOP_BIT_1, EVEN_PARITY, 7 },
  130. NULL
  131. }
  132. };
  133. static REPORT_RATE ReportRateTable[] = {
  134. {'D', 0 },
  135. {'J', 10},
  136. {'K', 20},
  137. {'L', 35},
  138. {'R', 50},
  139. {'M', 70},
  140. {'Q', 100},
  141. {'N', 150},
  142. {'O', 151} // Continuous
  143. };
  144. static CSER_BAUDRATE CserBaudRateTable[] = {
  145. { "*n", 1200 },
  146. { "*o", 2400 },
  147. { "*p", 4800 },
  148. { "*q", 9600 }
  149. };
  150. NTSTATUS
  151. CSerPowerUp(
  152. PDEVICE_EXTENSION DeviceExtension
  153. )
  154. /*++
  155. Routine Description:
  156. Powers up the mouse by making the RTS and DTR active.
  157. Arguments:
  158. Port - Pointer to the serial port.
  159. Return Value:
  160. TRUE.
  161. --*/
  162. {
  163. NTSTATUS status = STATUS_SUCCESS;
  164. IO_STATUS_BLOCK iosb;
  165. KEVENT event;
  166. ULONG bits;
  167. ULONG rtsDtr = SERIAL_RTS_STATE | SERIAL_DTR_STATE;
  168. PAGED_CODE();
  169. Print(DeviceExtension, DBG_SS_TRACE, ("(c) PowerUp called\n"));
  170. KeInitializeEvent(&event,
  171. NotificationEvent,
  172. FALSE
  173. );
  174. //
  175. // set DTR
  176. //
  177. Print(DeviceExtension, DBG_SS_NOISE, ("(c) Setting DTR...\n"));
  178. status = SerialMouseIoSyncIoctl(IOCTL_SERIAL_SET_DTR,
  179. DeviceExtension->TopOfStack,
  180. &event,
  181. &iosb
  182. );
  183. //
  184. // set RTS
  185. //
  186. Print(DeviceExtension, DBG_SS_NOISE, ("(c) Setting RTS...\n"));
  187. status = SerialMouseIoSyncIoctl(IOCTL_SERIAL_SET_RTS,
  188. DeviceExtension->TopOfStack,
  189. &event,
  190. &iosb
  191. );
  192. //
  193. // If the lines are high, the power is on for at least 500 ms due to the
  194. // MSeries detection.
  195. //
  196. status = SerialMouseIoSyncIoctlEx(IOCTL_SERIAL_GET_MODEMSTATUS,
  197. DeviceExtension->TopOfStack,
  198. &event,
  199. &iosb,
  200. NULL,
  201. 0,
  202. &bits,
  203. sizeof(ULONG)
  204. );
  205. if (NT_SUCCESS(status) && ((rtsDtr & bits) == rtsDtr)) {
  206. //
  207. // Wait CSER_POWER_UP milliseconds for the mouse to power up
  208. // correctly.
  209. //
  210. Print(DeviceExtension, DBG_SS_INFO,
  211. ("(c) Waiting awhile for the mouse to power up\n"));
  212. SerialMouseWait(DeviceExtension,
  213. -CSER_POWER_UP
  214. );
  215. }
  216. return status;
  217. }
  218. VOID
  219. CSerSetReportRate(
  220. PDEVICE_EXTENSION DeviceExtension,
  221. UCHAR ReportRate
  222. )
  223. /*++
  224. Routine Description:
  225. Set the mouse report rate. This can range from 0 (prompt mode) to
  226. continuous report rate.
  227. Arguments:
  228. Port - Pointer to serial port.
  229. ReportRate - The desired report rate.
  230. Return Value:
  231. None.
  232. --*/
  233. {
  234. LONG count;
  235. PAGED_CODE();
  236. Print(DeviceExtension, DBG_SS_TRACE, ("CSerSetReportRate called\n"));
  237. for (count = sizeofel(ReportRateTable) - 1; count >= 0; count--) {
  238. //
  239. // Get the character to send from the table.
  240. //
  241. if (ReportRate >= ReportRateTable[count].ReportRate) {
  242. //
  243. // Set the baud rate.
  244. //
  245. Print(DeviceExtension, DBG_SS_INFO,
  246. ("New ReportRate: %u\n",
  247. ReportRateTable[count].ReportRate
  248. ));
  249. SerialMouseWriteChar(DeviceExtension, ReportRateTable[count].Command);
  250. break;
  251. }
  252. }
  253. return;
  254. }
  255. VOID
  256. CSerSetBaudRate(
  257. PDEVICE_EXTENSION DeviceExtension,
  258. ULONG BaudRate
  259. )
  260. /*++
  261. Routine Description:
  262. Set the new mouse baud rate. This will change the serial port baud rate.
  263. Arguments:
  264. Port - Pointer to the serial port.
  265. BaudRate - Desired baud rate.
  266. BaudClock - The external frequency driving the serial chip.
  267. Return Value:
  268. None.
  269. --*/
  270. {
  271. LONG count;
  272. PAGED_CODE();
  273. Print(DeviceExtension, DBG_SS_TRACE, ("CSerSetBaudRate called\n"));
  274. //
  275. // Before we mess with the baud rate, put the mouse in prompt mode.
  276. //
  277. CSerSetReportRate(DeviceExtension, 0);
  278. for (count = sizeofel(CserBaudRateTable) - 1; count >= 0; count--) {
  279. if (BaudRate >= CserBaudRateTable[count].BaudRate) {
  280. //
  281. // Set the baud rate.
  282. //
  283. SerialMouseWriteString(DeviceExtension, CserBaudRateTable[count].Command);
  284. SerialMouseSetBaudRate(DeviceExtension, CserBaudRateTable[count].BaudRate);
  285. //
  286. // Delay to allow the UART and the mouse to synchronize
  287. // correctly.
  288. //
  289. SerialMouseWait(DeviceExtension,
  290. -CSER_BAUDRATE_DELAY
  291. );
  292. break;
  293. }
  294. }
  295. return;
  296. }
  297. PPROTOCOL_HANDLER
  298. CSerSetProtocol(
  299. PDEVICE_EXTENSION DeviceExtension,
  300. UCHAR NewProtocol
  301. )
  302. /*++
  303. Routine Description:
  304. Change the mouse protocol.
  305. Note: Not all the protocols are implemented in this driver.
  306. Arguments:
  307. Port - Pointer to the serial port.
  308. Return Value:
  309. Address of the protocol handler function. See the interrupt service
  310. routine.
  311. --*/
  312. {
  313. PAGED_CODE();
  314. Print(DeviceExtension, DBG_SS_TRACE, ("CSerSetProtocol called\n"));
  315. ASSERT(NewProtocol < CSER_PROTOCOL_MAX);
  316. //
  317. // Set the protocol.
  318. //
  319. SerialMouseWriteChar(DeviceExtension, Protocol[NewProtocol].Command);
  320. SerialMouseSetLineCtrl(DeviceExtension, &Protocol[NewProtocol].LineCtrl);
  321. Print(DeviceExtension, DBG_SS_INFO, ("NewProtocol: %u\n", NewProtocol & 0xFF));
  322. return Protocol[NewProtocol].Handler;
  323. }
  324. BOOLEAN
  325. CSerDetect(
  326. PDEVICE_EXTENSION DeviceExtension,
  327. PULONG HardwareButtons
  328. )
  329. /*++
  330. Routine Description:
  331. Detection of a CSeries type mouse. The main steps are:
  332. - Power up the mouse.
  333. - Cycle through the available baud rates and try to get an answer
  334. from the mouse.
  335. At the end of the routine, a default baud rate and report rate are set.
  336. Arguments:
  337. Port - Pointer to the serial port.
  338. HardwareButtons - Returns the number of hardware buttons detected.
  339. Return Value:
  340. TRUE if a CSeries type mouse is detected, otherwise FALSE.
  341. --*/
  342. {
  343. UCHAR status, numButtons;
  344. ULONG count;
  345. BOOLEAN detected = FALSE;
  346. Print(DeviceExtension, DBG_SS_TRACE, ("CSerDetect called\n"));
  347. //
  348. // Power up the mouse if necessary.
  349. //
  350. CSerPowerUp(DeviceExtension);
  351. //
  352. // Set the line control register to a format that the mouse can
  353. // understand (see below: the line is set after the report rate).
  354. //
  355. SerialMouseSetLineCtrl(DeviceExtension, &Protocol[CSER_PROTOCOL_MM].LineCtrl);
  356. //
  357. // Cycle through the different baud rates to detect the mouse.
  358. //
  359. for (count = 0; count < sizeofel(BaudRateDetect); count++) {
  360. SerialMouseSetBaudRate(DeviceExtension, BaudRateDetect[count]);
  361. //
  362. // Put the mouse in prompt mode.
  363. //
  364. CSerSetReportRate(DeviceExtension, 0);
  365. //
  366. // Set the MM protocol. This way we get the mouse to talk to us in a
  367. // specific format. This avoids receiving errors from the line
  368. // register.
  369. //
  370. CSerSetProtocol(DeviceExtension, CSER_PROTOCOL_MM);
  371. //
  372. // Try to get the status byte.
  373. //
  374. SerialMouseWriteChar(DeviceExtension, CSER_STATUS_COMMAND);
  375. //
  376. // In case something is already there...
  377. //
  378. SerialMouseFlushReadBuffer(DeviceExtension);
  379. SerialMouseSetReadTimeouts(DeviceExtension, 50);
  380. //
  381. // Read back the status character.
  382. //
  383. if (NT_SUCCESS(SerialMouseReadChar(DeviceExtension, &status)) &&
  384. (status == CSER_STATUS)) {
  385. detected = TRUE;
  386. Print(DeviceExtension, DBG_SS_INFO,
  387. ("Detected mouse at %u baud\n",
  388. BaudRateDetect[count]
  389. ));
  390. break;
  391. }
  392. }
  393. if (detected) {
  394. //
  395. // Get the number of buttons back from the mouse.
  396. //
  397. SerialMouseWriteChar(DeviceExtension, CSER_QUERY_BUTTONS_COMMAND);
  398. //
  399. // In case something is already there...
  400. //
  401. SerialMouseFlushReadBuffer(DeviceExtension);
  402. //
  403. // Read back the number of buttons.
  404. //
  405. SerialMouseSetReadTimeouts(DeviceExtension, CSER_STATUS_DELAY);
  406. if (NT_SUCCESS(SerialMouseReadChar(DeviceExtension, &numButtons))) {
  407. numButtons &= 0x0F;
  408. Print(DeviceExtension, DBG_SS_NOISE,
  409. ("Successfully read number of buttons (%1u)\n", numButtons));
  410. if (numButtons == 2 || numButtons == 3) {
  411. *HardwareButtons = numButtons;
  412. } else {
  413. *HardwareButtons = MOUSE_NUMBER_OF_BUTTONS;
  414. }
  415. } else {
  416. *HardwareButtons = MOUSE_NUMBER_OF_BUTTONS;
  417. }
  418. //
  419. // Make sure that all subsequent reads are blocking and do not timeout
  420. //
  421. SerialMouseSetReadTimeouts(DeviceExtension, 0);
  422. }
  423. //
  424. // Put the mouse back in a default mode. The protocol is already set.
  425. //
  426. CSerSetBaudRate(DeviceExtension, CSER_DEFAULT_BAUDRATE);
  427. CSerSetReportRate(DeviceExtension, CSER_DEFAULT_REPORTRATE);
  428. Print(DeviceExtension, DBG_SS_INFO,
  429. ("Detected: %s\n", detected ? "true" : "false"));
  430. Print(DeviceExtension, DBG_SS_INFO, ("Status byte: %#x\n", status));
  431. return detected;
  432. }
  433. BOOLEAN
  434. CSerHandlerMM(
  435. IN PDEVICE_EXTENSION DeviceExtension,
  436. IN PMOUSE_INPUT_DATA CurrentInput,
  437. IN PHANDLER_DATA HandlerData,
  438. IN UCHAR Value,
  439. IN UCHAR LineState)
  440. /*++
  441. Routine Description:
  442. This is the protocol handler routine for the MM protocol.
  443. Arguments:
  444. CurrentInput - Pointer to the report packet.
  445. Value - The input buffer value.
  446. LineState - The serial port line state.
  447. Return Value:
  448. Returns TRUE if the handler has a completed report.
  449. --*/
  450. {
  451. BOOLEAN retval = FALSE;
  452. Print(DeviceExtension, DBG_HANDLER_TRACE, ("MMHandler, enter\n"));
  453. if ((Value & CSER_SYNCH_BIT) && (HandlerData->State != STATE0)) {
  454. HandlerData->Error++;
  455. Print(DeviceExtension, DBG_HANDLER_ERROR,
  456. ("Synch error. State: %u\n",
  457. HandlerData->State
  458. ));
  459. HandlerData->State = STATE0;
  460. }
  461. else if (!(Value & CSER_SYNCH_BIT) && (HandlerData->State == STATE0)) {
  462. HandlerData->Error++;
  463. Print(DeviceExtension, DBG_HANDLER_ERROR,
  464. ("Synch error. State: %u\n",
  465. HandlerData->State
  466. ));
  467. goto LExit;
  468. }
  469. //
  470. // Check for a line state error.
  471. //
  472. Print(DeviceExtension, DBG_HANDLER_INFO,
  473. ("State%u\n", HandlerData->State));
  474. HandlerData->Raw[HandlerData->State] = Value;
  475. switch (HandlerData->State) {
  476. case STATE0:
  477. case STATE1:
  478. HandlerData->State++;
  479. break;
  480. case STATE2:
  481. HandlerData->State = STATE0;
  482. //
  483. // Buttons formatting.
  484. //
  485. CurrentInput->RawButtons =
  486. (HandlerData->Raw[STATE0] & CSER_BUTTON_LEFT) >> CSER_BUTTON_LEFT_SR;
  487. CurrentInput->RawButtons |=
  488. (HandlerData->Raw[STATE0] & CSER_BUTTON_RIGHT) << CSER_BUTTON_RIGHT_SL;
  489. CurrentInput->RawButtons |=
  490. (HandlerData->Raw[STATE0] & CSER_BUTTON_MIDDLE) << CSER_BUTTON_MIDDLE_SL;
  491. //
  492. // Displacement formatting.
  493. //
  494. CurrentInput->LastX = (HandlerData->Raw[STATE0] & SIGN_X) ?
  495. HandlerData->Raw[STATE1] :
  496. -(LONG)HandlerData->Raw[STATE1];
  497. //
  498. // Note: The Y displacement is positive to the south.
  499. //
  500. CurrentInput->LastY = (HandlerData->Raw[STATE0] & SIGN_Y) ?
  501. -(LONG)HandlerData->Raw[STATE2] :
  502. HandlerData->Raw[STATE2];
  503. Print(DeviceExtension, DBG_HANDLER_NOISE,
  504. ("Displacement X: %ld\n",
  505. CurrentInput->LastX
  506. ));
  507. Print(DeviceExtension, DBG_HANDLER_NOISE,
  508. ("Displacement Y: %ld\n",
  509. CurrentInput->LastY
  510. ));
  511. Print(DeviceExtension, DBG_HANDLER_NOISE,
  512. ("Raw Buttons: %0lx\n",
  513. CurrentInput->RawButtons
  514. ));
  515. //
  516. // The report is complete. Tell the interrupt handler to send it.
  517. //
  518. retval = TRUE;
  519. break;
  520. default:
  521. Print(DeviceExtension, DBG_HANDLER_ERROR,
  522. ("MM Handler failure: incorrect state value.\n"));
  523. ASSERT(FALSE);
  524. }
  525. LExit:
  526. Print(DeviceExtension, DBG_HANDLER_TRACE, ("MMHandler, exit\n"));
  527. return retval;
  528. }