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
KbdHid_DispatchInputData(IN PKBDHID_DEVICE_EXTENSION DeviceExtension,IN PKEYBOARD_INPUT_DATA InputData)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
KbdHid_InsertScanCodes(IN PVOID Context,IN PCHAR NewScanCodes,IN ULONG Length)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
KbdHid_ReadCompletion(IN PDEVICE_OBJECT DeviceObject,IN PIRP Irp,IN PVOID Context)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
KbdHid_InitiateRead(IN PKBDHID_DEVICE_EXTENSION DeviceExtension)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
KbdHid_CreateCompletion(IN PDEVICE_OBJECT DeviceObject,IN PIRP Irp,IN PVOID Context)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
KbdHid_Create(IN PDEVICE_OBJECT DeviceObject,IN PIRP Irp)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
KbdHid_Close(IN PDEVICE_OBJECT DeviceObject,IN PIRP Irp)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
KbdHid_InternalDeviceControl(IN PDEVICE_OBJECT DeviceObject,IN PIRP Irp)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
KbdHid_DeviceControl(IN PDEVICE_OBJECT DeviceObject,IN PIRP Irp)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
KbdHid_Power(IN PDEVICE_OBJECT DeviceObject,IN PIRP Irp)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
KbdHid_SystemControl(IN PDEVICE_OBJECT DeviceObject,IN PIRP Irp)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
KbdHid_SubmitRequest(PDEVICE_OBJECT DeviceObject,ULONG IoControlCode,ULONG InputBufferSize,PVOID InputBuffer,ULONG OutputBufferSize,PVOID OutputBuffer)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
KbdHid_StartDevice(IN PDEVICE_OBJECT DeviceObject)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
KbdHid_StartDeviceCompletion(IN PDEVICE_OBJECT DeviceObject,IN PIRP Irp,IN PVOID Context)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
KbdHid_FreeResources(IN PDEVICE_OBJECT DeviceObject)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
KbdHid_Flush(IN PDEVICE_OBJECT DeviceObject,IN PIRP Irp)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
KbdHid_Pnp(IN PDEVICE_OBJECT DeviceObject,IN PIRP Irp)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
KbdHid_AddDevice(IN PDRIVER_OBJECT DriverObject,IN PDEVICE_OBJECT PhysicalDeviceObject)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
KbdHid_Unload(IN PDRIVER_OBJECT DriverObject)1052 KbdHid_Unload(
1053 IN PDRIVER_OBJECT DriverObject)
1054 {
1055 UNIMPLEMENTED;
1056 }
1057
1058
1059 NTSTATUS
1060 NTAPI
DriverEntry(IN PDRIVER_OBJECT DriverObject,IN PUNICODE_STRING RegPath)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