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