deb67f496e080a9e8ea21f0e243f8f04660c8cc3
[reactos.git] / reactos / 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 ULONG
17 NTAPI
18 DllInitialize(ULONG Unknown)
19 {
20 return 0;
21 }
22
23 ULONG
24 NTAPI
25 DllUnload()
26 {
27 return 0;
28 }
29
30 NTSTATUS
31 NTAPI
32 HidClassAddDevice(
33 IN PDRIVER_OBJECT DriverObject,
34 IN PDEVICE_OBJECT PhysicalDeviceObject)
35 {
36 WCHAR CharDeviceName[64];
37 NTSTATUS Status;
38 UNICODE_STRING DeviceName;
39 PDEVICE_OBJECT NewDeviceObject;
40 PHIDCLASS_FDO_EXTENSION FDODeviceExtension;
41 ULONG DeviceExtensionSize;
42 PHIDCLASS_DRIVER_EXTENSION DriverExtension;
43
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 = (PHIDCLASS_DRIVER_EXTENSION) 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 = (PHIDCLASS_FDO_EXTENSION)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 = (PHIDCLASS_COMMON_DEVICE_EXTENSION)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 = (PHIDCLASS_PDO_DEVICE_EXTENSION)CommonDeviceExtension;
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 = (PHIDCLASS_FILEOP_CONTEXT)ExAllocatePool(NonPagedPool, sizeof(HIDCLASS_FILEOP_CONTEXT));
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
207 //
208 // store context
209 //
210 ASSERT(IoStack->FileObject);
211 IoStack->FileObject->FsContext = (PVOID)Context;
212
213 //
214 // done
215 //
216 Irp->IoStatus.Status = STATUS_SUCCESS;
217 IoCompleteRequest(Irp, IO_NO_INCREMENT);
218 return STATUS_SUCCESS;
219 }
220
221 NTSTATUS
222 NTAPI
223 HidClass_Close(
224 IN PDEVICE_OBJECT DeviceObject,
225 IN PIRP Irp)
226 {
227 PIO_STACK_LOCATION IoStack;
228 PHIDCLASS_COMMON_DEVICE_EXTENSION CommonDeviceExtension;
229 PHIDCLASS_IRP_CONTEXT IrpContext;
230
231 //
232 // get device extension
233 //
234 CommonDeviceExtension = (PHIDCLASS_COMMON_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
235
236 //
237 // is it a FDO request
238 //
239 if (CommonDeviceExtension->IsFDO)
240 {
241 //
242 // how did the request get there
243 //
244 Irp->IoStatus.Status = STATUS_INVALID_PARAMETER_1;
245 IoCompleteRequest(Irp, IO_NO_INCREMENT);
246 return STATUS_INVALID_PARAMETER_1;
247 }
248
249 //
250 // get stack location
251 //
252 IoStack = IoGetCurrentIrpStackLocation(Irp);
253
254 //
255 // sanity checks
256 //
257 ASSERT(IoStack->FileObject);
258 ASSERT(IoStack->FileObject->FsContext);
259
260 //
261 // get irp context
262 //
263 IrpContext = (PHIDCLASS_IRP_CONTEXT)IoStack->FileObject->FsContext;
264
265 //
266 // cancel pending irps
267 //
268 UNIMPLEMENTED
269
270 //
271 // remove context
272 //
273 IoStack->FileObject->FsContext = NULL;
274
275 //
276 // free context
277 //
278 ExFreePool(IrpContext);
279
280 //
281 // complete request
282 //
283 Irp->IoStatus.Status = STATUS_SUCCESS;
284 IoCompleteRequest(Irp, IO_NO_INCREMENT);
285 return STATUS_SUCCESS;
286 }
287
288 PVOID
289 HidClass_GetSystemAddress(
290 IN PMDL ReportMDL)
291 {
292 //
293 // sanity check
294 //
295 ASSERT(ReportMDL);
296
297 if (ReportMDL->MdlFlags & (MDL_SOURCE_IS_NONPAGED_POOL | MDL_MAPPED_TO_SYSTEM_VA))
298 {
299 //
300 // buffer is non paged pool
301 //
302 return ReportMDL->MappedSystemVa;
303 }
304 else
305 {
306 //
307 // map mdl
308 //
309 return MmMapLockedPages(ReportMDL, KernelMode);
310 }
311 }
312
313 NTSTATUS
314 NTAPI
315 HidClass_ReadCompleteIrp(
316 IN PDEVICE_OBJECT DeviceObject,
317 IN PIRP Irp,
318 IN PVOID Ctx)
319 {
320 PHIDCLASS_IRP_CONTEXT IrpContext;
321 KIRQL OldLevel;
322 PUCHAR Address;
323 ULONG Offset;
324 PHIDP_COLLECTION_DESC CollectionDescription;
325 PHIDP_REPORT_IDS ReportDescription;
326
327 //
328 // get irp context
329 //
330 IrpContext = (PHIDCLASS_IRP_CONTEXT)Ctx;
331
332 DPRINT("HidClass_ReadCompleteIrp Irql %lu\n", KeGetCurrentIrql());
333 DPRINT("HidClass_ReadCompleteIrp Status %lx\n", Irp->IoStatus.Status);
334 DPRINT("HidClass_ReadCompleteIrp Length %lu\n", Irp->IoStatus.Information);
335 DPRINT("HidClass_ReadCompleteIrp Irp %p\n", Irp);
336 DPRINT("HidClass_ReadCompleteIrp InputReportBuffer %p\n", IrpContext->InputReportBuffer);
337 DPRINT("HidClass_ReadCompleteIrp InputReportBufferLength %li\n", IrpContext->InputReportBufferLength);
338 DPRINT("HidClass_ReadCompleteIrp OriginalIrp %p\n", IrpContext->OriginalIrp);
339
340 //
341 // copy result
342 //
343 if (Irp->IoStatus.Information)
344 {
345 //
346 // get address
347 //
348 Address = (PUCHAR)HidClass_GetSystemAddress(IrpContext->OriginalIrp->MdlAddress);
349 if (Address)
350 {
351 //
352 // reports may have a report id prepended
353 //
354 Offset = 0;
355
356 //
357 // get collection description
358 //
359 CollectionDescription = HidClassPDO_GetCollectionDescription(&IrpContext->FileOp->DeviceExtension->Common.DeviceDescription, IrpContext->FileOp->DeviceExtension->CollectionNumber);
360 ASSERT(CollectionDescription);
361
362 //
363 // get report description
364 //
365 ReportDescription = HidClassPDO_GetReportDescription(&IrpContext->FileOp->DeviceExtension->Common.DeviceDescription, IrpContext->FileOp->DeviceExtension->CollectionNumber);
366 ASSERT(ReportDescription);
367
368 if (CollectionDescription && ReportDescription)
369 {
370 //
371 // calculate offset
372 //
373 ASSERT(CollectionDescription->InputLength >= ReportDescription->InputLength);
374 Offset = CollectionDescription->InputLength - ReportDescription->InputLength;
375 }
376
377 //
378 // copy result
379 //
380 RtlCopyMemory(&Address[Offset], IrpContext->InputReportBuffer, IrpContext->InputReportBufferLength);
381 }
382 }
383
384 //
385 // copy result status
386 //
387 IrpContext->OriginalIrp->IoStatus.Status = Irp->IoStatus.Status;
388 Irp->IoStatus.Information = Irp->IoStatus.Information;
389
390 //
391 // free input report buffer
392 //
393 ExFreePool(IrpContext->InputReportBuffer);
394
395 //
396 // remove us from pending list
397 //
398 KeAcquireSpinLock(&IrpContext->FileOp->Lock, &OldLevel);
399
400 //
401 // remove from pending list
402 //
403 RemoveEntryList(&Irp->Tail.Overlay.ListEntry);
404
405 //
406 // insert into completed list
407 //
408 InsertTailList(&IrpContext->FileOp->IrpCompletedListHead, &Irp->Tail.Overlay.ListEntry);
409
410 //
411 // release lock
412 //
413 KeReleaseSpinLock(&IrpContext->FileOp->Lock, OldLevel);
414
415 //
416 // complete original request
417 //
418 IoCompleteRequest(IrpContext->OriginalIrp, IO_NO_INCREMENT);
419
420 //
421 // free irp context
422 //
423 ExFreePool(IrpContext);
424
425 //
426 // done
427 //
428 return STATUS_MORE_PROCESSING_REQUIRED;
429 }
430
431 PIRP
432 HidClass_GetIrp(
433 IN PHIDCLASS_FILEOP_CONTEXT Context)
434 {
435 KIRQL OldLevel;
436 PIRP Irp = NULL;
437 PLIST_ENTRY ListEntry;
438
439 //
440 // acquire lock
441 //
442 KeAcquireSpinLock(&Context->Lock, &OldLevel);
443
444 //
445 // is list empty?
446 //
447 if (!IsListEmpty(&Context->IrpCompletedListHead))
448 {
449 //
450 // grab first entry
451 //
452 ListEntry = RemoveHeadList(&Context->IrpCompletedListHead);
453
454 //
455 // get irp
456 //
457 Irp = (PIRP)CONTAINING_RECORD(ListEntry, IRP, Tail.Overlay.ListEntry);
458 }
459
460 //
461 // release lock
462 //
463 KeReleaseSpinLock(&Context->Lock, OldLevel);
464
465 //
466 // done
467 //
468 return Irp;
469 }
470
471 NTSTATUS
472 HidClass_BuildIrp(
473 IN PDEVICE_OBJECT DeviceObject,
474 IN PIRP RequestIrp,
475 IN PHIDCLASS_FILEOP_CONTEXT Context,
476 IN ULONG DeviceIoControlCode,
477 IN ULONG BufferLength,
478 OUT PIRP *OutIrp,
479 OUT PHIDCLASS_IRP_CONTEXT *OutIrpContext)
480 {
481 PIRP Irp;
482 PIO_STACK_LOCATION IoStack;
483 PHIDCLASS_IRP_CONTEXT IrpContext;
484 PHIDCLASS_PDO_DEVICE_EXTENSION PDODeviceExtension;
485 PHIDP_COLLECTION_DESC CollectionDescription;
486 PHIDP_REPORT_IDS ReportDescription;
487
488 //
489 // get an irp from fresh list
490 //
491 Irp = HidClass_GetIrp(Context);
492 if (!Irp)
493 {
494 //
495 // build new irp
496 //
497 Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE);
498 if (!Irp)
499 {
500 //
501 // no memory
502 //
503 return STATUS_INSUFFICIENT_RESOURCES;
504 }
505 }
506 else
507 {
508 //
509 // re-use irp
510 //
511 IoReuseIrp(Irp, STATUS_SUCCESS);
512 }
513
514 //
515 // allocate completion context
516 //
517 IrpContext = (PHIDCLASS_IRP_CONTEXT)ExAllocatePool(NonPagedPool, sizeof(HIDCLASS_IRP_CONTEXT));
518 if (!IrpContext)
519 {
520 //
521 // no memory
522 //
523 IoFreeIrp(Irp);
524 return STATUS_INSUFFICIENT_RESOURCES;
525 }
526
527 //
528 // get device extension
529 //
530 PDODeviceExtension = (PHIDCLASS_PDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
531 ASSERT(PDODeviceExtension->Common.IsFDO == FALSE);
532
533 //
534 // init irp context
535 //
536 RtlZeroMemory(IrpContext, sizeof(HIDCLASS_IRP_CONTEXT));
537 IrpContext->OriginalIrp = RequestIrp;
538 IrpContext->FileOp = Context;
539
540 //
541 // get collection description
542 //
543 CollectionDescription = HidClassPDO_GetCollectionDescription(&IrpContext->FileOp->DeviceExtension->Common.DeviceDescription, IrpContext->FileOp->DeviceExtension->CollectionNumber);
544 ASSERT(CollectionDescription);
545
546 //
547 // get report description
548 //
549 ReportDescription = HidClassPDO_GetReportDescription(&IrpContext->FileOp->DeviceExtension->Common.DeviceDescription, IrpContext->FileOp->DeviceExtension->CollectionNumber);
550 ASSERT(ReportDescription);
551
552 //
553 // sanity check
554 //
555 ASSERT(CollectionDescription->InputLength >= ReportDescription->InputLength);
556
557 //
558 // store report length
559 //
560 IrpContext->InputReportBufferLength = ReportDescription->InputLength;
561
562 //
563 // allocate buffer
564 //
565 IrpContext->InputReportBuffer = ExAllocatePool(NonPagedPool, IrpContext->InputReportBufferLength);
566 if (!IrpContext->InputReportBuffer)
567 {
568 //
569 // no memory
570 //
571 IoFreeIrp(Irp);
572 ExFreePool(IrpContext);
573 return STATUS_INSUFFICIENT_RESOURCES;
574 }
575
576 //
577 // get stack location
578 //
579 IoStack = IoGetNextIrpStackLocation(Irp);
580
581 //
582 // init stack location
583 //
584 IoStack->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
585 IoStack->Parameters.DeviceIoControl.IoControlCode = DeviceIoControlCode;
586 IoStack->Parameters.DeviceIoControl.OutputBufferLength = IrpContext->InputReportBufferLength;
587 IoStack->Parameters.DeviceIoControl.InputBufferLength = 0;
588 IoStack->Parameters.DeviceIoControl.Type3InputBuffer = NULL;
589 Irp->UserBuffer = IrpContext->InputReportBuffer;
590 IoStack->DeviceObject = DeviceObject;
591
592 //
593 // store result
594 //
595 *OutIrp = Irp;
596 *OutIrpContext = IrpContext;
597
598 //
599 // done
600 //
601 return STATUS_SUCCESS;
602 }
603
604
605 NTSTATUS
606 NTAPI
607 HidClass_Read(
608 IN PDEVICE_OBJECT DeviceObject,
609 IN PIRP Irp)
610 {
611 PIO_STACK_LOCATION IoStack;
612 PHIDCLASS_FILEOP_CONTEXT Context;
613 KIRQL OldLevel;
614 NTSTATUS Status;
615 PIRP NewIrp;
616 PHIDCLASS_IRP_CONTEXT NewIrpContext;
617 PHIDCLASS_COMMON_DEVICE_EXTENSION CommonDeviceExtension;
618
619 //
620 // get current stack location
621 //
622 IoStack = IoGetCurrentIrpStackLocation(Irp);
623
624 //
625 // get device extension
626 //
627 CommonDeviceExtension = (PHIDCLASS_COMMON_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
628 ASSERT(CommonDeviceExtension->IsFDO == FALSE);
629
630 //
631 // sanity check
632 //
633 ASSERT(IoStack->FileObject);
634 ASSERT(IoStack->FileObject->FsContext);
635
636 //
637 // get context
638 //
639 Context = (PHIDCLASS_FILEOP_CONTEXT)IoStack->FileObject->FsContext;
640 ASSERT(Context);
641
642 //
643 // FIXME support polled devices
644 //
645 ASSERT(Context->DeviceExtension->Common.DriverExtension->DevicesArePolled == FALSE);
646
647 //
648 // build irp request
649 //
650 Status = HidClass_BuildIrp(DeviceObject, Irp, Context, IOCTL_HID_READ_REPORT, IoStack->Parameters.Read.Length, &NewIrp, &NewIrpContext);
651 if (!NT_SUCCESS(Status))
652 {
653 //
654 // failed
655 //
656 DPRINT1("HidClass_BuildIrp failed with %x\n", Status);
657 Irp->IoStatus.Status = Status;
658 IoCompleteRequest(Irp, IO_NO_INCREMENT);
659 return Status;
660 }
661
662 //
663 // acquire lock
664 //
665 KeAcquireSpinLock(&Context->Lock, &OldLevel);
666
667 //
668 // insert irp into pending list
669 //
670 InsertTailList(&Context->ReadPendingIrpListHead, &NewIrp->Tail.Overlay.ListEntry);
671
672 //
673 // set completion routine
674 //
675 IoSetCompletionRoutine(NewIrp, HidClass_ReadCompleteIrp, NewIrpContext, TRUE, TRUE, TRUE);
676
677 //
678 // make next location current
679 //
680 IoSetNextIrpStackLocation(NewIrp);
681
682 //
683 // release spin lock
684 //
685 KeReleaseSpinLock(&Context->Lock, OldLevel);
686
687 //
688 // mark irp pending
689 //
690 IoMarkIrpPending(Irp);
691
692 //
693 // lets dispatch the request
694 //
695 ASSERT(Context->DeviceExtension);
696 Status = Context->DeviceExtension->Common.DriverExtension->MajorFunction[IRP_MJ_INTERNAL_DEVICE_CONTROL](Context->DeviceExtension->FDODeviceObject, NewIrp);
697
698 //
699 // complete
700 //
701 return STATUS_PENDING;
702 }
703
704 NTSTATUS
705 NTAPI
706 HidClass_Write(
707 IN PDEVICE_OBJECT DeviceObject,
708 IN PIRP Irp)
709 {
710 UNIMPLEMENTED
711 ASSERT(FALSE);
712 Irp->IoStatus.Status = STATUS_NOT_IMPLEMENTED;
713 IoCompleteRequest(Irp, IO_NO_INCREMENT);
714 return STATUS_NOT_IMPLEMENTED;
715 }
716
717 NTSTATUS
718 NTAPI
719 HidClass_DeviceControl(
720 IN PDEVICE_OBJECT DeviceObject,
721 IN PIRP Irp)
722 {
723 PIO_STACK_LOCATION IoStack;
724 PHIDCLASS_COMMON_DEVICE_EXTENSION CommonDeviceExtension;
725 PHID_COLLECTION_INFORMATION CollectionInformation;
726 PHIDP_COLLECTION_DESC CollectionDescription;
727 PHIDCLASS_PDO_DEVICE_EXTENSION PDODeviceExtension;
728
729 //
730 // get device extension
731 //
732 CommonDeviceExtension = (PHIDCLASS_COMMON_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
733
734 //
735 // only PDO are supported
736 //
737 if (CommonDeviceExtension->IsFDO)
738 {
739 //
740 // invalid request
741 //
742 DPRINT1("[HIDCLASS] DeviceControl Irp for FDO arrived\n");
743 Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
744 IoCompleteRequest(Irp, IO_NO_INCREMENT);
745 return STATUS_INVALID_PARAMETER_1;
746 }
747
748 ASSERT(CommonDeviceExtension->IsFDO == FALSE);
749
750 //
751 // get pdo device extension
752 //
753 PDODeviceExtension = (PHIDCLASS_PDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
754
755 //
756 // get stack location
757 //
758 IoStack = IoGetCurrentIrpStackLocation(Irp);
759
760 switch(IoStack->Parameters.DeviceIoControl.IoControlCode)
761 {
762 case IOCTL_HID_GET_COLLECTION_INFORMATION:
763 {
764 //
765 // check if output buffer is big enough
766 //
767 if (IoStack->Parameters.DeviceIoControl.OutputBufferLength < sizeof(HID_COLLECTION_INFORMATION))
768 {
769 //
770 // invalid buffer size
771 //
772 Irp->IoStatus.Status = STATUS_INVALID_BUFFER_SIZE;
773 IoCompleteRequest(Irp, IO_NO_INCREMENT);
774 return STATUS_INVALID_BUFFER_SIZE;
775 }
776
777 //
778 // get output buffer
779 //
780 CollectionInformation = (PHID_COLLECTION_INFORMATION)Irp->AssociatedIrp.SystemBuffer;
781 ASSERT(CollectionInformation);
782
783 //
784 // get collection description
785 //
786 CollectionDescription = HidClassPDO_GetCollectionDescription(&CommonDeviceExtension->DeviceDescription, PDODeviceExtension->CollectionNumber);
787 ASSERT(CollectionDescription);
788
789 //
790 // init result buffer
791 //
792 CollectionInformation->DescriptorSize = CollectionDescription->PreparsedDataLength;
793 CollectionInformation->Polled = CommonDeviceExtension->DriverExtension->DevicesArePolled;
794 CollectionInformation->VendorID = CommonDeviceExtension->Attributes.VendorID;
795 CollectionInformation->ProductID = CommonDeviceExtension->Attributes.ProductID;
796 CollectionInformation->VersionNumber = CommonDeviceExtension->Attributes.VersionNumber;
797
798 //
799 // complete request
800 //
801 Irp->IoStatus.Information = sizeof(HID_COLLECTION_INFORMATION);
802 Irp->IoStatus.Status = STATUS_SUCCESS;
803 IoCompleteRequest(Irp, IO_NO_INCREMENT);
804 return STATUS_SUCCESS;
805 }
806 case IOCTL_HID_GET_COLLECTION_DESCRIPTOR:
807 {
808 //
809 // get collection description
810 //
811 CollectionDescription = HidClassPDO_GetCollectionDescription(&CommonDeviceExtension->DeviceDescription, PDODeviceExtension->CollectionNumber);
812 ASSERT(CollectionDescription);
813
814 //
815 // check if output buffer is big enough
816 //
817 if (IoStack->Parameters.DeviceIoControl.OutputBufferLength < CollectionDescription->PreparsedDataLength)
818 {
819 //
820 // invalid buffer size
821 //
822 Irp->IoStatus.Status = STATUS_INVALID_BUFFER_SIZE;
823 IoCompleteRequest(Irp, IO_NO_INCREMENT);
824 return STATUS_INVALID_BUFFER_SIZE;
825 }
826
827 //
828 // copy result
829 //
830 ASSERT(Irp->UserBuffer);
831 RtlCopyMemory(Irp->UserBuffer, CollectionDescription->PreparsedData, CollectionDescription->PreparsedDataLength);
832
833 //
834 // complete request
835 //
836 Irp->IoStatus.Information = CollectionDescription->PreparsedDataLength;
837 Irp->IoStatus.Status = STATUS_SUCCESS;
838 IoCompleteRequest(Irp, IO_NO_INCREMENT);
839 return STATUS_SUCCESS;
840 }
841 default:
842 {
843 DPRINT1("[HIDCLASS] DeviceControl IoControlCode 0x%x not implemented\n", IoStack->Parameters.DeviceIoControl.IoControlCode);
844 Irp->IoStatus.Status = STATUS_NOT_IMPLEMENTED;
845 IoCompleteRequest(Irp, IO_NO_INCREMENT);
846 return STATUS_NOT_IMPLEMENTED;
847 }
848 }
849 }
850
851 NTSTATUS
852 NTAPI
853 HidClass_InternalDeviceControl(
854 IN PDEVICE_OBJECT DeviceObject,
855 IN PIRP Irp)
856 {
857 UNIMPLEMENTED
858 ASSERT(FALSE);
859 Irp->IoStatus.Status = STATUS_NOT_IMPLEMENTED;
860 IoCompleteRequest(Irp, IO_NO_INCREMENT);
861 return STATUS_NOT_IMPLEMENTED;
862 }
863
864
865 NTSTATUS
866 NTAPI
867 HidClass_Power(
868 IN PDEVICE_OBJECT DeviceObject,
869 IN PIRP Irp)
870 {
871 UNIMPLEMENTED
872 return STATUS_NOT_IMPLEMENTED;
873 }
874
875 NTSTATUS
876 NTAPI
877 HidClass_PnP(
878 IN PDEVICE_OBJECT DeviceObject,
879 IN PIRP Irp)
880 {
881 PHIDCLASS_COMMON_DEVICE_EXTENSION CommonDeviceExtension;
882
883 //
884 // get common device extension
885 //
886 CommonDeviceExtension = (PHIDCLASS_COMMON_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
887
888 //
889 // check type of device object
890 //
891 if (CommonDeviceExtension->IsFDO)
892 {
893 //
894 // handle request
895 //
896 return HidClassFDO_PnP(DeviceObject, Irp);
897 }
898 else
899 {
900 //
901 // handle request
902 //
903 return HidClassPDO_PnP(DeviceObject, Irp);
904 }
905 }
906
907 NTSTATUS
908 NTAPI
909 HidClass_DispatchDefault(
910 IN PDEVICE_OBJECT DeviceObject,
911 IN PIRP Irp)
912 {
913 PHIDCLASS_COMMON_DEVICE_EXTENSION CommonDeviceExtension;
914
915 //
916 // get common device extension
917 //
918 CommonDeviceExtension = (PHIDCLASS_COMMON_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
919
920 //
921 // FIXME: support PDO
922 //
923 ASSERT(CommonDeviceExtension->IsFDO == TRUE);
924
925 //
926 // skip current irp stack location
927 //
928 IoSkipCurrentIrpStackLocation(Irp);
929
930 //
931 // dispatch to lower device object
932 //
933 return IoCallDriver(CommonDeviceExtension->HidDeviceExtension.NextDeviceObject, Irp);
934 }
935
936
937 NTSTATUS
938 NTAPI
939 HidClassDispatch(
940 IN PDEVICE_OBJECT DeviceObject,
941 IN PIRP Irp)
942 {
943 PIO_STACK_LOCATION IoStack;
944
945 //
946 // get current stack location
947 //
948 IoStack = IoGetCurrentIrpStackLocation(Irp);
949 DPRINT("[HIDCLASS] Dispatch Major %x Minor %x\n", IoStack->MajorFunction, IoStack->MinorFunction);
950
951 //
952 // dispatch request based on major function
953 //
954 switch(IoStack->MajorFunction)
955 {
956 case IRP_MJ_CREATE:
957 return HidClass_Create(DeviceObject, Irp);
958 case IRP_MJ_CLOSE:
959 return HidClass_Close(DeviceObject, Irp);
960 case IRP_MJ_READ:
961 return HidClass_Read(DeviceObject, Irp);
962 case IRP_MJ_WRITE:
963 return HidClass_Write(DeviceObject, Irp);
964 case IRP_MJ_DEVICE_CONTROL:
965 return HidClass_DeviceControl(DeviceObject, Irp);
966 case IRP_MJ_INTERNAL_DEVICE_CONTROL:
967 return HidClass_InternalDeviceControl(DeviceObject, Irp);
968 case IRP_MJ_POWER:
969 return HidClass_Power(DeviceObject, Irp);
970 case IRP_MJ_PNP:
971 return HidClass_PnP(DeviceObject, Irp);
972 default:
973 return HidClass_DispatchDefault(DeviceObject, Irp);
974 }
975 }
976
977 NTSTATUS
978 NTAPI
979 HidRegisterMinidriver(
980 IN PHID_MINIDRIVER_REGISTRATION MinidriverRegistration)
981 {
982 NTSTATUS Status;
983 PHIDCLASS_DRIVER_EXTENSION DriverExtension;
984
985 /* check if the version matches */
986 if (MinidriverRegistration->Revision > HID_REVISION)
987 {
988 /* revision mismatch */
989 ASSERT(FALSE);
990 return STATUS_REVISION_MISMATCH;
991 }
992
993 /* now allocate the driver object extension */
994 Status = IoAllocateDriverObjectExtension(MinidriverRegistration->DriverObject, (PVOID)ClientIdentificationAddress, sizeof(HIDCLASS_DRIVER_EXTENSION), (PVOID*)&DriverExtension);
995 if (!NT_SUCCESS(Status))
996 {
997 /* failed to allocate driver extension */
998 ASSERT(FALSE);
999 return Status;
1000 }
1001
1002 /* zero driver extension */
1003 RtlZeroMemory(DriverExtension, sizeof(HIDCLASS_DRIVER_EXTENSION));
1004
1005 /* init driver extension */
1006 DriverExtension->DriverObject = MinidriverRegistration->DriverObject;
1007 DriverExtension->DeviceExtensionSize = MinidriverRegistration->DeviceExtensionSize;
1008 DriverExtension->DevicesArePolled = MinidriverRegistration->DevicesArePolled;
1009 DriverExtension->AddDevice = MinidriverRegistration->DriverObject->DriverExtension->AddDevice;
1010 DriverExtension->DriverUnload = MinidriverRegistration->DriverObject->DriverUnload;
1011
1012 /* copy driver dispatch routines */
1013 RtlCopyMemory(DriverExtension->MajorFunction, MinidriverRegistration->DriverObject->MajorFunction, sizeof(PDRIVER_DISPATCH) * (IRP_MJ_MAXIMUM_FUNCTION+1));
1014
1015 /* initialize lock */
1016 KeInitializeSpinLock(&DriverExtension->Lock);
1017
1018 /* now replace dispatch routines */
1019 DriverExtension->DriverObject->DriverExtension->AddDevice = HidClassAddDevice;
1020 DriverExtension->DriverObject->DriverUnload = HidClassDriverUnload;
1021 DriverExtension->DriverObject->MajorFunction[IRP_MJ_CREATE] = HidClassDispatch;
1022 DriverExtension->DriverObject->MajorFunction[IRP_MJ_CLOSE] = HidClassDispatch;
1023 DriverExtension->DriverObject->MajorFunction[IRP_MJ_READ] = HidClassDispatch;
1024 DriverExtension->DriverObject->MajorFunction[IRP_MJ_WRITE] = HidClassDispatch;
1025 DriverExtension->DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = HidClassDispatch;
1026 DriverExtension->DriverObject->MajorFunction[IRP_MJ_INTERNAL_DEVICE_CONTROL] = HidClassDispatch;
1027 DriverExtension->DriverObject->MajorFunction[IRP_MJ_POWER] = HidClassDispatch;
1028 DriverExtension->DriverObject->MajorFunction[IRP_MJ_PNP] = HidClassDispatch;
1029
1030 /* done */
1031 return STATUS_SUCCESS;
1032 }