[HIDCLASS] Implement IOCTL_HID_GET_FEATURE/IOCTL_HID_SET_FEATURE
[reactos.git] / drivers / hid / hidclass / hidclass.c
1 /*
2 * PROJECT: ReactOS Universal Serial Bus Human Interface Device Driver
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: drivers/hid/hidclass/hidclass.c
5 * PURPOSE: HID Class Driver
6 * PROGRAMMERS:
7 * Michael Martin (michael.martin@reactos.org)
8 * Johannes Anderwald (johannes.anderwald@reactos.org)
9 */
10
11 #include "precomp.h"
12
13 #define NDEBUG
14 #include <debug.h>
15
16 static LPWSTR ClientIdentificationAddress = L"HIDCLASS";
17 static ULONG HidClassDeviceNumber = 0;
18
19 NTSTATUS
20 NTAPI
21 DllInitialize(
22 IN PUNICODE_STRING RegistryPath)
23 {
24 return STATUS_SUCCESS;
25 }
26
27 NTSTATUS
28 NTAPI
29 DllUnload(VOID)
30 {
31 return STATUS_SUCCESS;
32 }
33
34 NTSTATUS
35 NTAPI
36 HidClassAddDevice(
37 IN PDRIVER_OBJECT DriverObject,
38 IN PDEVICE_OBJECT PhysicalDeviceObject)
39 {
40 WCHAR CharDeviceName[64];
41 NTSTATUS Status;
42 UNICODE_STRING DeviceName;
43 PDEVICE_OBJECT NewDeviceObject;
44 PHIDCLASS_FDO_EXTENSION FDODeviceExtension;
45 ULONG DeviceExtensionSize;
46 PHIDCLASS_DRIVER_EXTENSION DriverExtension;
47
48 /* increment device number */
49 InterlockedIncrement((PLONG)&HidClassDeviceNumber);
50
51 /* construct device name */
52 swprintf(CharDeviceName, L"\\Device\\_HID%08x", HidClassDeviceNumber);
53
54 /* initialize device name */
55 RtlInitUnicodeString(&DeviceName, CharDeviceName);
56
57 /* get driver object extension */
58 DriverExtension = IoGetDriverObjectExtension(DriverObject, ClientIdentificationAddress);
59 if (!DriverExtension)
60 {
61 /* device removed */
62 ASSERT(FALSE);
63 return STATUS_DEVICE_CONFIGURATION_ERROR;
64 }
65
66 /* calculate device extension size */
67 DeviceExtensionSize = sizeof(HIDCLASS_FDO_EXTENSION) + DriverExtension->DeviceExtensionSize;
68
69 /* now create the device */
70 Status = IoCreateDevice(DriverObject, DeviceExtensionSize, &DeviceName, FILE_DEVICE_UNKNOWN, 0, FALSE, &NewDeviceObject);
71 if (!NT_SUCCESS(Status))
72 {
73 /* failed to create device object */
74 ASSERT(FALSE);
75 return Status;
76 }
77
78 /* get device extension */
79 FDODeviceExtension = NewDeviceObject->DeviceExtension;
80
81 /* zero device extension */
82 RtlZeroMemory(FDODeviceExtension, sizeof(HIDCLASS_FDO_EXTENSION));
83
84 /* initialize device extension */
85 FDODeviceExtension->Common.IsFDO = TRUE;
86 FDODeviceExtension->Common.DriverExtension = DriverExtension;
87 FDODeviceExtension->Common.HidDeviceExtension.PhysicalDeviceObject = PhysicalDeviceObject;
88 FDODeviceExtension->Common.HidDeviceExtension.MiniDeviceExtension = (PVOID)((ULONG_PTR)FDODeviceExtension + sizeof(HIDCLASS_FDO_EXTENSION));
89 FDODeviceExtension->Common.HidDeviceExtension.NextDeviceObject = IoAttachDeviceToDeviceStack(NewDeviceObject, PhysicalDeviceObject);
90 if (FDODeviceExtension->Common.HidDeviceExtension.NextDeviceObject == NULL)
91 {
92 /* no PDO */
93 IoDeleteDevice(NewDeviceObject);
94 DPRINT1("[HIDCLASS] failed to attach to device stack\n");
95 return STATUS_DEVICE_REMOVED;
96 }
97
98 /* sanity check */
99 ASSERT(FDODeviceExtension->Common.HidDeviceExtension.NextDeviceObject);
100
101 /* increment stack size */
102 NewDeviceObject->StackSize++;
103
104 /* init device object */
105 NewDeviceObject->Flags |= DO_BUFFERED_IO | DO_POWER_PAGABLE;
106 NewDeviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
107
108 /* now call driver provided add device routine */
109 ASSERT(DriverExtension->AddDevice != 0);
110 Status = DriverExtension->AddDevice(DriverObject, NewDeviceObject);
111 if (!NT_SUCCESS(Status))
112 {
113 /* failed */
114 DPRINT1("HIDCLASS: AddDevice failed with %x\n", Status);
115 IoDetachDevice(FDODeviceExtension->Common.HidDeviceExtension.NextDeviceObject);
116 IoDeleteDevice(NewDeviceObject);
117 return Status;
118 }
119
120 /* succeeded */
121 return Status;
122 }
123
124 VOID
125 NTAPI
126 HidClassDriverUnload(
127 IN PDRIVER_OBJECT DriverObject)
128 {
129 UNIMPLEMENTED;
130 }
131
132 NTSTATUS
133 NTAPI
134 HidClass_Create(
135 IN PDEVICE_OBJECT DeviceObject,
136 IN PIRP Irp)
137 {
138 PIO_STACK_LOCATION IoStack;
139 PHIDCLASS_COMMON_DEVICE_EXTENSION CommonDeviceExtension;
140 PHIDCLASS_PDO_DEVICE_EXTENSION PDODeviceExtension;
141 PHIDCLASS_FILEOP_CONTEXT Context;
142
143 //
144 // get device extension
145 //
146 CommonDeviceExtension = DeviceObject->DeviceExtension;
147 if (CommonDeviceExtension->IsFDO)
148 {
149 //
150 // only supported for PDO
151 //
152 Irp->IoStatus.Status = STATUS_UNSUCCESSFUL;
153 IoCompleteRequest(Irp, IO_NO_INCREMENT);
154 return STATUS_UNSUCCESSFUL;
155 }
156
157 //
158 // must be a PDO
159 //
160 ASSERT(CommonDeviceExtension->IsFDO == FALSE);
161
162 //
163 // get device extension
164 //
165 PDODeviceExtension = DeviceObject->DeviceExtension;
166
167 //
168 // get stack location
169 //
170 IoStack = IoGetCurrentIrpStackLocation(Irp);
171
172 DPRINT("ShareAccess %x\n", IoStack->Parameters.Create.ShareAccess);
173 DPRINT("Options %x\n", IoStack->Parameters.Create.Options);
174 DPRINT("DesiredAccess %x\n", IoStack->Parameters.Create.SecurityContext->DesiredAccess);
175
176 //
177 // allocate context
178 //
179 Context = ExAllocatePoolWithTag(NonPagedPool, sizeof(HIDCLASS_FILEOP_CONTEXT), HIDCLASS_TAG);
180 if (!Context)
181 {
182 //
183 // no memory
184 //
185 Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
186 IoCompleteRequest(Irp, IO_NO_INCREMENT);
187 return STATUS_INSUFFICIENT_RESOURCES;
188 }
189
190 //
191 // init context
192 //
193 RtlZeroMemory(Context, sizeof(HIDCLASS_FILEOP_CONTEXT));
194 Context->DeviceExtension = PDODeviceExtension;
195 KeInitializeSpinLock(&Context->Lock);
196 InitializeListHead(&Context->ReadPendingIrpListHead);
197 InitializeListHead(&Context->IrpCompletedListHead);
198 KeInitializeEvent(&Context->IrpReadComplete, NotificationEvent, FALSE);
199
200 //
201 // store context
202 //
203 ASSERT(IoStack->FileObject);
204 IoStack->FileObject->FsContext = Context;
205
206 //
207 // done
208 //
209 Irp->IoStatus.Status = STATUS_SUCCESS;
210 IoCompleteRequest(Irp, IO_NO_INCREMENT);
211 return STATUS_SUCCESS;
212 }
213
214 NTSTATUS
215 NTAPI
216 HidClass_Close(
217 IN PDEVICE_OBJECT DeviceObject,
218 IN PIRP Irp)
219 {
220 PIO_STACK_LOCATION IoStack;
221 PHIDCLASS_COMMON_DEVICE_EXTENSION CommonDeviceExtension;
222 PHIDCLASS_FILEOP_CONTEXT IrpContext;
223 BOOLEAN IsRequestPending = FALSE;
224 KIRQL OldLevel;
225 PLIST_ENTRY Entry;
226 PIRP ListIrp;
227
228 //
229 // get device extension
230 //
231 CommonDeviceExtension = DeviceObject->DeviceExtension;
232
233 //
234 // is it a FDO request
235 //
236 if (CommonDeviceExtension->IsFDO)
237 {
238 //
239 // how did the request get there
240 //
241 Irp->IoStatus.Status = STATUS_INVALID_PARAMETER_1;
242 IoCompleteRequest(Irp, IO_NO_INCREMENT);
243 return STATUS_INVALID_PARAMETER_1;
244 }
245
246 //
247 // get stack location
248 //
249 IoStack = IoGetCurrentIrpStackLocation(Irp);
250
251 //
252 // sanity checks
253 //
254 ASSERT(IoStack->FileObject);
255 ASSERT(IoStack->FileObject->FsContext);
256
257 //
258 // get irp context
259 //
260 IrpContext = IoStack->FileObject->FsContext;
261 ASSERT(IrpContext);
262
263 //
264 // acquire lock
265 //
266 KeAcquireSpinLock(&IrpContext->Lock, &OldLevel);
267
268 if (!IsListEmpty(&IrpContext->ReadPendingIrpListHead))
269 {
270 //
271 // FIXME cancel irp
272 //
273 IsRequestPending = TRUE;
274 }
275
276 //
277 // signal stop
278 //
279 IrpContext->StopInProgress = TRUE;
280
281 //
282 // release lock
283 //
284 KeReleaseSpinLock(&IrpContext->Lock, OldLevel);
285
286 if (IsRequestPending)
287 {
288 //
289 // wait for request to complete
290 //
291 DPRINT1("[HIDCLASS] Waiting for read irp completion...\n");
292 KeWaitForSingleObject(&IrpContext->IrpReadComplete, Executive, KernelMode, FALSE, NULL);
293 }
294
295 //
296 // acquire lock
297 //
298 KeAcquireSpinLock(&IrpContext->Lock, &OldLevel);
299
300 //
301 // sanity check
302 //
303 ASSERT(IsListEmpty(&IrpContext->ReadPendingIrpListHead));
304
305 //
306 // now free all irps
307 //
308 while (!IsListEmpty(&IrpContext->IrpCompletedListHead))
309 {
310 //
311 // remove head irp
312 //
313 Entry = RemoveHeadList(&IrpContext->IrpCompletedListHead);
314
315 //
316 // get irp
317 //
318 ListIrp = CONTAINING_RECORD(Entry, IRP, Tail.Overlay.ListEntry);
319
320 //
321 // free the irp
322 //
323 IoFreeIrp(ListIrp);
324 }
325
326 //
327 // release lock
328 //
329 KeReleaseSpinLock(&IrpContext->Lock, OldLevel);
330
331 //
332 // remove context
333 //
334 IoStack->FileObject->FsContext = NULL;
335
336 //
337 // free context
338 //
339 ExFreePoolWithTag(IrpContext, HIDCLASS_TAG);
340
341 //
342 // complete request
343 //
344 Irp->IoStatus.Status = STATUS_SUCCESS;
345 IoCompleteRequest(Irp, IO_NO_INCREMENT);
346 return STATUS_SUCCESS;
347 }
348
349 NTSTATUS
350 NTAPI
351 HidClass_ReadCompleteIrp(
352 IN PDEVICE_OBJECT DeviceObject,
353 IN PIRP Irp,
354 IN PVOID Ctx)
355 {
356 PHIDCLASS_IRP_CONTEXT IrpContext;
357 KIRQL OldLevel;
358 PUCHAR Address;
359 ULONG Offset;
360 PHIDP_COLLECTION_DESC CollectionDescription;
361 PHIDP_REPORT_IDS ReportDescription;
362 BOOLEAN IsEmpty;
363
364 //
365 // get irp context
366 //
367 IrpContext = Ctx;
368
369 DPRINT("HidClass_ReadCompleteIrp Irql %lu\n", KeGetCurrentIrql());
370 DPRINT("HidClass_ReadCompleteIrp Status %lx\n", Irp->IoStatus.Status);
371 DPRINT("HidClass_ReadCompleteIrp Length %lu\n", Irp->IoStatus.Information);
372 DPRINT("HidClass_ReadCompleteIrp Irp %p\n", Irp);
373 DPRINT("HidClass_ReadCompleteIrp InputReportBuffer %p\n", IrpContext->InputReportBuffer);
374 DPRINT("HidClass_ReadCompleteIrp InputReportBufferLength %li\n", IrpContext->InputReportBufferLength);
375 DPRINT("HidClass_ReadCompleteIrp OriginalIrp %p\n", IrpContext->OriginalIrp);
376
377 //
378 // copy result
379 //
380 if (Irp->IoStatus.Information)
381 {
382 //
383 // get address
384 //
385 Address = MmGetSystemAddressForMdlSafe(IrpContext->OriginalIrp->MdlAddress, NormalPagePriority);
386 if (Address)
387 {
388 //
389 // reports may have a report id prepended
390 //
391 Offset = 0;
392
393 //
394 // get collection description
395 //
396 CollectionDescription = HidClassPDO_GetCollectionDescription(&IrpContext->FileOp->DeviceExtension->Common.DeviceDescription,
397 IrpContext->FileOp->DeviceExtension->CollectionNumber);
398 ASSERT(CollectionDescription);
399
400 //
401 // get report description
402 //
403 ReportDescription = HidClassPDO_GetReportDescription(&IrpContext->FileOp->DeviceExtension->Common.DeviceDescription,
404 IrpContext->FileOp->DeviceExtension->CollectionNumber);
405 ASSERT(ReportDescription);
406
407 if (CollectionDescription && ReportDescription)
408 {
409 //
410 // calculate offset
411 //
412 ASSERT(CollectionDescription->InputLength >= ReportDescription->InputLength);
413 Offset = CollectionDescription->InputLength - ReportDescription->InputLength;
414 }
415
416 //
417 // copy result
418 //
419 RtlCopyMemory(&Address[Offset], IrpContext->InputReportBuffer, IrpContext->InputReportBufferLength);
420 }
421 }
422
423 //
424 // copy result status
425 //
426 IrpContext->OriginalIrp->IoStatus.Status = Irp->IoStatus.Status;
427 IrpContext->OriginalIrp->IoStatus.Information = Irp->IoStatus.Information;
428
429 //
430 // free input report buffer
431 //
432 ExFreePoolWithTag(IrpContext->InputReportBuffer, HIDCLASS_TAG);
433
434 //
435 // remove us from pending list
436 //
437 KeAcquireSpinLock(&IrpContext->FileOp->Lock, &OldLevel);
438
439 //
440 // remove from pending list
441 //
442 RemoveEntryList(&Irp->Tail.Overlay.ListEntry);
443
444 //
445 // is list empty
446 //
447 IsEmpty = IsListEmpty(&IrpContext->FileOp->ReadPendingIrpListHead);
448
449 //
450 // insert into completed list
451 //
452 InsertTailList(&IrpContext->FileOp->IrpCompletedListHead, &Irp->Tail.Overlay.ListEntry);
453
454 //
455 // release lock
456 //
457 KeReleaseSpinLock(&IrpContext->FileOp->Lock, OldLevel);
458
459 //
460 // complete original request
461 //
462 IoCompleteRequest(IrpContext->OriginalIrp, IO_NO_INCREMENT);
463
464
465 DPRINT("StopInProgress %x IsEmpty %x\n", IrpContext->FileOp->StopInProgress, IsEmpty);
466 if (IrpContext->FileOp->StopInProgress && IsEmpty)
467 {
468 //
469 // last pending irp
470 //
471 DPRINT1("[HIDCLASS] LastPendingTransfer Signalling\n");
472 KeSetEvent(&IrpContext->FileOp->IrpReadComplete, 0, FALSE);
473 }
474
475 if (IrpContext->FileOp->StopInProgress && IsEmpty)
476 {
477 //
478 // last pending irp
479 //
480 DPRINT1("[HIDCLASS] LastPendingTransfer Signalling\n");
481 KeSetEvent(&IrpContext->FileOp->IrpReadComplete, 0, FALSE);
482 }
483
484 //
485 // free irp context
486 //
487 ExFreePoolWithTag(IrpContext, HIDCLASS_TAG);
488
489 //
490 // done
491 //
492 return STATUS_MORE_PROCESSING_REQUIRED;
493 }
494
495 PIRP
496 HidClass_GetIrp(
497 IN PHIDCLASS_FILEOP_CONTEXT Context)
498 {
499 KIRQL OldLevel;
500 PIRP Irp = NULL;
501 PLIST_ENTRY ListEntry;
502
503 //
504 // acquire lock
505 //
506 KeAcquireSpinLock(&Context->Lock, &OldLevel);
507
508 //
509 // is list empty?
510 //
511 if (!IsListEmpty(&Context->IrpCompletedListHead))
512 {
513 //
514 // grab first entry
515 //
516 ListEntry = RemoveHeadList(&Context->IrpCompletedListHead);
517
518 //
519 // get irp
520 //
521 Irp = CONTAINING_RECORD(ListEntry, IRP, Tail.Overlay.ListEntry);
522 }
523
524 //
525 // release lock
526 //
527 KeReleaseSpinLock(&Context->Lock, OldLevel);
528
529 //
530 // done
531 //
532 return Irp;
533 }
534
535 NTSTATUS
536 HidClass_BuildIrp(
537 IN PDEVICE_OBJECT DeviceObject,
538 IN PIRP RequestIrp,
539 IN PHIDCLASS_FILEOP_CONTEXT Context,
540 IN ULONG DeviceIoControlCode,
541 IN ULONG BufferLength,
542 OUT PIRP *OutIrp,
543 OUT PHIDCLASS_IRP_CONTEXT *OutIrpContext)
544 {
545 PIRP Irp;
546 PIO_STACK_LOCATION IoStack;
547 PHIDCLASS_IRP_CONTEXT IrpContext;
548 PHIDCLASS_PDO_DEVICE_EXTENSION PDODeviceExtension;
549 PHIDP_COLLECTION_DESC CollectionDescription;
550 PHIDP_REPORT_IDS ReportDescription;
551
552 //
553 // get an irp from fresh list
554 //
555 Irp = HidClass_GetIrp(Context);
556 if (!Irp)
557 {
558 //
559 // build new irp
560 //
561 Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE);
562 if (!Irp)
563 {
564 //
565 // no memory
566 //
567 return STATUS_INSUFFICIENT_RESOURCES;
568 }
569 }
570 else
571 {
572 //
573 // re-use irp
574 //
575 IoReuseIrp(Irp, STATUS_SUCCESS);
576 }
577
578 //
579 // allocate completion context
580 //
581 IrpContext = ExAllocatePoolWithTag(NonPagedPool, sizeof(HIDCLASS_IRP_CONTEXT), HIDCLASS_TAG);
582 if (!IrpContext)
583 {
584 //
585 // no memory
586 //
587 IoFreeIrp(Irp);
588 return STATUS_INSUFFICIENT_RESOURCES;
589 }
590
591 //
592 // get device extension
593 //
594 PDODeviceExtension = DeviceObject->DeviceExtension;
595 ASSERT(PDODeviceExtension->Common.IsFDO == FALSE);
596
597 //
598 // init irp context
599 //
600 RtlZeroMemory(IrpContext, sizeof(HIDCLASS_IRP_CONTEXT));
601 IrpContext->OriginalIrp = RequestIrp;
602 IrpContext->FileOp = Context;
603
604 //
605 // get collection description
606 //
607 CollectionDescription = HidClassPDO_GetCollectionDescription(&IrpContext->FileOp->DeviceExtension->Common.DeviceDescription,
608 IrpContext->FileOp->DeviceExtension->CollectionNumber);
609 ASSERT(CollectionDescription);
610
611 //
612 // get report description
613 //
614 ReportDescription = HidClassPDO_GetReportDescription(&IrpContext->FileOp->DeviceExtension->Common.DeviceDescription,
615 IrpContext->FileOp->DeviceExtension->CollectionNumber);
616 ASSERT(ReportDescription);
617
618 //
619 // sanity check
620 //
621 ASSERT(CollectionDescription->InputLength >= ReportDescription->InputLength);
622
623 if (Context->StopInProgress)
624 {
625 //
626 // stop in progress
627 //
628 DPRINT1("[HIDCLASS] Stop In Progress\n");
629 Irp->IoStatus.Status = STATUS_CANCELLED;
630 IoCompleteRequest(Irp, IO_NO_INCREMENT);
631 return STATUS_CANCELLED;
632
633 }
634
635 //
636 // store report length
637 //
638 IrpContext->InputReportBufferLength = ReportDescription->InputLength;
639
640 //
641 // allocate buffer
642 //
643 IrpContext->InputReportBuffer = ExAllocatePoolWithTag(NonPagedPool, IrpContext->InputReportBufferLength, HIDCLASS_TAG);
644 if (!IrpContext->InputReportBuffer)
645 {
646 //
647 // no memory
648 //
649 IoFreeIrp(Irp);
650 ExFreePoolWithTag(IrpContext, HIDCLASS_TAG);
651 return STATUS_INSUFFICIENT_RESOURCES;
652 }
653
654 //
655 // get stack location
656 //
657 IoStack = IoGetNextIrpStackLocation(Irp);
658
659 //
660 // init stack location
661 //
662 IoStack->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
663 IoStack->Parameters.DeviceIoControl.IoControlCode = DeviceIoControlCode;
664 IoStack->Parameters.DeviceIoControl.OutputBufferLength = IrpContext->InputReportBufferLength;
665 IoStack->Parameters.DeviceIoControl.InputBufferLength = 0;
666 IoStack->Parameters.DeviceIoControl.Type3InputBuffer = NULL;
667 Irp->UserBuffer = IrpContext->InputReportBuffer;
668 IoStack->DeviceObject = DeviceObject;
669
670 //
671 // store result
672 //
673 *OutIrp = Irp;
674 *OutIrpContext = IrpContext;
675
676 //
677 // done
678 //
679 return STATUS_SUCCESS;
680 }
681
682 NTSTATUS
683 NTAPI
684 HidClass_Read(
685 IN PDEVICE_OBJECT DeviceObject,
686 IN PIRP Irp)
687 {
688 PIO_STACK_LOCATION IoStack;
689 PHIDCLASS_FILEOP_CONTEXT Context;
690 KIRQL OldLevel;
691 NTSTATUS Status;
692 PIRP NewIrp;
693 PHIDCLASS_IRP_CONTEXT NewIrpContext;
694 PHIDCLASS_COMMON_DEVICE_EXTENSION CommonDeviceExtension;
695
696 //
697 // get current stack location
698 //
699 IoStack = IoGetCurrentIrpStackLocation(Irp);
700
701 //
702 // get device extension
703 //
704 CommonDeviceExtension = DeviceObject->DeviceExtension;
705 ASSERT(CommonDeviceExtension->IsFDO == FALSE);
706
707 //
708 // sanity check
709 //
710 ASSERT(IoStack->FileObject);
711 ASSERT(IoStack->FileObject->FsContext);
712
713 //
714 // get context
715 //
716 Context = IoStack->FileObject->FsContext;
717 ASSERT(Context);
718
719 //
720 // FIXME support polled devices
721 //
722 ASSERT(Context->DeviceExtension->Common.DriverExtension->DevicesArePolled == FALSE);
723
724 if (Context->StopInProgress)
725 {
726 //
727 // stop in progress
728 //
729 DPRINT1("[HIDCLASS] Stop In Progress\n");
730 Irp->IoStatus.Status = STATUS_CANCELLED;
731 IoCompleteRequest(Irp, IO_NO_INCREMENT);
732 return STATUS_CANCELLED;
733 }
734
735 //
736 // build irp request
737 //
738 Status = HidClass_BuildIrp(DeviceObject,
739 Irp,
740 Context,
741 IOCTL_HID_READ_REPORT,
742 IoStack->Parameters.Read.Length,
743 &NewIrp,
744 &NewIrpContext);
745 if (!NT_SUCCESS(Status))
746 {
747 //
748 // failed
749 //
750 DPRINT1("HidClass_BuildIrp failed with %x\n", Status);
751 Irp->IoStatus.Status = Status;
752 IoCompleteRequest(Irp, IO_NO_INCREMENT);
753 return Status;
754 }
755
756 //
757 // acquire lock
758 //
759 KeAcquireSpinLock(&Context->Lock, &OldLevel);
760
761 //
762 // insert irp into pending list
763 //
764 InsertTailList(&Context->ReadPendingIrpListHead, &NewIrp->Tail.Overlay.ListEntry);
765
766 //
767 // set completion routine
768 //
769 IoSetCompletionRoutine(NewIrp, HidClass_ReadCompleteIrp, NewIrpContext, TRUE, TRUE, TRUE);
770
771 //
772 // make next location current
773 //
774 IoSetNextIrpStackLocation(NewIrp);
775
776 //
777 // release spin lock
778 //
779 KeReleaseSpinLock(&Context->Lock, OldLevel);
780
781 //
782 // mark irp pending
783 //
784 IoMarkIrpPending(Irp);
785
786 //
787 // let's dispatch the request
788 //
789 ASSERT(Context->DeviceExtension);
790 Status = Context->DeviceExtension->Common.DriverExtension->MajorFunction[IRP_MJ_INTERNAL_DEVICE_CONTROL](Context->DeviceExtension->FDODeviceObject, NewIrp);
791
792 //
793 // complete
794 //
795 return STATUS_PENDING;
796 }
797
798 NTSTATUS
799 NTAPI
800 HidClass_Write(
801 IN PDEVICE_OBJECT DeviceObject,
802 IN PIRP Irp)
803 {
804 UNIMPLEMENTED;
805 ASSERT(FALSE);
806 Irp->IoStatus.Status = STATUS_NOT_IMPLEMENTED;
807 IoCompleteRequest(Irp, IO_NO_INCREMENT);
808 return STATUS_NOT_IMPLEMENTED;
809 }
810
811 NTSTATUS
812 NTAPI
813 HidClass_DeviceControl(
814 IN PDEVICE_OBJECT DeviceObject,
815 IN PIRP Irp)
816 {
817 PIO_STACK_LOCATION IoStack;
818 PHIDCLASS_COMMON_DEVICE_EXTENSION CommonDeviceExtension;
819 PHID_COLLECTION_INFORMATION CollectionInformation;
820 PHIDP_COLLECTION_DESC CollectionDescription;
821 PHIDCLASS_PDO_DEVICE_EXTENSION PDODeviceExtension;
822
823 //
824 // get device extension
825 //
826 CommonDeviceExtension = DeviceObject->DeviceExtension;
827
828 //
829 // only PDO are supported
830 //
831 if (CommonDeviceExtension->IsFDO)
832 {
833 //
834 // invalid request
835 //
836 DPRINT1("[HIDCLASS] DeviceControl Irp for FDO arrived\n");
837 Irp->IoStatus.Status = STATUS_INVALID_PARAMETER_1;
838 IoCompleteRequest(Irp, IO_NO_INCREMENT);
839 return STATUS_INVALID_PARAMETER_1;
840 }
841
842 ASSERT(CommonDeviceExtension->IsFDO == FALSE);
843
844 //
845 // get pdo device extension
846 //
847 PDODeviceExtension = DeviceObject->DeviceExtension;
848
849 //
850 // get stack location
851 //
852 IoStack = IoGetCurrentIrpStackLocation(Irp);
853
854 switch (IoStack->Parameters.DeviceIoControl.IoControlCode)
855 {
856 case IOCTL_HID_GET_COLLECTION_INFORMATION:
857 {
858 //
859 // check if output buffer is big enough
860 //
861 if (IoStack->Parameters.DeviceIoControl.OutputBufferLength < sizeof(HID_COLLECTION_INFORMATION))
862 {
863 //
864 // invalid buffer size
865 //
866 Irp->IoStatus.Status = STATUS_INVALID_BUFFER_SIZE;
867 IoCompleteRequest(Irp, IO_NO_INCREMENT);
868 return STATUS_INVALID_BUFFER_SIZE;
869 }
870
871 //
872 // get output buffer
873 //
874 CollectionInformation = Irp->AssociatedIrp.SystemBuffer;
875 ASSERT(CollectionInformation);
876
877 //
878 // get collection description
879 //
880 CollectionDescription = HidClassPDO_GetCollectionDescription(&CommonDeviceExtension->DeviceDescription,
881 PDODeviceExtension->CollectionNumber);
882 ASSERT(CollectionDescription);
883
884 //
885 // init result buffer
886 //
887 CollectionInformation->DescriptorSize = CollectionDescription->PreparsedDataLength;
888 CollectionInformation->Polled = CommonDeviceExtension->DriverExtension->DevicesArePolled;
889 CollectionInformation->VendorID = CommonDeviceExtension->Attributes.VendorID;
890 CollectionInformation->ProductID = CommonDeviceExtension->Attributes.ProductID;
891 CollectionInformation->VersionNumber = CommonDeviceExtension->Attributes.VersionNumber;
892
893 //
894 // complete request
895 //
896 Irp->IoStatus.Information = sizeof(HID_COLLECTION_INFORMATION);
897 Irp->IoStatus.Status = STATUS_SUCCESS;
898 IoCompleteRequest(Irp, IO_NO_INCREMENT);
899 return STATUS_SUCCESS;
900 }
901 case IOCTL_HID_GET_COLLECTION_DESCRIPTOR:
902 {
903 //
904 // get collection description
905 //
906 CollectionDescription = HidClassPDO_GetCollectionDescription(&CommonDeviceExtension->DeviceDescription,
907 PDODeviceExtension->CollectionNumber);
908 ASSERT(CollectionDescription);
909
910 //
911 // check if output buffer is big enough
912 //
913 if (IoStack->Parameters.DeviceIoControl.OutputBufferLength < CollectionDescription->PreparsedDataLength)
914 {
915 //
916 // invalid buffer size
917 //
918 Irp->IoStatus.Status = STATUS_INVALID_BUFFER_SIZE;
919 IoCompleteRequest(Irp, IO_NO_INCREMENT);
920 return STATUS_INVALID_BUFFER_SIZE;
921 }
922
923 //
924 // copy result
925 //
926 ASSERT(Irp->UserBuffer);
927 RtlCopyMemory(Irp->UserBuffer, CollectionDescription->PreparsedData, CollectionDescription->PreparsedDataLength);
928
929 //
930 // complete request
931 //
932 Irp->IoStatus.Information = CollectionDescription->PreparsedDataLength;
933 Irp->IoStatus.Status = STATUS_SUCCESS;
934 IoCompleteRequest(Irp, IO_NO_INCREMENT);
935 return STATUS_SUCCESS;
936 }
937 case IOCTL_HID_GET_FEATURE:
938 {
939 PIRP SubIrp;
940 KEVENT Event;
941 IO_STATUS_BLOCK IoStatusBlock;
942 HID_XFER_PACKET XferPacket;
943 NTSTATUS Status;
944 PHIDP_REPORT_IDS ReportDescription;
945
946 if (IoStack->Parameters.DeviceIoControl.InputBufferLength < 1)
947 {
948 Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
949 IoCompleteRequest(Irp, IO_NO_INCREMENT);
950 return STATUS_INVALID_PARAMETER;
951 }
952 ReportDescription = HidClassPDO_GetReportDescriptionByReportID(&PDODeviceExtension->Common.DeviceDescription, ((PUCHAR)Irp->AssociatedIrp.SystemBuffer)[0]);
953 if (!ReportDescription || IoStack->Parameters.DeviceIoControl.OutputBufferLength < ReportDescription->FeatureLength)
954 {
955 Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
956 IoCompleteRequest(Irp, IO_NO_INCREMENT);
957 return STATUS_INVALID_PARAMETER;
958 }
959
960 RtlZeroMemory(&XferPacket, sizeof(XferPacket));
961 XferPacket.reportBufferLen = ReportDescription->FeatureLength;
962 XferPacket.reportBuffer = MmGetSystemAddressForMdlSafe(Irp->MdlAddress, NormalPagePriority);
963 XferPacket.reportId = ((PUCHAR)Irp->AssociatedIrp.SystemBuffer)[0];
964 if (!XferPacket.reportBuffer)
965 {
966 Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
967 IoCompleteRequest(Irp, IO_NO_INCREMENT);
968 return STATUS_INSUFFICIENT_RESOURCES;
969 }
970
971 SubIrp = IoBuildDeviceIoControlRequest(
972 IOCTL_HID_GET_FEATURE,
973 CommonDeviceExtension->HidDeviceExtension.NextDeviceObject,
974 NULL, 0,
975 NULL, 0,
976 TRUE,
977 &Event,
978 &IoStatusBlock);
979 if (!SubIrp)
980 {
981 Irp->IoStatus.Status = STATUS_NO_MEMORY;
982 IoCompleteRequest(Irp, IO_NO_INCREMENT);
983 return STATUS_NOT_IMPLEMENTED;
984 }
985 SubIrp->UserBuffer = &XferPacket;
986 KeInitializeEvent(&Event, SynchronizationEvent, FALSE);
987 Status = IoCallDriver(CommonDeviceExtension->HidDeviceExtension.NextDeviceObject, SubIrp);
988 if (Status == STATUS_PENDING)
989 {
990 KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
991 Status = IoStatusBlock.Status;
992 }
993 Irp->IoStatus.Status = Status;
994 IoCompleteRequest(Irp, IO_NO_INCREMENT);
995 return Status;
996 }
997 case IOCTL_HID_SET_FEATURE:
998 {
999 PIRP SubIrp;
1000 KEVENT Event;
1001 IO_STATUS_BLOCK IoStatusBlock;
1002 HID_XFER_PACKET XferPacket;
1003 NTSTATUS Status;
1004 PHIDP_REPORT_IDS ReportDescription;
1005
1006 if (IoStack->Parameters.DeviceIoControl.InputBufferLength < 1)
1007 {
1008 Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
1009 IoCompleteRequest(Irp, IO_NO_INCREMENT);
1010 return STATUS_INVALID_PARAMETER;
1011 }
1012 ReportDescription = HidClassPDO_GetReportDescriptionByReportID(&PDODeviceExtension->Common.DeviceDescription, ((PUCHAR)Irp->AssociatedIrp.SystemBuffer)[0]);
1013 if (!ReportDescription || IoStack->Parameters.DeviceIoControl.InputBufferLength < ReportDescription->FeatureLength)
1014 {
1015 Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
1016 IoCompleteRequest(Irp, IO_NO_INCREMENT);
1017 return STATUS_INVALID_PARAMETER;
1018 }
1019
1020 RtlZeroMemory(&XferPacket, sizeof(XferPacket));
1021 XferPacket.reportBufferLen = ReportDescription->FeatureLength;
1022 XferPacket.reportBuffer = Irp->AssociatedIrp.SystemBuffer;
1023 XferPacket.reportId = XferPacket.reportBuffer[0];
1024
1025 SubIrp = IoBuildDeviceIoControlRequest(
1026 IOCTL_HID_SET_FEATURE,
1027 CommonDeviceExtension->HidDeviceExtension.NextDeviceObject,
1028 NULL, 0,
1029 NULL, 0,
1030 TRUE,
1031 &Event,
1032 &IoStatusBlock);
1033 if (!SubIrp)
1034 {
1035 Irp->IoStatus.Status = STATUS_NO_MEMORY;
1036 IoCompleteRequest(Irp, IO_NO_INCREMENT);
1037 return STATUS_NOT_IMPLEMENTED;
1038 }
1039 SubIrp->UserBuffer = &XferPacket;
1040 KeInitializeEvent(&Event, SynchronizationEvent, FALSE);
1041 Status = IoCallDriver(CommonDeviceExtension->HidDeviceExtension.NextDeviceObject, SubIrp);
1042 if (Status == STATUS_PENDING)
1043 {
1044 KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
1045 Status = IoStatusBlock.Status;
1046 }
1047 Irp->IoStatus.Status = Status;
1048 IoCompleteRequest(Irp, IO_NO_INCREMENT);
1049 return Status;
1050 }
1051 default:
1052 {
1053 DPRINT1("[HIDCLASS] DeviceControl IoControlCode 0x%x not implemented\n", IoStack->Parameters.DeviceIoControl.IoControlCode);
1054 Irp->IoStatus.Status = STATUS_NOT_IMPLEMENTED;
1055 IoCompleteRequest(Irp, IO_NO_INCREMENT);
1056 return STATUS_NOT_IMPLEMENTED;
1057 }
1058 }
1059 }
1060
1061 NTSTATUS
1062 NTAPI
1063 HidClass_InternalDeviceControl(
1064 IN PDEVICE_OBJECT DeviceObject,
1065 IN PIRP Irp)
1066 {
1067 UNIMPLEMENTED;
1068 ASSERT(FALSE);
1069 Irp->IoStatus.Status = STATUS_NOT_IMPLEMENTED;
1070 IoCompleteRequest(Irp, IO_NO_INCREMENT);
1071 return STATUS_NOT_IMPLEMENTED;
1072 }
1073
1074 NTSTATUS
1075 NTAPI
1076 HidClass_Power(
1077 IN PDEVICE_OBJECT DeviceObject,
1078 IN PIRP Irp)
1079 {
1080 PHIDCLASS_COMMON_DEVICE_EXTENSION CommonDeviceExtension;
1081 CommonDeviceExtension = DeviceObject->DeviceExtension;
1082
1083 if (CommonDeviceExtension->IsFDO)
1084 {
1085 IoCopyCurrentIrpStackLocationToNext(Irp);
1086 return HidClassFDO_DispatchRequest(DeviceObject, Irp);
1087 }
1088 else
1089 {
1090 Irp->IoStatus.Status = STATUS_SUCCESS;
1091 PoStartNextPowerIrp(Irp);
1092 IoCompleteRequest(Irp, IO_NO_INCREMENT);
1093 return STATUS_SUCCESS;
1094 }
1095 }
1096
1097 NTSTATUS
1098 NTAPI
1099 HidClass_PnP(
1100 IN PDEVICE_OBJECT DeviceObject,
1101 IN PIRP Irp)
1102 {
1103 PHIDCLASS_COMMON_DEVICE_EXTENSION CommonDeviceExtension;
1104
1105 //
1106 // get common device extension
1107 //
1108 CommonDeviceExtension = DeviceObject->DeviceExtension;
1109
1110 //
1111 // check type of device object
1112 //
1113 if (CommonDeviceExtension->IsFDO)
1114 {
1115 //
1116 // handle request
1117 //
1118 return HidClassFDO_PnP(DeviceObject, Irp);
1119 }
1120 else
1121 {
1122 //
1123 // handle request
1124 //
1125 return HidClassPDO_PnP(DeviceObject, Irp);
1126 }
1127 }
1128
1129 NTSTATUS
1130 NTAPI
1131 HidClass_DispatchDefault(
1132 IN PDEVICE_OBJECT DeviceObject,
1133 IN PIRP Irp)
1134 {
1135 PHIDCLASS_COMMON_DEVICE_EXTENSION CommonDeviceExtension;
1136
1137 //
1138 // get common device extension
1139 //
1140 CommonDeviceExtension = DeviceObject->DeviceExtension;
1141
1142 //
1143 // FIXME: support PDO
1144 //
1145 ASSERT(CommonDeviceExtension->IsFDO == TRUE);
1146
1147 //
1148 // skip current irp stack location
1149 //
1150 IoSkipCurrentIrpStackLocation(Irp);
1151
1152 //
1153 // dispatch to lower device object
1154 //
1155 return IoCallDriver(CommonDeviceExtension->HidDeviceExtension.NextDeviceObject, Irp);
1156 }
1157
1158 NTSTATUS
1159 NTAPI
1160 HidClassDispatch(
1161 IN PDEVICE_OBJECT DeviceObject,
1162 IN PIRP Irp)
1163 {
1164 PIO_STACK_LOCATION IoStack;
1165
1166 //
1167 // get current stack location
1168 //
1169 IoStack = IoGetCurrentIrpStackLocation(Irp);
1170 DPRINT("[HIDCLASS] Dispatch Major %x Minor %x\n", IoStack->MajorFunction, IoStack->MinorFunction);
1171
1172 //
1173 // dispatch request based on major function
1174 //
1175 switch (IoStack->MajorFunction)
1176 {
1177 case IRP_MJ_CREATE:
1178 return HidClass_Create(DeviceObject, Irp);
1179 case IRP_MJ_CLOSE:
1180 return HidClass_Close(DeviceObject, Irp);
1181 case IRP_MJ_READ:
1182 return HidClass_Read(DeviceObject, Irp);
1183 case IRP_MJ_WRITE:
1184 return HidClass_Write(DeviceObject, Irp);
1185 case IRP_MJ_DEVICE_CONTROL:
1186 return HidClass_DeviceControl(DeviceObject, Irp);
1187 case IRP_MJ_INTERNAL_DEVICE_CONTROL:
1188 return HidClass_InternalDeviceControl(DeviceObject, Irp);
1189 case IRP_MJ_POWER:
1190 return HidClass_Power(DeviceObject, Irp);
1191 case IRP_MJ_PNP:
1192 return HidClass_PnP(DeviceObject, Irp);
1193 default:
1194 return HidClass_DispatchDefault(DeviceObject, Irp);
1195 }
1196 }
1197
1198 NTSTATUS
1199 NTAPI
1200 HidRegisterMinidriver(
1201 IN PHID_MINIDRIVER_REGISTRATION MinidriverRegistration)
1202 {
1203 NTSTATUS Status;
1204 PHIDCLASS_DRIVER_EXTENSION DriverExtension;
1205
1206 /* check if the version matches */
1207 if (MinidriverRegistration->Revision > HID_REVISION)
1208 {
1209 /* revision mismatch */
1210 ASSERT(FALSE);
1211 return STATUS_REVISION_MISMATCH;
1212 }
1213
1214 /* now allocate the driver object extension */
1215 Status = IoAllocateDriverObjectExtension(MinidriverRegistration->DriverObject,
1216 ClientIdentificationAddress,
1217 sizeof(HIDCLASS_DRIVER_EXTENSION),
1218 (PVOID *)&DriverExtension);
1219 if (!NT_SUCCESS(Status))
1220 {
1221 /* failed to allocate driver extension */
1222 ASSERT(FALSE);
1223 return Status;
1224 }
1225
1226 /* zero driver extension */
1227 RtlZeroMemory(DriverExtension, sizeof(HIDCLASS_DRIVER_EXTENSION));
1228
1229 /* init driver extension */
1230 DriverExtension->DriverObject = MinidriverRegistration->DriverObject;
1231 DriverExtension->DeviceExtensionSize = MinidriverRegistration->DeviceExtensionSize;
1232 DriverExtension->DevicesArePolled = MinidriverRegistration->DevicesArePolled;
1233 DriverExtension->AddDevice = MinidriverRegistration->DriverObject->DriverExtension->AddDevice;
1234 DriverExtension->DriverUnload = MinidriverRegistration->DriverObject->DriverUnload;
1235
1236 /* copy driver dispatch routines */
1237 RtlCopyMemory(DriverExtension->MajorFunction,
1238 MinidriverRegistration->DriverObject->MajorFunction,
1239 sizeof(PDRIVER_DISPATCH) * (IRP_MJ_MAXIMUM_FUNCTION + 1));
1240
1241 /* initialize lock */
1242 KeInitializeSpinLock(&DriverExtension->Lock);
1243
1244 /* now replace dispatch routines */
1245 DriverExtension->DriverObject->DriverExtension->AddDevice = HidClassAddDevice;
1246 DriverExtension->DriverObject->DriverUnload = HidClassDriverUnload;
1247 DriverExtension->DriverObject->MajorFunction[IRP_MJ_CREATE] = HidClassDispatch;
1248 DriverExtension->DriverObject->MajorFunction[IRP_MJ_CLOSE] = HidClassDispatch;
1249 DriverExtension->DriverObject->MajorFunction[IRP_MJ_READ] = HidClassDispatch;
1250 DriverExtension->DriverObject->MajorFunction[IRP_MJ_WRITE] = HidClassDispatch;
1251 DriverExtension->DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = HidClassDispatch;
1252 DriverExtension->DriverObject->MajorFunction[IRP_MJ_INTERNAL_DEVICE_CONTROL] = HidClassDispatch;
1253 DriverExtension->DriverObject->MajorFunction[IRP_MJ_POWER] = HidClassDispatch;
1254 DriverExtension->DriverObject->MajorFunction[IRP_MJ_PNP] = HidClassDispatch;
1255
1256 /* done */
1257 return STATUS_SUCCESS;
1258 }