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