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