|
|
1.1 root 1: /*++
2:
3: Copyright (c) 1993 Microsoft Corporation
4: Copyright (c) 1993 Logitech Inc.
5:
6: Module Name:
7:
8: mseries.c
9:
10: Abstract:
11:
12:
13: Environment:
14:
15: Kernel mode only.
16:
17: Notes:
18:
19:
20: Revision History:
21:
22: --*/
23:
24: //
25: // Includes.
26: //
27:
28: #include "ntddk.h"
29: #include "uart.h"
30: #include "sermouse.h"
31: #include "debug.h"
32: #include "cseries.h"
33: #include "mseries.h"
34:
35: //
36: // Use the alloc_text pragma to specify the driver initialization routines
37: // (they can be paged out).
38: //
39:
40: #ifdef ALLOC_PRAGMA
41: #pragma alloc_text(init,MSerSetProtocol)
42: #pragma alloc_text(init,MSerPowerUp)
43: #pragma alloc_text(init,MSerPowerDown)
44: #pragma alloc_text(init,MSerReset)
45: #pragma alloc_text(init,MSerDetect)
46: #endif // ALLOC_PRAGMA
47:
48: //
49: // Constants.
50: //
51:
52: #define MSER_BAUDRATE 1200
53: #define MAX_RESET_BUFFER 8
54: #define MINIMUM_RESET_TIME 200
55:
56: //
57: // Microsoft Plus.
58: //
59:
60: #define MP_SYNCH_BIT 0x40
61:
62: #define MP_BUTTON_LEFT 0x20
63: #define MP_BUTTON_RIGHT 0x10
64: #define MP_BUTTON_MIDDLE 0x20
65:
66: #define MP_BUTTON_LEFT_SR 5
67: #define MP_BUTTON_RIGHT_SR 3
68: #define MP_BUTTON_MIDDLE_SR 3
69:
70: #define MP_BUTTON_MIDDLE_MASK 0x04
71:
72: #define MP_UPPER_MASKX 0x03
73: #define MP_UPPER_MASKY 0x0C
74:
75: #define MP_UPPER_MASKX_SL 6
76: #define MP_UPPER_MASKY_SL 4
77:
78: //
79: // Microsoft BallPoint.
80: //
81:
82: #define BP_SYNCH_BIT 0x40
83:
84: #define BP_BUTTON_LEFT 0x20
85: #define BP_BUTTON_RIGHT 0x10
86: #define BP_BUTTON_3 0x04
87: #define BP_BUTTON_4 0x08
88:
89: #define BP_BUTTON_LEFT_SR 5
90: #define BP_BUTTON_RIGHT_SR 3
91: #define BP_BUTTON_3_SL 0
92: #define BP_BUTTON_4_SL 0
93:
94: #define BP_UPPER_MASKX 0x03
95: #define BP_UPPER_MASKY 0x0C
96:
97: #define BP_UPPER_MASKX_SL 6
98: #define BP_UPPER_MASKY_SL 4
99:
100: #define BP_SIGN_MASKX 0x01
101: #define BP_SIGN_MASKY 0x02
102:
103: //
104: // Type definitions.
105: //
106:
107: typedef struct _PROTOCOL {
108: PPROTOCOL_HANDLER Handler;
109: UCHAR LineCtrl;
110: } PROTOCOL;
111:
112: //
113: // This list is indexed by protocol values MSER_PROTOCOL_*.
114: //
115:
116: static PROTOCOL Protocol[] = {
117: {
118: MSerHandlerMP, // Microsoft Plus
119: ACE_7BW | ACE_1SB
120: },
121: {
122: MSerHandlerBP, // BALLPOINT
123: ACE_7BW | ACE_1SB
124: }
125: };
126:
127: PPROTOCOL_HANDLER
128: MSerSetProtocol(
129: PUCHAR Port,
130: UCHAR NewProtocol
131: )
132: /*++
133:
134: Routine Description:
135:
136: Set the mouse protocol. This function only sets the serial port
137: line control register.
138:
139: Arguments:
140:
141: Port - Pointer to the serial port.
142:
143: NewProtocol - Index into the protocol table.
144:
145: Return Value:
146:
147: Pointer to the protocol handler function.
148:
149: --*/
150: {
151: ASSERT(NewProtocol < MSER_PROTOCOL_MAX);
152:
153: //
154: // Set the protocol
155: //
156:
157: UARTSetLineCtrl(Port, Protocol[NewProtocol].LineCtrl);
158:
159: return Protocol[NewProtocol].Handler;
160: }
161:
162: BOOLEAN
163: MSerPowerUp(
164: PUCHAR Port
165: )
166: /*++
167:
168: Routine Description:
169:
170: Powers up the mouse. Just sets the RTS and DTR lines and returns.
171:
172: Arguments:
173:
174: Port - Pointer to the serial port.
175:
176: Return Value:
177:
178: TRUE.
179:
180: --*/
181: {
182:
183: //
184: // Turn RTS on to power the mouse up (DTR should already be on,
185: // but make extra sure).
186: //
187:
188: UARTSetModemCtrl(Port, ACE_DTR | ACE_RTS);
189:
190: //
191: // Wait 10 ms. The power-up response byte(s) should take at least
192: // this long to get transmitted.
193: //
194:
195: KeStallExecutionProcessor(10 * MS_TO_MICROSECONDS);
196:
197: return TRUE;
198: }
199:
200: BOOLEAN
201: MSerPowerDown(
202: PUCHAR Port
203: )
204: /*++
205:
206: Routine Description:
207:
208: Powers down the mouse. Sets the RTS line to an inactive state.
209:
210: Arguments:
211:
212: Port - Pointer to the serial port.
213:
214: Return Value:
215:
216: TRUE.
217:
218: --*/
219: {
220: UCHAR lineCtrl = UARTGetModemCtrl(Port);
221:
222: SerMouPrint((
223: 2,
224: "SERMOUSE-MSerPowerDown: The intial line control is: %#X\n",
225: lineCtrl & 0xFF
226: ));
227:
228: UARTSetModemCtrl(Port, (UCHAR)(lineCtrl & (~ACE_RTS | ACE_DTR)));
229:
230: //
231: // Keep RTS low for at least 150 ms, in order to correctly power
232: // down older Microsoft serial mice. Wait even longer to avoid
233: // sending some Logitech CSeries mice into the floating point world...
234: //
235:
236: ASSERT(CSER_POWER_DOWN >= 150);
237:
238: KeStallExecutionProcessor(CSER_POWER_DOWN * MS_TO_MICROSECONDS);
239:
240: return TRUE;
241: }
242:
243: BOOLEAN
244: MSerReset(
245: PUCHAR Port
246: )
247: /*++
248:
249: Routine Description:
250:
251: Reset the serial mouse.
252:
253: Arguments:
254:
255: Port - Pointer to the serial port.
256:
257: Return Value:
258:
259: TRUE.
260:
261: --*/
262: {
263:
264: //
265: // Remove mouse power if necessary.
266: //
267:
268: MSerPowerDown(Port);
269:
270: //
271: // Clean possible garbage in uart input buffer.
272: //
273:
274: UARTFlushReadBuffer(Port);
275:
276: //
277: // Power up the mouse (reset).
278: //
279:
280: MSerPowerUp(Port);
281:
282: return TRUE;
283: }
284:
285: MOUSETYPE
286: MSerDetect(
287: PUCHAR Port,
288: ULONG BaudClock
289: )
290: /*++
291:
292: Routine Description:
293:
294: Detection code for pointing devices that identify themselves at
295: power on time.
296:
297: Arguments:
298:
299: Port - Pointer to the serial port.
300:
301: BaudClock - The external frequency driving the serial chip.
302:
303: Return Value:
304:
305: The type of mouse detected.
306:
307: --*/
308: {
309: ULONG count = 0;
310: MOUSETYPE mouseType;
311: CHAR receiveBuffer[MAX_RESET_BUFFER];
312: ULONG i;
313:
314: //
315: // Set the debug output to the main display to avoid timing problems.
316: //
317:
318: SerMouSetDebugOutput(DBG_COLOR);
319:
320: //
321: // Set the baud rate.
322: //
323:
324: UARTSetBaudRate(Port, MSER_BAUDRATE, BaudClock);
325:
326: //
327: // Set the data format so that the possible answer can be recognized.
328: //
329:
330: UARTSetLineCtrl(Port, Protocol[MSER_PROTOCOL_MP].LineCtrl);
331:
332: //
333: // Apply the reset to the mouse.
334: //
335:
336: MSerReset(Port);
337:
338: //
339: // Get the possible first reset character ('M' or 'B'), followed
340: // by any other characters the hardware happens to send back.
341: //
342: // Note: Typically, we expect to get just one character ('M' or
343: // 'B'), perhaps followed by a '2' or '3' (to indicate the
344: // number of mouse buttons. On some machines, we're
345: // getting extraneous characters before the 'M'. Sometimes
346: // we get extraneous characters after the expected data, as
347: // well. They either get read in here, or get flushed
348: // when SerMouEnableInterrupts executes.
349: //
350:
351: ASSERT(CSER_POWER_UP >= MINIMUM_RESET_TIME);
352:
353: if (UARTReadChar(Port, &receiveBuffer[count], CSER_POWER_UP)) {
354: count++;
355: while (count < (MAX_RESET_BUFFER - 1)) {
356: if (UARTReadChar(Port, &receiveBuffer[count], 100)) {
357: count++;
358: } else {
359: break;
360: }
361: }
362: }
363:
364: *(receiveBuffer + count) = 0;
365:
366: SerMouPrint((2, "SERMOUSE-Receive buffer:\n"));
367: for (i = 0; i < count; i++) {
368: SerMouPrint((2, "\t0x%x\n", receiveBuffer[i]));
369: }
370: SerMouPrint((2, "\n"));
371:
372: //
373: // Redirect the output to the serial port.
374: //
375:
376: SerMouSetDebugOutput(DBG_SERIAL);
377:
378: //
379: //
380: // Analyze the possible mouse answer. Start at the beginning of the
381: // "good" data in the receive buffer, ignoring extraneous characters
382: // that may have come in before the 'M' or 'B'.
383: //
384:
385: for (i = 0; i < count; i++) {
386: if (receiveBuffer[i] == 'M') {
387: if (receiveBuffer[i + 1] == '3') {
388: SerMouPrint((2, "SERMOUSE-Detected MSeries 3 buttons\n"));
389: mouseType = MOUSE_3B;
390: }
391: else {
392: SerMouPrint((2, "SERMOUSE-Detected MSeries 2 buttons\n"));
393: mouseType = MOUSE_2B;
394: }
395: break;
396: } else if (receiveBuffer[i] == 'B') {
397: SerMouPrint((2, "SERMOUSE-Detected Ballpoint\n"));
398: mouseType = BALLPOINT;
399: break;
400: }
401: }
402:
403: if (i >= count) {
404:
405: //
406: // Special case: If another device is connected (CSeries, for
407: // example) and this device sends a character (movement), the
408: // minimum power up time might not be respected. Take
409: // care of this unlikely case.
410: //
411:
412: if (count != 0) {
413: KeStallExecutionProcessor(CSER_POWER_UP * MS_TO_MICROSECONDS);
414: }
415:
416: SerMouPrint((1, "SERMOUSE-No MSeries detected\n"));
417: mouseType = NO_MOUSE;
418: }
419:
420: return mouseType;
421: }
422:
423:
424: BOOLEAN
425: MSerHandlerMP(
426: IN PMOUSE_INPUT_DATA CurrentInput,
427: IN PHANDLER_DATA HandlerData,
428: IN UCHAR Value,
429: IN UCHAR LineState
430: )
431:
432: /*++
433:
434: Routine Description:
435:
436: This is the protocol handler routine for the Microsoft Plus protocol.
437:
438: Arguments:
439:
440: CurrentInput - Pointer to the report packet.
441:
442: HandlerData - Instance specific static data for the handler.
443:
444: Value - The input buffer value.
445:
446: LineState - The serial port line state.
447:
448: Return Value:
449:
450: Returns TRUE if the handler has a complete report ready.
451:
452: --*/
453:
454: {
455: BOOLEAN retval = FALSE;
456: ULONG middleButton;
457:
458: SerMouPrint((2, "SERMOUSE-MP protocol handler: enter\n"));
459:
460:
461: if ((Value & MP_SYNCH_BIT) && (HandlerData->State != STATE0)) {
462: if ((HandlerData->State != STATE3)) {
463:
464: //
465: // We definitely have a synchronization problem (likely a data
466: // overrun).
467: //
468:
469: HandlerData->Error++;
470: }
471: else if ((HandlerData->PreviousButtons & MOUSE_BUTTON_3) != 0) {
472:
473: //
474: // We didn't receive the expected fourth byte. Missed it?
475: // Reset button 3 to zero.
476: //
477:
478: HandlerData->PreviousButtons ^= MOUSE_BUTTON_3;
479: HandlerData->Error++;
480: }
481:
482: SerMouPrint((
483: 1,
484: "SERMOUSE-Synch error. State: %u\n", HandlerData->State
485: ));
486:
487: HandlerData->State = STATE0;
488: }
489: else if (!(Value & MP_SYNCH_BIT) && (HandlerData->State == STATE0)) {
490: HandlerData->Error++;
491: SerMouPrint((
492: 1,
493: "SERMOUSE-Synch error. State: %u\n", HandlerData->State
494: ));
495: goto LExit;
496: }
497:
498: //
499: // Check for a line state error.
500: //
501:
502: if (LineState & ACE_LERR) {
503:
504: //
505: // Reset the handler state.
506: //
507:
508: HandlerData->State = STATE0;
509: HandlerData->Error++;
510: SerMouPrint((1, "SERMOUSE-Line status error: %#x\n", LineState));
511: }
512: else {
513:
514: //
515: // Set the untranslated value.
516: //
517:
518: HandlerData->Raw[HandlerData->State] = Value;
519: SerMouPrint((3, "SERMOUSE-State%u\n", HandlerData->State));
520:
521: switch (HandlerData->State) {
522: case STATE0:
523: case STATE1:
524: HandlerData->State++;
525: break;
526: case STATE2:
527: HandlerData->State++;
528:
529: //
530: // Build the report.
531: //
532:
533: CurrentInput->RawButtons =
534: (HandlerData->Raw[0] & MP_BUTTON_LEFT) >> MP_BUTTON_LEFT_SR;
535: CurrentInput->RawButtons |=
536: (HandlerData->Raw[0] & MP_BUTTON_RIGHT) >> MP_BUTTON_RIGHT_SR;
537: CurrentInput->RawButtons |=
538: HandlerData->PreviousButtons & MOUSE_BUTTON_3;
539:
540: CurrentInput->LastX =
541: (SCHAR)(HandlerData->Raw[1] |
542: ((HandlerData->Raw[0] & MP_UPPER_MASKX) << MP_UPPER_MASKX_SL));
543: CurrentInput->LastY =
544: (SCHAR)(HandlerData->Raw[2] |
545: ((HandlerData->Raw[0] & MP_UPPER_MASKY) << MP_UPPER_MASKY_SL));
546:
547: retval = TRUE;
548:
549: break;
550:
551: case STATE3:
552: HandlerData->State = STATE0;
553: middleButton =
554: (HandlerData->Raw[STATE3] & MP_BUTTON_MIDDLE) >> MP_BUTTON_MIDDLE_SR;
555:
556: //
557: // Send a report only if the middle button state changed.
558: //
559:
560: if (middleButton ^ (HandlerData->PreviousButtons & MOUSE_BUTTON_3)) {
561:
562: //
563: // Toggle the state of the middle button.
564: //
565:
566: CurrentInput->RawButtons ^= MP_BUTTON_MIDDLE_MASK;
567: CurrentInput->LastX = 0;
568: CurrentInput->LastY = 0;
569:
570: //
571: // Send the report one more time.
572: //
573:
574: retval = TRUE;
575: }
576:
577: break;
578:
579: default:
580: SerMouPrint((
581: 0,
582: "SERMOUSE-MP Handler failure: incorrect state value.\n"
583: ));
584: ASSERT(FALSE);
585: }
586: }
587:
588: LExit:
589: SerMouPrint((2, "SERMOUSE-MP protocol handler: exit\n"));
590:
591: return retval;
592:
593: }
594:
595: BOOLEAN
596: MSerHandlerBP(
597: IN PMOUSE_INPUT_DATA CurrentInput,
598: IN PHANDLER_DATA HandlerData,
599: IN UCHAR Value,
600: IN UCHAR LineState
601: )
602:
603: /*++
604:
605: Routine Description:
606:
607: This is the protocol handler routine for the Microsoft Ballpoint protocol.
608:
609: Arguments:
610:
611: CurrentInput - Pointer to the report packet.
612:
613: HandlerData - Instance specific static data for the handler.
614:
615: Value - The input buffer value.
616:
617: LineState - The serial port line state.
618:
619: Return Value:
620:
621: Returns TRUE if the handler has a complete report ready.
622:
623: --*/
624:
625: {
626: BOOLEAN retval = FALSE;
627:
628: SerMouPrint((2, "SERMOUSE-BP protocol handler: enter\n"));
629:
630: //
631: // Check for synchronization errors.
632: //
633:
634: if ((Value & BP_SYNCH_BIT) && (HandlerData->State != STATE0)) {
635: HandlerData->Error++;
636: SerMouPrint((
637: 1,
638: "SERMOUSE-Synch error. State: %u\n", HandlerData->State
639: ));
640: HandlerData->State = STATE0;
641: }
642: else if (!(Value & BP_SYNCH_BIT) && (HandlerData->State == STATE0)) {
643: HandlerData->Error++;
644: SerMouPrint((
645: 1,
646: "SERMOUSE-Synch error. State: %u\n", HandlerData->State
647: ));
648: goto LExit;
649: }
650:
651: //
652: // Check for a line state error.
653: //
654:
655: if (LineState & ACE_LERR) {
656:
657: //
658: // Reset the handler state.
659: //
660:
661: HandlerData->State = STATE0;
662: HandlerData->Error++;
663: SerMouPrint((1, "SERMOUSE-Line status error: %#x\n", LineState));
664: }
665: else {
666:
667: //
668: // Set the untranslated value.
669: //
670:
671: HandlerData->Raw[HandlerData->State] = Value;
672:
673: SerMouPrint((3, "SERMOUSE-State%u\n", HandlerData->State));
674:
675: switch (HandlerData->State) {
676:
677: case STATE0:
678: case STATE1:
679: case STATE2:
680: HandlerData->State++;
681: break;
682:
683: case STATE3:
684: HandlerData->State = STATE0;
685:
686: //
687: // Build the report.
688: //
689:
690: CurrentInput->RawButtons =
691: (HandlerData->Raw[0] & BP_BUTTON_LEFT) >> BP_BUTTON_LEFT_SR;
692: CurrentInput->RawButtons |=
693: (HandlerData->Raw[0] & BP_BUTTON_RIGHT) >> BP_BUTTON_RIGHT_SR;
694:
695: #if 0
696: CurrentInput->Buttons |=
697: (HandlerData->Raw[3] & BP_BUTTON_3) << BP_BUTTON_3_SL;
698: CurrentInput->Buttons |=
699: (HandlerData->Raw[3] & BP_BUTTON_4) << BP_BUTTON_4_SL;
700: #endif
701: CurrentInput->LastX = HandlerData->Raw[3] & BP_SIGN_MASKX ?
702: (LONG)(HandlerData->Raw[1] | (ULONG)(-1 & ~0xFF) |
703: ((HandlerData->Raw[0] & BP_UPPER_MASKX) << BP_UPPER_MASKX_SL)):
704: (LONG)(HandlerData->Raw[1] |
705: ((HandlerData->Raw[0] & BP_UPPER_MASKX) << BP_UPPER_MASKX_SL));
706:
707: CurrentInput->LastY = HandlerData->Raw[3] & BP_SIGN_MASKY ?
708: (LONG)(HandlerData->Raw[2] | (ULONG)(-1 & ~0xFF) |
709: ((HandlerData->Raw[0] & BP_UPPER_MASKY) << BP_UPPER_MASKY_SL)):
710: (LONG)(HandlerData->Raw[2] |
711: ((HandlerData->Raw[0] & BP_UPPER_MASKY) << BP_UPPER_MASKY_SL));
712:
713: retval = TRUE;
714:
715: break;
716:
717: default:
718: SerMouPrint((
719: 0,
720: "SERMOUSE-BP Handler failure: incorrect state value.\n"
721: ));
722: ASSERT(FALSE);
723: }
724: }
725:
726: LExit:
727: SerMouPrint((2, "SERMOUSE-BP protocol handler: exit\n"));
728:
729: return retval;
730:
731: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.