|
|
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.