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