|
|
1.1 root 1:
2: /*++
3:
4: Copyright (c) 1990, 1991, 1992, 1993 Microsoft Corporation
5:
6: Module Name:
7:
8: moucmn.c
9:
10: Abstract:
11:
12: The common portions of the Intel i8042 port driver which
13: apply to the auxiliary (PS/2 mouse) device.
14:
15: Environment:
16:
17: Kernel mode only.
18:
19: Notes:
20:
21: NOTES: (Future/outstanding issues)
22:
23: - Powerfail not implemented.
24:
25: - Consolidate duplicate code, where possible and appropriate.
26:
27: Revision History:
28:
29: --*/
30:
31: #include "stdarg.h"
32: #include "stdio.h"
33: #include "string.h"
34: #include "ntddk.h"
35: #include "i8042prt.h"
36:
37:
38: VOID
39: I8042MouseIsrDpc(
40: IN PKDPC Dpc,
41: IN PDEVICE_OBJECT DeviceObject,
42: IN PIRP Irp,
43: IN PVOID Context
44: )
45:
46: /*++
47:
48: Routine Description:
49:
50: This routine runs at DISPATCH_LEVEL IRQL to finish processing
51: mouse interrupts. It is queued in the mouse ISR. The real
52: work is done via a callback to the connected mouse class driver.
53:
54: Arguments:
55:
56: Dpc - Pointer to the DPC object.
57:
58: DeviceObject - Pointer to the device object.
59:
60: Irp - Pointer to the Irp.
61:
62: Context - Not used.
63:
64: Return Value:
65:
66: None.
67:
68: --*/
69:
70: {
71:
72: PDEVICE_EXTENSION deviceExtension;
73: GET_DATA_POINTER_CONTEXT getPointerContext;
74: SET_DATA_POINTER_CONTEXT setPointerContext;
75: VARIABLE_OPERATION_CONTEXT operationContext;
76: PVOID classService;
77: PVOID classDeviceObject;
78: LONG interlockedResult;
79: BOOLEAN moreDpcProcessing;
80: ULONG dataNotConsumed = 0;
81: ULONG inputDataConsumed = 0;
82: LARGE_INTEGER deltaTime;
83:
84: UNREFERENCED_PARAMETER(Dpc);
85: UNREFERENCED_PARAMETER(Irp);
86: UNREFERENCED_PARAMETER(Context);
87:
88: I8xPrint((2, "I8042PRT-I8042MouseIsrDpc: enter\n"));
89:
90: deviceExtension = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension;
91:
92: //
93: // Use DpcInterlockMouse to determine whether the DPC is running
94: // concurrently on another processor. We only want one instantiation
95: // of the DPC to actually do any work. DpcInterlockMouse is -1
96: // when no DPC is executing. We increment it, and if the result is
97: // zero then the current instantiation is the only one executing, and it
98: // is okay to proceed. Otherwise, we just return.
99: //
100: //
101:
102: operationContext.VariableAddress =
103: &deviceExtension->DpcInterlockMouse;
104: operationContext.Operation = IncrementOperation;
105: operationContext.NewValue = &interlockedResult;
106:
107: KeSynchronizeExecution(
108: deviceExtension->MouseInterruptObject,
109: (PKSYNCHRONIZE_ROUTINE) I8xDpcVariableOperation,
110: (PVOID) &operationContext
111: );
112:
113: moreDpcProcessing = (interlockedResult == 0)? TRUE:FALSE;
114:
115: while (moreDpcProcessing) {
116:
117: dataNotConsumed = 0;
118: inputDataConsumed = 0;
119:
120: //
121: // Get the port InputData queue pointers synchronously.
122: //
123:
124: getPointerContext.DeviceExtension = deviceExtension;
125: setPointerContext.DeviceExtension = deviceExtension;
126: getPointerContext.DeviceType = (CCHAR) MouseDeviceType;
127: setPointerContext.DeviceType = (CCHAR) MouseDeviceType;
128: setPointerContext.InputCount = 0;
129:
130: KeSynchronizeExecution(
131: deviceExtension->MouseInterruptObject,
132: (PKSYNCHRONIZE_ROUTINE) I8xGetDataQueuePointer,
133: (PVOID) &getPointerContext
134: );
135:
136: if (getPointerContext.InputCount != 0) {
137:
138: //
139: // Call the connected class driver's callback ISR with the
140: // port InputData queue pointers. If we have to wrap the queue,
141: // break the operation into two pieces, and call the class callback
142: // ISR once for each piece.
143: //
144:
145: classDeviceObject =
146: deviceExtension->MouseExtension.ConnectData.ClassDeviceObject;
147: classService =
148: deviceExtension->MouseExtension.ConnectData.ClassService;
149: ASSERT(classService != NULL);
150:
151: if (getPointerContext.DataOut >= getPointerContext.DataIn) {
152:
153: //
154: // We'll have to wrap the InputData circular buffer. Call
155: // the class callback ISR with the chunk of data starting at
156: // DataOut and ending at the end of the queue.
157: //
158:
159: I8xPrint((
160: 2,
161: "I8042PRT-I8042MouseIsrDpc: calling class callback\n"
162: ));
163: I8xPrint((
164: 2,
165: "I8042PRT-I8042MouseIsrDpc: with Start 0x%x and End 0x%x\n",
166: getPointerContext.DataOut,
167: deviceExtension->MouseExtension.DataEnd
168: ));
169:
170: (*(PSERVICE_CALLBACK_ROUTINE) classService)(
171: classDeviceObject,
172: getPointerContext.DataOut,
173: deviceExtension->MouseExtension.DataEnd,
174: &inputDataConsumed
175: );
176:
177: dataNotConsumed = (((PUCHAR)
178: deviceExtension->MouseExtension.DataEnd -
179: (PUCHAR) getPointerContext.DataOut)
180: / sizeof(MOUSE_INPUT_DATA)) - inputDataConsumed;
181:
182: I8xPrint((
183: 2,
184: "I8042PRT-I8042MouseIsrDpc: (Wrap) Call callback consumed %d items, left %d\n",
185: inputDataConsumed,
186: dataNotConsumed
187: ));
188:
189: setPointerContext.InputCount += inputDataConsumed;
190:
191: if (dataNotConsumed) {
192: setPointerContext.DataOut =
193: ((PUCHAR)getPointerContext.DataOut) +
194: (inputDataConsumed * sizeof(MOUSE_INPUT_DATA));
195: } else {
196: setPointerContext.DataOut =
197: deviceExtension->MouseExtension.InputData;
198: getPointerContext.DataOut = setPointerContext.DataOut;
199: }
200: }
201:
202: //
203: // Call the class callback ISR with data remaining in the queue.
204: //
205:
206: if ((dataNotConsumed == 0) &&
207: (inputDataConsumed < getPointerContext.InputCount)){
208: I8xPrint((
209: 2,
210: "I8042PRT-I8042MouseIsrDpc: calling class callback\n"
211: ));
212: I8xPrint((
213: 2,
214: "I8042PRT-I8042MouseIsrDpc: with Start 0x%x and End 0x%x\n",
215: getPointerContext.DataOut,
216: getPointerContext.DataIn
217: ));
218:
219: (*(PSERVICE_CALLBACK_ROUTINE) classService)(
220: classDeviceObject,
221: getPointerContext.DataOut,
222: getPointerContext.DataIn,
223: &inputDataConsumed
224: );
225:
226: dataNotConsumed = (((PUCHAR) getPointerContext.DataIn -
227: (PUCHAR) getPointerContext.DataOut)
228: / sizeof(MOUSE_INPUT_DATA)) - inputDataConsumed;
229:
230: I8xPrint((
231: 2,
232: "I8042PRT-I8042MouseIsrDpc: Call callback consumed %d items, left %d\n",
233: inputDataConsumed,
234: dataNotConsumed
235: ));
236:
237: setPointerContext.DataOut =
238: ((PUCHAR)getPointerContext.DataOut) +
239: (inputDataConsumed * sizeof(MOUSE_INPUT_DATA));
240: setPointerContext.InputCount += inputDataConsumed;
241:
242: }
243:
244: //
245: // Update the port InputData queue DataOut pointer and InputCount
246: // synchronously.
247: //
248:
249: KeSynchronizeExecution(
250: deviceExtension->MouseInterruptObject,
251: (PKSYNCHRONIZE_ROUTINE) I8xSetDataQueuePointer,
252: (PVOID) &setPointerContext
253: );
254:
255: }
256:
257: if (dataNotConsumed) {
258:
259: //
260: // The class driver was unable to consume all the data.
261: // Reset the interlocked variable to -1. We do not want
262: // to attempt to move more data to the class driver at this
263: // point, because it is already overloaded. Need to wait a
264: // while to give the Raw Input Thread a chance to read some
265: // of the data out of the class driver's queue. We accomplish
266: // this "wait" via a timer.
267: //
268:
269: I8xPrint((2, "I8042PRT-I8042MouseIsrDpc: set timer in DPC\n"));
270:
271: operationContext.Operation = WriteOperation;
272: interlockedResult = -1;
273: operationContext.NewValue = &interlockedResult;
274:
275: KeSynchronizeExecution(
276: deviceExtension->MouseInterruptObject,
277: (PKSYNCHRONIZE_ROUTINE) I8xDpcVariableOperation,
278: (PVOID) &operationContext
279: );
280:
281: deltaTime.LowPart = (ULONG)(-10 * 1000 * 1000);
282: deltaTime.HighPart = -1;
283:
284: (VOID) KeSetTimer(
285: &deviceExtension->MouseExtension.DataConsumptionTimer,
286: deltaTime,
287: &deviceExtension->MouseIsrDpcRetry
288: );
289:
290: moreDpcProcessing = FALSE;
291:
292: } else {
293:
294: //
295: // Decrement DpcInterlockMouse. If the result goes negative,
296: // then we're all finished processing the DPC. Otherwise, either
297: // the ISR incremented DpcInterlockMouse because it has more
298: // work for the ISR DPC to do, or a concurrent DPC executed on
299: // some processor while the current DPC was running (the
300: // concurrent DPC wouldn't have done any work). Make sure that
301: // the current DPC handles any extra work that is ready to be
302: // done.
303: //
304:
305: operationContext.Operation = DecrementOperation;
306: operationContext.NewValue = &interlockedResult;
307:
308: KeSynchronizeExecution(
309: deviceExtension->MouseInterruptObject,
310: (PKSYNCHRONIZE_ROUTINE) I8xDpcVariableOperation,
311: (PVOID) &operationContext
312: );
313:
314: if (interlockedResult != -1) {
315:
316: //
317: // The interlocked variable is still greater than or equal to
318: // zero. Reset it to zero, so that we execute the loop one
319: // more time (assuming no more DPCs execute and bump the
320: // variable up again).
321: //
322:
323: operationContext.Operation = WriteOperation;
324: interlockedResult = 0;
325: operationContext.NewValue = &interlockedResult;
326:
327: KeSynchronizeExecution(
328: deviceExtension->MouseInterruptObject,
329: (PKSYNCHRONIZE_ROUTINE) I8xDpcVariableOperation,
330: (PVOID) &operationContext
331: );
332:
333: I8xPrint((2, "I8042PRT-I8042MouseIsrDpc: loop in DPC\n"));
334: } else {
335: moreDpcProcessing = FALSE;
336: }
337: }
338: }
339:
340: I8xPrint((2, "I8042PRT-I8042MouseIsrDpc: exit\n"));
341:
342: }
343:
344: BOOLEAN
345: I8xWriteDataToMouseQueue(
346: PPORT_MOUSE_EXTENSION MouseExtension,
347: IN PMOUSE_INPUT_DATA InputData
348: )
349:
350: /*++
351:
352: Routine Description:
353:
354: This routine adds input data from the mouse to the InputData queue.
355:
356: Arguments:
357:
358: MouseExtension - Pointer to the mouse portion of the device extension.
359:
360: InputData - Pointer to the data to add to the InputData queue.
361:
362: Return Value:
363:
364: Returns TRUE if the data was added, otherwise FALSE.
365:
366: --*/
367:
368: {
369:
370: I8xPrint((2,"I8042PRT-I8xWriteDataToMouseQueue: enter\n"));
371: I8xPrint((
372: 3,
373: "I8042PRT-I8xWriteDataToMouseQueue: DataIn 0x%x, DataOut 0x%x\n",
374: MouseExtension->DataIn,
375: MouseExtension->DataOut
376: ));
377: I8xPrint((
378: 3,
379: "I8042PRT-I8xWriteDataToMouseQueue: InputCount %d\n",
380: MouseExtension->InputCount
381: ));
382:
383: //
384: // Check for full input data queue.
385: //
386:
387: if ((MouseExtension->DataIn == MouseExtension->DataOut) &&
388: (MouseExtension->InputCount != 0)) {
389:
390: //
391: // The input data queue is full. Intentionally ignore
392: // the new data.
393: //
394:
395: I8xPrint((1,"I8042PRT-I8xWriteDataToMouseQueue: OVERFLOW\n"));
396: return(FALSE);
397:
398: } else {
399: *(MouseExtension->DataIn) = *InputData;
400: MouseExtension->InputCount += 1;
401: MouseExtension->DataIn++;
402: I8xPrint((
403: 2,
404: "I8042PRT-I8xWriteDataToMouseQueue: new InputCount %d\n",
405: MouseExtension->InputCount
406: ));
407: if (MouseExtension->DataIn == MouseExtension->DataEnd) {
408: I8xPrint((2,"I8042PRT-I8xWriteDataToMouseQueue: wrap buffer\n"));
409: MouseExtension->DataIn = MouseExtension->InputData;
410: }
411: }
412:
413: I8xPrint((2,"I8042PRT-I8xWriteDataToMouseQueue: exit\n"));
414:
415: return(TRUE);
416: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.