OSDN Git Service

fix ticket #18663
[yamy/yamy.git] / d / mayud.c
1 ///////////////////////////////////////////////////////////////////////////////\r
2 // Driver for Madotsukai no Yu^utsu for Windows2000\r
3 \r
4 \r
5 #include <ntddk.h>\r
6 #include <ntddkbd.h>\r
7 #include <devioctl.h>\r
8 \r
9 #pragma warning(3 : 4061 4100 4132 4701 4706)\r
10 \r
11 #include "ioctl.h"\r
12 #include "keyque.c"\r
13 \r
14 //#define USE_TOUCHPAD // very experimental!\r
15 \r
16 #if DBG\r
17 // Enable debug logging only on checked build:\r
18 // We use macro to avoid function call overhead\r
19 // in non-logging case, and use double paren such\r
20 // as DEBUG_LOG((...)) because of va_list in macro.\r
21 #include "log.h"\r
22 #define DEBUG_LOG_INIT(x) mayuLogInit x\r
23 #define DEBUG_LOG_TERM(x) mayuLogTerm x\r
24 #define DEBUG_LOG(x) mayuLogEnque x\r
25 #define DEBUG_LOG_RETRIEVE(x) mayuLogDeque x\r
26 #else\r
27 #define DEBUG_LOG_INIT(x)\r
28 #define DEBUG_LOG_TERM(x)\r
29 #define DEBUG_LOG(x)\r
30 #define DEBUG_LOG_RETRIEVE(x) STATUS_INVALID_DEVICE_REQUEST\r
31 #endif\r
32 \r
33 ///////////////////////////////////////////////////////////////////////////////\r
34 // Device Extensions\r
35 \r
36 struct _DetourDeviceExtension;\r
37 struct _FilterDeviceExtension;\r
38 \r
39 typedef struct _DetourDeviceExtension {\r
40         PDRIVER_DISPATCH MajorFunction[IRP_MJ_MAXIMUM_FUNCTION + 1];\r
41 \r
42         KSPIN_LOCK lock; // lock below datum\r
43         PDEVICE_OBJECT filterDevObj;\r
44         LONG isOpen;\r
45         BOOLEAN wasCleanupInitiated; //\r
46         PIRP irpq;\r
47         KeyQue readQue; // when IRP_MJ_READ, the contents of readQue are returned\r
48 } DetourDeviceExtension;\r
49 \r
50 typedef struct _FilterDeviceExtension {\r
51         PDRIVER_DISPATCH MajorFunction[IRP_MJ_MAXIMUM_FUNCTION + 1];\r
52 \r
53         PDEVICE_OBJECT detourDevObj;\r
54         PDEVICE_OBJECT kbdClassDevObj; // keyboard class device object\r
55 \r
56 #ifdef USE_TOUCHPAD\r
57         BOOLEAN isKeyboard;\r
58 #endif\r
59         KSPIN_LOCK lock; // lock below datum\r
60         PIRP irpq;\r
61         KeyQue readQue; // when IRP_MJ_READ, the contents of readQue are returned\r
62 #ifdef USE_TOUCHPAD\r
63         BOOLEAN isTouched;\r
64 #endif\r
65 } FilterDeviceExtension;\r
66 \r
67 ///////////////////////////////////////////////////////////////////////////////\r
68 // Protorypes (TODO)\r
69 \r
70 \r
71 NTSTATUS DriverEntry       (IN PDRIVER_OBJECT, IN PUNICODE_STRING);\r
72 NTSTATUS mayuAddDevice     (IN PDRIVER_OBJECT, IN PDEVICE_OBJECT);\r
73 VOID mayuUnloadDriver      (IN PDRIVER_OBJECT);\r
74 VOID mayuDetourReadCancel (IN PDEVICE_OBJECT, IN PIRP);\r
75 \r
76 NTSTATUS filterGenericCompletion (IN PDEVICE_OBJECT, IN PIRP, IN PVOID);\r
77 NTSTATUS filterReadCompletion    (IN PDEVICE_OBJECT, IN PIRP, IN PVOID);\r
78 \r
79 NTSTATUS mayuGenericDispatch (IN PDEVICE_OBJECT, IN PIRP);\r
80 NTSTATUS detourCreate        (IN PDEVICE_OBJECT, IN PIRP);\r
81 NTSTATUS detourClose         (IN PDEVICE_OBJECT, IN PIRP);\r
82 NTSTATUS detourRead          (IN PDEVICE_OBJECT, IN PIRP);\r
83 NTSTATUS detourWrite         (IN PDEVICE_OBJECT, IN PIRP);\r
84 NTSTATUS detourCleanup       (IN PDEVICE_OBJECT, IN PIRP);\r
85 NTSTATUS detourDeviceControl (IN PDEVICE_OBJECT, IN PIRP);\r
86 NTSTATUS filterRead          (IN PDEVICE_OBJECT, IN PIRP);\r
87 NTSTATUS filterPassThrough   (IN PDEVICE_OBJECT, IN PIRP);\r
88 NTSTATUS detourPnP           (IN PDEVICE_OBJECT, IN PIRP);\r
89 NTSTATUS filterPnP           (IN PDEVICE_OBJECT, IN PIRP);\r
90 #ifndef MAYUD_NT4\r
91 NTSTATUS detourPower         (IN PDEVICE_OBJECT, IN PIRP);\r
92 NTSTATUS filterPower         (IN PDEVICE_OBJECT, IN PIRP);\r
93 #endif // !MAYUD_NT4\r
94 \r
95 BOOLEAN CancelKeyboardClassRead(IN PIRP, IN PDEVICE_OBJECT);\r
96 NTSTATUS readq(KeyQue*, PIRP);\r
97 \r
98 #ifdef USE_TOUCHPAD\r
99 NTSTATUS filterTouchpadCompletion (IN PDEVICE_OBJECT, IN PIRP, IN PVOID);\r
100 NTSTATUS filterTouchpad      (IN PDEVICE_OBJECT, IN PIRP);\r
101 #endif\r
102 \r
103 #ifdef ALLOC_PRAGMA\r
104 #pragma alloc_text( init, DriverEntry )\r
105 #endif // ALLOC_PRAGMA\r
106 \r
107 \r
108 ///////////////////////////////////////////////////////////////////////////////\r
109 // Global Constants / Variables\r
110 \r
111 BOOLEAN g_isPnP;\r
112 BOOLEAN g_isXp;\r
113 ULONG g_SpinLock_offset;\r
114 ULONG g_RequestIsPending_offset;\r
115 \r
116 // Device names\r
117 #define UnicodeString(str) { sizeof(str) - sizeof(UNICODE_NULL),        \\r
118                              sizeof(str) - sizeof(UNICODE_NULL), str }\r
119 \r
120 static UNICODE_STRING MayuDetourDeviceName =\r
121         UnicodeString(L"\\Device\\MayuDetour0");\r
122 \r
123 static UNICODE_STRING MayuDetourWin32DeviceName =\r
124         UnicodeString(L"\\DosDevices\\MayuDetour1");\r
125 \r
126 static UNICODE_STRING KeyboardClassDeviceName =\r
127         UnicodeString(DD_KEYBOARD_DEVICE_NAME_U L"0");\r
128 \r
129 static UNICODE_STRING KeyboardClassDriverName =\r
130         UnicodeString(L"\\Driver\\kbdclass");\r
131 \r
132 #ifdef USE_TOUCHPAD\r
133 #define TOUCHPAD_PRESSURE_OFFSET 7\r
134 #endif\r
135 \r
136 // Global Variables\r
137 PDRIVER_DISPATCH _IopInvalidDeviceRequest; // Default dispatch function\r
138 \r
139 \r
140 #define MAYUD_MODE L""\r
141 static UNICODE_STRING MayuDriverVersion =\r
142         UnicodeString(L"$Revision: 1.27 $" MAYUD_MODE);\r
143 \r
144 \r
145 ///////////////////////////////////////////////////////////////////////////////\r
146 // Entry / Unload\r
147 \r
148 void DEBUG_LOGChain(PDRIVER_OBJECT driverObject)\r
149 {\r
150         PDEVICE_OBJECT deviceObject = driverObject->DeviceObject;\r
151 \r
152         if (deviceObject) {\r
153                 while (deviceObject->NextDevice) {\r
154                         DEBUG_LOG(("%x->", deviceObject));\r
155                         deviceObject = deviceObject->NextDevice;\r
156                 }\r
157                 DEBUG_LOG(("%x", deviceObject));\r
158         }\r
159         return;\r
160 }\r
161 \r
162 // initialize driver\r
163 NTSTATUS DriverEntry(IN PDRIVER_OBJECT driverObject,\r
164                                          IN PUNICODE_STRING registryPath)\r
165 {\r
166         NTSTATUS status;\r
167         BOOLEAN is_symbolicLinkCreated = FALSE;\r
168         ULONG i;\r
169         PDEVICE_OBJECT detourDevObj = NULL;\r
170         DetourDeviceExtension *detourDevExt = NULL;\r
171         ULONG start = 0;\r
172         RTL_QUERY_REGISTRY_TABLE query[2];\r
173 \r
174         UNREFERENCED_PARAMETER(registryPath);\r
175 \r
176         DEBUG_LOG_INIT(("mayud: start logging"));\r
177 \r
178         // Environment specific initialize\r
179         RtlZeroMemory(query, sizeof(query));\r
180         query[0].Name = L"Start";\r
181         query[0].Flags = RTL_QUERY_REGISTRY_DIRECT;\r
182         query[0].EntryContext = &start;\r
183         RtlQueryRegistryValues(RTL_REGISTRY_SERVICES, L"mayud", query, NULL, NULL);\r
184         if (start == 0x03) {\r
185                 g_isPnP = TRUE;\r
186                 DEBUG_LOG(("is PnP"));\r
187         } else {\r
188                 g_isPnP = FALSE;\r
189                 DEBUG_LOG(("is not PnP"));\r
190         }\r
191 #ifdef MAYUD_NT4\r
192         g_isXp = FALSE;\r
193         g_SpinLock_offset = 48;\r
194         g_RequestIsPending_offset = 0;\r
195 #else /* !MAYUD_NT4 */\r
196         if (IoIsWdmVersionAvailable(1, 0x20)) { // is WindowsXP\r
197                 DEBUG_LOG(("is WindowsXp"));\r
198                 g_isXp = TRUE;\r
199                 g_SpinLock_offset = 108;\r
200                 g_RequestIsPending_offset = 0;\r
201         } else if (IoIsWdmVersionAvailable(1, 0x10)) { // is Windows2000\r
202                 DEBUG_LOG(("is Windows2000"));\r
203                 g_isXp =FALSE;\r
204                 g_SpinLock_offset = 116;\r
205                 g_RequestIsPending_offset = 48;\r
206         } else { // Unknown version\r
207                 DEBUG_LOG(("unknown Windows"));\r
208                 status = STATUS_UNKNOWN_REVISION;\r
209                 goto error;\r
210         }\r
211 #endif /* MAYUD_NT4 */\r
212 \r
213         // initialize global variables\r
214         _IopInvalidDeviceRequest = driverObject->MajorFunction[IRP_MJ_CREATE];\r
215 \r
216         // set major functions\r
217         driverObject->DriverUnload = mayuUnloadDriver;\r
218         if (g_isPnP == TRUE) {\r
219                 driverObject->DriverExtension->AddDevice = mayuAddDevice;\r
220         }\r
221         for (i = 0; i < IRP_MJ_MAXIMUM_FUNCTION; i++)\r
222 #ifdef MAYUD_NT4\r
223                 if (i != IRP_MJ_POWER)\r
224 #endif // MAYUD_NT4\r
225                         driverObject->MajorFunction[i] = mayuGenericDispatch;\r
226         if (g_isPnP == TRUE) {\r
227                 driverObject->MajorFunction[IRP_MJ_PNP] = mayuGenericDispatch;\r
228         }\r
229 \r
230         // create a device\r
231         {\r
232                 // create detour device\r
233                 status = IoCreateDevice(driverObject, sizeof(DetourDeviceExtension),\r
234                                                                 &MayuDetourDeviceName, FILE_DEVICE_KEYBOARD,\r
235                                                                 0, FALSE, &detourDevObj);\r
236 \r
237                 if (!NT_SUCCESS(status)) goto error;\r
238                 DEBUG_LOG(("create detour device: %x", detourDevObj));\r
239                 DEBUG_LOGChain(driverObject);\r
240                 detourDevObj->Flags |= DO_BUFFERED_IO;\r
241 #ifndef MAYUD_NT4\r
242                 detourDevObj->Flags |= DO_POWER_PAGABLE;\r
243 #endif // !MAYUD_NT4\r
244 \r
245                 // initialize detour device extension\r
246                 detourDevExt = (DetourDeviceExtension*)detourDevObj->DeviceExtension;\r
247                 RtlZeroMemory(detourDevExt, sizeof(DetourDeviceExtension));\r
248                 detourDevExt->filterDevObj = NULL;\r
249 \r
250                 KeInitializeSpinLock(&detourDevExt->lock);\r
251                 detourDevExt->isOpen = FALSE;\r
252                 detourDevExt->wasCleanupInitiated = FALSE;\r
253                 detourDevExt->irpq = NULL;\r
254                 status = KqInitialize(&detourDevExt->readQue);\r
255                 if (!NT_SUCCESS(status)) goto error;\r
256 \r
257                 // create symbolic link for detour\r
258                 status =\r
259                         IoCreateSymbolicLink(&MayuDetourWin32DeviceName, &MayuDetourDeviceName);\r
260                 if (!NT_SUCCESS(status)) goto error;\r
261                 is_symbolicLinkCreated = TRUE;\r
262 \r
263                 if (g_isPnP == FALSE)\r
264                         // attach filter device to keyboard class device\r
265                 {\r
266                         PFILE_OBJECT f;\r
267                         PDEVICE_OBJECT kbdClassDevObj;\r
268 \r
269                         status = IoGetDeviceObjectPointer(&KeyboardClassDeviceName,\r
270                                                                                           FILE_ALL_ACCESS, &f,\r
271                                                                                           &kbdClassDevObj);\r
272                         if (!NT_SUCCESS(status)) goto error;\r
273                         ObDereferenceObject(f);\r
274                         status = mayuAddDevice(driverObject, kbdClassDevObj);\r
275 \r
276                         // why cannot I do below ?\r
277 //      status = IoAttachDevice(filterDevObj, &KeyboardClassDeviceName,\r
278 //                            &filterDevExt->kbdClassDevObj);\r
279                         if (!NT_SUCCESS(status)) goto error;\r
280                 }\r
281 \r
282                 // initialize Major Functions\r
283                 for (i = 0; i < IRP_MJ_MAXIMUM_FUNCTION; i++) {\r
284                         detourDevExt->MajorFunction[i] = _IopInvalidDeviceRequest;\r
285                 }\r
286 \r
287                 detourDevExt->MajorFunction[IRP_MJ_READ] = detourRead;\r
288                 detourDevExt->MajorFunction[IRP_MJ_WRITE] = detourWrite;\r
289                 detourDevExt->MajorFunction[IRP_MJ_CREATE] = detourCreate;\r
290                 detourDevExt->MajorFunction[IRP_MJ_CLOSE] = detourClose;\r
291                 detourDevExt->MajorFunction[IRP_MJ_CLEANUP] = detourCleanup;\r
292                 detourDevExt->MajorFunction[IRP_MJ_DEVICE_CONTROL] = detourDeviceControl;\r
293 \r
294 #ifndef MAYUD_NT4\r
295                 detourDevExt->MajorFunction[IRP_MJ_POWER] = detourPower;\r
296 #endif // !MAYUD_NT4\r
297                 if (g_isPnP == TRUE) {\r
298                         detourDevExt->MajorFunction[IRP_MJ_PNP] = detourPnP;\r
299                 }\r
300         }\r
301         detourDevObj->Flags &= ~DO_DEVICE_INITIALIZING;\r
302 \r
303         return STATUS_SUCCESS;\r
304 \r
305 error: {\r
306                 if (is_symbolicLinkCreated)\r
307                         IoDeleteSymbolicLink(&MayuDetourWin32DeviceName);\r
308                 if (detourDevObj) {\r
309                         KqFinalize(&detourDevExt->readQue);\r
310                         IoDeleteDevice(detourDevObj);\r
311                 }\r
312         }\r
313         return status;\r
314 }\r
315 \r
316 NTSTATUS mayuAddDevice(IN PDRIVER_OBJECT driverObject,\r
317                                            IN PDEVICE_OBJECT kbdClassDevObj)\r
318 {\r
319         NTSTATUS status;\r
320         PDEVICE_OBJECT devObj;\r
321         PDEVICE_OBJECT filterDevObj;\r
322         PDEVICE_OBJECT attachedDevObj;\r
323         DetourDeviceExtension *detourDevExt;\r
324         FilterDeviceExtension *filterDevExt;\r
325         ULONG i;\r
326 \r
327         DEBUG_LOG(("attach to device: %x", kbdClassDevObj));\r
328         DEBUG_LOG(("type of device: %x", kbdClassDevObj->DeviceType));\r
329         DEBUG_LOG(("name of driver: %T", &(kbdClassDevObj->DriverObject->DriverName)));\r
330 \r
331         // create filter device\r
332         status = IoCreateDevice(driverObject, sizeof(FilterDeviceExtension),\r
333                                                         NULL, FILE_DEVICE_KEYBOARD,\r
334                                                         0, FALSE, &filterDevObj);\r
335         DEBUG_LOG(("add filter device: %x", filterDevObj));\r
336         DEBUG_LOGChain(driverObject);\r
337         if (!NT_SUCCESS(status)) return status;\r
338         filterDevObj->Flags |= DO_BUFFERED_IO;\r
339 #ifndef MAYUD_NT4\r
340         filterDevObj->Flags |= DO_POWER_PAGABLE;\r
341 #endif // !MAYUD_NT4\r
342 \r
343         // initialize filter device extension\r
344         filterDevExt = (FilterDeviceExtension*)filterDevObj->DeviceExtension;\r
345         RtlZeroMemory(filterDevExt, sizeof(FilterDeviceExtension));\r
346 \r
347         KeInitializeSpinLock(&filterDevExt->lock);\r
348         filterDevExt->irpq = NULL;\r
349         status = KqInitialize(&filterDevExt->readQue);\r
350         if (!NT_SUCCESS(status)) goto error;\r
351 #ifdef USE_TOUCHPAD\r
352         filterDevExt->isKeyboard = FALSE;\r
353         filterDevExt->isTouched = FALSE;\r
354 #endif\r
355 \r
356         attachedDevObj = kbdClassDevObj->AttachedDevice;\r
357         while (attachedDevObj) {\r
358                 DEBUG_LOG(("attached to %T", &(attachedDevObj->DriverObject->DriverName)));\r
359                 DEBUG_LOG(("type of attched device: %x", attachedDevObj->DeviceType));\r
360 #ifdef USE_TOUCHPAD\r
361                 if (RtlCompareUnicodeString(&KeyboardClassDriverName, &attachedDevObj->DriverObject->DriverName, TRUE) == 0)\r
362                         filterDevExt->isKeyboard = TRUE;\r
363 #endif\r
364                 attachedDevObj = attachedDevObj->AttachedDevice;\r
365         }\r
366 \r
367         devObj = filterDevObj->NextDevice;\r
368         while (devObj->NextDevice) {\r
369                 devObj = devObj->NextDevice;\r
370         }\r
371         filterDevExt->detourDevObj = devObj;\r
372         detourDevExt = (DetourDeviceExtension*)devObj->DeviceExtension;\r
373         if (!detourDevExt->filterDevObj) {\r
374                 detourDevExt->filterDevObj = filterDevObj;\r
375         }\r
376 \r
377         filterDevExt->kbdClassDevObj =\r
378                 IoAttachDeviceToDeviceStack(filterDevObj, kbdClassDevObj);\r
379         if (!filterDevExt->kbdClassDevObj) goto error;\r
380 \r
381         for (i = 0; i < IRP_MJ_MAXIMUM_FUNCTION; i++) {\r
382                 filterDevExt->MajorFunction[i] =\r
383                         (filterDevExt->kbdClassDevObj->DriverObject->MajorFunction[i]\r
384                          == _IopInvalidDeviceRequest) ?\r
385                         _IopInvalidDeviceRequest : filterPassThrough;\r
386         }\r
387 #ifdef USE_TOUCHPAD\r
388         if (filterDevExt->isKeyboard == FALSE) {\r
389                 DEBUG_LOG(("filter read: GlidePoint"));\r
390                 filterDevObj->DeviceType = FILE_DEVICE_MOUSE;\r
391                 filterDevExt->MajorFunction[IRP_MJ_INTERNAL_DEVICE_CONTROL] = filterTouchpad;\r
392         } else\r
393 #endif\r
394         {\r
395                 DEBUG_LOG(("filter read: Keyboard"));\r
396                 filterDevExt->MajorFunction[IRP_MJ_READ] = filterRead;\r
397         }\r
398 #ifndef MAYUD_NT4\r
399         filterDevExt->MajorFunction[IRP_MJ_POWER] = filterPower;\r
400 #endif // !MAYUD_NT4\r
401         if (g_isPnP == TRUE) {\r
402                 filterDevExt->MajorFunction[IRP_MJ_PNP] = filterPnP;\r
403         }\r
404         filterDevObj->Flags &= ~DO_DEVICE_INITIALIZING;\r
405 \r
406         return STATUS_SUCCESS;\r
407 \r
408 error:\r
409         DEBUG_LOG(("mayuAddDevice: error"));\r
410         if (filterDevObj) {\r
411                 KqFinalize(&filterDevExt->readQue);\r
412                 IoDeleteDevice(filterDevObj);\r
413         }\r
414         return status;\r
415 }\r
416 \r
417 BOOLEAN CancelKeyboardClassRead(PIRP cancelIrp, PDEVICE_OBJECT kbdClassDevObj)\r
418 {\r
419         PVOID kbdClassDevExt;\r
420         BOOLEAN isSafe;\r
421         PKSPIN_LOCK SpinLock;\r
422         KIRQL currentIrql;\r
423 \r
424         kbdClassDevExt = kbdClassDevObj->DeviceExtension;\r
425         SpinLock = (PKSPIN_LOCK)((ULONG)kbdClassDevExt + g_SpinLock_offset);\r
426         KeAcquireSpinLock(SpinLock, &currentIrql);\r
427         if (g_isXp == TRUE) {\r
428                 isSafe = cancelIrp->CancelRoutine ? TRUE : FALSE;\r
429         } else {\r
430                 isSafe = *(BOOLEAN*)((ULONG)kbdClassDevExt + g_RequestIsPending_offset);\r
431         }\r
432         if (isSafe == TRUE) {\r
433                 KeReleaseSpinLock(SpinLock, currentIrql);\r
434                 IoCancelIrp(cancelIrp);\r
435         } else {\r
436                 DEBUG_LOG(("cancel irp not pending"));\r
437                 KeReleaseSpinLock(SpinLock, currentIrql);\r
438         }\r
439         return isSafe;\r
440 }\r
441 \r
442 // unload driver\r
443 VOID mayuUnloadDriver(IN PDRIVER_OBJECT driverObject)\r
444 {\r
445         KIRQL currentIrql;\r
446         PIRP cancelIrp;\r
447         PDEVICE_OBJECT devObj;\r
448         DetourDeviceExtension *detourDevExt;\r
449 \r
450         // walk on device chain(the last one is detour device?)\r
451         devObj = driverObject->DeviceObject;\r
452         while (devObj->NextDevice) {\r
453                 FilterDeviceExtension *filterDevExt\r
454                 = (FilterDeviceExtension*)devObj->DeviceExtension;\r
455                 PDEVICE_OBJECT delObj;\r
456                 PDEVICE_OBJECT kbdClassDevObj;\r
457 \r
458                 // detach\r
459                 IoDetachDevice(filterDevExt->kbdClassDevObj);\r
460                 // cancel filter IRP_MJ_READ\r
461                 KeAcquireSpinLock(&filterDevExt->lock, &currentIrql);\r
462                 // TODO: at this point, the irp may be completed (but what can I do for it ?)\r
463                 // finalize read que\r
464                 KqFinalize(&filterDevExt->readQue);\r
465                 cancelIrp = filterDevExt->irpq;\r
466                 filterDevExt->irpq = NULL;\r
467                 kbdClassDevObj = filterDevExt->kbdClassDevObj;\r
468                 KeReleaseSpinLock(&filterDevExt->lock, currentIrql);\r
469                 if (cancelIrp) {\r
470                         while (CancelKeyboardClassRead(cancelIrp, kbdClassDevObj) != TRUE);\r
471                 }\r
472                 // delete device objects\r
473                 delObj= devObj;\r
474                 devObj = devObj->NextDevice;\r
475                 IoDeleteDevice(delObj);\r
476         }\r
477 \r
478         detourDevExt = (DetourDeviceExtension*)devObj->DeviceExtension;\r
479         // cancel filter IRP_MJ_READ\r
480         KeAcquireSpinLock(&detourDevExt->lock, &currentIrql);\r
481         // TODO: at this point, the irp may be completed (but what can I do for it ?)\r
482         cancelIrp = detourDevExt->irpq;\r
483         // finalize read que\r
484         KqFinalize(&detourDevExt->readQue);\r
485         KeReleaseSpinLock(&detourDevExt->lock, currentIrql);\r
486         if (cancelIrp)\r
487                 IoCancelIrp(cancelIrp);\r
488         // delete device objects\r
489         IoDeleteDevice(devObj);\r
490 \r
491         // delete symbolic link\r
492         IoDeleteSymbolicLink(&MayuDetourWin32DeviceName);\r
493         DEBUG_LOG_TERM(());\r
494 }\r
495 \r
496 \r
497 ///////////////////////////////////////////////////////////////////////////////\r
498 // Cancel Functionss\r
499 \r
500 \r
501 // detour read cancel\r
502 VOID mayuDetourReadCancel(IN PDEVICE_OBJECT deviceObject, IN PIRP irp)\r
503 {\r
504         DetourDeviceExtension *devExt =\r
505                 (DetourDeviceExtension *)deviceObject->DeviceExtension;\r
506         KIRQL currentIrql;\r
507 \r
508         KeAcquireSpinLock(&devExt->lock, &currentIrql);\r
509         devExt->irpq = NULL;\r
510         KeReleaseSpinLock(&devExt->lock, currentIrql);\r
511         IoReleaseCancelSpinLock(irp->CancelIrql);\r
512         DEBUG_LOG(("detourReadCancel:"));\r
513 #if 0\r
514         KeAcquireSpinLock(&devExt->lock, &currentIrql);\r
515         if (devExt->irpq && irp == deviceObject->CurrentIrp)\r
516                 // the current request is being cancelled\r
517         {\r
518                 deviceObject->CurrentIrp = NULL;\r
519                 devExt->irpq = NULL;\r
520                 KeReleaseSpinLock(&devExt->lock, currentIrql);\r
521                 IoStartNextPacket(deviceObject, TRUE);\r
522         } else {\r
523                 // Cancel a request in the device queue\r
524                 KIRQL cancelIrql;\r
525 \r
526                 IoAcquireCancelSpinLock(&cancelIrql);\r
527                 KeRemoveEntryDeviceQueue(&deviceObject->DeviceQueue,\r
528                                                                  &irp->Tail.Overlay.DeviceQueueEntry);\r
529                 IoReleaseCancelSpinLock(cancelIrql);\r
530                 KeReleaseSpinLock(&devExt->lock, currentIrql);\r
531         }\r
532 #endif\r
533 \r
534         irp->IoStatus.Status = STATUS_CANCELLED;\r
535         irp->IoStatus.Information = 0;\r
536         IoCompleteRequest(irp, IO_KEYBOARD_INCREMENT);\r
537 }\r
538 \r
539 ///////////////////////////////////////////////////////////////////////////////\r
540 // Complete Functions\r
541 \r
542 \r
543 //\r
544 NTSTATUS filterGenericCompletion(IN PDEVICE_OBJECT deviceObject,\r
545                                                                  IN PIRP irp, IN PVOID context)\r
546 {\r
547         UNREFERENCED_PARAMETER(deviceObject);\r
548         UNREFERENCED_PARAMETER(context);\r
549 \r
550         if (irp->PendingReturned)\r
551                 IoMarkIrpPending(irp);\r
552         return STATUS_SUCCESS;\r
553 }\r
554 \r
555 \r
556 //\r
557 NTSTATUS filterReadCompletion(IN PDEVICE_OBJECT deviceObject,\r
558                                                           IN PIRP irp, IN PVOID context)\r
559 {\r
560         NTSTATUS status;\r
561         KIRQL currentIrql, cancelIrql;\r
562         PIRP irpCancel = NULL;\r
563         FilterDeviceExtension *filterDevExt =\r
564                 (FilterDeviceExtension*)deviceObject->DeviceExtension;\r
565         PDEVICE_OBJECT detourDevObj = filterDevExt->detourDevObj;\r
566         DetourDeviceExtension *detourDevExt =\r
567                 (DetourDeviceExtension*)detourDevObj->DeviceExtension;\r
568 \r
569         UNREFERENCED_PARAMETER(context);\r
570 \r
571         KeAcquireSpinLock(&filterDevExt->lock, &currentIrql);\r
572         filterDevExt->irpq = NULL;\r
573         KeReleaseSpinLock(&filterDevExt->lock, currentIrql);\r
574         if (irp->PendingReturned) {\r
575                 status = STATUS_PENDING;\r
576                 IoMarkIrpPending(irp);\r
577         } else {\r
578                 status = STATUS_SUCCESS;\r
579         }\r
580 \r
581         KeAcquireSpinLock(&detourDevExt->lock, &currentIrql);\r
582         if (detourDevExt->isOpen && !detourDevExt->wasCleanupInitiated) {\r
583                 // if detour is opened, key datum are forwarded to detour\r
584                 if (irp->IoStatus.Status == STATUS_SUCCESS) {\r
585                         PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation(irp);\r
586 \r
587                         KqEnque(&detourDevExt->readQue,\r
588                                         (KEYBOARD_INPUT_DATA *)irp->AssociatedIrp.SystemBuffer,\r
589                                         irp->IoStatus.Information / sizeof(KEYBOARD_INPUT_DATA));\r
590 \r
591                         irp->IoStatus.Status = STATUS_CANCELLED;\r
592                         irp->IoStatus.Information = 0;\r
593                         detourDevExt->filterDevObj = deviceObject;\r
594                 }\r
595 \r
596                 IoAcquireCancelSpinLock(&cancelIrql);\r
597                 if (detourDevExt->irpq) {\r
598                         if (readq(&detourDevExt->readQue, detourDevExt->irpq) ==\r
599                                         STATUS_SUCCESS) {\r
600                                 IoSetCancelRoutine(detourDevExt->irpq, NULL);\r
601                                 IoCompleteRequest(detourDevExt->irpq, IO_KEYBOARD_INCREMENT);\r
602                                 detourDevExt->irpq = NULL;\r
603                         }\r
604                 }\r
605                 IoReleaseCancelSpinLock(cancelIrql);\r
606                 KeReleaseSpinLock(&detourDevExt->lock, currentIrql);\r
607 \r
608                 KeAcquireSpinLock(&filterDevExt->lock, &currentIrql);\r
609                 status = readq(&filterDevExt->readQue, irp);\r
610                 KeReleaseSpinLock(&filterDevExt->lock, currentIrql);\r
611         } else {\r
612                 KeReleaseSpinLock(&detourDevExt->lock, currentIrql);\r
613         }\r
614 \r
615         if (status == STATUS_SUCCESS)\r
616                 irp->IoStatus.Status = STATUS_SUCCESS;\r
617         return irp->IoStatus.Status;\r
618 }\r
619 \r
620 NTSTATUS readq(KeyQue *readQue, PIRP irp)\r
621 {\r
622         if (!KqIsEmpty(readQue)) {\r
623                 PIO_STACK_LOCATION irpSp;\r
624                 ULONG len;\r
625 \r
626                 irpSp = IoGetCurrentIrpStackLocation(irp);\r
627                 len = KqDeque(readQue,\r
628                                           (KEYBOARD_INPUT_DATA *)irp->AssociatedIrp.SystemBuffer,\r
629                                           irpSp->Parameters.Read.Length / sizeof(KEYBOARD_INPUT_DATA));\r
630                 irp->IoStatus.Status = STATUS_SUCCESS;\r
631                 irp->IoStatus.Information = len * sizeof(KEYBOARD_INPUT_DATA);\r
632                 irpSp->Parameters.Read.Length = irp->IoStatus.Information;\r
633                 return STATUS_SUCCESS;\r
634         } else {\r
635                 irp->IoStatus.Status = STATUS_PENDING;\r
636                 irp->IoStatus.Information = 0;\r
637                 return STATUS_PENDING;\r
638         }\r
639 }\r
640 \r
641 ///////////////////////////////////////////////////////////////////////////////\r
642 // Dispatch Functions\r
643 \r
644 \r
645 // Generic Dispatcher\r
646 NTSTATUS mayuGenericDispatch(IN PDEVICE_OBJECT deviceObject, IN PIRP irp)\r
647 {\r
648         PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation(irp);\r
649 \r
650         if (deviceObject->NextDevice) {\r
651                 FilterDeviceExtension *filterDevExt =\r
652                         (FilterDeviceExtension *)deviceObject->DeviceExtension;\r
653 \r
654 #ifdef USE_TOUCHPAD\r
655                 if (filterDevExt->isKeyboard == FALSE) {\r
656                         DEBUG_LOG(("MajorFunction: %x", irpSp->MajorFunction));\r
657                 }\r
658 #endif\r
659                 return filterDevExt->MajorFunction[irpSp->MajorFunction](deviceObject, irp);\r
660         } else {\r
661                 DetourDeviceExtension *detourDevExt =\r
662                         (DetourDeviceExtension *)deviceObject->DeviceExtension;\r
663 \r
664                 return detourDevExt->MajorFunction[irpSp->MajorFunction](deviceObject, irp);\r
665         }\r
666 }\r
667 \r
668 \r
669 // detour IRP_MJ_CREATE\r
670 NTSTATUS detourCreate(IN PDEVICE_OBJECT deviceObject, IN PIRP irp)\r
671 {\r
672         DetourDeviceExtension *detourDevExt =\r
673                 (DetourDeviceExtension*)deviceObject->DeviceExtension;\r
674 \r
675         if (1 < InterlockedIncrement(&detourDevExt->isOpen))\r
676                 // mayu detour device can be opend only once at a time\r
677         {\r
678                 InterlockedDecrement(&detourDevExt->isOpen);\r
679                 irp->IoStatus.Status = STATUS_INTERNAL_ERROR;\r
680         } else {\r
681                 PIRP irpCancel;\r
682                 KIRQL currentIrql;\r
683                 PDEVICE_OBJECT filterDevObj;\r
684 \r
685                 KeAcquireSpinLock(&detourDevExt->lock, &currentIrql);\r
686                 detourDevExt->wasCleanupInitiated = FALSE;\r
687                 KqClear(&detourDevExt->readQue);\r
688                 filterDevObj = detourDevExt->filterDevObj;\r
689                 KeReleaseSpinLock(&detourDevExt->lock, currentIrql);\r
690                 if (filterDevObj) {\r
691                         FilterDeviceExtension *filterDevExt =\r
692                                 (FilterDeviceExtension*)filterDevObj->DeviceExtension;\r
693                         PDEVICE_OBJECT kbdClassDevObj;\r
694 \r
695                         KeAcquireSpinLock(&filterDevExt->lock, &currentIrql);\r
696                         irpCancel = filterDevExt->kbdClassDevObj->CurrentIrp;\r
697                         kbdClassDevObj = filterDevExt->kbdClassDevObj;\r
698                         KeReleaseSpinLock(&filterDevExt->lock, currentIrql);\r
699                         if (irpCancel) {\r
700                                 CancelKeyboardClassRead(irpCancel, kbdClassDevObj);\r
701                         }\r
702                 }\r
703 \r
704                 irp->IoStatus.Status = STATUS_SUCCESS;\r
705         }\r
706         irp->IoStatus.Information = 0;\r
707         IoCompleteRequest(irp, IO_NO_INCREMENT);\r
708         return irp->IoStatus.Status;\r
709 }\r
710 \r
711 \r
712 // detour IRP_MJ_CLOSE\r
713 NTSTATUS detourClose(IN PDEVICE_OBJECT deviceObject, IN PIRP irp)\r
714 {\r
715         DetourDeviceExtension *detourDevExt =\r
716                 (DetourDeviceExtension*)deviceObject->DeviceExtension;\r
717         KIRQL currentIrql;\r
718 \r
719         KeAcquireSpinLock(&detourDevExt->lock, &currentIrql);\r
720         InterlockedDecrement(&detourDevExt->isOpen);\r
721         KeReleaseSpinLock(&detourDevExt->lock, currentIrql);\r
722         irp->IoStatus.Status = STATUS_SUCCESS;\r
723         irp->IoStatus.Information = 0;\r
724         IoCompleteRequest(irp, IO_NO_INCREMENT);\r
725         DEBUG_LOG_TERM(());\r
726         return STATUS_SUCCESS;\r
727 }\r
728 \r
729 \r
730 // detour IRP_MJ_READ\r
731 NTSTATUS detourRead(IN PDEVICE_OBJECT deviceObject, IN PIRP irp)\r
732 {\r
733         NTSTATUS status;\r
734         PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation(irp);\r
735         DetourDeviceExtension *detourDevExt =\r
736                 (DetourDeviceExtension*)deviceObject->DeviceExtension;\r
737         KIRQL currentIrql, cancelIrql;\r
738 \r
739         KeAcquireSpinLock(&detourDevExt->lock, &currentIrql);\r
740         if (irpSp->Parameters.Read.Length == 0)\r
741                 status = STATUS_SUCCESS;\r
742         else if (irpSp->Parameters.Read.Length % sizeof(KEYBOARD_INPUT_DATA))\r
743                 status = STATUS_BUFFER_TOO_SMALL;\r
744         else\r
745                 status = readq(&detourDevExt->readQue, irp);\r
746         if (status == STATUS_PENDING) {\r
747                 IoAcquireCancelSpinLock(&cancelIrql);\r
748                 IoMarkIrpPending(irp);\r
749                 detourDevExt->irpq = irp;\r
750                 IoSetCancelRoutine(irp, mayuDetourReadCancel);\r
751                 IoReleaseCancelSpinLock(cancelIrql);\r
752         } else {\r
753                 IoCompleteRequest(irp, IO_KEYBOARD_INCREMENT);\r
754         }\r
755         KeReleaseSpinLock(&detourDevExt->lock, currentIrql);\r
756         return status;\r
757 }\r
758 \r
759 \r
760 // detour IRP_MJ_WRITE\r
761 NTSTATUS detourWrite(IN PDEVICE_OBJECT deviceObject, IN PIRP irp)\r
762 {\r
763         NTSTATUS status;\r
764         PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation(irp);\r
765         ULONG len = irpSp->Parameters.Write.Length;\r
766         DetourDeviceExtension *detourDevExt =\r
767                 (DetourDeviceExtension*)deviceObject->DeviceExtension;\r
768 \r
769         irp->IoStatus.Information = 0;\r
770         if (len == 0)\r
771                 status = STATUS_SUCCESS;\r
772         else if (len % sizeof(KEYBOARD_INPUT_DATA))\r
773                 status = STATUS_INVALID_PARAMETER;\r
774         else {\r
775                 // write to filter que\r
776                 KIRQL cancelIrql, currentIrql;\r
777                 PIRP irpCancel;\r
778                 PDEVICE_OBJECT filterDevObj;\r
779 \r
780                 KeAcquireSpinLock(&detourDevExt->lock, &currentIrql);\r
781                 filterDevObj = detourDevExt->filterDevObj;\r
782                 KeReleaseSpinLock(&detourDevExt->lock, currentIrql);\r
783                 // enque filter que\r
784                 if (filterDevObj) {\r
785                         FilterDeviceExtension *filterDevExt =\r
786                                 (FilterDeviceExtension*)filterDevObj->DeviceExtension;\r
787                         PDEVICE_OBJECT kbdClassDevObj;\r
788 \r
789                         KeAcquireSpinLock(&filterDevExt->lock, &currentIrql);\r
790 \r
791                         len /= sizeof(KEYBOARD_INPUT_DATA);\r
792                         len = KqEnque(&filterDevExt->readQue,\r
793                                                   (KEYBOARD_INPUT_DATA *)irp->AssociatedIrp.SystemBuffer,\r
794                                                   len);\r
795                         irp->IoStatus.Information = len * sizeof(KEYBOARD_INPUT_DATA);\r
796                         irpSp->Parameters.Write.Length = irp->IoStatus.Information;\r
797                         // cancel filter irp\r
798                         irpCancel = filterDevExt->irpq;\r
799                         filterDevExt->irpq = NULL;\r
800                         kbdClassDevObj = filterDevExt->kbdClassDevObj;\r
801                         KeReleaseSpinLock(&filterDevExt->lock, currentIrql);\r
802                         if (irpCancel) {\r
803                                 CancelKeyboardClassRead(irpCancel, kbdClassDevObj);\r
804                         }\r
805                         status = STATUS_SUCCESS;\r
806                 } else {\r
807                         irp->IoStatus.Information = 0;\r
808                         irpSp->Parameters.Write.Length = irp->IoStatus.Information;\r
809                         status = STATUS_CANCELLED;\r
810                 }\r
811         }\r
812         IoCompleteRequest(irp, IO_NO_INCREMENT);\r
813         return status;\r
814 }\r
815 \r
816 \r
817 // detour IRP_MJ_CLEANUP\r
818 NTSTATUS detourCleanup(IN PDEVICE_OBJECT deviceObject, IN PIRP irp)\r
819 {\r
820         KIRQL currentIrql, cancelIrql;\r
821         PIO_STACK_LOCATION irpSp;\r
822         PIRP  currentIrp = NULL, irpCancel;\r
823         DetourDeviceExtension *detourDevExt =\r
824                 (DetourDeviceExtension*)deviceObject->DeviceExtension;\r
825 \r
826         KeAcquireSpinLock(&detourDevExt->lock, &currentIrql);\r
827         IoAcquireCancelSpinLock(&cancelIrql);\r
828         irpSp = IoGetCurrentIrpStackLocation(irp);\r
829         detourDevExt->wasCleanupInitiated = TRUE;\r
830 \r
831         // Complete all requests queued by this thread with STATUS_CANCELLED\r
832         currentIrp = deviceObject->CurrentIrp;\r
833         deviceObject->CurrentIrp = NULL;\r
834         detourDevExt->irpq = NULL;\r
835 \r
836         while (currentIrp != NULL) {\r
837                 IoSetCancelRoutine(currentIrp, NULL);\r
838                 currentIrp->IoStatus.Status = STATUS_CANCELLED;\r
839                 currentIrp->IoStatus.Information = 0;\r
840 \r
841                 IoReleaseCancelSpinLock(cancelIrql);\r
842                 KeReleaseSpinLock(&detourDevExt->lock, currentIrql);\r
843                 IoCompleteRequest(currentIrp, IO_NO_INCREMENT);\r
844                 KeAcquireSpinLock(&detourDevExt->lock, &currentIrql);\r
845                 IoAcquireCancelSpinLock(&cancelIrql);\r
846 \r
847                 // Dequeue the next packet (IRP) from the device work queue.\r
848                 {\r
849                         PKDEVICE_QUEUE_ENTRY packet =\r
850                                 KeRemoveDeviceQueue(&deviceObject->DeviceQueue);\r
851                         currentIrp = packet ?\r
852                                                  CONTAINING_RECORD(packet, IRP, Tail.Overlay.DeviceQueueEntry) : NULL;\r
853                 }\r
854         }\r
855 \r
856         IoReleaseCancelSpinLock(cancelIrql);\r
857         KeReleaseSpinLock(&detourDevExt->lock, currentIrql);\r
858 \r
859         // Complete the cleanup request with STATUS_SUCCESS.\r
860         irp->IoStatus.Status = STATUS_SUCCESS;\r
861         irp->IoStatus.Information = 0;\r
862         IoCompleteRequest(irp, IO_NO_INCREMENT);\r
863 \r
864         return STATUS_SUCCESS;\r
865 }\r
866 \r
867 \r
868 // detour IRP_MJ_DEVICE_CONTROL\r
869 NTSTATUS detourDeviceControl(IN PDEVICE_OBJECT deviceObject, IN PIRP irp)\r
870 {\r
871         NTSTATUS status;\r
872         PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation(irp);\r
873         DetourDeviceExtension *detourDevExt =\r
874                 (DetourDeviceExtension*)deviceObject->DeviceExtension;\r
875 \r
876         irp->IoStatus.Information = 0;\r
877         if (irpSp->Parameters.DeviceIoControl.IoControlCode != IOCTL_MAYU_GET_LOG) DEBUG_LOG(("DeviceIoControl: %x", irpSp->Parameters.DeviceIoControl.IoControlCode));\r
878         status = STATUS_INVALID_DEVICE_REQUEST;\r
879         switch (irpSp->Parameters.DeviceIoControl.IoControlCode) {\r
880         case IOCTL_MAYU_DETOUR_CANCEL: {\r
881                 KIRQL currentIrql;\r
882                 PIRP irpCancel = NULL;\r
883 \r
884                 KeAcquireSpinLock(&detourDevExt->lock, &currentIrql);\r
885                 if (detourDevExt->isOpen)\r
886                         irpCancel = detourDevExt->irpq;\r
887                 KeReleaseSpinLock(&detourDevExt->lock, currentIrql);\r
888 \r
889                 if (irpCancel)\r
890                         IoCancelIrp(irpCancel);// at this point, the irpCancel may be completed\r
891                 status = STATUS_SUCCESS;\r
892                 break;\r
893         }\r
894         case IOCTL_MAYU_GET_VERSION: {\r
895                 if (irpSp->Parameters.DeviceIoControl.OutputBufferLength <\r
896                                 MayuDriverVersion.Length) {\r
897                         status = STATUS_INVALID_PARAMETER;\r
898                         break;\r
899                 }\r
900                 RtlCopyMemory(irp->AssociatedIrp.SystemBuffer,\r
901                                           MayuDriverVersion.Buffer, MayuDriverVersion.Length);\r
902                 irp->IoStatus.Information = MayuDriverVersion.Length;\r
903                 DEBUG_LOG(("Version: %T", &MayuDriverVersion));\r
904                 status = STATUS_SUCCESS;\r
905                 break;\r
906         }\r
907         case IOCTL_MAYU_GET_LOG:\r
908                 status = DEBUG_LOG_RETRIEVE((irp));\r
909                 break;\r
910         case IOCTL_MAYU_FORCE_KEYBOARD_INPUT: {\r
911                 KIRQL currentIrql, cancelIrql;\r
912 \r
913                 // if detour is opened, key datum are forwarded to detour\r
914                 if (irpSp->Parameters.DeviceIoControl.InputBufferLength %\r
915                                 sizeof(KEYBOARD_INPUT_DATA)) {\r
916                         status = STATUS_INVALID_PARAMETER;\r
917                         break;\r
918                 }\r
919                 KeAcquireSpinLock(&detourDevExt->lock, &currentIrql);\r
920                 KqEnque(&detourDevExt->readQue,\r
921                                 (KEYBOARD_INPUT_DATA *)irp->AssociatedIrp.SystemBuffer,\r
922                                 irpSp->Parameters.DeviceIoControl.InputBufferLength\r
923                                 / sizeof(KEYBOARD_INPUT_DATA));\r
924 \r
925                 if (detourDevExt->irpq) {\r
926                         if (readq(&detourDevExt->readQue, detourDevExt->irpq) ==\r
927                                         STATUS_SUCCESS) {\r
928                                 IoAcquireCancelSpinLock(&cancelIrql);\r
929                                 IoSetCancelRoutine(detourDevExt->irpq, NULL);\r
930                                 IoReleaseCancelSpinLock(cancelIrql);\r
931                                 IoCompleteRequest(detourDevExt->irpq, IO_KEYBOARD_INCREMENT);\r
932                                 detourDevExt->irpq = NULL;\r
933                         }\r
934                 }\r
935                 KeReleaseSpinLock(&detourDevExt->lock, currentIrql);\r
936                 status = STATUS_SUCCESS;\r
937                 break;\r
938         }\r
939         default:\r
940                 status = STATUS_INVALID_DEVICE_REQUEST;\r
941                 break;\r
942         }\r
943         irp->IoStatus.Status = status;\r
944         if (status != STATUS_PENDING)\r
945                 IoCompleteRequest(irp, IO_NO_INCREMENT);\r
946 \r
947         return status;\r
948 }\r
949 \r
950 \r
951 #ifndef MAYUD_NT4\r
952 // detour IRP_MJ_POWER\r
953 NTSTATUS detourPower(IN PDEVICE_OBJECT deviceObject, IN PIRP irp)\r
954 {\r
955         UNREFERENCED_PARAMETER(deviceObject);\r
956 \r
957         PoStartNextPowerIrp(irp);\r
958         irp->IoStatus.Status = STATUS_SUCCESS;\r
959         irp->IoStatus.Information = 0;\r
960         IoCompleteRequest(irp, IO_NO_INCREMENT);\r
961         return STATUS_SUCCESS;\r
962 }\r
963 #endif // !MAYUD_NT4\r
964 \r
965 \r
966 // filter IRP_MJ_READ\r
967 NTSTATUS filterRead(IN PDEVICE_OBJECT deviceObject, IN PIRP irp)\r
968 {\r
969         NTSTATUS status;\r
970         PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation(irp);\r
971         FilterDeviceExtension *filterDevExt =\r
972                 (FilterDeviceExtension*)deviceObject->DeviceExtension;\r
973         DetourDeviceExtension *detourDevExt =\r
974                 (DetourDeviceExtension*)filterDevExt->detourDevObj->DeviceExtension;\r
975         KIRQL currentIrql;\r
976 \r
977         KeAcquireSpinLock(&detourDevExt->lock, &currentIrql);\r
978         if (detourDevExt->isOpen && !detourDevExt->wasCleanupInitiated)\r
979                 // read from que\r
980         {\r
981                 ULONG len = irpSp->Parameters.Read.Length;\r
982 \r
983                 KeReleaseSpinLock(&detourDevExt->lock, currentIrql);\r
984                 irp->IoStatus.Information = 0;\r
985                 KeAcquireSpinLock(&filterDevExt->lock, &currentIrql);\r
986                 if (len == 0)\r
987                         status = STATUS_SUCCESS;\r
988                 else if (len % sizeof(KEYBOARD_INPUT_DATA))\r
989                         status = STATUS_BUFFER_TOO_SMALL;\r
990                 else\r
991                         status = readq(&filterDevExt->readQue, irp);\r
992                 KeReleaseSpinLock(&filterDevExt->lock, currentIrql);\r
993                 if (status != STATUS_PENDING) {\r
994                         irp->IoStatus.Status = status;\r
995                         IoCompleteRequest(irp, IO_NO_INCREMENT);\r
996                         return status;\r
997                 }\r
998         } else {\r
999                 KeReleaseSpinLock(&detourDevExt->lock, currentIrql);\r
1000         }\r
1001         KeAcquireSpinLock(&filterDevExt->lock, &currentIrql);\r
1002         filterDevExt->irpq = irp;\r
1003         KeReleaseSpinLock(&filterDevExt->lock, currentIrql);\r
1004 \r
1005         *IoGetNextIrpStackLocation(irp) = *irpSp;\r
1006         IoSetCompletionRoutine(irp, filterReadCompletion, NULL, TRUE, TRUE, TRUE);\r
1007         return IoCallDriver(filterDevExt->kbdClassDevObj, irp);\r
1008 }\r
1009 \r
1010 \r
1011 // pass throught irp to keyboard class driver\r
1012 NTSTATUS filterPassThrough(IN PDEVICE_OBJECT deviceObject, IN PIRP irp)\r
1013 {\r
1014         FilterDeviceExtension *filterDevExt =\r
1015                 (FilterDeviceExtension*)deviceObject->DeviceExtension;\r
1016 \r
1017         *IoGetNextIrpStackLocation(irp) = *IoGetCurrentIrpStackLocation(irp);\r
1018         IoSetCompletionRoutine(irp, filterGenericCompletion,\r
1019                                                    NULL, TRUE, TRUE, TRUE);\r
1020         return IoCallDriver(filterDevExt->kbdClassDevObj, irp);\r
1021 }\r
1022 \r
1023 \r
1024 #ifndef MAYUD_NT4\r
1025 // filter IRP_MJ_POWER\r
1026 NTSTATUS filterPower(IN PDEVICE_OBJECT deviceObject, IN PIRP irp)\r
1027 {\r
1028         FilterDeviceExtension *filterDevExt =\r
1029                 (FilterDeviceExtension*)deviceObject->DeviceExtension;\r
1030 \r
1031         PoStartNextPowerIrp(irp);\r
1032         IoSkipCurrentIrpStackLocation(irp);\r
1033         return PoCallDriver(filterDevExt->kbdClassDevObj, irp);\r
1034 }\r
1035 #endif // !MAYUD_NT4\r
1036 NTSTATUS filterPnP(IN PDEVICE_OBJECT deviceObject, IN PIRP irp)\r
1037 {\r
1038         PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation(irp);\r
1039         FilterDeviceExtension *filterDevExt =\r
1040                 (FilterDeviceExtension*)deviceObject->DeviceExtension;\r
1041         DetourDeviceExtension *detourDevExt =\r
1042                 (DetourDeviceExtension*)filterDevExt->detourDevObj->DeviceExtension;\r
1043         KIRQL currentIrql;\r
1044         NTSTATUS status;\r
1045         ULONG minor;\r
1046         PIRP cancelIrp;\r
1047         PDRIVER_OBJECT driverObject = deviceObject->DriverObject;\r
1048 \r
1049         minor = irpSp->MinorFunction;\r
1050         IoSkipCurrentIrpStackLocation(irp);\r
1051         status = IoCallDriver(filterDevExt->kbdClassDevObj, irp);\r
1052         DEBUG_LOG(("filterPnP: minor=%d(%x)", minor, minor));\r
1053         switch (minor) {\r
1054         case IRP_MN_SURPRISE_REMOVAL:\r
1055         case IRP_MN_REMOVE_DEVICE:\r
1056                 KeAcquireSpinLock(&detourDevExt->lock, &currentIrql);\r
1057                 if (detourDevExt->filterDevObj == deviceObject) {\r
1058                         PDEVICE_OBJECT devObj = deviceObject->DriverObject->DeviceObject;\r
1059 \r
1060                         DEBUG_LOG(("filterPnP: current filter(%x) was removed", deviceObject));\r
1061                         detourDevExt->filterDevObj = NULL;\r
1062                         while (devObj->NextDevice) {\r
1063                                 if (devObj != deviceObject) {\r
1064                                         detourDevExt->filterDevObj = devObj;\r
1065                                         break;\r
1066                                 }\r
1067                                 devObj = devObj->NextDevice;\r
1068                         }\r
1069                         DEBUG_LOG(("filterPnP: current filter was changed to %x", detourDevExt->filterDevObj));\r
1070                 }\r
1071                 KeReleaseSpinLock(&detourDevExt->lock, currentIrql);\r
1072                 // detach\r
1073                 IoDetachDevice(filterDevExt->kbdClassDevObj);\r
1074 \r
1075                 KeAcquireSpinLock(&filterDevExt->lock, &currentIrql);\r
1076                 // TODO: at this point, the irp may be completed (but what can I do for it ?)\r
1077                 cancelIrp = filterDevExt->irpq;\r
1078                 KqFinalize(&filterDevExt->readQue);\r
1079 \r
1080                 KeReleaseSpinLock(&filterDevExt->lock, currentIrql);\r
1081                 if (cancelIrp) {\r
1082                         IoCancelIrp(cancelIrp);\r
1083                 }\r
1084                 IoDeleteDevice(deviceObject);\r
1085                 DEBUG_LOG(("delete filter device: %x", deviceObject));\r
1086                 DEBUG_LOGChain(driverObject);\r
1087                 break;\r
1088         default:\r
1089                 break;\r
1090         }\r
1091         return status;\r
1092 }\r
1093 \r
1094 \r
1095 #ifdef USE_TOUCHPAD\r
1096 //\r
1097 NTSTATUS filterTouchpadCompletion(IN PDEVICE_OBJECT deviceObject,\r
1098                                                                   IN PIRP irp, IN PVOID context)\r
1099 {\r
1100         KIRQL currentIrql;\r
1101         FilterDeviceExtension *filterDevExt =\r
1102                 (FilterDeviceExtension*)deviceObject->DeviceExtension;\r
1103         PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation(irp);\r
1104         //PIO_STACK_LOCATION irpSp = IoGetNextIrpStackLocation(irp);\r
1105         UCHAR *data = irp->UserBuffer;\r
1106         UCHAR pressure;\r
1107 \r
1108         UNREFERENCED_PARAMETER(context);\r
1109 \r
1110         if (irp->PendingReturned)\r
1111                 IoMarkIrpPending(irp);\r
1112 \r
1113         if (data)\r
1114                 pressure = data[TOUCHPAD_PRESSURE_OFFSET];\r
1115         else\r
1116                 pressure = 0;\r
1117 \r
1118         if (data) {\r
1119                 ULONG *p = (ULONG*)data;\r
1120                 //DEBUG_LOG(("UserBuffer: %2x %2x %2x %2x", data[4], data[5], data[6], data[7]));\r
1121                 //DEBUG_LOG(("UserBuffer: %x %x %x %x %x %x %x %x", p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7]));\r
1122         }\r
1123         KeAcquireSpinLock(&filterDevExt->lock, &currentIrql);\r
1124         if (filterDevExt->isTouched == FALSE && pressure) {\r
1125                 KIRQL currentIrql, cancelIrql;\r
1126                 PDEVICE_OBJECT detourDevObj = filterDevExt->detourDevObj;\r
1127                 DetourDeviceExtension *detourDevExt =\r
1128                         (DetourDeviceExtension*)detourDevObj->DeviceExtension;\r
1129                 if (detourDevExt->isOpen) {\r
1130                         KEYBOARD_INPUT_DATA PadKey = {0, TOUCHPAD_SCANCODE, 0, 0, 0};\r
1131                         KeAcquireSpinLock(&detourDevExt->lock, &currentIrql);\r
1132                         // if detour is opened, key datum are forwarded to detour\r
1133                         KqEnque(&detourDevExt->readQue, &PadKey, 1);\r
1134                         detourDevExt->filterDevObj = deviceObject;\r
1135 \r
1136                         if (detourDevExt->irpq) {\r
1137                                 if (readq(&detourDevExt->readQue, detourDevExt->irpq) ==\r
1138                                                 STATUS_SUCCESS) {\r
1139                                         IoAcquireCancelSpinLock(&cancelIrql);\r
1140                                         IoSetCancelRoutine(detourDevExt->irpq, NULL);\r
1141                                         IoReleaseCancelSpinLock(cancelIrql);\r
1142                                         IoCompleteRequest(detourDevExt->irpq, IO_KEYBOARD_INCREMENT);\r
1143                                         detourDevExt->irpq = NULL;\r
1144                                 }\r
1145                         }\r
1146                         KeReleaseSpinLock(&detourDevExt->lock, currentIrql);\r
1147                 }\r
1148                 filterDevExt->isTouched = TRUE;\r
1149         } else {\r
1150                 if (filterDevExt->isTouched == TRUE && pressure == 0) {\r
1151                         KIRQL currentIrql, cancelIrql;\r
1152                         PDEVICE_OBJECT detourDevObj = filterDevExt->detourDevObj;\r
1153                         DetourDeviceExtension *detourDevExt =\r
1154                                 (DetourDeviceExtension*)detourDevObj->DeviceExtension;\r
1155                         if (detourDevExt->isOpen) {\r
1156                                 KEYBOARD_INPUT_DATA PadKey = {0, TOUCHPAD_SCANCODE, 1, 0, 0};\r
1157                                 KeAcquireSpinLock(&detourDevExt->lock, &currentIrql);\r
1158                                 // if detour is opened, key datum are forwarded to detour\r
1159                                 KqEnque(&detourDevExt->readQue, &PadKey, 1);\r
1160                                 detourDevExt->filterDevObj = deviceObject;\r
1161 \r
1162                                 if (detourDevExt->irpq) {\r
1163                                         if (readq(&detourDevExt->readQue, detourDevExt->irpq) ==\r
1164                                                         STATUS_SUCCESS) {\r
1165                                                 IoAcquireCancelSpinLock(&cancelIrql);\r
1166                                                 IoSetCancelRoutine(detourDevExt->irpq, NULL);\r
1167                                                 IoReleaseCancelSpinLock(cancelIrql);\r
1168                                                 IoCompleteRequest(detourDevExt->irpq, IO_KEYBOARD_INCREMENT);\r
1169                                                 detourDevExt->irpq = NULL;\r
1170                                         }\r
1171                                 }\r
1172                                 KeReleaseSpinLock(&detourDevExt->lock, currentIrql);\r
1173                         }\r
1174                         filterDevExt->isTouched = FALSE;\r
1175                 }\r
1176         }\r
1177         //DEBUG_LOG(("touchpad pressed: out=%u in=%u code=%u status=%x SystemBuffer=%x UserBuffer=%x", irpSp->Parameters.DeviceIoControl.OutputBufferLength, irpSp->Parameters.DeviceIoControl.InputBufferLength, irpSp->Parameters.DeviceIoControl.IoControlCode, irp->IoStatus.Status, irp->AssociatedIrp.SystemBuffer, irp->UserBuffer));\r
1178         KeReleaseSpinLock(&filterDevExt->lock, currentIrql);\r
1179         return STATUS_SUCCESS;\r
1180 }\r
1181 \r
1182 \r
1183 // filter touchpad input\r
1184 NTSTATUS filterTouchpad(IN PDEVICE_OBJECT deviceObject, IN PIRP irp)\r
1185 {\r
1186         FilterDeviceExtension *filterDevExt =\r
1187                 (FilterDeviceExtension*)deviceObject->DeviceExtension;\r
1188 \r
1189         *IoGetNextIrpStackLocation(irp) = *IoGetCurrentIrpStackLocation(irp);\r
1190         IoSetCompletionRoutine(irp, filterTouchpadCompletion,\r
1191                                                    NULL, TRUE, TRUE, TRUE);\r
1192         return IoCallDriver(filterDevExt->kbdClassDevObj, irp);\r
1193 }\r
1194 #endif\r
1195 \r
1196 \r
1197 NTSTATUS detourPnP(IN PDEVICE_OBJECT deviceObject, IN PIRP irp)\r
1198 {\r
1199         UNREFERENCED_PARAMETER(deviceObject);\r
1200 \r
1201         IoSkipCurrentIrpStackLocation(irp);\r
1202         irp->IoStatus.Status = STATUS_SUCCESS;\r
1203         irp->IoStatus.Information = 0;\r
1204         IoCompleteRequest(irp, IO_NO_INCREMENT);\r
1205         return STATUS_SUCCESS;\r
1206 }\r