|
|
1.1 root 1:
2: /*++
3:
4: Copyright (c) 1990, 1991, 1992, 1993 Microsoft Corporation
5:
6: Module Name:
7:
8: kbdcmn.c
9:
10: Abstract:
11:
12: The common portions of the Intel i8042 port driver which
13: apply to the keyboard 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: I8042KeyboardIsrDpc(
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: keyboard interrupts. It is queued in the keyboard ISR. The real
52: work is done via a callback to the connected keyboard 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-I8042KeyboardIsrDpc: enter\n"));
89:
90: deviceExtension = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension;
91:
92: //
93: // Use DpcInterlockKeyboard 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. DpcInterlockKeyboard 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->DpcInterlockKeyboard;
104: operationContext.Operation = IncrementOperation;
105: operationContext.NewValue = &interlockedResult;
106:
107: KeSynchronizeExecution(
108: deviceExtension->KeyboardInterruptObject,
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) KeyboardDeviceType;
127: setPointerContext.DeviceType = (CCHAR) KeyboardDeviceType;
128: setPointerContext.InputCount = 0;
129:
130: KeSynchronizeExecution(
131: deviceExtension->KeyboardInterruptObject,
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
142: // callback ISR once for each piece.
143: //
144:
145: classDeviceObject =
146: deviceExtension->KeyboardExtension.ConnectData.ClassDeviceObject;
147: classService =
148: deviceExtension->KeyboardExtension.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-I8042KeyboardIsrDpc: calling class callback\n"
162: ));
163: I8xPrint((
164: 2,
165: "I8042PRT-I8042KeyboardIsrDpc: with Start 0x%x and End 0x%x\n",
166: getPointerContext.DataOut,
167: deviceExtension->KeyboardExtension.DataEnd
168: ));
169:
170: (*(PSERVICE_CALLBACK_ROUTINE) classService)(
171: classDeviceObject,
172: getPointerContext.DataOut,
173: deviceExtension->KeyboardExtension.DataEnd,
174: &inputDataConsumed
175: );
176:
177: dataNotConsumed = (((PUCHAR)
178: deviceExtension->KeyboardExtension.DataEnd -
179: (PUCHAR) getPointerContext.DataOut)
180: / sizeof(KEYBOARD_INPUT_DATA)) - inputDataConsumed;
181:
182: I8xPrint((
183: 2,
184: "I8042PRT-I8042KeyboardIsrDpc: (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(KEYBOARD_INPUT_DATA));
195: } else {
196: setPointerContext.DataOut =
197: deviceExtension->KeyboardExtension.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-I8042KeyboardIsrDpc: calling class callback\n"
211: ));
212: I8xPrint((
213: 2,
214: "I8042PRT-I8042KeyboardIsrDpc: 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(KEYBOARD_INPUT_DATA)) - inputDataConsumed;
229:
230: I8xPrint((
231: 2,
232: "I8042PRT-I8042KeyboardIsrDpc: Call callback consumed %d items, left %d\n",
233: inputDataConsumed,
234: dataNotConsumed
235: ));
236:
237: setPointerContext.DataOut =
238: ((PUCHAR)getPointerContext.DataOut) +
239: (inputDataConsumed * sizeof(KEYBOARD_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->KeyboardInterruptObject,
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-I8042KeyboardIsrDpc: set timer in DPC\n"));
270:
271: operationContext.Operation = WriteOperation;
272: interlockedResult = -1;
273: operationContext.NewValue = &interlockedResult;
274:
275: KeSynchronizeExecution(
276: deviceExtension->KeyboardInterruptObject,
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->KeyboardExtension.DataConsumptionTimer,
286: deltaTime,
287: &deviceExtension->KeyboardIsrDpcRetry
288: );
289:
290: moreDpcProcessing = FALSE;
291:
292: } else {
293:
294: //
295: // Decrement DpcInterlockKeyboard. If the result goes negative,
296: // then we're all finished processing the DPC. Otherwise, either
297: // the ISR incremented DpcInterlockKeyboard 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->KeyboardInterruptObject,
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->KeyboardInterruptObject,
329: (PKSYNCHRONIZE_ROUTINE) I8xDpcVariableOperation,
330: (PVOID) &operationContext
331: );
332:
333: I8xPrint((2, "I8042PRT-I8042KeyboardIsrDpc: loop in DPC\n"));
334: } else {
335: moreDpcProcessing = FALSE;
336: }
337: }
338:
339: }
340:
341: I8xPrint((2, "I8042PRT-I8042KeyboardIsrDpc: exit\n"));
342:
343: }
344:
345: BOOLEAN
346: I8xWriteDataToKeyboardQueue(
347: PPORT_KEYBOARD_EXTENSION KeyboardExtension,
348: IN PKEYBOARD_INPUT_DATA InputData
349: )
350:
351: /*++
352:
353: Routine Description:
354:
355: This routine adds input data from the keyboard to the InputData queue.
356:
357: Arguments:
358:
359: KeyboardExtension - Pointer to the keyboard portion of the device extension.
360:
361: InputData - Pointer to the data to add to the InputData queue.
362:
363: Return Value:
364:
365: Returns TRUE if the data was added, otherwise FALSE.
366:
367: --*/
368:
369: {
370:
371: PKEYBOARD_INPUT_DATA previousDataIn;
372:
373: I8xPrint((2,"I8042PRT-I8xWriteDataToKeyboardQueue: enter\n"));
374: I8xPrint((
375: 3,
376: "I8042PRT-I8xWriteDataToKeyboardQueue: DataIn 0x%x, DataOut 0x%x\n",
377: KeyboardExtension->DataIn,
378: KeyboardExtension->DataOut
379: ));
380: I8xPrint((
381: 3,
382: "I8042PRT-I8xWriteDataToKeyboardQueue: InputCount %d\n",
383: KeyboardExtension->InputCount
384: ));
385:
386: //
387: // Check for full input data queue.
388: //
389:
390: if ((KeyboardExtension->DataIn == KeyboardExtension->DataOut) &&
391: (KeyboardExtension->InputCount != 0)) {
392:
393: //
394: // Queue overflow. Replace the previous input data packet
395: // with a keyboard overrun data packet, thus losing both the
396: // previous and the current input data packet.
397: //
398:
399: I8xPrint((1,"I8042PRT-I8xWriteDataToKeyboardQueue: OVERFLOW\n"));
400:
401: if (KeyboardExtension->DataIn == KeyboardExtension->InputData) {
402: I8xPrint((2,"I8042PRT-I8xWriteDataToKeyboardQueue: wrap buffer\n"));
403: previousDataIn = KeyboardExtension->DataEnd;
404: } else {
405: previousDataIn = KeyboardExtension->DataIn - 1;
406: }
407:
408: previousDataIn->MakeCode = KEYBOARD_OVERRUN_MAKE_CODE;
409: previousDataIn->Flags = 0;
410:
411: I8xPrint((2,"I8042PRT-I8xWriteDataToKeyboardQueue: exit\n"));
412: return(FALSE);
413:
414: } else {
415: *(KeyboardExtension->DataIn) = *InputData;
416: KeyboardExtension->InputCount += 1;
417: KeyboardExtension->DataIn++;
418: I8xPrint((
419: 2,
420: "I8042PRT-I8xWriteDataToKeyboardQueue: new InputCount %d\n",
421: KeyboardExtension->InputCount
422: ));
423: if (KeyboardExtension->DataIn ==
424: KeyboardExtension->DataEnd) {
425: I8xPrint((2,"I8042PRT-I8xWriteDataToKeyboardQueue: wrap buffer\n"));
426: KeyboardExtension->DataIn = KeyboardExtension->InputData;
427: }
428: }
429:
430: I8xPrint((2,"I8042PRT-I8xWriteDataToKeyboardQueue: exit\n"));
431:
432: return(TRUE);
433: }
434:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.