|
|
1.1 root 1: /*++
2:
3: Copyright (c) 1990, 1991, 1992, 1993 Microsoft Corporation
4: Copyright (c) 1993 Logitech Inc.
5:
6: Module Name:
7:
8: sermcmn.c
9:
10: Abstract:
11:
12: The common portions of the Microsoft serial (i8250) mouse port driver.
13: This file should not require modification to support new mice
14: that are similar to the serial mouse.
15:
16: Environment:
17:
18: Kernel mode only.
19:
20: Notes:
21:
22: NOTES: (Future/outstanding issues)
23:
24: - Powerfail not implemented.
25:
26: - IOCTL_INTERNAL_MOUSE_DISCONNECT has not been implemented. It's not
27: needed until the class unload routine is implemented. Right now,
28: we don't want to allow the mouse class driver to unload.
29:
30: - Consolidate duplicate code, where possible and appropriate.
31:
32: Revision History:
33:
34:
35: --*/
36:
37: #include "stdarg.h"
38: #include "stdio.h"
39: #include "string.h"
40: #include "ntddk.h"
41: #include "sermouse.h"
42: #include "sermlog.h"
43: #include "debug.h"
44:
45:
46: VOID
47: SerialMouseErrorLogDpc(
48: IN PKDPC Dpc,
49: IN PDEVICE_OBJECT DeviceObject,
50: IN PIRP Irp,
51: IN PVOID Context
52: )
53:
54: /*++
55:
56: Routine Description:
57:
58: This routine runs at DISPATCH_LEVEL IRQL to log errors that are
59: discovered at IRQL > DISPATCH_LEVEL (e.g., in the ISR routine or
60: in a routine that is executed via KeSynchronizeExecution). There
61: is not necessarily a current request associated with this condition.
62:
63: Arguments:
64:
65: Dpc - Pointer to the DPC object.
66:
67: DeviceObject - Pointer to the device object.
68:
69: Irp - Not used.
70:
71: Context - Indicates type of error to log.
72:
73: Return Value:
74:
75: None.
76:
77: --*/
78:
79: {
80: PDEVICE_EXTENSION deviceExtension;
81: PIO_ERROR_LOG_PACKET errorLogEntry;
82:
83: UNREFERENCED_PARAMETER(Dpc);
84: UNREFERENCED_PARAMETER(Irp);
85:
86: SerMouPrint((2, "SERMOUSE-SerialMouseErrorLogDpc: enter\n"));
87:
88: deviceExtension = DeviceObject->DeviceExtension;
89:
90: //
91: // Log an error packet.
92: //
93:
94: errorLogEntry = (PIO_ERROR_LOG_PACKET)IoAllocateErrorLogEntry(
95: DeviceObject,
96: sizeof(IO_ERROR_LOG_PACKET)
97: + (2 * sizeof(ULONG))
98: );
99: if (errorLogEntry != NULL) {
100:
101: errorLogEntry->DumpDataSize = 2 * sizeof(ULONG);
102:
103: if ((ULONG) Context == SERMOUSE_MOU_BUFFER_OVERFLOW) {
104: errorLogEntry->UniqueErrorValue = SERIAL_MOUSE_ERROR_VALUE_BASE + 210;
105: errorLogEntry->DumpData[0] = sizeof(MOUSE_INPUT_DATA);
106: errorLogEntry->DumpData[1] =
107: deviceExtension->Configuration.MouseAttributes.InputDataQueueLength;
108: } else {
109: errorLogEntry->UniqueErrorValue = SERIAL_MOUSE_ERROR_VALUE_BASE + 220;
110: errorLogEntry->DumpData[0] = 0;
111: errorLogEntry->DumpData[1] = 0;
112: }
113:
114: errorLogEntry->ErrorCode = (ULONG) Context;
115: errorLogEntry->SequenceNumber = 0;
116: errorLogEntry->MajorFunctionCode = 0;
117: errorLogEntry->IoControlCode = 0;
118: errorLogEntry->RetryCount = 0;
119: errorLogEntry->FinalStatus = 0;
120:
121: IoWriteErrorLogEntry(errorLogEntry);
122: }
123:
124: SerMouPrint((2, "SERMOUSE-SerialMouseErrorLogDpc: exit\n"));
125:
126: }
127:
128: NTSTATUS
129: SerialMouseFlush(
130: IN PDEVICE_OBJECT DeviceObject,
131: IN PIRP Irp
132: )
133: {
134: UNREFERENCED_PARAMETER(DeviceObject);
135: UNREFERENCED_PARAMETER(Irp);
136:
137: SerMouPrint((2,"SERMOUSE-SerialMouseFlush: enter\n"));
138: SerMouPrint((2,"SERMOUSE-SerialMouseFlush: exit\n"));
139:
140: return(STATUS_NOT_IMPLEMENTED);
141: }
142:
143: NTSTATUS
144: SerialMouseInternalDeviceControl(
145: IN PDEVICE_OBJECT DeviceObject,
146: IN PIRP Irp
147: )
148:
149: /*++
150:
151: Routine Description:
152:
153: This routine is the dispatch routine for internal device control requests.
154:
155: Arguments:
156:
157: DeviceObject - Pointer to the device object.
158:
159: Irp - Pointer to the request packet.
160:
161: Return Value:
162:
163: Status is returned.
164:
165: --*/
166:
167: {
168:
169: PIO_STACK_LOCATION irpSp;
170: PDEVICE_EXTENSION deviceExtension;
171: NTSTATUS status;
172:
173: SerMouPrint((2,"SERMOUSE-SerialMouseInternalDeviceControl: enter\n"));
174:
175: //
176: // Get a pointer to the device extension.
177: //
178:
179: deviceExtension = DeviceObject->DeviceExtension;
180:
181: //
182: // Initialize the returned Information field.
183: //
184:
185: Irp->IoStatus.Information = 0;
186:
187: //
188: // Get a pointer to the current parameters for this request. The
189: // information is contained in the current stack location.
190: //
191:
192: irpSp = IoGetCurrentIrpStackLocation(Irp);
193:
194: //
195: // Case on the device control subfunction that is being performed by the
196: // requestor.
197: //
198:
199: switch (irpSp->Parameters.DeviceIoControl.IoControlCode) {
200:
201: //
202: // Connect a mouse class device driver to the port driver.
203: //
204:
205: case IOCTL_INTERNAL_MOUSE_CONNECT:
206:
207: SerMouPrint((
208: 2,
209: "SERMOUSE-SerialMouseInternalDeviceControl: mouse connect\n"
210: ));
211:
212: //
213: // Only allow one connection.
214: //
215: // FUTURE: Consider allowing multiple connections, just for
216: // the sake of generality?
217: //
218:
219: if (deviceExtension->ConnectData.ClassService
220: != NULL) {
221:
222: SerMouPrint((
223: 2,
224: "SERMOUSE-SerialMouseInternalDeviceControl: error - already connected\n"
225: ));
226:
227: status = STATUS_SHARING_VIOLATION;
228: break;
229:
230: } else
231: if (irpSp->Parameters.DeviceIoControl.InputBufferLength <
232: sizeof(CONNECT_DATA)) {
233:
234: SerMouPrint((
235: 2,
236: "SERMOUSE-SerialMouseInternalDeviceControl: error - invalid buffer length\n"
237: ));
238:
239: status = STATUS_INVALID_PARAMETER;
240: break;
241: }
242:
243: //
244: // Copy the connection parameters to the device extension.
245: //
246:
247: deviceExtension->ConnectData =
248: *((PCONNECT_DATA) (irpSp->Parameters.DeviceIoControl.Type3InputBuffer));
249:
250: //
251: // Reinitialize the port input data queue synchronously.
252: //
253:
254: KeSynchronizeExecution(
255: deviceExtension->InterruptObject,
256: (PKSYNCHRONIZE_ROUTINE) SerMouInitializeDataQueue,
257: (PVOID) deviceExtension
258: );
259:
260: //
261: // Set the completion status.
262: //
263:
264: status = STATUS_SUCCESS;
265: break;
266:
267: //
268: // Disconnect a mouse class device driver from the port driver.
269: //
270: // NOTE: Not implemented.
271: //
272:
273: case IOCTL_INTERNAL_MOUSE_DISCONNECT:
274:
275: SerMouPrint((
276: 2,
277: "SERMOUSE-SerialMouseInternalDeviceControl: mouse disconnect\n"
278: ));
279:
280: //
281: // Perform a mouse interrupt disable call.
282: //
283:
284: //
285: // Clear the connection parameters in the device extension.
286: // NOTE: Must synchronize this with the mouse ISR.
287: //
288: //
289: //deviceExtension->ConnectData.ClassDeviceObject =
290: // Null;
291: //deviceExtension->ConnectData.ClassService =
292: // Null;
293:
294: //
295: // Set the completion status.
296: //
297:
298: status = STATUS_NOT_IMPLEMENTED;
299: break;
300:
301: //
302: // Enable mouse interrupts (mark the request pending and handle
303: // it in StartIo).
304: //
305:
306: case IOCTL_INTERNAL_MOUSE_ENABLE:
307:
308: SerMouPrint((
309: 2,
310: "SERMOUSE-SerialMouseInternalDeviceControl: mouse enable\n"
311: ));
312:
313: status = STATUS_PENDING;
314: break;
315:
316: //
317: // Disable mouse interrupts (mark the request pending and handle
318: // it in StartIo).
319: //
320:
321: case IOCTL_INTERNAL_MOUSE_DISABLE:
322:
323: SerMouPrint((
324: 2,
325: "SERMOUSE-SerialMouseInternalDeviceControl: mouse disable\n"
326: ));
327:
328: status = STATUS_PENDING;
329: break;
330:
331: //
332: // Query the mouse attributes. First check for adequate buffer
333: // length. Then, copy the mouse attributes from the device
334: // extension to the output buffer.
335: //
336:
337: case IOCTL_MOUSE_QUERY_ATTRIBUTES:
338:
339: SerMouPrint((
340: 2,
341: "SERMOUSE-SerialMouseInternalDeviceControl: mouse query attributes\n"
342: ));
343:
344: if (irpSp->Parameters.DeviceIoControl.OutputBufferLength <
345: sizeof(MOUSE_ATTRIBUTES)) {
346: status = STATUS_BUFFER_TOO_SMALL;
347: } else {
348:
349: //
350: // Copy the attributes from the DeviceExtension to the
351: // buffer.
352: //
353:
354: *(PMOUSE_ATTRIBUTES) Irp->AssociatedIrp.SystemBuffer =
355: deviceExtension->Configuration.MouseAttributes;
356:
357: Irp->IoStatus.Information = sizeof(MOUSE_ATTRIBUTES);
358: status = STATUS_SUCCESS;
359: }
360:
361: break;
362:
363: default:
364:
365: SerMouPrint((
366: 2,
367: "SERMOUSE-SerialMouseInternalDeviceControl: INVALID REQUEST\n"
368: ));
369:
370: status = STATUS_INVALID_DEVICE_REQUEST;
371: break;
372: }
373:
374: Irp->IoStatus.Status = status;
375: if (status == STATUS_PENDING) {
376: IoMarkIrpPending(Irp);
377: IoStartPacket(DeviceObject, Irp, (PULONG)NULL, NULL);
378: } else {
379: IoCompleteRequest(Irp, IO_NO_INCREMENT);
380: }
381:
382: SerMouPrint((2,"SERMOUSE-SerialMouseInternalDeviceControl: exit\n"));
383:
384: return(status);
385:
386: }
387:
388: BOOLEAN
389: SerialMouseInterruptService(
390: IN PKINTERRUPT Interrupt,
391: IN PVOID Context
392: )
393:
394: /*++
395:
396: Routine Description:
397:
398: This is the interrupt service routine for the mouse device.
399:
400: Arguments:
401:
402: Interrupt - A pointer to the interrupt object for this interrupt.
403:
404: Context - A pointer to the device object.
405:
406: Return Value:
407:
408: Returns TRUE if the interrupt was expected (and therefore processed);
409: otherwise, FALSE is returned.
410:
411: --*/
412:
413: {
414: PDEVICE_EXTENSION deviceExtension;
415: PDEVICE_OBJECT deviceObject;
416: PMOUSE_INPUT_DATA currentInput;
417: PUCHAR port;
418: UCHAR value;
419: UCHAR lineState;
420: ULONG buttonsDelta;
421:
422: UNREFERENCED_PARAMETER(Interrupt);
423:
424: SerMouPrint((2, "SERMOUSE-SerialMouseInterruptService: enter\n"));
425:
426: //
427: // Get the device extension.
428: //
429:
430: deviceObject = (PDEVICE_OBJECT) Context;
431: deviceExtension = (PDEVICE_EXTENSION) deviceObject->DeviceExtension;
432:
433: //
434: // Get the serial mouse port address.
435: //
436:
437: port = deviceExtension->Configuration.DeviceRegisters[0];
438:
439: //
440: // Verify that the interrupt really belongs to this driver.
441: //
442:
443: if ((READ_PORT_UCHAR((PUCHAR) (port + ACE_IIDR)) & ACE_IIP) == ACE_IIP) {
444:
445: //
446: // Not our interrupt.
447: //
448:
449: SerMouPrint((
450: 2,
451: "SERMOUSE-SerialMouseInterruptService: not our interrupt\n"
452: ));
453: return(FALSE);
454: }
455:
456: //
457: // Get the line state byte. This value can be checked by the
458: // protocol handler for errors.
459: //
460:
461: lineState = READ_PORT_UCHAR((PUCHAR) (port + ACE_LSR));
462: SerMouPrint((
463: 2,
464: "SERMOUSE-Line status: 0x%x\n", lineState
465: ));
466:
467: //
468: // Read the byte from the serial mouse port. If the mouse has not
469: // been enabled, don't process the byte further.
470: //
471:
472: value = READ_PORT_UCHAR((PUCHAR) port + ACE_RBR);
473:
474: SerMouPrint((
475: 2,
476: "SERMOUSE-SerialMouseInterruptService: byte 0x%x\n", value
477: ));
478:
479: if (deviceExtension->MouseEnableCount == 0) {
480: SerMouPrint((
481: 2,
482: "SERMOUSE-SerialMouseInterruptService: not enabled\n"
483: ));
484: return(TRUE);
485: }
486:
487: //
488: // At this point, the protocol handler should already be set because
489: // the hardware is enabled.
490: //
491:
492: ASSERT(deviceExtension->ProtocolHandler);
493:
494: currentInput = &deviceExtension->CurrentInput;
495:
496: //
497: // Call the current protocol handler for this device
498: //
499:
500: if ((*deviceExtension->ProtocolHandler)(
501: currentInput,
502: &deviceExtension->HandlerData,
503: value,
504: lineState
505: )){
506:
507: //
508: // The report is complete, compute the button deltas and queue it.
509: //
510:
511: currentInput->UnitId = deviceExtension->UnitId;
512: currentInput->Buttons = 0;
513:
514: //
515: // Do we have a button state change?
516: //
517:
518: if (deviceExtension->HandlerData.PreviousButtons ^ currentInput->RawButtons) {
519:
520:
521: //
522: // The state of the buttons changed. Make some calculations...
523: //
524:
525: buttonsDelta = deviceExtension->HandlerData.PreviousButtons ^
526: currentInput->RawButtons;
527:
528: //
529: // Button 1.
530: //
531:
532: if (buttonsDelta & MOUSE_BUTTON_1) {
533: if (currentInput->RawButtons & MOUSE_BUTTON_1) {
534: currentInput->Buttons |= MOUSE_BUTTON_1_DOWN;
535: }
536: else {
537: currentInput->Buttons |= MOUSE_BUTTON_1_UP;
538: }
539: }
540:
541: //
542: // Button 2.
543: //
544:
545: if (buttonsDelta & MOUSE_BUTTON_2) {
546: if (currentInput->RawButtons & MOUSE_BUTTON_2) {
547: currentInput->Buttons |= MOUSE_BUTTON_2_DOWN;
548: }
549: else {
550: currentInput->Buttons |= MOUSE_BUTTON_2_UP;
551: }
552: }
553:
554: //
555: // Button 3.
556: //
557:
558: if (buttonsDelta & MOUSE_BUTTON_3) {
559: if (currentInput->RawButtons & MOUSE_BUTTON_3) {
560: currentInput->Buttons |= MOUSE_BUTTON_3_DOWN;
561: }
562: else {
563: currentInput->Buttons |= MOUSE_BUTTON_3_UP;
564: }
565: }
566:
567: deviceExtension->HandlerData.PreviousButtons =
568: currentInput->RawButtons;
569:
570: }
571:
572: SerMouPrint((1, "SERMOUSE-Buttons: %0lx\n", currentInput->Buttons));
573:
574: SerMouSendReport(deviceObject);
575: }
576:
577: SerMouPrint((2, "SERMOUSE-SerialMouseInterruptService: exit\n"));
578:
579: return TRUE;
580: }
581:
582: VOID
583: SerialMouseIsrDpc(
584: IN PKDPC Dpc,
585: IN PDEVICE_OBJECT DeviceObject,
586: IN PIRP Irp,
587: IN PVOID Context
588: )
589:
590: /*++
591:
592: Routine Description:
593:
594: This routine runs at DISPATCH_LEVEL IRQL to finish processing
595: mouse interrupts. It is queued in the mouse ISR. The real
596: work is done via a callback to the connected mouse class driver.
597:
598: Arguments:
599:
600: Dpc - Pointer to the DPC object.
601:
602: DeviceObject - Pointer to the device object.
603:
604: Irp - Pointer to the Irp.
605:
606: Context - Not used.
607:
608: Return Value:
609:
610: None.
611:
612: --*/
613:
614: {
615:
616: PDEVICE_EXTENSION deviceExtension;
617: GET_DATA_POINTER_CONTEXT getPointerContext;
618: SET_DATA_POINTER_CONTEXT setPointerContext;
619: VARIABLE_OPERATION_CONTEXT operationContext;
620: PVOID classService;
621: PVOID classDeviceObject;
622: LONG interlockedResult;
623: BOOLEAN moreDpcProcessing;
624: ULONG dataNotConsumed = 0;
625: ULONG inputDataConsumed = 0;
626: LARGE_INTEGER deltaTime;
627:
628: UNREFERENCED_PARAMETER(Dpc);
629: UNREFERENCED_PARAMETER(Irp);
630: UNREFERENCED_PARAMETER(Context);
631:
632: SerMouPrint((2, "SERMOUSE-SerialMouseIsrDpc: enter\n"));
633:
634: deviceExtension = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension;
635:
636: //
637: // Use DpcInterlockVariable to determine whether the DPC is running
638: // concurrently on another processor. We only want one instantiation
639: // of the DPC to actually do any work. DpcInterlockVariable is -1
640: // when no DPC is executing. We increment it, and if the result is
641: // zero then the current instantiation is the only one executing, and it
642: // is okay to proceed. Otherwise, we just return.
643: //
644: //
645:
646: operationContext.VariableAddress =
647: &deviceExtension->DpcInterlockVariable;
648: operationContext.Operation = IncrementOperation;
649: operationContext.NewValue = &interlockedResult;
650:
651: KeSynchronizeExecution(
652: deviceExtension->InterruptObject,
653: (PKSYNCHRONIZE_ROUTINE) SerMouDpcVariableOperation,
654: (PVOID) &operationContext
655: );
656:
657: moreDpcProcessing = (interlockedResult == 0)? TRUE:FALSE;
658:
659: while (moreDpcProcessing) {
660:
661: dataNotConsumed = 0;
662: inputDataConsumed = 0;
663:
664: //
665: // Get the port InputData queue pointers synchronously.
666: //
667:
668: getPointerContext.DeviceExtension = deviceExtension;
669: setPointerContext.DeviceExtension = deviceExtension;
670: setPointerContext.InputCount = 0;
671:
672: KeSynchronizeExecution(
673: deviceExtension->InterruptObject,
674: (PKSYNCHRONIZE_ROUTINE) SerMouGetDataQueuePointer,
675: (PVOID) &getPointerContext
676: );
677:
678: if (getPointerContext.InputCount != 0) {
679:
680: //
681: // Call the connected class driver's callback ISR with the
682: // port InputData queue pointers. If we have to wrap the queue,
683: // break the operation into two pieces, and call the class callback
684: // ISR once for each piece.
685: //
686:
687: classDeviceObject =
688: deviceExtension->ConnectData.ClassDeviceObject;
689: classService =
690: deviceExtension->ConnectData.ClassService;
691: ASSERT(classService != NULL);
692:
693: if (getPointerContext.DataOut >= getPointerContext.DataIn) {
694:
695: //
696: // We'll have to wrap the InputData circular buffer. Call
697: // the class callback ISR with the chunk of data starting at
698: // DataOut and ending at the end of the queue.
699: //
700:
701: SerMouPrint((
702: 2,
703: "SERMOUSE-SerialMouseIsrDpc: calling class callback\n"
704: ));
705: SerMouPrint((
706: 2,
707: "SERMOUSE-SerialMouseIsrDpc: with Start 0x%x and End 0x%x\n",
708: getPointerContext.DataOut,
709: deviceExtension->DataEnd
710: ));
711:
712: (*(PSERVICE_CALLBACK_ROUTINE) classService)(
713: classDeviceObject,
714: getPointerContext.DataOut,
715: deviceExtension->DataEnd,
716: &inputDataConsumed
717: );
718:
719: dataNotConsumed = (((PUCHAR)
720: deviceExtension->DataEnd -
721: (PUCHAR) getPointerContext.DataOut)
722: / sizeof(MOUSE_INPUT_DATA)) - inputDataConsumed;
723:
724: SerMouPrint((
725: 2,
726: "SERMOUSE-SerialMouseIsrDpc: (Wrap) Call callback consumed %d items, left %d\n",
727: inputDataConsumed,
728: dataNotConsumed
729: ));
730:
731: setPointerContext.InputCount += inputDataConsumed;
732:
733: if (dataNotConsumed) {
734: setPointerContext.DataOut =
735: ((PUCHAR)getPointerContext.DataOut) +
736: (inputDataConsumed * sizeof(MOUSE_INPUT_DATA));
737: } else {
738: setPointerContext.DataOut =
739: deviceExtension->InputData;
740: getPointerContext.DataOut = setPointerContext.DataOut;
741: }
742: }
743:
744: //
745: // Call the class callback ISR with data remaining in the queue.
746: //
747:
748: if ((dataNotConsumed == 0) &&
749: (inputDataConsumed < getPointerContext.InputCount)){
750: SerMouPrint((
751: 2,
752: "SERMOUSE-SerialMouseIsrDpc: calling class callback\n"
753: ));
754: SerMouPrint((
755: 2,
756: "SERMOUSE-SerialMouseIsrDpc: with Start 0x%x and End 0x%x\n",
757: getPointerContext.DataOut,
758: getPointerContext.DataIn
759: ));
760:
761: (*(PSERVICE_CALLBACK_ROUTINE) classService)(
762: classDeviceObject,
763: getPointerContext.DataOut,
764: getPointerContext.DataIn,
765: &inputDataConsumed
766: );
767:
768: dataNotConsumed = (((PUCHAR) getPointerContext.DataIn -
769: (PUCHAR) getPointerContext.DataOut)
770: / sizeof(MOUSE_INPUT_DATA)) - inputDataConsumed;
771:
772: SerMouPrint((
773: 2,
774: "SERMOUSE-SerialMouseIsrDpc: Call callback consumed %d items, left %d\n",
775: inputDataConsumed,
776: dataNotConsumed
777: ));
778:
779: setPointerContext.DataOut =
780: ((PUCHAR)getPointerContext.DataOut) +
781: (inputDataConsumed * sizeof(MOUSE_INPUT_DATA));
782: setPointerContext.InputCount += inputDataConsumed;
783:
784: }
785:
786: //
787: // Update the port InputData queue DataOut pointer and InputCount
788: // synchronously.
789: //
790:
791: KeSynchronizeExecution(
792: deviceExtension->InterruptObject,
793: (PKSYNCHRONIZE_ROUTINE) SerMouSetDataQueuePointer,
794: (PVOID) &setPointerContext
795: );
796:
797: }
798:
799: if (dataNotConsumed) {
800:
801: //
802: // The class driver was unable to consume all the data.
803: // Reset the interlocked variable to -1. We do not want
804: // to attempt to move more data to the class driver at this
805: // point, because it is already overloaded. Need to wait a
806: // while to give the Raw Input Thread a chance to read some
807: // of the data out of the class driver's queue. We accomplish
808: // this "wait" via a timer.
809: //
810:
811: SerMouPrint((2, "SERMOUSE-SerialMouseIsrDpc: set timer in DPC\n"));
812:
813: operationContext.Operation = WriteOperation;
814: interlockedResult = -1;
815: operationContext.NewValue = &interlockedResult;
816:
817: KeSynchronizeExecution(
818: deviceExtension->InterruptObject,
819: (PKSYNCHRONIZE_ROUTINE) SerMouDpcVariableOperation,
820: (PVOID) &operationContext
821: );
822:
823: deltaTime.LowPart = (ULONG)(-10 * 1000 * 1000);
824: deltaTime.HighPart = -1;
825:
826: (VOID) KeSetTimer(
827: &deviceExtension->DataConsumptionTimer,
828: deltaTime,
829: &deviceExtension->IsrDpcRetry
830: );
831:
832: moreDpcProcessing = FALSE;
833:
834: } else {
835:
836: //
837: // Decrement DpcInterlockVariable. If the result goes negative,
838: // then we're all finished processing the DPC. Otherwise, either
839: // the ISR incremented DpcInterlockVariable because it has more
840: // work for the ISR DPC to do, or a concurrent DPC executed on
841: // some processor while the current DPC was running (the
842: // concurrent DPC wouldn't have done any work). Make sure that
843: // the current DPC handles any extra work that is ready to be
844: // done.
845: //
846:
847: operationContext.Operation = DecrementOperation;
848: operationContext.NewValue = &interlockedResult;
849:
850: KeSynchronizeExecution(
851: deviceExtension->InterruptObject,
852: (PKSYNCHRONIZE_ROUTINE) SerMouDpcVariableOperation,
853: (PVOID) &operationContext
854: );
855:
856: if (interlockedResult != -1) {
857:
858: //
859: // The interlocked variable is still greater than or equal to
860: // zero. Reset it to zero, so that we execute the loop one
861: // more time (assuming no more DPCs execute and bump the
862: // variable up again).
863: //
864:
865: operationContext.Operation = WriteOperation;
866: interlockedResult = 0;
867: operationContext.NewValue = &interlockedResult;
868:
869: KeSynchronizeExecution(
870: deviceExtension->InterruptObject,
871: (PKSYNCHRONIZE_ROUTINE) SerMouDpcVariableOperation,
872: (PVOID) &operationContext
873: );
874:
875: SerMouPrint((2, "SERMOUSE-SerialMouseIsrDpc: loop in DPC\n"));
876: } else {
877: moreDpcProcessing = FALSE;
878: }
879: }
880: }
881:
882: SerMouPrint((2, "SERMOUSE-SerialMouseIsrDpc: exit\n"));
883:
884: }
885:
886: NTSTATUS
887: SerialMouseOpenClose(
888: IN PDEVICE_OBJECT DeviceObject,
889: IN PIRP Irp
890: )
891:
892: /*++
893:
894: Routine Description:
895:
896: This is the dispatch routine for create/open and close requests.
897: These requests complete successfully.
898:
899: Arguments:
900:
901: DeviceObject - Pointer to the device object.
902:
903: Irp - Pointer to the request packet.
904:
905: Return Value:
906:
907: Status is returned.
908:
909: --*/
910:
911: {
912:
913: UNREFERENCED_PARAMETER(DeviceObject);
914:
915: SerMouPrint((3,"SERMOUSE-SerialMouseOpenClose: enter\n"));
916:
917: //
918: // Complete the request with successful status.
919: //
920:
921: Irp->IoStatus.Status = STATUS_SUCCESS;
922: Irp->IoStatus.Information = 0;
923: IoCompleteRequest(Irp, IO_NO_INCREMENT);
924:
925: SerMouPrint((3,"SERMOUSE-SerialMouseOpenClose: exit\n"));
926:
927: return(STATUS_SUCCESS);
928:
929: } // end SerialMouseOpenClose
930:
931: VOID
932: SerialMouseStartIo(
933: IN PDEVICE_OBJECT DeviceObject,
934: IN PIRP Irp
935: )
936:
937: /*++
938:
939: Routine Description:
940:
941: This routine starts an I/O operation for the device.
942:
943: Arguments:
944:
945: DeviceObject - Pointer to the device object.
946:
947: Irp - Pointer to the request packet.
948:
949: Return Value:
950:
951: None.
952:
953: --*/
954:
955: {
956: PDEVICE_EXTENSION deviceExtension;
957: PIO_STACK_LOCATION irpSp;
958:
959: SerMouPrint((2, "SERMOUSE-SerialMouseStartIo: enter\n"));
960:
961: deviceExtension = DeviceObject->DeviceExtension;
962:
963: //
964: // Bump the error log sequence number.
965: //
966:
967: deviceExtension->SequenceNumber += 1;
968:
969: //
970: // Get a pointer to the current parameters for this request. The
971: // information is contained in the current stack location.
972: //
973:
974: irpSp = IoGetCurrentIrpStackLocation(Irp);
975:
976: //
977: // We know we got here with an internal device control request. Switch
978: // on IoControlCode.
979: //
980:
981: switch(irpSp->Parameters.DeviceIoControl.IoControlCode) {
982:
983: //
984: // Enable mouse interrupts, by calling SerMouEnableInterrupts
985: // synchronously.
986: //
987:
988: case IOCTL_INTERNAL_MOUSE_ENABLE:
989:
990: KeSynchronizeExecution(
991: deviceExtension->InterruptObject,
992: (PKSYNCHRONIZE_ROUTINE) SerMouEnableInterrupts,
993: (PVOID) deviceExtension
994: );
995:
996: SerMouPrint((
997: 2,
998: "SERMOUSE-SerialMouseStartIo: mouse enable (count %d)\n",
999: deviceExtension->MouseEnableCount
1000: ));
1001:
1002: Irp->IoStatus.Status = STATUS_SUCCESS;
1003:
1004: //
1005: // Complete the request.
1006: //
1007:
1008: IoStartNextPacket(DeviceObject, FALSE);
1009: IoCompleteRequest(Irp, IO_MOUSE_INCREMENT);
1010:
1011: break;
1012:
1013: //
1014: // Disable mouse interrupts, by calling SerMouDisableInterrupts
1015: // synchronously.
1016: //
1017:
1018: case IOCTL_INTERNAL_MOUSE_DISABLE:
1019:
1020: SerMouPrint((2, "SERMOUSE-SerialMouseStartIo: mouse disable"));
1021:
1022: if (deviceExtension->MouseEnableCount == 0) {
1023:
1024: //
1025: // Mouse already disabled.
1026: //
1027:
1028: SerMouPrint((2, " - error\n"));
1029:
1030: Irp->IoStatus.Status = STATUS_DEVICE_DATA_ERROR;
1031:
1032: } else {
1033:
1034: //
1035: // Disable mouse by calling SerMouDisableInterrupts.
1036: //
1037:
1038: KeSynchronizeExecution(
1039: deviceExtension->InterruptObject,
1040: (PKSYNCHRONIZE_ROUTINE) SerMouDisableInterrupts,
1041: (PVOID) deviceExtension
1042: );
1043:
1044: SerMouPrint((
1045: 2,
1046: " (count %d)\n",
1047: deviceExtension->MouseEnableCount
1048: ));
1049:
1050: Irp->IoStatus.Status = STATUS_SUCCESS;
1051: }
1052:
1053: //
1054: // Complete the request.
1055: //
1056:
1057: IoStartNextPacket(DeviceObject, FALSE);
1058: IoCompleteRequest(Irp, IO_MOUSE_INCREMENT);
1059:
1060: break;
1061:
1062: default:
1063:
1064: SerMouPrint((2, "SERMOUSE-SerialMouseStartIo: INVALID REQUEST\n"));
1065:
1066: //
1067: // Log an internal error. Note that we're calling the
1068: // error log DPC routine directly, rather than duplicating
1069: // code.
1070: //
1071:
1072: SerialMouseErrorLogDpc(
1073: (PKDPC) NULL,
1074: DeviceObject,
1075: Irp,
1076: (PVOID) (ULONG) SERMOUSE_INVALID_STARTIO_REQUEST
1077: );
1078:
1079:
1080: ASSERT(FALSE);
1081: break;
1082: }
1083:
1084: SerMouPrint((2, "SERMOUSE-SerialMouseStartIo: exit\n"));
1085:
1086: return;
1087: }
1088:
1089: VOID
1090: SerMouDpcVariableOperation(
1091: IN PVOID Context
1092: )
1093:
1094: /*++
1095:
1096: Routine Description:
1097:
1098: This routine is called synchronously by the ISR DPC to perform an
1099: operation on the InterlockedDpcVariable. The operations that can be
1100: performed include increment, decrement, write, and read. The ISR
1101: itself reads and writes the InterlockedDpcVariable without calling this
1102: routine.
1103:
1104: Arguments:
1105:
1106: Context - Pointer to a structure containing the address of the variable
1107: to be operated on, the operation to perform, and the address at
1108: which to copy the resulting value of the variable (the latter is also
1109: used to pass in the value to write to the variable, on a write
1110: operation).
1111:
1112: Return Value:
1113:
1114: None.
1115:
1116: --*/
1117:
1118: {
1119: PVARIABLE_OPERATION_CONTEXT operationContext = Context;
1120:
1121: SerMouPrint((3,"SERMOUSE-SerMouDpcVariableOperation: enter\n"));
1122: SerMouPrint((
1123: 3,
1124: "\tPerforming %s at 0x%x (current value 0x%x)\n",
1125: (operationContext->Operation == IncrementOperation)? "increment":
1126: (operationContext->Operation == DecrementOperation)? "decrement":
1127: (operationContext->Operation == WriteOperation)? "write":
1128: (operationContext->Operation == ReadOperation)? "read":"",
1129: operationContext->VariableAddress,
1130: *(operationContext->VariableAddress)
1131: ));
1132:
1133: //
1134: // Perform the specified operation at the specified address.
1135: //
1136:
1137: switch(operationContext->Operation) {
1138: case IncrementOperation:
1139: *(operationContext->VariableAddress) += 1;
1140: break;
1141: case DecrementOperation:
1142: *(operationContext->VariableAddress) -= 1;
1143: break;
1144: case ReadOperation:
1145: break;
1146: case WriteOperation:
1147: SerMouPrint((
1148: 3,
1149: "\tWriting 0x%x\n",
1150: *(operationContext->NewValue)
1151: ));
1152: *(operationContext->VariableAddress) =
1153: *(operationContext->NewValue);
1154: break;
1155: default:
1156: ASSERT(FALSE);
1157: break;
1158: }
1159:
1160: *(operationContext->NewValue) = *(operationContext->VariableAddress);
1161:
1162: SerMouPrint((
1163: 3,
1164: "SERMOUSE-SerMouDpcVariableOperation: exit with value 0x%x\n",
1165: *(operationContext->NewValue)
1166: ));
1167: }
1168:
1169: VOID
1170: SerMouGetDataQueuePointer(
1171: IN PVOID Context
1172: )
1173:
1174: /*++
1175:
1176: Routine Description:
1177:
1178: This routine is called synchronously to get the current DataIn and DataOut
1179: pointers for the port InputData queue.
1180:
1181: Arguments:
1182:
1183: Context - Pointer to a structure containing the device extension,
1184: address at which to store the current DataIn pointer, and the
1185: address at which to store the current DataOut pointer.
1186:
1187: Return Value:
1188:
1189: None.
1190:
1191: --*/
1192:
1193: {
1194: PDEVICE_EXTENSION deviceExtension;
1195:
1196: SerMouPrint((3,"SERMOUSE-SerMouGetDataQueuePointer: enter\n"));
1197:
1198: //
1199: // Get address of device extension.
1200: //
1201:
1202: deviceExtension = (PDEVICE_EXTENSION)
1203: ((PGET_DATA_POINTER_CONTEXT) Context)->DeviceExtension;
1204:
1205: //
1206: // Get the DataIn and DataOut pointers.
1207: //
1208:
1209: SerMouPrint((
1210: 3,
1211: "SERMOUSE-SerMouGetDataQueuePointer: DataIn 0x%x, DataOut 0x%x\n",
1212: deviceExtension->DataIn,
1213: deviceExtension->DataOut
1214: ));
1215: ((PGET_DATA_POINTER_CONTEXT) Context)->DataIn = deviceExtension->DataIn;
1216: ((PGET_DATA_POINTER_CONTEXT) Context)->DataOut = deviceExtension->DataOut;
1217: ((PGET_DATA_POINTER_CONTEXT) Context)->InputCount =
1218: deviceExtension->InputCount;
1219:
1220: SerMouPrint((3,"SERMOUSE-SerMouGetDataQueuePointer: exit\n"));
1221: }
1222:
1223: VOID
1224: SerMouInitializeDataQueue (
1225: IN PVOID Context
1226: )
1227:
1228: /*++
1229:
1230: Routine Description:
1231:
1232: This routine initializes the input data queue. It is called
1233: via KeSynchronization, except when called from the initialization routine.
1234:
1235: Arguments:
1236:
1237: Context - Pointer to the device extension.
1238:
1239: Return Value:
1240:
1241: None.
1242:
1243: --*/
1244:
1245: {
1246:
1247: PDEVICE_EXTENSION deviceExtension;
1248:
1249: SerMouPrint((3,"SERMOUSE-SerMouInitializeDataQueue: enter\n"));
1250:
1251: //
1252: // Get address of device extension.
1253: //
1254:
1255: deviceExtension = (PDEVICE_EXTENSION) Context;
1256:
1257: //
1258: // Initialize the input data queue.
1259: //
1260:
1261: deviceExtension->InputCount = 0;
1262: deviceExtension->DataIn = deviceExtension->InputData;
1263: deviceExtension->DataOut = deviceExtension->InputData;
1264:
1265: deviceExtension->OkayToLogOverflow = TRUE;
1266:
1267: SerMouPrint((3,"SERMOUSE-SerMouInitializeDataQueue: exit\n"));
1268:
1269: } // end SerMouInitializeDataQueue
1270:
1271: VOID
1272: SerMouSendReport(
1273: IN PDEVICE_OBJECT DeviceObject
1274: )
1275: /*++
1276:
1277: Routine Description:
1278:
1279: Place a completed report in the queue for subsequent processing by a DPC.
1280:
1281: Arguments:
1282:
1283: Device Object - Pointer to the device object.
1284:
1285: Return Value:
1286:
1287: None.
1288:
1289: --*/
1290:
1291: {
1292: PDEVICE_EXTENSION deviceExtension;
1293:
1294: deviceExtension = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension;
1295:
1296: if (!SerMouWriteDataToQueue(
1297: deviceExtension,
1298: &deviceExtension->CurrentInput
1299: )) {
1300:
1301: //
1302: // The mouse input data queue is full. Just drop the
1303: // latest input on the floor.
1304: //
1305: // Queue a DPC to log an overrun error.
1306: //
1307:
1308: SerMouPrint((
1309: 1,
1310: "SERMOUSE-SerMouSendReport: queue overflow\n"
1311: ));
1312:
1313: if (deviceExtension->OkayToLogOverflow) {
1314: KeInsertQueueDpc(
1315: &deviceExtension->ErrorLogDpc,
1316: (PIRP) NULL,
1317: (PVOID) (ULONG) SERMOUSE_MOU_BUFFER_OVERFLOW
1318: );
1319: deviceExtension->OkayToLogOverflow = FALSE;
1320: }
1321:
1322: } else if (deviceExtension->DpcInterlockVariable >= 0) {
1323:
1324: //
1325: // The ISR DPC is already executing. Tell the ISR DPC it has
1326: // more work to do by incrementing the DpcInterlockVariable.
1327: //
1328:
1329: deviceExtension->DpcInterlockVariable += 1;
1330:
1331: } else {
1332:
1333: //
1334: // Queue the ISR DPC.
1335: //
1336:
1337: KeInsertQueueDpc(
1338: &deviceExtension->IsrDpc,
1339: DeviceObject->CurrentIrp,
1340: NULL
1341: );
1342:
1343: }
1344:
1345: return;
1346: }
1347:
1348: VOID
1349: SerMouSetDataQueuePointer(
1350: IN PVOID Context
1351: )
1352:
1353: /*++
1354:
1355: Routine Description:
1356:
1357: This routine is called synchronously to set the DataOut pointer
1358: and InputCount for the port InputData queue.
1359:
1360: Arguments:
1361:
1362: Context - Pointer to a structure containing the device extension
1363: and the new DataOut value for the port InputData queue.
1364:
1365: Return Value:
1366:
1367: None.
1368:
1369: --*/
1370:
1371: {
1372: PDEVICE_EXTENSION deviceExtension;
1373:
1374: SerMouPrint((3,"SERMOUSE-SerMouSetDataQueuePointer: enter\n"));
1375:
1376: //
1377: // Get address of device extension.
1378: //
1379:
1380: deviceExtension = (PDEVICE_EXTENSION)
1381: ((PSET_DATA_POINTER_CONTEXT) Context)->DeviceExtension;
1382:
1383: //
1384: // Set the DataOut pointer.
1385: //
1386:
1387: SerMouPrint((
1388: 3,
1389: "SERMOUSE-SerMouSetDataQueuePointer: old mouse DataOut 0x%x, InputCount %d\n",
1390: deviceExtension->DataOut,
1391: deviceExtension->InputCount
1392: ));
1393: deviceExtension->DataOut = ((PSET_DATA_POINTER_CONTEXT) Context)->DataOut;
1394: deviceExtension->InputCount -=
1395: ((PSET_DATA_POINTER_CONTEXT) Context)->InputCount;
1396:
1397: if (deviceExtension->InputCount == 0) {
1398:
1399: //
1400: // Reset the flag that determines whether it is time to log
1401: // queue overflow errors. We don't want to log errors too often.
1402: // Instead, log an error on the first overflow that occurs after
1403: // the ring buffer has been emptied, and then stop logging errors
1404: // until it gets cleared out and overflows again.
1405: //
1406:
1407: SerMouPrint((
1408: 1,
1409: "SERMOUSE-SerMouSetDataQueuePointer: Okay to log overflow\n"
1410: ));
1411: deviceExtension->OkayToLogOverflow = TRUE;
1412: }
1413:
1414: SerMouPrint((
1415: 3,
1416: "SERMOUSE-SerMouSetDataQueuePointer: new mouse DataOut 0x%x, InputCount %d\n",
1417: deviceExtension->DataOut,
1418: deviceExtension->InputCount
1419: ));
1420:
1421: SerMouPrint((3,"SERMOUSE-SerMouSetDataQueuePointer: exit\n"));
1422: }
1423:
1424: BOOLEAN
1425: SerMouWriteDataToQueue(
1426: PDEVICE_EXTENSION DeviceExtension,
1427: IN PMOUSE_INPUT_DATA InputData
1428: )
1429:
1430: /*++
1431:
1432: Routine Description:
1433:
1434: This routine adds input data from the mouse to the InputData queue.
1435:
1436: Arguments:
1437:
1438: DeviceExtension - Pointer to the device extension.
1439:
1440: InputData - Pointer to the data to add to the InputData queue.
1441:
1442: Return Value:
1443:
1444: Returns TRUE if the data was added, otherwise FALSE.
1445:
1446: --*/
1447:
1448: {
1449:
1450: SerMouPrint((2,"SERMOUSE-SerMouWriteDataToQueue: enter\n"));
1451: SerMouPrint((
1452: 3,
1453: "SERMOUSE-SerMouWriteDataToQueue: DataIn 0x%x, DataOut 0x%x\n",
1454: DeviceExtension->DataIn,
1455: DeviceExtension->DataOut
1456: ));
1457: SerMouPrint((
1458: 3,
1459: "SERMOUSE-SerMouWriteDataToQueue: InputCount %d\n",
1460: DeviceExtension->InputCount
1461: ));
1462:
1463: //
1464: // Check for full input data queue.
1465: //
1466:
1467: if ((DeviceExtension->DataIn == DeviceExtension->DataOut) &&
1468: (DeviceExtension->InputCount != 0)) {
1469:
1470: //
1471: // The input data queue is full. Intentionally ignore
1472: // the new data.
1473: //
1474:
1475: SerMouPrint((1,"SERMOUSE-SerMouWriteDataToQueue: OVERFLOW\n"));
1476: return(FALSE);
1477:
1478: } else {
1479: *(DeviceExtension->DataIn) = *InputData;
1480: DeviceExtension->InputCount += 1;
1481: DeviceExtension->DataIn++;
1482: SerMouPrint((
1483: 2,
1484: "SERMOUSE-SerMouWriteDataToQueue: new InputCount %d\n",
1485: DeviceExtension->InputCount
1486: ));
1487: if (DeviceExtension->DataIn ==
1488: DeviceExtension->DataEnd) {
1489: SerMouPrint((2,"SERMOUSE-SerMouWriteDataToQueue: wrap buffer\n"));
1490: DeviceExtension->DataIn = DeviceExtension->InputData;
1491: }
1492: }
1493:
1494: SerMouPrint((2,"SERMOUSE-SerMouWriteDataToQueue: exit\n"));
1495:
1496: return(TRUE);
1497: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.