VirtualBox

source: vbox/trunk/src/VBox/Additions/WINNT/i8042prt/kbdcmn.c@ 16684

Last change on this file since 16684 was 1, checked in by vboxsync, 55 years ago

import

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

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette