4b240a46afd71169bdf45f857495e2576bcd89ed
[reactos.git] / drivers / hid / kbdhid / kbdhid.c
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 KeResetEvent(&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 }