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