Sync with trunk r63270.
[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 #ifndef __REACTOS__
150
151 //
152 // only supported for PDO
153 //
154 Irp->IoStatus.Status = STATUS_UNSUCCESSFUL;
155 IoCompleteRequest(Irp, IO_NO_INCREMENT);
156 return STATUS_UNSUCCESSFUL;
157 #else
158 //
159 // ReactOS PnP manager [...]
160 //
161 DPRINT1("[HIDCLASS] PnP HACK\n");
162 Irp->IoStatus.Status = STATUS_SUCCESS;
163 IoCompleteRequest(Irp, IO_NO_INCREMENT);
164 return STATUS_SUCCESS;
165 #endif
166 }
167
168 //
169 // must be a PDO
170 //
171 ASSERT(CommonDeviceExtension->IsFDO == FALSE);
172
173 //
174 // get device extension
175 //
176 PDODeviceExtension = DeviceObject->DeviceExtension;
177
178 //
179 // get stack location
180 //
181 IoStack = IoGetCurrentIrpStackLocation(Irp);
182
183 DPRINT("ShareAccess %x\n", IoStack->Parameters.Create.ShareAccess);
184 DPRINT("Options %x\n", IoStack->Parameters.Create.Options);
185 DPRINT("DesiredAccess %x\n", IoStack->Parameters.Create.SecurityContext->DesiredAccess);
186
187 //
188 // allocate context
189 //
190 Context = ExAllocatePoolWithTag(NonPagedPool, sizeof(HIDCLASS_FILEOP_CONTEXT), HIDCLASS_TAG);
191 if (!Context)
192 {
193 //
194 // no memory
195 //
196 Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
197 IoCompleteRequest(Irp, IO_NO_INCREMENT);
198 return STATUS_INSUFFICIENT_RESOURCES;
199 }
200
201 //
202 // init context
203 //
204 RtlZeroMemory(Context, sizeof(HIDCLASS_FILEOP_CONTEXT));
205 Context->DeviceExtension = PDODeviceExtension;
206 KeInitializeSpinLock(&Context->Lock);
207 InitializeListHead(&Context->ReadPendingIrpListHead);
208 InitializeListHead(&Context->IrpCompletedListHead);
209 KeInitializeEvent(&Context->IrpReadComplete, NotificationEvent, FALSE);
210
211 //
212 // store context
213 //
214 ASSERT(IoStack->FileObject);
215 IoStack->FileObject->FsContext = Context;
216
217 //
218 // done
219 //
220 Irp->IoStatus.Status = STATUS_SUCCESS;
221 IoCompleteRequest(Irp, IO_NO_INCREMENT);
222 return STATUS_SUCCESS;
223 }
224
225 NTSTATUS
226 NTAPI
227 HidClass_Close(
228 IN PDEVICE_OBJECT DeviceObject,
229 IN PIRP Irp)
230 {
231 PIO_STACK_LOCATION IoStack;
232 PHIDCLASS_COMMON_DEVICE_EXTENSION CommonDeviceExtension;
233 PHIDCLASS_FILEOP_CONTEXT IrpContext;
234 BOOLEAN IsRequestPending = FALSE;
235 KIRQL OldLevel;
236 PLIST_ENTRY Entry;
237 PIRP ListIrp;
238
239 //
240 // get device extension
241 //
242 CommonDeviceExtension = DeviceObject->DeviceExtension;
243
244 //
245 // is it a FDO request
246 //
247 if (CommonDeviceExtension->IsFDO)
248 {
249 //
250 // how did the request get there
251 //
252 Irp->IoStatus.Status = STATUS_INVALID_PARAMETER_1;
253 IoCompleteRequest(Irp, IO_NO_INCREMENT);
254 return STATUS_INVALID_PARAMETER_1;
255 }
256
257 //
258 // get stack location
259 //
260 IoStack = IoGetCurrentIrpStackLocation(Irp);
261
262 //
263 // sanity checks
264 //
265 ASSERT(IoStack->FileObject);
266 ASSERT(IoStack->FileObject->FsContext);
267
268 //
269 // get irp context
270 //
271 IrpContext = IoStack->FileObject->FsContext;
272 ASSERT(IrpContext);
273
274 //
275 // acquire lock
276 //
277 KeAcquireSpinLock(&IrpContext->Lock, &OldLevel);
278
279 if (!IsListEmpty(&IrpContext->ReadPendingIrpListHead))
280 {
281 //
282 // FIXME cancel irp
283 //
284 IsRequestPending = TRUE;
285 }
286
287 //
288 // signal stop
289 //
290 IrpContext->StopInProgress = TRUE;
291
292 //
293 // release lock
294 //
295 KeReleaseSpinLock(&IrpContext->Lock, OldLevel);
296
297 if (IsRequestPending)
298 {
299 //
300 // wait for request to complete
301 //
302 DPRINT1("[HIDCLASS] Waiting for read irp completion...\n");
303 KeWaitForSingleObject(&IrpContext->IrpReadComplete, Executive, KernelMode, FALSE, NULL);
304 }
305
306 //
307 // acquire lock
308 //
309 KeAcquireSpinLock(&IrpContext->Lock, &OldLevel);
310
311 //
312 // sanity check
313 //
314 ASSERT(IsListEmpty(&IrpContext->ReadPendingIrpListHead));
315
316 //
317 // now free all irps
318 //
319 while (!IsListEmpty(&IrpContext->IrpCompletedListHead))
320 {
321 //
322 // remove head irp
323 //
324 Entry = RemoveHeadList(&IrpContext->IrpCompletedListHead);
325
326 //
327 // get irp
328 //
329 ListIrp = CONTAINING_RECORD(Entry, IRP, Tail.Overlay.ListEntry);
330
331 //
332 // free the irp
333 //
334 IoFreeIrp(ListIrp);
335 }
336
337 //
338 // release lock
339 //
340 KeReleaseSpinLock(&IrpContext->Lock, OldLevel);
341
342 //
343 // remove context
344 //
345 IoStack->FileObject->FsContext = NULL;
346
347 //
348 // free context
349 //
350 ExFreePoolWithTag(IrpContext, HIDCLASS_TAG);
351
352 //
353 // complete request
354 //
355 Irp->IoStatus.Status = STATUS_SUCCESS;
356 IoCompleteRequest(Irp, IO_NO_INCREMENT);
357 return STATUS_SUCCESS;
358 }
359
360 NTSTATUS
361 NTAPI
362 HidClass_ReadCompleteIrp(
363 IN PDEVICE_OBJECT DeviceObject,
364 IN PIRP Irp,
365 IN PVOID Ctx)
366 {
367 PHIDCLASS_IRP_CONTEXT IrpContext;
368 KIRQL OldLevel;
369 PUCHAR Address;
370 ULONG Offset;
371 PHIDP_COLLECTION_DESC CollectionDescription;
372 PHIDP_REPORT_IDS ReportDescription;
373 BOOLEAN IsEmpty;
374
375 //
376 // get irp context
377 //
378 IrpContext = Ctx;
379
380 DPRINT("HidClass_ReadCompleteIrp Irql %lu\n", KeGetCurrentIrql());
381 DPRINT("HidClass_ReadCompleteIrp Status %lx\n", Irp->IoStatus.Status);
382 DPRINT("HidClass_ReadCompleteIrp Length %lu\n", Irp->IoStatus.Information);
383 DPRINT("HidClass_ReadCompleteIrp Irp %p\n", Irp);
384 DPRINT("HidClass_ReadCompleteIrp InputReportBuffer %p\n", IrpContext->InputReportBuffer);
385 DPRINT("HidClass_ReadCompleteIrp InputReportBufferLength %li\n", IrpContext->InputReportBufferLength);
386 DPRINT("HidClass_ReadCompleteIrp OriginalIrp %p\n", IrpContext->OriginalIrp);
387
388 //
389 // copy result
390 //
391 if (Irp->IoStatus.Information)
392 {
393 //
394 // get address
395 //
396 Address = MmGetSystemAddressForMdlSafe(IrpContext->OriginalIrp->MdlAddress, NormalPagePriority);
397 if (Address)
398 {
399 //
400 // reports may have a report id prepended
401 //
402 Offset = 0;
403
404 //
405 // get collection description
406 //
407 CollectionDescription = HidClassPDO_GetCollectionDescription(&IrpContext->FileOp->DeviceExtension->Common.DeviceDescription,
408 IrpContext->FileOp->DeviceExtension->CollectionNumber);
409 ASSERT(CollectionDescription);
410
411 //
412 // get report description
413 //
414 ReportDescription = HidClassPDO_GetReportDescription(&IrpContext->FileOp->DeviceExtension->Common.DeviceDescription,
415 IrpContext->FileOp->DeviceExtension->CollectionNumber);
416 ASSERT(ReportDescription);
417
418 if (CollectionDescription && ReportDescription)
419 {
420 //
421 // calculate offset
422 //
423 ASSERT(CollectionDescription->InputLength >= ReportDescription->InputLength);
424 Offset = CollectionDescription->InputLength - ReportDescription->InputLength;
425 }
426
427 //
428 // copy result
429 //
430 RtlCopyMemory(&Address[Offset], IrpContext->InputReportBuffer, IrpContext->InputReportBufferLength);
431 }
432 }
433
434 //
435 // copy result status
436 //
437 IrpContext->OriginalIrp->IoStatus.Status = Irp->IoStatus.Status;
438 IrpContext->OriginalIrp->IoStatus.Information = Irp->IoStatus.Information;
439
440 //
441 // free input report buffer
442 //
443 ExFreePoolWithTag(IrpContext->InputReportBuffer, HIDCLASS_TAG);
444
445 //
446 // remove us from pending list
447 //
448 KeAcquireSpinLock(&IrpContext->FileOp->Lock, &OldLevel);
449
450 //
451 // remove from pending list
452 //
453 RemoveEntryList(&Irp->Tail.Overlay.ListEntry);
454
455 //
456 // is list empty
457 //
458 IsEmpty = IsListEmpty(&IrpContext->FileOp->ReadPendingIrpListHead);
459
460 //
461 // insert into completed list
462 //
463 InsertTailList(&IrpContext->FileOp->IrpCompletedListHead, &Irp->Tail.Overlay.ListEntry);
464
465 //
466 // release lock
467 //
468 KeReleaseSpinLock(&IrpContext->FileOp->Lock, OldLevel);
469
470 //
471 // complete original request
472 //
473 IoCompleteRequest(IrpContext->OriginalIrp, IO_NO_INCREMENT);
474
475
476 DPRINT("StopInProgress %x IsEmpty %x\n", IrpContext->FileOp->StopInProgress, IsEmpty);
477 if (IrpContext->FileOp->StopInProgress && IsEmpty)
478 {
479 //
480 // last pending irp
481 //
482 DPRINT1("[HIDCLASS] LastPendingTransfer Signalling\n");
483 KeSetEvent(&IrpContext->FileOp->IrpReadComplete, 0, FALSE);
484 }
485
486 if (IrpContext->FileOp->StopInProgress && IsEmpty)
487 {
488 //
489 // last pending irp
490 //
491 DPRINT1("[HIDCLASS] LastPendingTransfer Signalling\n");
492 KeSetEvent(&IrpContext->FileOp->IrpReadComplete, 0, FALSE);
493 }
494
495 //
496 // free irp context
497 //
498 ExFreePoolWithTag(IrpContext, HIDCLASS_TAG);
499
500 //
501 // done
502 //
503 return STATUS_MORE_PROCESSING_REQUIRED;
504 }
505
506 PIRP
507 HidClass_GetIrp(
508 IN PHIDCLASS_FILEOP_CONTEXT Context)
509 {
510 KIRQL OldLevel;
511 PIRP Irp = NULL;
512 PLIST_ENTRY ListEntry;
513
514 //
515 // acquire lock
516 //
517 KeAcquireSpinLock(&Context->Lock, &OldLevel);
518
519 //
520 // is list empty?
521 //
522 if (!IsListEmpty(&Context->IrpCompletedListHead))
523 {
524 //
525 // grab first entry
526 //
527 ListEntry = RemoveHeadList(&Context->IrpCompletedListHead);
528
529 //
530 // get irp
531 //
532 Irp = CONTAINING_RECORD(ListEntry, IRP, Tail.Overlay.ListEntry);
533 }
534
535 //
536 // release lock
537 //
538 KeReleaseSpinLock(&Context->Lock, OldLevel);
539
540 //
541 // done
542 //
543 return Irp;
544 }
545
546 NTSTATUS
547 HidClass_BuildIrp(
548 IN PDEVICE_OBJECT DeviceObject,
549 IN PIRP RequestIrp,
550 IN PHIDCLASS_FILEOP_CONTEXT Context,
551 IN ULONG DeviceIoControlCode,
552 IN ULONG BufferLength,
553 OUT PIRP *OutIrp,
554 OUT PHIDCLASS_IRP_CONTEXT *OutIrpContext)
555 {
556 PIRP Irp;
557 PIO_STACK_LOCATION IoStack;
558 PHIDCLASS_IRP_CONTEXT IrpContext;
559 PHIDCLASS_PDO_DEVICE_EXTENSION PDODeviceExtension;
560 PHIDP_COLLECTION_DESC CollectionDescription;
561 PHIDP_REPORT_IDS ReportDescription;
562
563 //
564 // get an irp from fresh list
565 //
566 Irp = HidClass_GetIrp(Context);
567 if (!Irp)
568 {
569 //
570 // build new irp
571 //
572 Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE);
573 if (!Irp)
574 {
575 //
576 // no memory
577 //
578 return STATUS_INSUFFICIENT_RESOURCES;
579 }
580 }
581 else
582 {
583 //
584 // re-use irp
585 //
586 IoReuseIrp(Irp, STATUS_SUCCESS);
587 }
588
589 //
590 // allocate completion context
591 //
592 IrpContext = ExAllocatePoolWithTag(NonPagedPool, sizeof(HIDCLASS_IRP_CONTEXT), HIDCLASS_TAG);
593 if (!IrpContext)
594 {
595 //
596 // no memory
597 //
598 IoFreeIrp(Irp);
599 return STATUS_INSUFFICIENT_RESOURCES;
600 }
601
602 //
603 // get device extension
604 //
605 PDODeviceExtension = DeviceObject->DeviceExtension;
606 ASSERT(PDODeviceExtension->Common.IsFDO == FALSE);
607
608 //
609 // init irp context
610 //
611 RtlZeroMemory(IrpContext, sizeof(HIDCLASS_IRP_CONTEXT));
612 IrpContext->OriginalIrp = RequestIrp;
613 IrpContext->FileOp = Context;
614
615 //
616 // get collection description
617 //
618 CollectionDescription = HidClassPDO_GetCollectionDescription(&IrpContext->FileOp->DeviceExtension->Common.DeviceDescription,
619 IrpContext->FileOp->DeviceExtension->CollectionNumber);
620 ASSERT(CollectionDescription);
621
622 //
623 // get report description
624 //
625 ReportDescription = HidClassPDO_GetReportDescription(&IrpContext->FileOp->DeviceExtension->Common.DeviceDescription,
626 IrpContext->FileOp->DeviceExtension->CollectionNumber);
627 ASSERT(ReportDescription);
628
629 //
630 // sanity check
631 //
632 ASSERT(CollectionDescription->InputLength >= ReportDescription->InputLength);
633
634 if (Context->StopInProgress)
635 {
636 //
637 // stop in progress
638 //
639 DPRINT1("[HIDCLASS] Stop In Progress\n");
640 Irp->IoStatus.Status = STATUS_CANCELLED;
641 IoCompleteRequest(Irp, IO_NO_INCREMENT);
642 return STATUS_CANCELLED;
643
644 }
645
646 //
647 // store report length
648 //
649 IrpContext->InputReportBufferLength = ReportDescription->InputLength;
650
651 //
652 // allocate buffer
653 //
654 IrpContext->InputReportBuffer = ExAllocatePoolWithTag(NonPagedPool, IrpContext->InputReportBufferLength, HIDCLASS_TAG);
655 if (!IrpContext->InputReportBuffer)
656 {
657 //
658 // no memory
659 //
660 IoFreeIrp(Irp);
661 ExFreePoolWithTag(IrpContext, HIDCLASS_TAG);
662 return STATUS_INSUFFICIENT_RESOURCES;
663 }
664
665 //
666 // get stack location
667 //
668 IoStack = IoGetNextIrpStackLocation(Irp);
669
670 //
671 // init stack location
672 //
673 IoStack->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
674 IoStack->Parameters.DeviceIoControl.IoControlCode = DeviceIoControlCode;
675 IoStack->Parameters.DeviceIoControl.OutputBufferLength = IrpContext->InputReportBufferLength;
676 IoStack->Parameters.DeviceIoControl.InputBufferLength = 0;
677 IoStack->Parameters.DeviceIoControl.Type3InputBuffer = NULL;
678 Irp->UserBuffer = IrpContext->InputReportBuffer;
679 IoStack->DeviceObject = DeviceObject;
680
681 //
682 // store result
683 //
684 *OutIrp = Irp;
685 *OutIrpContext = IrpContext;
686
687 //
688 // done
689 //
690 return STATUS_SUCCESS;
691 }
692
693 NTSTATUS
694 NTAPI
695 HidClass_Read(
696 IN PDEVICE_OBJECT DeviceObject,
697 IN PIRP Irp)
698 {
699 PIO_STACK_LOCATION IoStack;
700 PHIDCLASS_FILEOP_CONTEXT Context;
701 KIRQL OldLevel;
702 NTSTATUS Status;
703 PIRP NewIrp;
704 PHIDCLASS_IRP_CONTEXT NewIrpContext;
705 PHIDCLASS_COMMON_DEVICE_EXTENSION CommonDeviceExtension;
706
707 //
708 // get current stack location
709 //
710 IoStack = IoGetCurrentIrpStackLocation(Irp);
711
712 //
713 // get device extension
714 //
715 CommonDeviceExtension = DeviceObject->DeviceExtension;
716 ASSERT(CommonDeviceExtension->IsFDO == FALSE);
717
718 //
719 // sanity check
720 //
721 ASSERT(IoStack->FileObject);
722 ASSERT(IoStack->FileObject->FsContext);
723
724 //
725 // get context
726 //
727 Context = IoStack->FileObject->FsContext;
728 ASSERT(Context);
729
730 //
731 // FIXME support polled devices
732 //
733 ASSERT(Context->DeviceExtension->Common.DriverExtension->DevicesArePolled == FALSE);
734
735 if (Context->StopInProgress)
736 {
737 //
738 // stop in progress
739 //
740 DPRINT1("[HIDCLASS] Stop In Progress\n");
741 Irp->IoStatus.Status = STATUS_CANCELLED;
742 IoCompleteRequest(Irp, IO_NO_INCREMENT);
743 return STATUS_CANCELLED;
744 }
745
746 //
747 // build irp request
748 //
749 Status = HidClass_BuildIrp(DeviceObject,
750 Irp,
751 Context,
752 IOCTL_HID_READ_REPORT,
753 IoStack->Parameters.Read.Length,
754 &NewIrp,
755 &NewIrpContext);
756 if (!NT_SUCCESS(Status))
757 {
758 //
759 // failed
760 //
761 DPRINT1("HidClass_BuildIrp failed with %x\n", Status);
762 Irp->IoStatus.Status = Status;
763 IoCompleteRequest(Irp, IO_NO_INCREMENT);
764 return Status;
765 }
766
767 //
768 // acquire lock
769 //
770 KeAcquireSpinLock(&Context->Lock, &OldLevel);
771
772 //
773 // insert irp into pending list
774 //
775 InsertTailList(&Context->ReadPendingIrpListHead, &NewIrp->Tail.Overlay.ListEntry);
776
777 //
778 // set completion routine
779 //
780 IoSetCompletionRoutine(NewIrp, HidClass_ReadCompleteIrp, NewIrpContext, TRUE, TRUE, TRUE);
781
782 //
783 // make next location current
784 //
785 IoSetNextIrpStackLocation(NewIrp);
786
787 //
788 // release spin lock
789 //
790 KeReleaseSpinLock(&Context->Lock, OldLevel);
791
792 //
793 // mark irp pending
794 //
795 IoMarkIrpPending(Irp);
796
797 //
798 // let's dispatch the request
799 //
800 ASSERT(Context->DeviceExtension);
801 Status = Context->DeviceExtension->Common.DriverExtension->MajorFunction[IRP_MJ_INTERNAL_DEVICE_CONTROL](Context->DeviceExtension->FDODeviceObject, NewIrp);
802
803 //
804 // complete
805 //
806 return STATUS_PENDING;
807 }
808
809 NTSTATUS
810 NTAPI
811 HidClass_Write(
812 IN PDEVICE_OBJECT DeviceObject,
813 IN PIRP Irp)
814 {
815 UNIMPLEMENTED
816 ASSERT(FALSE);
817 Irp->IoStatus.Status = STATUS_NOT_IMPLEMENTED;
818 IoCompleteRequest(Irp, IO_NO_INCREMENT);
819 return STATUS_NOT_IMPLEMENTED;
820 }
821
822 NTSTATUS
823 NTAPI
824 HidClass_DeviceControl(
825 IN PDEVICE_OBJECT DeviceObject,
826 IN PIRP Irp)
827 {
828 PIO_STACK_LOCATION IoStack;
829 PHIDCLASS_COMMON_DEVICE_EXTENSION CommonDeviceExtension;
830 PHID_COLLECTION_INFORMATION CollectionInformation;
831 PHIDP_COLLECTION_DESC CollectionDescription;
832 PHIDCLASS_PDO_DEVICE_EXTENSION PDODeviceExtension;
833
834 //
835 // get device extension
836 //
837 CommonDeviceExtension = DeviceObject->DeviceExtension;
838
839 //
840 // only PDO are supported
841 //
842 if (CommonDeviceExtension->IsFDO)
843 {
844 //
845 // invalid request
846 //
847 DPRINT1("[HIDCLASS] DeviceControl Irp for FDO arrived\n");
848 Irp->IoStatus.Status = STATUS_INVALID_PARAMETER_1;
849 IoCompleteRequest(Irp, IO_NO_INCREMENT);
850 return STATUS_INVALID_PARAMETER_1;
851 }
852
853 ASSERT(CommonDeviceExtension->IsFDO == FALSE);
854
855 //
856 // get pdo device extension
857 //
858 PDODeviceExtension = DeviceObject->DeviceExtension;
859
860 //
861 // get stack location
862 //
863 IoStack = IoGetCurrentIrpStackLocation(Irp);
864
865 switch (IoStack->Parameters.DeviceIoControl.IoControlCode)
866 {
867 case IOCTL_HID_GET_COLLECTION_INFORMATION:
868 {
869 //
870 // check if output buffer is big enough
871 //
872 if (IoStack->Parameters.DeviceIoControl.OutputBufferLength < sizeof(HID_COLLECTION_INFORMATION))
873 {
874 //
875 // invalid buffer size
876 //
877 Irp->IoStatus.Status = STATUS_INVALID_BUFFER_SIZE;
878 IoCompleteRequest(Irp, IO_NO_INCREMENT);
879 return STATUS_INVALID_BUFFER_SIZE;
880 }
881
882 //
883 // get output buffer
884 //
885 CollectionInformation = Irp->AssociatedIrp.SystemBuffer;
886 ASSERT(CollectionInformation);
887
888 //
889 // get collection description
890 //
891 CollectionDescription = HidClassPDO_GetCollectionDescription(&CommonDeviceExtension->DeviceDescription,
892 PDODeviceExtension->CollectionNumber);
893 ASSERT(CollectionDescription);
894
895 //
896 // init result buffer
897 //
898 CollectionInformation->DescriptorSize = CollectionDescription->PreparsedDataLength;
899 CollectionInformation->Polled = CommonDeviceExtension->DriverExtension->DevicesArePolled;
900 CollectionInformation->VendorID = CommonDeviceExtension->Attributes.VendorID;
901 CollectionInformation->ProductID = CommonDeviceExtension->Attributes.ProductID;
902 CollectionInformation->VersionNumber = CommonDeviceExtension->Attributes.VersionNumber;
903
904 //
905 // complete request
906 //
907 Irp->IoStatus.Information = sizeof(HID_COLLECTION_INFORMATION);
908 Irp->IoStatus.Status = STATUS_SUCCESS;
909 IoCompleteRequest(Irp, IO_NO_INCREMENT);
910 return STATUS_SUCCESS;
911 }
912 case IOCTL_HID_GET_COLLECTION_DESCRIPTOR:
913 {
914 //
915 // get collection description
916 //
917 CollectionDescription = HidClassPDO_GetCollectionDescription(&CommonDeviceExtension->DeviceDescription,
918 PDODeviceExtension->CollectionNumber);
919 ASSERT(CollectionDescription);
920
921 //
922 // check if output buffer is big enough
923 //
924 if (IoStack->Parameters.DeviceIoControl.OutputBufferLength < CollectionDescription->PreparsedDataLength)
925 {
926 //
927 // invalid buffer size
928 //
929 Irp->IoStatus.Status = STATUS_INVALID_BUFFER_SIZE;
930 IoCompleteRequest(Irp, IO_NO_INCREMENT);
931 return STATUS_INVALID_BUFFER_SIZE;
932 }
933
934 //
935 // copy result
936 //
937 ASSERT(Irp->UserBuffer);
938 RtlCopyMemory(Irp->UserBuffer, CollectionDescription->PreparsedData, CollectionDescription->PreparsedDataLength);
939
940 //
941 // complete request
942 //
943 Irp->IoStatus.Information = CollectionDescription->PreparsedDataLength;
944 Irp->IoStatus.Status = STATUS_SUCCESS;
945 IoCompleteRequest(Irp, IO_NO_INCREMENT);
946 return STATUS_SUCCESS;
947 }
948 default:
949 {
950 DPRINT1("[HIDCLASS] DeviceControl IoControlCode 0x%x not implemented\n", IoStack->Parameters.DeviceIoControl.IoControlCode);
951 Irp->IoStatus.Status = STATUS_NOT_IMPLEMENTED;
952 IoCompleteRequest(Irp, IO_NO_INCREMENT);
953 return STATUS_NOT_IMPLEMENTED;
954 }
955 }
956 }
957
958 NTSTATUS
959 NTAPI
960 HidClass_InternalDeviceControl(
961 IN PDEVICE_OBJECT DeviceObject,
962 IN PIRP Irp)
963 {
964 UNIMPLEMENTED
965 ASSERT(FALSE);
966 Irp->IoStatus.Status = STATUS_NOT_IMPLEMENTED;
967 IoCompleteRequest(Irp, IO_NO_INCREMENT);
968 return STATUS_NOT_IMPLEMENTED;
969 }
970
971 NTSTATUS
972 NTAPI
973 HidClass_Power(
974 IN PDEVICE_OBJECT DeviceObject,
975 IN PIRP Irp)
976 {
977 PHIDCLASS_COMMON_DEVICE_EXTENSION CommonDeviceExtension;
978 CommonDeviceExtension = DeviceObject->DeviceExtension;
979
980 if (CommonDeviceExtension->IsFDO)
981 {
982 IoCopyCurrentIrpStackLocationToNext(Irp);
983 return HidClassFDO_DispatchRequest(DeviceObject, Irp);
984 }
985 else
986 {
987 Irp->IoStatus.Status = STATUS_SUCCESS;
988 PoStartNextPowerIrp(Irp);
989 IoCompleteRequest(Irp, IO_NO_INCREMENT);
990 return STATUS_SUCCESS;
991 }
992 }
993
994 NTSTATUS
995 NTAPI
996 HidClass_PnP(
997 IN PDEVICE_OBJECT DeviceObject,
998 IN PIRP Irp)
999 {
1000 PHIDCLASS_COMMON_DEVICE_EXTENSION CommonDeviceExtension;
1001
1002 //
1003 // get common device extension
1004 //
1005 CommonDeviceExtension = DeviceObject->DeviceExtension;
1006
1007 //
1008 // check type of device object
1009 //
1010 if (CommonDeviceExtension->IsFDO)
1011 {
1012 //
1013 // handle request
1014 //
1015 return HidClassFDO_PnP(DeviceObject, Irp);
1016 }
1017 else
1018 {
1019 //
1020 // handle request
1021 //
1022 return HidClassPDO_PnP(DeviceObject, Irp);
1023 }
1024 }
1025
1026 NTSTATUS
1027 NTAPI
1028 HidClass_DispatchDefault(
1029 IN PDEVICE_OBJECT DeviceObject,
1030 IN PIRP Irp)
1031 {
1032 PHIDCLASS_COMMON_DEVICE_EXTENSION CommonDeviceExtension;
1033
1034 //
1035 // get common device extension
1036 //
1037 CommonDeviceExtension = DeviceObject->DeviceExtension;
1038
1039 //
1040 // FIXME: support PDO
1041 //
1042 ASSERT(CommonDeviceExtension->IsFDO == TRUE);
1043
1044 //
1045 // skip current irp stack location
1046 //
1047 IoSkipCurrentIrpStackLocation(Irp);
1048
1049 //
1050 // dispatch to lower device object
1051 //
1052 return IoCallDriver(CommonDeviceExtension->HidDeviceExtension.NextDeviceObject, Irp);
1053 }
1054
1055 NTSTATUS
1056 NTAPI
1057 HidClassDispatch(
1058 IN PDEVICE_OBJECT DeviceObject,
1059 IN PIRP Irp)
1060 {
1061 PIO_STACK_LOCATION IoStack;
1062
1063 //
1064 // get current stack location
1065 //
1066 IoStack = IoGetCurrentIrpStackLocation(Irp);
1067 DPRINT("[HIDCLASS] Dispatch Major %x Minor %x\n", IoStack->MajorFunction, IoStack->MinorFunction);
1068
1069 //
1070 // dispatch request based on major function
1071 //
1072 switch (IoStack->MajorFunction)
1073 {
1074 case IRP_MJ_CREATE:
1075 return HidClass_Create(DeviceObject, Irp);
1076 case IRP_MJ_CLOSE:
1077 return HidClass_Close(DeviceObject, Irp);
1078 case IRP_MJ_READ:
1079 return HidClass_Read(DeviceObject, Irp);
1080 case IRP_MJ_WRITE:
1081 return HidClass_Write(DeviceObject, Irp);
1082 case IRP_MJ_DEVICE_CONTROL:
1083 return HidClass_DeviceControl(DeviceObject, Irp);
1084 case IRP_MJ_INTERNAL_DEVICE_CONTROL:
1085 return HidClass_InternalDeviceControl(DeviceObject, Irp);
1086 case IRP_MJ_POWER:
1087 return HidClass_Power(DeviceObject, Irp);
1088 case IRP_MJ_PNP:
1089 return HidClass_PnP(DeviceObject, Irp);
1090 default:
1091 return HidClass_DispatchDefault(DeviceObject, Irp);
1092 }
1093 }
1094
1095 NTSTATUS
1096 NTAPI
1097 HidRegisterMinidriver(
1098 IN PHID_MINIDRIVER_REGISTRATION MinidriverRegistration)
1099 {
1100 NTSTATUS Status;
1101 PHIDCLASS_DRIVER_EXTENSION DriverExtension;
1102
1103 /* check if the version matches */
1104 if (MinidriverRegistration->Revision > HID_REVISION)
1105 {
1106 /* revision mismatch */
1107 ASSERT(FALSE);
1108 return STATUS_REVISION_MISMATCH;
1109 }
1110
1111 /* now allocate the driver object extension */
1112 Status = IoAllocateDriverObjectExtension(MinidriverRegistration->DriverObject,
1113 ClientIdentificationAddress,
1114 sizeof(HIDCLASS_DRIVER_EXTENSION),
1115 (PVOID *)&DriverExtension);
1116 if (!NT_SUCCESS(Status))
1117 {
1118 /* failed to allocate driver extension */
1119 ASSERT(FALSE);
1120 return Status;
1121 }
1122
1123 /* zero driver extension */
1124 RtlZeroMemory(DriverExtension, sizeof(HIDCLASS_DRIVER_EXTENSION));
1125
1126 /* init driver extension */
1127 DriverExtension->DriverObject = MinidriverRegistration->DriverObject;
1128 DriverExtension->DeviceExtensionSize = MinidriverRegistration->DeviceExtensionSize;
1129 DriverExtension->DevicesArePolled = MinidriverRegistration->DevicesArePolled;
1130 DriverExtension->AddDevice = MinidriverRegistration->DriverObject->DriverExtension->AddDevice;
1131 DriverExtension->DriverUnload = MinidriverRegistration->DriverObject->DriverUnload;
1132
1133 /* copy driver dispatch routines */
1134 RtlCopyMemory(DriverExtension->MajorFunction,
1135 MinidriverRegistration->DriverObject->MajorFunction,
1136 sizeof(PDRIVER_DISPATCH) * (IRP_MJ_MAXIMUM_FUNCTION + 1));
1137
1138 /* initialize lock */
1139 KeInitializeSpinLock(&DriverExtension->Lock);
1140
1141 /* now replace dispatch routines */
1142 DriverExtension->DriverObject->DriverExtension->AddDevice = HidClassAddDevice;
1143 DriverExtension->DriverObject->DriverUnload = HidClassDriverUnload;
1144 DriverExtension->DriverObject->MajorFunction[IRP_MJ_CREATE] = HidClassDispatch;
1145 DriverExtension->DriverObject->MajorFunction[IRP_MJ_CLOSE] = HidClassDispatch;
1146 DriverExtension->DriverObject->MajorFunction[IRP_MJ_READ] = HidClassDispatch;
1147 DriverExtension->DriverObject->MajorFunction[IRP_MJ_WRITE] = HidClassDispatch;
1148 DriverExtension->DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = HidClassDispatch;
1149 DriverExtension->DriverObject->MajorFunction[IRP_MJ_INTERNAL_DEVICE_CONTROL] = HidClassDispatch;
1150 DriverExtension->DriverObject->MajorFunction[IRP_MJ_POWER] = HidClassDispatch;
1151 DriverExtension->DriverObject->MajorFunction[IRP_MJ_PNP] = HidClassDispatch;
1152
1153 /* done */
1154 return STATUS_SUCCESS;
1155 }