xref: /reactos/drivers/hid/kbdhid/kbdhid.c (revision 40462c92)
1 /*
2  * PROJECT:     ReactOS HID Stack
3  * LICENSE:     GPL - See COPYING in the top level directory
4  * FILE:        drivers/hid/kbdhid/kbdhid.c
5  * PURPOSE:     Keyboard HID Driver
6  * PROGRAMMERS:
7  *              Michael Martin (michael.martin@reactos.org)
8  *              Johannes Anderwald (johannes.anderwald@reactos.org)
9  */
10 
11 #include "kbdhid.h"
12 
13 VOID
14 KbdHid_DispatchInputData(
15     IN PKBDHID_DEVICE_EXTENSION DeviceExtension,
16     IN PKEYBOARD_INPUT_DATA InputData)
17 {
18     KIRQL OldIrql;
19     ULONG InputDataConsumed;
20 
21     if (!DeviceExtension->ClassService)
22         return;
23 
24     /* sanity check */
25     ASSERT(DeviceExtension->ClassService);
26     ASSERT(DeviceExtension->ClassDeviceObject);
27 
28     /* raise irql */
29     KeRaiseIrql(DISPATCH_LEVEL, &OldIrql);
30 
31     /* dispatch input data */
32     (*(PSERVICE_CALLBACK_ROUTINE)DeviceExtension->ClassService)(DeviceExtension->ClassDeviceObject, InputData, InputData + 1, &InputDataConsumed);
33 
34     /* lower irql to previous level */
35     KeLowerIrql(OldIrql);
36 }
37 
38 BOOLEAN
39 NTAPI
40 KbdHid_InsertScanCodes(
41     IN PVOID  Context,
42     IN PCHAR  NewScanCodes,
43     IN ULONG  Length)
44 {
45     KEYBOARD_INPUT_DATA InputData;
46     ULONG Index;
47     PKBDHID_DEVICE_EXTENSION DeviceExtension;
48     CHAR Prefix = 0;
49 
50     /* get device extension */
51     DeviceExtension = Context;
52 
53     for(Index = 0; Index < Length; Index++)
54     {
55         DPRINT("[KBDHID] ScanCode Index %lu ScanCode %x\n", Index, NewScanCodes[Index] & 0xFF);
56 
57         /* check if this is E0 or E1 prefix */
58         if (NewScanCodes[Index] == (CHAR)0xE0 || NewScanCodes[Index] == (CHAR)0xE1)
59         {
60             Prefix = NewScanCodes[Index];
61             continue;
62         }
63 
64         /* init input data */
65         RtlZeroMemory(&InputData, sizeof(KEYBOARD_INPUT_DATA));
66 
67         /* use keyboard unit id */
68         InputData.UnitId = DeviceExtension->KeyboardTypematic.UnitId;
69 
70         if (NewScanCodes[Index] & 0x80)
71         {
72             /* scan codes with 0x80 flag are a key break */
73             InputData.Flags |= KEY_BREAK;
74         }
75 
76         /* set a prefix if needed */
77         if (Prefix)
78         {
79             InputData.Flags |= (Prefix == (CHAR)0xE0 ? KEY_E0 : KEY_E1);
80             Prefix = 0;
81         }
82 
83         /* store key code */
84         InputData.MakeCode = NewScanCodes[Index] & 0x7F;
85 
86         /* dispatch scan codes */
87         KbdHid_DispatchInputData(Context, &InputData);
88     }
89 
90     /* done */
91     return TRUE;
92 }
93 
94 
95 NTSTATUS
96 NTAPI
97 KbdHid_ReadCompletion(
98     IN PDEVICE_OBJECT  DeviceObject,
99     IN PIRP  Irp,
100     IN PVOID  Context)
101 {
102     PKBDHID_DEVICE_EXTENSION DeviceExtension;
103     NTSTATUS Status;
104     ULONG ButtonLength;
105 
106     /* get device extension */
107     DeviceExtension = Context;
108 
109     if (Irp->IoStatus.Status == STATUS_PRIVILEGE_NOT_HELD ||
110         Irp->IoStatus.Status == STATUS_DEVICE_NOT_CONNECTED ||
111         Irp->IoStatus.Status == STATUS_CANCELLED ||
112         DeviceExtension->StopReadReport)
113     {
114         /* failed to read or should be stopped*/
115         DPRINT1("[KBDHID] ReadCompletion terminating read Status %x\n", Irp->IoStatus.Status);
116 
117         /* report no longer active */
118         DeviceExtension->ReadReportActive = FALSE;
119 
120         /* request stopping of the report cycle */
121         DeviceExtension->StopReadReport = FALSE;
122 
123         /* signal completion event */
124         KeSetEvent(&DeviceExtension->ReadCompletionEvent, 0, 0);
125         return STATUS_MORE_PROCESSING_REQUIRED;
126     }
127 
128     //
129     // print out raw report
130     //
131     ASSERT(DeviceExtension->ReportLength >= 9);
132     DPRINT("[KBDHID] ReadCompletion %02x %02x %02x %02x %02x %02x %02x %02x %02x\n", DeviceExtension->Report[0], DeviceExtension->Report[1], DeviceExtension->Report[2],
133         DeviceExtension->Report[3], DeviceExtension->Report[4], DeviceExtension->Report[5],
134         DeviceExtension->Report[6], DeviceExtension->Report[7], DeviceExtension->Report[8]);
135 
136 
137     /* get current usages */
138     ButtonLength = DeviceExtension->UsageListLength;
139     Status = HidP_GetUsagesEx(HidP_Input,
140                               HIDP_LINK_COLLECTION_UNSPECIFIED,
141                               DeviceExtension->CurrentUsageList,
142                               &ButtonLength,
143                               DeviceExtension->PreparsedData,
144                               DeviceExtension->Report,
145                               DeviceExtension->ReportLength);
146     ASSERT(Status == HIDP_STATUS_SUCCESS);
147 
148     /* FIXME check if needs mapping */
149 
150     /* get usage difference */
151     Status = HidP_UsageAndPageListDifference(DeviceExtension->PreviousUsageList,
152                                              DeviceExtension->CurrentUsageList,
153                                              DeviceExtension->BreakUsageList,
154                                              DeviceExtension->MakeUsageList,
155                                              DeviceExtension->UsageListLength);
156     ASSERT(Status == HIDP_STATUS_SUCCESS);
157 
158     /* replace previous usage list with current list */
159     RtlMoveMemory(DeviceExtension->PreviousUsageList,
160                   DeviceExtension->CurrentUsageList,
161                   sizeof(USAGE_AND_PAGE) * DeviceExtension->UsageListLength);
162 
163     /* translate break usage list */
164     HidP_TranslateUsageAndPagesToI8042ScanCodes(DeviceExtension->BreakUsageList,
165                                                 DeviceExtension->UsageListLength,
166                                                 HidP_Keyboard_Break,
167                                                 &DeviceExtension->ModifierState,
168                                                 KbdHid_InsertScanCodes,
169                                                 DeviceExtension);
170     ASSERT(Status == HIDP_STATUS_SUCCESS);
171 
172     /* translate new usage list */
173     HidP_TranslateUsageAndPagesToI8042ScanCodes(DeviceExtension->MakeUsageList,
174                                                 DeviceExtension->UsageListLength,
175                                                 HidP_Keyboard_Make,
176                                                 &DeviceExtension->ModifierState,
177                                                 KbdHid_InsertScanCodes,
178                                                 DeviceExtension);
179     ASSERT(Status == HIDP_STATUS_SUCCESS);
180 
181     /* re-init read */
182     KbdHid_InitiateRead(DeviceExtension);
183 
184     /* stop completion */
185     return STATUS_MORE_PROCESSING_REQUIRED;
186 }
187 
188 NTSTATUS
189 KbdHid_InitiateRead(
190     IN PKBDHID_DEVICE_EXTENSION DeviceExtension)
191 {
192     PIO_STACK_LOCATION IoStack;
193     NTSTATUS Status;
194 
195     /* re-use irp */
196     IoReuseIrp(DeviceExtension->Irp, STATUS_SUCCESS);
197 
198     /* init irp */
199     DeviceExtension->Irp->MdlAddress = DeviceExtension->ReportMDL;
200 
201     /* get next stack location */
202     IoStack = IoGetNextIrpStackLocation(DeviceExtension->Irp);
203 
204     /* init stack location */
205     IoStack->Parameters.Read.Length = DeviceExtension->ReportLength;
206     IoStack->Parameters.Read.Key = 0;
207     IoStack->Parameters.Read.ByteOffset.QuadPart = 0LL;
208     IoStack->MajorFunction = IRP_MJ_READ;
209     IoStack->FileObject = DeviceExtension->FileObject;
210 
211     /* set completion routine */
212     IoSetCompletionRoutine(DeviceExtension->Irp, KbdHid_ReadCompletion, DeviceExtension, TRUE, TRUE, TRUE);
213 
214     /* read is active */
215     DeviceExtension->ReadReportActive = TRUE;
216 
217     /* start the read */
218     Status = IoCallDriver(DeviceExtension->NextDeviceObject, DeviceExtension->Irp);
219 
220     /* done */
221     return Status;
222 }
223 
224 NTSTATUS
225 NTAPI
226 KbdHid_CreateCompletion(
227     IN PDEVICE_OBJECT  DeviceObject,
228     IN PIRP  Irp,
229     IN PVOID  Context)
230 {
231     KeSetEvent((PKEVENT)Context, 0, FALSE);
232     return STATUS_MORE_PROCESSING_REQUIRED;
233 }
234 
235 
236 NTSTATUS
237 NTAPI
238 KbdHid_Create(
239     IN PDEVICE_OBJECT DeviceObject,
240     IN PIRP Irp)
241 {
242     PIO_STACK_LOCATION IoStack;
243     NTSTATUS Status;
244     KEVENT Event;
245     PKBDHID_DEVICE_EXTENSION DeviceExtension;
246 
247     DPRINT("[KBDHID]: IRP_MJ_CREATE\n");
248 
249     /* get device extension */
250     DeviceExtension = DeviceObject->DeviceExtension;
251 
252     /* get stack location */
253     IoStack = IoGetCurrentIrpStackLocation(Irp);
254 
255     /* copy stack location to next */
256     IoCopyCurrentIrpStackLocationToNext(Irp);
257 
258     /* init event */
259     KeInitializeEvent(&Event, NotificationEvent, FALSE);
260 
261     /* prepare irp */
262     IoSetCompletionRoutine(Irp, KbdHid_CreateCompletion, &Event, TRUE, TRUE, TRUE);
263 
264     /* call lower driver */
265     Status = IoCallDriver(DeviceExtension->NextDeviceObject, Irp);
266     if (Status == STATUS_PENDING)
267     {
268         /* request pending */
269         KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
270     }
271 
272     /* check for success */
273     if (!NT_SUCCESS(Status))
274     {
275         /* failed */
276         Irp->IoStatus.Status = Status;
277         IoCompleteRequest(Irp, IO_NO_INCREMENT);
278         return Status;
279     }
280 
281     /* is the driver already in use */
282     if (DeviceExtension->FileObject == NULL)
283     {
284          /* did the caller specify correct attributes */
285          ASSERT(IoStack->Parameters.Create.SecurityContext);
286          if (IoStack->Parameters.Create.SecurityContext->DesiredAccess)
287          {
288              /* store file object */
289              DeviceExtension->FileObject = IoStack->FileObject;
290 
291              /* reset event */
292              KeClearEvent(&DeviceExtension->ReadCompletionEvent);
293 
294              /* initiating read */
295              Status = KbdHid_InitiateRead(DeviceExtension);
296              DPRINT("[KBDHID] KbdHid_InitiateRead: status %x\n", Status);
297              if (Status == STATUS_PENDING)
298              {
299                  /* report irp is pending */
300                  Status = STATUS_SUCCESS;
301              }
302          }
303     }
304 
305     /* complete request */
306     Irp->IoStatus.Status = Status;
307     IoCompleteRequest(Irp, IO_NO_INCREMENT);
308     return Status;
309 }
310 
311 
312 NTSTATUS
313 NTAPI
314 KbdHid_Close(
315     IN PDEVICE_OBJECT DeviceObject,
316     IN PIRP Irp)
317 {
318     PKBDHID_DEVICE_EXTENSION DeviceExtension;
319 
320     /* get device extension */
321     DeviceExtension = DeviceObject->DeviceExtension;
322 
323     DPRINT("[KBDHID] IRP_MJ_CLOSE ReadReportActive %x\n", DeviceExtension->ReadReportActive);
324 
325     if (DeviceExtension->ReadReportActive)
326     {
327         /* request stopping of the report cycle */
328         DeviceExtension->StopReadReport = TRUE;
329 
330         /* wait until the reports have been read */
331         KeWaitForSingleObject(&DeviceExtension->ReadCompletionEvent, Executive, KernelMode, FALSE, NULL);
332 
333         /* cancel irp */
334         IoCancelIrp(DeviceExtension->Irp);
335     }
336 
337     DPRINT("[KBDHID] IRP_MJ_CLOSE ReadReportActive %x\n", DeviceExtension->ReadReportActive);
338 
339     /* remove file object */
340     DeviceExtension->FileObject = NULL;
341 
342     /* skip location */
343     IoSkipCurrentIrpStackLocation(Irp);
344 
345     /* pass irp to down the stack */
346     return IoCallDriver(DeviceExtension->NextDeviceObject, Irp);
347 }
348 
349 NTSTATUS
350 NTAPI
351 KbdHid_InternalDeviceControl(
352     IN PDEVICE_OBJECT DeviceObject,
353     IN PIRP Irp)
354 {
355     PIO_STACK_LOCATION IoStack;
356     PKBDHID_DEVICE_EXTENSION DeviceExtension;
357     PCONNECT_DATA Data;
358     PKEYBOARD_ATTRIBUTES Attributes;
359 
360     /* get current stack location */
361     IoStack = IoGetCurrentIrpStackLocation(Irp);
362 
363     DPRINT("[KBDHID] InternalDeviceControl %x\n", IoStack->Parameters.DeviceIoControl.IoControlCode);
364 
365     /* get device extension */
366     DeviceExtension = DeviceObject->DeviceExtension;
367 
368     switch (IoStack->Parameters.DeviceIoControl.IoControlCode)
369     {
370         case IOCTL_KEYBOARD_QUERY_ATTRIBUTES:
371             /* verify output buffer length */
372             if (IoStack->Parameters.DeviceIoControl.OutputBufferLength < sizeof(MOUSE_ATTRIBUTES))
373             {
374                 /* invalid request */
375                 DPRINT1("[KBDHID] IOCTL_KEYBOARD_QUERY_ATTRIBUTES Buffer too small\n");
376                 Irp->IoStatus.Status = STATUS_BUFFER_TOO_SMALL;
377                 IoCompleteRequest(Irp, IO_NO_INCREMENT);
378                 return STATUS_BUFFER_TOO_SMALL;
379             }
380 
381             /* get output buffer */
382             Attributes = Irp->AssociatedIrp.SystemBuffer;
383 
384             /* copy attributes */
385             RtlCopyMemory(Attributes,
386                           &DeviceExtension->Attributes,
387                           sizeof(KEYBOARD_ATTRIBUTES));
388 
389             /* complete request */
390             Irp->IoStatus.Information = sizeof(MOUSE_ATTRIBUTES);
391             Irp->IoStatus.Status = STATUS_SUCCESS;
392             IoCompleteRequest(Irp, IO_NO_INCREMENT);
393             return STATUS_SUCCESS;
394 
395         case IOCTL_INTERNAL_KEYBOARD_CONNECT:
396             /* verify input buffer length */
397             if (IoStack->Parameters.DeviceIoControl.InputBufferLength < sizeof(CONNECT_DATA))
398             {
399                 /* invalid request */
400                 Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
401                 IoCompleteRequest(Irp, IO_NO_INCREMENT);
402                 return STATUS_INVALID_PARAMETER;
403             }
404 
405             /* is it already connected */
406             if (DeviceExtension->ClassService)
407             {
408                 /* already connected */
409                 Irp->IoStatus.Status = STATUS_SHARING_VIOLATION;
410                 IoCompleteRequest(Irp, IO_NO_INCREMENT);
411                 return STATUS_SHARING_VIOLATION;
412             }
413 
414             /* get connect data */
415             Data = IoStack->Parameters.DeviceIoControl.Type3InputBuffer;
416 
417             /* store connect details */
418             DeviceExtension->ClassDeviceObject = Data->ClassDeviceObject;
419             DeviceExtension->ClassService = Data->ClassService;
420 
421             /* completed successfully */
422             Irp->IoStatus.Status = STATUS_SUCCESS;
423             IoCompleteRequest(Irp, IO_NO_INCREMENT);
424             return STATUS_SUCCESS;
425 
426         case IOCTL_INTERNAL_KEYBOARD_DISCONNECT:
427             /* not implemented */
428             Irp->IoStatus.Status = STATUS_NOT_IMPLEMENTED;
429             IoCompleteRequest(Irp, IO_NO_INCREMENT);
430             return STATUS_NOT_IMPLEMENTED;
431 
432         case IOCTL_INTERNAL_KEYBOARD_ENABLE:
433             /* not supported */
434             Irp->IoStatus.Status = STATUS_NOT_SUPPORTED;
435             IoCompleteRequest(Irp, IO_NO_INCREMENT);
436             return STATUS_NOT_SUPPORTED;
437 
438         case IOCTL_INTERNAL_KEYBOARD_DISABLE:
439             /* not supported */
440             Irp->IoStatus.Status = STATUS_NOT_SUPPORTED;
441             IoCompleteRequest(Irp, IO_NO_INCREMENT);
442             return STATUS_NOT_SUPPORTED;
443 
444         case IOCTL_KEYBOARD_QUERY_INDICATORS:
445             if (IoStack->Parameters.DeviceIoControl.OutputBufferLength < sizeof(KEYBOARD_INDICATOR_PARAMETERS))
446             {
447                 /* invalid parameter */
448                 Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
449                 IoCompleteRequest(Irp, IO_NO_INCREMENT);
450                 return STATUS_INVALID_PARAMETER;
451             }
452 
453             /* copy indicators */
454             RtlCopyMemory(Irp->AssociatedIrp.SystemBuffer,
455                           &DeviceExtension->KeyboardIndicator,
456                           sizeof(KEYBOARD_INDICATOR_PARAMETERS));
457 
458             /* complete request */
459             Irp->IoStatus.Status = STATUS_SUCCESS;
460             Irp->IoStatus.Information = sizeof(KEYBOARD_INDICATOR_PARAMETERS);
461             IoCompleteRequest(Irp, IO_NO_INCREMENT);
462             return STATUS_NOT_IMPLEMENTED;
463 
464         case IOCTL_KEYBOARD_QUERY_TYPEMATIC:
465             if (IoStack->Parameters.DeviceIoControl.OutputBufferLength < sizeof(KEYBOARD_TYPEMATIC_PARAMETERS))
466             {
467                 /* invalid parameter */
468                 Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
469                 IoCompleteRequest(Irp, IO_NO_INCREMENT);
470                 return STATUS_INVALID_PARAMETER;
471             }
472 
473             /* copy indicators */
474             RtlCopyMemory(Irp->AssociatedIrp.SystemBuffer,
475                           &DeviceExtension->KeyboardTypematic,
476                           sizeof(KEYBOARD_TYPEMATIC_PARAMETERS));
477 
478             /* done */
479             Irp->IoStatus.Status = STATUS_SUCCESS;
480             Irp->IoStatus.Information = sizeof(KEYBOARD_TYPEMATIC_PARAMETERS);
481             IoCompleteRequest(Irp, IO_NO_INCREMENT);
482             return STATUS_SUCCESS;
483 
484         case IOCTL_KEYBOARD_SET_INDICATORS:
485             if (IoStack->Parameters.DeviceIoControl.InputBufferLength < sizeof(KEYBOARD_INDICATOR_PARAMETERS))
486             {
487                 /* invalid parameter */
488                 Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
489                 IoCompleteRequest(Irp, IO_NO_INCREMENT);
490                 return STATUS_INVALID_PARAMETER;
491             }
492 
493             /* copy indicators */
494             RtlCopyMemory(&DeviceExtension->KeyboardIndicator,
495                           Irp->AssociatedIrp.SystemBuffer,
496                           sizeof(KEYBOARD_INDICATOR_PARAMETERS));
497 
498             /* done */
499             Irp->IoStatus.Status = STATUS_SUCCESS;
500             Irp->IoStatus.Information = 0;
501             IoCompleteRequest(Irp, IO_NO_INCREMENT);
502             return STATUS_SUCCESS;
503 
504         case IOCTL_KEYBOARD_SET_TYPEMATIC:
505             if (IoStack->Parameters.DeviceIoControl.InputBufferLength < sizeof(KEYBOARD_TYPEMATIC_PARAMETERS))
506             {
507                 /* invalid parameter */
508                 Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
509                 IoCompleteRequest(Irp, IO_NO_INCREMENT);
510                 return STATUS_INVALID_PARAMETER;
511             }
512 
513             /* copy indicators */
514             RtlCopyMemory(&DeviceExtension->KeyboardTypematic,
515                           Irp->AssociatedIrp.SystemBuffer,
516                           sizeof(KEYBOARD_TYPEMATIC_PARAMETERS));
517 
518             /* done */
519             Irp->IoStatus.Status = STATUS_SUCCESS;
520             Irp->IoStatus.Information = 0;
521             IoCompleteRequest(Irp, IO_NO_INCREMENT);
522             return STATUS_SUCCESS;
523 
524         case IOCTL_KEYBOARD_QUERY_INDICATOR_TRANSLATION:
525             /* not implemented */
526             DPRINT1("IOCTL_KEYBOARD_QUERY_INDICATOR_TRANSLATION not implemented\n");
527             Irp->IoStatus.Status = STATUS_NOT_IMPLEMENTED;
528             IoCompleteRequest(Irp, IO_NO_INCREMENT);
529             return STATUS_NOT_IMPLEMENTED;
530     }
531 
532     /* unknown control code */
533     DPRINT1("[KBDHID] Unknown DeviceControl %x\n", IoStack->Parameters.DeviceIoControl.IoControlCode);
534     /* unknown request not supported */
535     Irp->IoStatus.Status = STATUS_NOT_SUPPORTED;
536     IoCompleteRequest(Irp, IO_NO_INCREMENT);
537     return STATUS_NOT_SUPPORTED;
538 }
539 
540 NTSTATUS
541 NTAPI
542 KbdHid_DeviceControl(
543     IN PDEVICE_OBJECT DeviceObject,
544     IN PIRP Irp)
545 {
546     PKBDHID_DEVICE_EXTENSION DeviceExtension;
547 
548     /* get device extension */
549     DeviceExtension = DeviceObject->DeviceExtension;
550 
551     /* skip stack location */
552     IoSkipCurrentIrpStackLocation(Irp);
553 
554     /* pass and forget */
555     return IoCallDriver(DeviceExtension->NextDeviceObject, Irp);
556 }
557 
558 NTSTATUS
559 NTAPI
560 KbdHid_Power(
561     IN PDEVICE_OBJECT DeviceObject,
562     IN PIRP Irp)
563 {
564     PKBDHID_DEVICE_EXTENSION DeviceExtension;
565 
566     DeviceExtension = DeviceObject->DeviceExtension;
567     PoStartNextPowerIrp(Irp);
568     IoSkipCurrentIrpStackLocation(Irp);
569     return PoCallDriver(DeviceExtension->NextDeviceObject, Irp);
570 }
571 
572 NTSTATUS
573 NTAPI
574 KbdHid_SystemControl(
575     IN PDEVICE_OBJECT DeviceObject,
576     IN PIRP Irp)
577 {
578     PKBDHID_DEVICE_EXTENSION DeviceExtension;
579 
580     DeviceExtension = DeviceObject->DeviceExtension;
581     IoSkipCurrentIrpStackLocation(Irp);
582     return IoCallDriver(DeviceExtension->NextDeviceObject, Irp);
583 }
584 
585 NTSTATUS
586 KbdHid_SubmitRequest(
587     PDEVICE_OBJECT DeviceObject,
588     ULONG IoControlCode,
589     ULONG InputBufferSize,
590     PVOID InputBuffer,
591     ULONG OutputBufferSize,
592     PVOID OutputBuffer)
593 {
594     KEVENT Event;
595     PKBDHID_DEVICE_EXTENSION DeviceExtension;
596     PIRP Irp;
597     NTSTATUS Status;
598     IO_STATUS_BLOCK IoStatus;
599 
600     /* get device extension */
601     DeviceExtension = DeviceObject->DeviceExtension;
602 
603     /* init event */
604     KeInitializeEvent(&Event, NotificationEvent, FALSE);
605 
606     /* build request */
607     Irp = IoBuildDeviceIoControlRequest(IoControlCode,
608                                         DeviceExtension->NextDeviceObject,
609                                         InputBuffer,
610                                         InputBufferSize,
611                                         OutputBuffer,
612                                         OutputBufferSize,
613                                         FALSE,
614                                         &Event,
615                                         &IoStatus);
616     if (!Irp)
617     {
618         /* no memory */
619         return STATUS_INSUFFICIENT_RESOURCES;
620     }
621 
622     /* send request */
623     Status = IoCallDriver(DeviceExtension->NextDeviceObject, Irp);
624     if (Status == STATUS_PENDING)
625     {
626         /* wait for request to complete */
627         KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
628         Status = IoStatus.Status;
629     }
630 
631     /* done */
632     return Status;
633 }
634 
635 NTSTATUS
636 NTAPI
637 KbdHid_StartDevice(
638     IN PDEVICE_OBJECT DeviceObject)
639 {
640     NTSTATUS Status;
641     ULONG Buttons;
642     HID_COLLECTION_INFORMATION Information;
643     PHIDP_PREPARSED_DATA PreparsedData;
644     HIDP_CAPS Capabilities;
645     PKBDHID_DEVICE_EXTENSION DeviceExtension;
646     PUSAGE_AND_PAGE Buffer;
647 
648     /* get device extension */
649     DeviceExtension = DeviceObject->DeviceExtension;
650 
651     /* query collection information */
652     Status = KbdHid_SubmitRequest(DeviceObject,
653                                   IOCTL_HID_GET_COLLECTION_INFORMATION,
654                                   0,
655                                   NULL,
656                                   sizeof(HID_COLLECTION_INFORMATION),
657                                   &Information);
658     if (!NT_SUCCESS(Status))
659     {
660         /* failed to query collection information */
661         DPRINT1("[KBDHID] failed to obtain collection information with %x\n", Status);
662         return Status;
663     }
664 
665     /* lets allocate space for preparsed data */
666     PreparsedData = ExAllocatePoolWithTag(NonPagedPool, Information.DescriptorSize, KBDHID_TAG);
667     if (!PreparsedData)
668     {
669         /* no memory */
670         DPRINT1("[KBDHID] no memory size %u\n", Information.DescriptorSize);
671         return STATUS_INSUFFICIENT_RESOURCES;
672     }
673 
674     /* now obtain the preparsed data */
675     Status = KbdHid_SubmitRequest(DeviceObject,
676                                   IOCTL_HID_GET_COLLECTION_DESCRIPTOR,
677                                   0,
678                                   NULL,
679                                   Information.DescriptorSize,
680                                   PreparsedData);
681     if (!NT_SUCCESS(Status))
682     {
683         /* failed to get preparsed data */
684         DPRINT1("[KBDHID] failed to obtain collection information with %x\n", Status);
685         ExFreePoolWithTag(PreparsedData, KBDHID_TAG);
686         return Status;
687     }
688 
689     /* lets get the caps */
690     Status = HidP_GetCaps(PreparsedData, &Capabilities);
691     if (Status != HIDP_STATUS_SUCCESS)
692     {
693         /* failed to get capabilities */
694         DPRINT1("[KBDHID] failed to obtain caps with %x\n", Status);
695         ExFreePoolWithTag(PreparsedData, KBDHID_TAG);
696         return Status;
697     }
698 
699     DPRINT("[KBDHID] Usage %x UsagePage %x InputReportLength %lu\n", Capabilities.Usage, Capabilities.UsagePage, Capabilities.InputReportByteLength);
700 
701     /* init input report */
702     DeviceExtension->ReportLength = Capabilities.InputReportByteLength;
703     ASSERT(DeviceExtension->ReportLength);
704     DeviceExtension->Report = ExAllocatePoolWithTag(NonPagedPool, DeviceExtension->ReportLength, KBDHID_TAG);
705     ASSERT(DeviceExtension->Report);
706     RtlZeroMemory(DeviceExtension->Report, DeviceExtension->ReportLength);
707 
708     /* build mdl */
709     DeviceExtension->ReportMDL = IoAllocateMdl(DeviceExtension->Report,
710                                                DeviceExtension->ReportLength,
711                                                FALSE,
712                                                FALSE,
713                                                NULL);
714     ASSERT(DeviceExtension->ReportMDL);
715 
716     /* init mdl */
717     MmBuildMdlForNonPagedPool(DeviceExtension->ReportMDL);
718 
719     /* get max number of buttons */
720     Buttons = HidP_MaxUsageListLength(HidP_Input, HID_USAGE_PAGE_KEYBOARD, PreparsedData);
721     DPRINT("[KBDHID] Buttons %lu\n", Buttons);
722     ASSERT(Buttons > 0);
723 
724     /* now allocate an array for those buttons */
725     Buffer = ExAllocatePoolWithTag(NonPagedPool, sizeof(USAGE_AND_PAGE) * 4 * Buttons, KBDHID_TAG);
726     if (!Buffer)
727     {
728         /* no memory */
729         ExFreePoolWithTag(PreparsedData, KBDHID_TAG);
730         return STATUS_INSUFFICIENT_RESOURCES;
731     }
732     DeviceExtension->UsageListBuffer = Buffer;
733 
734     /* init usage lists */
735     RtlZeroMemory(Buffer, sizeof(USAGE_AND_PAGE) * 4 * Buttons);
736     DeviceExtension->CurrentUsageList = Buffer;
737     Buffer += Buttons;
738     DeviceExtension->PreviousUsageList = Buffer;
739     Buffer += Buttons;
740     DeviceExtension->MakeUsageList = Buffer;
741     Buffer += Buttons;
742     DeviceExtension->BreakUsageList = Buffer;
743 
744     //
745     // FIMXE: implement device hacks
746     //
747     // UsageMappings
748     // KeyboardTypeOverride
749     // KeyboardSubTypeOverride
750     // KeyboardNumberTotalKeysOverride
751     // KeyboardNumberFunctionKeysOverride
752     // KeyboardNumberIndicatorsOverride
753 
754     /* store number of buttons */
755     DeviceExtension->UsageListLength = (USHORT)Buttons;
756 
757     /* store preparsed data */
758     DeviceExtension->PreparsedData = PreparsedData;
759 
760     /* completed successfully */
761     return STATUS_SUCCESS;
762 }
763 
764 NTSTATUS
765 NTAPI
766 KbdHid_StartDeviceCompletion(
767     IN PDEVICE_OBJECT  DeviceObject,
768     IN PIRP  Irp,
769     IN PVOID  Context)
770 {
771     KeSetEvent((PKEVENT)Context, 0, FALSE);
772     return STATUS_MORE_PROCESSING_REQUIRED;
773 }
774 
775 NTSTATUS
776 NTAPI
777 KbdHid_FreeResources(
778     IN PDEVICE_OBJECT DeviceObject)
779 {
780     PKBDHID_DEVICE_EXTENSION DeviceExtension;
781 
782     /* get device extension */
783     DeviceExtension = DeviceObject->DeviceExtension;
784 
785     /* free resources */
786     if (DeviceExtension->PreparsedData)
787     {
788         ExFreePoolWithTag(DeviceExtension->PreparsedData, KBDHID_TAG);
789         DeviceExtension->PreparsedData = NULL;
790     }
791 
792     if (DeviceExtension->UsageListBuffer)
793     {
794         ExFreePoolWithTag(DeviceExtension->UsageListBuffer, KBDHID_TAG);
795         DeviceExtension->UsageListBuffer = NULL;
796         DeviceExtension->CurrentUsageList = NULL;
797         DeviceExtension->PreviousUsageList = NULL;
798         DeviceExtension->MakeUsageList = NULL;
799         DeviceExtension->BreakUsageList = NULL;
800     }
801 
802     if (DeviceExtension->ReportMDL)
803     {
804         IoFreeMdl(DeviceExtension->ReportMDL);
805         DeviceExtension->ReportMDL = NULL;
806     }
807 
808     if (DeviceExtension->Report)
809     {
810         ExFreePoolWithTag(DeviceExtension->Report, KBDHID_TAG);
811         DeviceExtension->Report = NULL;
812     }
813 
814     return STATUS_SUCCESS;
815 }
816 
817 NTSTATUS
818 NTAPI
819 KbdHid_Flush(
820     IN PDEVICE_OBJECT DeviceObject,
821     IN PIRP Irp)
822 {
823     PIO_STACK_LOCATION IoStack;
824     PKBDHID_DEVICE_EXTENSION DeviceExtension;
825 
826     /* get device extension */
827     DeviceExtension = DeviceObject->DeviceExtension;
828 
829     /* skip current stack location */
830     IoSkipCurrentIrpStackLocation(Irp);
831 
832     /* get next stack location */
833     IoStack = IoGetNextIrpStackLocation(Irp);
834 
835     /* change request to hid flush queue request */
836     IoStack->MajorFunction = IRP_MJ_DEVICE_CONTROL;
837     IoStack->Parameters.DeviceIoControl.IoControlCode = IOCTL_HID_FLUSH_QUEUE;
838 
839     /* call device */
840     return IoCallDriver(DeviceExtension->NextDeviceObject, Irp);
841 }
842 
843 NTSTATUS
844 NTAPI
845 KbdHid_Pnp(
846     IN PDEVICE_OBJECT DeviceObject,
847     IN PIRP Irp)
848 {
849     PIO_STACK_LOCATION IoStack;
850     KEVENT Event;
851     NTSTATUS Status;
852     PKBDHID_DEVICE_EXTENSION DeviceExtension;
853 
854     /* get device extension */
855     DeviceExtension = DeviceObject->DeviceExtension;
856 
857     /* get current irp stack */
858     IoStack = IoGetCurrentIrpStackLocation(Irp);
859     DPRINT("[KBDHID] IRP_MJ_PNP Request: %x\n", IoStack->MinorFunction);
860 
861     switch (IoStack->MinorFunction)
862     {
863     case IRP_MN_STOP_DEVICE:
864     case IRP_MN_SURPRISE_REMOVAL:
865         /* free resources */
866         KbdHid_FreeResources(DeviceObject);
867         /* fall through */
868     case IRP_MN_CANCEL_REMOVE_DEVICE:
869     case IRP_MN_QUERY_STOP_DEVICE:
870     case IRP_MN_CANCEL_STOP_DEVICE:
871     case IRP_MN_QUERY_REMOVE_DEVICE:
872         /* indicate success */
873         Irp->IoStatus.Status = STATUS_SUCCESS;
874 
875         /* skip irp stack location */
876         IoSkipCurrentIrpStackLocation(Irp);
877 
878         /* dispatch to lower device */
879         return IoCallDriver(DeviceExtension->NextDeviceObject, Irp);
880 
881     case IRP_MN_REMOVE_DEVICE:
882         /* FIXME synchronization */
883 
884         /* cancel irp */
885         IoCancelIrp(DeviceExtension->Irp);
886 
887         /* free resources */
888         KbdHid_FreeResources(DeviceObject);
889 
890         /* indicate success */
891         Irp->IoStatus.Status = STATUS_SUCCESS;
892 
893         /* skip irp stack location */
894         IoSkipCurrentIrpStackLocation(Irp);
895 
896         /* dispatch to lower device */
897         Status = IoCallDriver(DeviceExtension->NextDeviceObject, Irp);
898 
899         IoFreeIrp(DeviceExtension->Irp);
900         IoDetachDevice(DeviceExtension->NextDeviceObject);
901         IoDeleteDevice(DeviceObject);
902         return Status;
903 
904     case IRP_MN_START_DEVICE:
905         /* init event */
906         KeInitializeEvent(&Event, NotificationEvent, FALSE);
907 
908         /* copy stack location */
909         IoCopyCurrentIrpStackLocationToNext (Irp);
910 
911         /* set completion routine */
912         IoSetCompletionRoutine(Irp, KbdHid_StartDeviceCompletion, &Event, TRUE, TRUE, TRUE);
913         Irp->IoStatus.Status = 0;
914 
915         /* pass request */
916         Status = IoCallDriver(DeviceExtension->NextDeviceObject, Irp);
917         if (Status == STATUS_PENDING)
918         {
919             KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
920             Status = Irp->IoStatus.Status;
921         }
922 
923         if (!NT_SUCCESS(Status))
924         {
925             /* failed */
926             Irp->IoStatus.Status = Status;
927             IoCompleteRequest(Irp, IO_NO_INCREMENT);
928             return Status;
929         }
930 
931         /* lets start the device */
932         Status = KbdHid_StartDevice(DeviceObject);
933         DPRINT("KbdHid_StartDevice %x\n", Status);
934 
935         /* complete request */
936         Irp->IoStatus.Status = Status;
937         IoCompleteRequest(Irp, IO_NO_INCREMENT);
938 
939         /* done */
940         return Status;
941 
942     default:
943         /* skip irp stack location */
944         IoSkipCurrentIrpStackLocation(Irp);
945 
946         /* dispatch to lower device */
947         return IoCallDriver(DeviceExtension->NextDeviceObject, Irp);
948     }
949 }
950 
951 NTSTATUS
952 NTAPI
953 KbdHid_AddDevice(
954     IN PDRIVER_OBJECT DriverObject,
955     IN PDEVICE_OBJECT PhysicalDeviceObject)
956 {
957     NTSTATUS Status;
958     PDEVICE_OBJECT DeviceObject, NextDeviceObject;
959     PKBDHID_DEVICE_EXTENSION DeviceExtension;
960     POWER_STATE State;
961 
962     /* create device object */
963     Status = IoCreateDevice(DriverObject,
964                             sizeof(KBDHID_DEVICE_EXTENSION),
965                             NULL,
966                             FILE_DEVICE_KEYBOARD,
967                             0,
968                             FALSE,
969                             &DeviceObject);
970     if (!NT_SUCCESS(Status))
971     {
972         /* failed to create device object */
973         return Status;
974     }
975 
976     /* now attach it */
977     NextDeviceObject = IoAttachDeviceToDeviceStack(DeviceObject, PhysicalDeviceObject);
978     if (!NextDeviceObject)
979     {
980         /* failed to attach */
981         IoDeleteDevice(DeviceObject);
982         return STATUS_DEVICE_NOT_CONNECTED;
983     }
984 
985     /* get device extension */
986     DeviceExtension = DeviceObject->DeviceExtension;
987 
988     /* zero extension */
989     RtlZeroMemory(DeviceExtension, sizeof(KBDHID_DEVICE_EXTENSION));
990 
991     /* init device extension */
992     DeviceExtension->NextDeviceObject = NextDeviceObject;
993     KeInitializeEvent(&DeviceExtension->ReadCompletionEvent, NotificationEvent, FALSE);
994 
995     /* init keyboard attributes */
996     DeviceExtension->Attributes.KeyboardIdentifier.Type = KEYBOARD_TYPE_UNKNOWN;
997     DeviceExtension->Attributes.KeyboardIdentifier.Subtype = MICROSOFT_KBD_101_TYPE;
998     DeviceExtension->Attributes.NumberOfFunctionKeys = MICROSOFT_KBD_FUNC;
999     DeviceExtension->Attributes.NumberOfIndicators = 3; // caps, num lock, scroll lock
1000     DeviceExtension->Attributes.NumberOfKeysTotal = 101;
1001     DeviceExtension->Attributes.InputDataQueueLength = 1;
1002     DeviceExtension->Attributes.KeyRepeatMinimum.Rate = KEYBOARD_TYPEMATIC_RATE_MINIMUM;
1003     DeviceExtension->Attributes.KeyRepeatMinimum.Delay = KEYBOARD_TYPEMATIC_DELAY_MINIMUM;
1004     DeviceExtension->Attributes.KeyRepeatMaximum.Rate = KEYBOARD_TYPEMATIC_RATE_DEFAULT;
1005     DeviceExtension->Attributes.KeyRepeatMaximum.Delay = KEYBOARD_TYPEMATIC_DELAY_MAXIMUM;
1006 
1007     /* allocate irp */
1008     DeviceExtension->Irp = IoAllocateIrp(NextDeviceObject->StackSize, FALSE);
1009 
1010     /* FIXME handle allocation error */
1011     ASSERT(DeviceExtension->Irp);
1012 
1013     /* set power state to D0 */
1014     State.DeviceState =  PowerDeviceD0;
1015     PoSetPowerState(DeviceObject, DevicePowerState, State);
1016 
1017     /* init device object */
1018     DeviceObject->Flags |= DO_BUFFERED_IO | DO_POWER_PAGABLE;
1019     DeviceObject->Flags  &= ~DO_DEVICE_INITIALIZING;
1020 
1021     /* completed successfully */
1022     return STATUS_SUCCESS;
1023 }
1024 
1025 VOID
1026 NTAPI
1027 KbdHid_Unload(
1028     IN PDRIVER_OBJECT DriverObject)
1029 {
1030     UNIMPLEMENTED;
1031 }
1032 
1033 
1034 NTSTATUS
1035 NTAPI
1036 DriverEntry(
1037     IN PDRIVER_OBJECT DriverObject,
1038     IN PUNICODE_STRING RegPath)
1039 {
1040     /* initialize driver object */
1041     DriverObject->MajorFunction[IRP_MJ_CREATE] = KbdHid_Create;
1042     DriverObject->MajorFunction[IRP_MJ_CLOSE] = KbdHid_Close;
1043     DriverObject->MajorFunction[IRP_MJ_FLUSH_BUFFERS] = KbdHid_Flush;
1044     DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = KbdHid_DeviceControl;
1045     DriverObject->MajorFunction[IRP_MJ_INTERNAL_DEVICE_CONTROL] = KbdHid_InternalDeviceControl;
1046     DriverObject->MajorFunction[IRP_MJ_POWER] = KbdHid_Power;
1047     DriverObject->MajorFunction[IRP_MJ_PNP] = KbdHid_Pnp;
1048     DriverObject->MajorFunction[IRP_MJ_SYSTEM_CONTROL] = KbdHid_SystemControl;
1049     DriverObject->DriverUnload = KbdHid_Unload;
1050     DriverObject->DriverExtension->AddDevice = KbdHid_AddDevice;
1051 
1052     /* done */
1053     return STATUS_SUCCESS;
1054 }
1055