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