[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_DEVICE_DESC DeviceDescription;
308 ULONG CollectionIndex;
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 = HidClass_GetSystemAddress(IrpContext->OriginalIrp->MdlAddress);
332 if (Address)
333 {
334 //
335 // reports may have a report id prepended
336 //
337 CollectionIndex = IrpContext->FileOp->DeviceExtension->CollectionIndex;
338 DeviceDescription = &IrpContext->FileOp->DeviceExtension->Common.DeviceDescription;
339
340 //
341 // calculate offset
342 //
343 ASSERT(DeviceDescription->CollectionDesc[CollectionIndex].InputLength >= DeviceDescription->ReportIDs[CollectionIndex].InputLength);
344 Offset = DeviceDescription->CollectionDesc[CollectionIndex].InputLength - DeviceDescription->ReportIDs[CollectionIndex].InputLength;
345
346 //
347 // copy result
348 //
349 RtlCopyMemory(&Address[Offset], IrpContext->InputReportBuffer, IrpContext->InputReportBufferLength);
350 }
351 }
352
353 //
354 // copy result status
355 //
356 IrpContext->OriginalIrp->IoStatus.Status = Irp->IoStatus.Status;
357 Irp->IoStatus.Information = Irp->IoStatus.Information;
358
359 //
360 // free input report buffer
361 //
362 ExFreePool(IrpContext->InputReportBuffer);
363
364 //
365 // remove us from pending list
366 //
367 KeAcquireSpinLock(&IrpContext->FileOp->Lock, &OldLevel);
368
369 //
370 // remove from pending list
371 //
372 RemoveEntryList(&Irp->Tail.Overlay.ListEntry);
373
374 //
375 // insert into completed list
376 //
377 InsertTailList(&IrpContext->FileOp->IrpCompletedListHead, &Irp->Tail.Overlay.ListEntry);
378
379 //
380 // release lock
381 //
382 KeReleaseSpinLock(&IrpContext->FileOp->Lock, OldLevel);
383
384 //
385 // complete original request
386 //
387 IoCompleteRequest(IrpContext->OriginalIrp, IO_NO_INCREMENT);
388
389 //
390 // free irp context
391 //
392 ExFreePool(IrpContext);
393
394 //
395 // done
396 //
397 return STATUS_MORE_PROCESSING_REQUIRED;
398 }
399
400 PIRP
401 HidClass_GetIrp(
402 IN PHIDCLASS_FILEOP_CONTEXT Context)
403 {
404 KIRQL OldLevel;
405 PIRP Irp = NULL;
406 PLIST_ENTRY ListEntry;
407
408 //
409 // acquire lock
410 //
411 KeAcquireSpinLock(&Context->Lock, &OldLevel);
412
413 //
414 // is list empty?
415 //
416 if (!IsListEmpty(&Context->IrpCompletedListHead))
417 {
418 //
419 // grab first entry
420 //
421 ListEntry = RemoveHeadList(&Context->IrpCompletedListHead);
422
423 //
424 // get irp
425 //
426 Irp = (PIRP)CONTAINING_RECORD(ListEntry, IRP, Tail.Overlay.ListEntry);
427 }
428
429 //
430 // release lock
431 //
432 KeReleaseSpinLock(&Context->Lock, OldLevel);
433
434 //
435 // done
436 //
437 return Irp;
438 }
439
440 NTSTATUS
441 HidClass_BuildIrp(
442 IN PDEVICE_OBJECT DeviceObject,
443 IN PIRP RequestIrp,
444 IN PHIDCLASS_FILEOP_CONTEXT Context,
445 IN ULONG DeviceIoControlCode,
446 IN ULONG BufferLength,
447 OUT PIRP *OutIrp,
448 OUT PHIDCLASS_IRP_CONTEXT *OutIrpContext)
449 {
450 PIRP Irp;
451 PIO_STACK_LOCATION IoStack;
452 PHIDCLASS_IRP_CONTEXT IrpContext;
453 PHIDCLASS_PDO_DEVICE_EXTENSION PDODeviceExtension;
454
455 //
456 // get an irp from fresh list
457 //
458 Irp = HidClass_GetIrp(Context);
459 if (!Irp)
460 {
461 //
462 // build new irp
463 //
464 Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE);
465 if (!Irp)
466 {
467 //
468 // no memory
469 //
470 return STATUS_INSUFFICIENT_RESOURCES;
471 }
472 }
473 else
474 {
475 //
476 // re-use irp
477 //
478 IoReuseIrp(Irp, STATUS_SUCCESS);
479 }
480
481 //
482 // allocate completion context
483 //
484 IrpContext = (PHIDCLASS_IRP_CONTEXT)ExAllocatePool(NonPagedPool, sizeof(HIDCLASS_IRP_CONTEXT));
485 if (!IrpContext)
486 {
487 //
488 // no memory
489 //
490 IoFreeIrp(Irp);
491 return STATUS_INSUFFICIENT_RESOURCES;
492 }
493
494 //
495 // get device extension
496 //
497 PDODeviceExtension = (PHIDCLASS_PDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
498 ASSERT(PDODeviceExtension->Common.IsFDO == FALSE);
499
500 //
501 // sanity checks
502 //
503 ASSERT(PDODeviceExtension->CollectionIndex < PDODeviceExtension->Common.DeviceDescription.CollectionDescLength);
504 ASSERT(PDODeviceExtension->CollectionIndex < PDODeviceExtension->Common.DeviceDescription.ReportIDsLength);
505 ASSERT(PDODeviceExtension->Common.DeviceDescription.ReportIDs[PDODeviceExtension->CollectionIndex].InputLength > 0);
506 ASSERT(PDODeviceExtension->Common.DeviceDescription.CollectionDesc[PDODeviceExtension->CollectionIndex].InputLength == BufferLength);
507
508 //
509 // init irp context
510 //
511 RtlZeroMemory(IrpContext, sizeof(HIDCLASS_IRP_CONTEXT));
512 IrpContext->InputReportBufferLength = PDODeviceExtension->Common.DeviceDescription.ReportIDs[PDODeviceExtension->CollectionIndex].InputLength;
513 IrpContext->OriginalIrp = RequestIrp;
514 IrpContext->FileOp = Context;
515
516 //
517 // allocate buffer
518 //
519 IrpContext->InputReportBuffer = ExAllocatePool(NonPagedPool, IrpContext->InputReportBufferLength);
520 if (!IrpContext->InputReportBuffer)
521 {
522 //
523 // no memory
524 //
525 IoFreeIrp(Irp);
526 ExFreePool(IrpContext);
527 return STATUS_INSUFFICIENT_RESOURCES;
528 }
529
530 //
531 // get stack location
532 //
533 IoStack = IoGetNextIrpStackLocation(Irp);
534
535 //
536 // init stack location
537 //
538 IoStack->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
539 IoStack->Parameters.DeviceIoControl.IoControlCode = DeviceIoControlCode;
540 IoStack->Parameters.DeviceIoControl.OutputBufferLength = IrpContext->InputReportBufferLength;
541 IoStack->Parameters.DeviceIoControl.InputBufferLength = 0;
542 IoStack->Parameters.DeviceIoControl.Type3InputBuffer = NULL;
543 Irp->UserBuffer = IrpContext->InputReportBuffer;
544 IoStack->DeviceObject = DeviceObject;
545
546 //
547 // store result
548 //
549 *OutIrp = Irp;
550 *OutIrpContext = IrpContext;
551
552 //
553 // done
554 //
555 return STATUS_SUCCESS;
556 }
557
558
559 NTSTATUS
560 NTAPI
561 HidClass_Read(
562 IN PDEVICE_OBJECT DeviceObject,
563 IN PIRP Irp)
564 {
565 PIO_STACK_LOCATION IoStack;
566 PHIDCLASS_FILEOP_CONTEXT Context;
567 KIRQL OldLevel;
568 NTSTATUS Status;
569 PIRP NewIrp;
570 PHIDCLASS_IRP_CONTEXT NewIrpContext;
571 PHIDCLASS_COMMON_DEVICE_EXTENSION CommonDeviceExtension;
572
573 //
574 // get current stack location
575 //
576 IoStack = IoGetCurrentIrpStackLocation(Irp);
577
578 //
579 // get device extension
580 //
581 CommonDeviceExtension = (PHIDCLASS_COMMON_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
582 ASSERT(CommonDeviceExtension->IsFDO == FALSE);
583
584 //
585 // sanity check
586 //
587 ASSERT(IoStack->FileObject);
588 ASSERT(IoStack->FileObject->FsContext);
589
590 //
591 // get context
592 //
593 Context = (PHIDCLASS_FILEOP_CONTEXT)IoStack->FileObject->FsContext;
594 ASSERT(Context);
595
596 //
597 // FIXME support polled devices
598 //
599 ASSERT(Context->DeviceExtension->Common.DriverExtension->DevicesArePolled == FALSE);
600
601 //
602 // build irp request
603 //
604 Status = HidClass_BuildIrp(DeviceObject, Irp, Context, IOCTL_HID_READ_REPORT, IoStack->Parameters.Read.Length, &NewIrp, &NewIrpContext);
605 if (!NT_SUCCESS(Status))
606 {
607 //
608 // failed
609 //
610 DPRINT1("HidClass_BuildIrp failed with %x\n", Status);
611 Irp->IoStatus.Status = Status;
612 IoCompleteRequest(Irp, IO_NO_INCREMENT);
613 return Status;
614 }
615
616 //
617 // acquire lock
618 //
619 KeAcquireSpinLock(&Context->Lock, &OldLevel);
620
621 //
622 // insert irp into pending list
623 //
624 InsertTailList(&Context->ReadPendingIrpListHead, &NewIrp->Tail.Overlay.ListEntry);
625
626 //
627 // set completion routine
628 //
629 IoSetCompletionRoutine(NewIrp, HidClass_ReadCompleteIrp, NewIrpContext, TRUE, TRUE, TRUE);
630
631 //
632 // make next location current
633 //
634 IoSetNextIrpStackLocation(NewIrp);
635
636 //
637 // release spin lock
638 //
639 KeReleaseSpinLock(&Context->Lock, OldLevel);
640
641 //
642 // mark irp pending
643 //
644 IoMarkIrpPending(Irp);
645
646 //
647 // lets dispatch the request
648 //
649 ASSERT(Context->DeviceExtension);
650 Status = Context->DeviceExtension->Common.DriverExtension->MajorFunction[IRP_MJ_INTERNAL_DEVICE_CONTROL](Context->DeviceExtension->FDODeviceObject, NewIrp);
651
652 //
653 // complete
654 //
655 return STATUS_PENDING;
656 }
657
658 NTSTATUS
659 NTAPI
660 HidClass_Write(
661 IN PDEVICE_OBJECT DeviceObject,
662 IN PIRP Irp)
663 {
664 UNIMPLEMENTED
665 ASSERT(FALSE);
666 Irp->IoStatus.Status = STATUS_NOT_IMPLEMENTED;
667 IoCompleteRequest(Irp, IO_NO_INCREMENT);
668 return STATUS_NOT_IMPLEMENTED;
669 }
670
671 NTSTATUS
672 NTAPI
673 HidClass_DeviceControl(
674 IN PDEVICE_OBJECT DeviceObject,
675 IN PIRP Irp)
676 {
677 PIO_STACK_LOCATION IoStack;
678 PHIDCLASS_COMMON_DEVICE_EXTENSION CommonDeviceExtension;
679 PHID_COLLECTION_INFORMATION CollectionInformation;
680
681 //
682 // get device extension
683 //
684 CommonDeviceExtension = (PHIDCLASS_COMMON_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
685
686 //
687 // get stack location
688 //
689 IoStack = IoGetCurrentIrpStackLocation(Irp);
690
691 switch(IoStack->Parameters.DeviceIoControl.IoControlCode)
692 {
693 case IOCTL_HID_GET_COLLECTION_INFORMATION:
694 {
695 //
696 // check if output buffer is big enough
697 //
698 if (IoStack->Parameters.DeviceIoControl.OutputBufferLength < sizeof(HID_COLLECTION_INFORMATION))
699 {
700 //
701 // invalid buffer size
702 //
703 Irp->IoStatus.Status = STATUS_INVALID_BUFFER_SIZE;
704 IoCompleteRequest(Irp, IO_NO_INCREMENT);
705 return STATUS_INVALID_BUFFER_SIZE;
706 }
707
708 //
709 // get output buffer
710 //
711 CollectionInformation = (PHID_COLLECTION_INFORMATION)Irp->AssociatedIrp.SystemBuffer;
712 ASSERT(CollectionInformation);
713
714 //
715 // init result buffer
716 //
717 CollectionInformation->DescriptorSize = CommonDeviceExtension->DeviceDescription.CollectionDesc[0].PreparsedDataLength; //FIXME which collection is to be retrieved for composite devices / multi collection devices?
718 CollectionInformation->Polled = CommonDeviceExtension->DriverExtension->DevicesArePolled;
719 CollectionInformation->VendorID = CommonDeviceExtension->Attributes.VendorID;
720 CollectionInformation->ProductID = CommonDeviceExtension->Attributes.ProductID;
721 CollectionInformation->VersionNumber = CommonDeviceExtension->Attributes.VersionNumber;
722
723 //
724 // complete request
725 //
726 Irp->IoStatus.Information = sizeof(HID_COLLECTION_INFORMATION);
727 Irp->IoStatus.Status = STATUS_SUCCESS;
728 IoCompleteRequest(Irp, IO_NO_INCREMENT);
729 return STATUS_SUCCESS;
730 }
731 case IOCTL_HID_GET_COLLECTION_DESCRIPTOR:
732 {
733 //
734 // FIXME: which collection to use for composite / multi collection devices...
735 //
736
737 //
738 // check if output buffer is big enough
739 //
740 if (IoStack->Parameters.DeviceIoControl.OutputBufferLength < CommonDeviceExtension->DeviceDescription.CollectionDesc[0].PreparsedDataLength)
741 {
742 //
743 // invalid buffer size
744 //
745 Irp->IoStatus.Status = STATUS_INVALID_BUFFER_SIZE;
746 IoCompleteRequest(Irp, IO_NO_INCREMENT);
747 return STATUS_INVALID_BUFFER_SIZE;
748 }
749
750 //
751 // copy result
752 //
753 ASSERT(Irp->UserBuffer);
754 RtlCopyMemory(Irp->UserBuffer, CommonDeviceExtension->DeviceDescription.CollectionDesc[0].PreparsedData, CommonDeviceExtension->DeviceDescription.CollectionDesc[0].PreparsedDataLength);
755
756 //
757 // complete request
758 //
759 Irp->IoStatus.Information = CommonDeviceExtension->DeviceDescription.CollectionDesc[0].PreparsedDataLength;
760 Irp->IoStatus.Status = STATUS_SUCCESS;
761 IoCompleteRequest(Irp, IO_NO_INCREMENT);
762 return STATUS_SUCCESS;
763 }
764 default:
765 {
766 DPRINT1("[HIDCLASS] DeviceControl IoControlCode 0x%x not implemented\n", IoStack->Parameters.DeviceIoControl.IoControlCode);
767 Irp->IoStatus.Status = STATUS_NOT_IMPLEMENTED;
768 IoCompleteRequest(Irp, IO_NO_INCREMENT);
769 return STATUS_NOT_IMPLEMENTED;
770 }
771 }
772 }
773
774 NTSTATUS
775 NTAPI
776 HidClass_InternalDeviceControl(
777 IN PDEVICE_OBJECT DeviceObject,
778 IN PIRP Irp)
779 {
780 UNIMPLEMENTED
781 ASSERT(FALSE);
782 Irp->IoStatus.Status = STATUS_NOT_IMPLEMENTED;
783 IoCompleteRequest(Irp, IO_NO_INCREMENT);
784 return STATUS_NOT_IMPLEMENTED;
785 }
786
787
788 NTSTATUS
789 NTAPI
790 HidClass_Power(
791 IN PDEVICE_OBJECT DeviceObject,
792 IN PIRP Irp)
793 {
794 UNIMPLEMENTED
795 ASSERT(FALSE);
796 return STATUS_NOT_IMPLEMENTED;
797 }
798
799 NTSTATUS
800 NTAPI
801 HidClass_PnP(
802 IN PDEVICE_OBJECT DeviceObject,
803 IN PIRP Irp)
804 {
805 PHIDCLASS_COMMON_DEVICE_EXTENSION CommonDeviceExtension;
806
807 //
808 // get common device extension
809 //
810 CommonDeviceExtension = (PHIDCLASS_COMMON_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
811
812 //
813 // check type of device object
814 //
815 if (CommonDeviceExtension->IsFDO)
816 {
817 //
818 // handle request
819 //
820 return HidClassFDO_PnP(DeviceObject, Irp);
821 }
822 else
823 {
824 //
825 // handle request
826 //
827 return HidClassPDO_PnP(DeviceObject, Irp);
828 }
829 }
830
831 NTSTATUS
832 NTAPI
833 HidClass_DispatchDefault(
834 IN PDEVICE_OBJECT DeviceObject,
835 IN PIRP Irp)
836 {
837 PHIDCLASS_COMMON_DEVICE_EXTENSION CommonDeviceExtension;
838
839 //
840 // get common device extension
841 //
842 CommonDeviceExtension = (PHIDCLASS_COMMON_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
843
844 //
845 // FIXME: support PDO
846 //
847 ASSERT(CommonDeviceExtension->IsFDO == TRUE);
848
849 //
850 // skip current irp stack location
851 //
852 IoSkipCurrentIrpStackLocation(Irp);
853
854 //
855 // dispatch to lower device object
856 //
857 return IoCallDriver(CommonDeviceExtension->HidDeviceExtension.NextDeviceObject, Irp);
858 }
859
860
861 NTSTATUS
862 NTAPI
863 HidClassDispatch(
864 IN PDEVICE_OBJECT DeviceObject,
865 IN PIRP Irp)
866 {
867 PIO_STACK_LOCATION IoStack;
868
869 //
870 // get current stack location
871 //
872 IoStack = IoGetCurrentIrpStackLocation(Irp);
873 DPRINT("[HIDCLASS] Dispatch Major %x Minor %x\n", IoStack->MajorFunction, IoStack->MinorFunction);
874
875 //
876 // dispatch request based on major function
877 //
878 switch(IoStack->MajorFunction)
879 {
880 case IRP_MJ_CREATE:
881 return HidClass_Create(DeviceObject, Irp);
882 case IRP_MJ_CLOSE:
883 return HidClass_Close(DeviceObject, Irp);
884 case IRP_MJ_READ:
885 return HidClass_Read(DeviceObject, Irp);
886 case IRP_MJ_WRITE:
887 return HidClass_Write(DeviceObject, Irp);
888 case IRP_MJ_DEVICE_CONTROL:
889 return HidClass_DeviceControl(DeviceObject, Irp);
890 case IRP_MJ_INTERNAL_DEVICE_CONTROL:
891 return HidClass_InternalDeviceControl(DeviceObject, Irp);
892 case IRP_MJ_POWER:
893 return HidClass_Power(DeviceObject, Irp);
894 case IRP_MJ_PNP:
895 return HidClass_PnP(DeviceObject, Irp);
896 default:
897 return HidClass_DispatchDefault(DeviceObject, Irp);
898 }
899 }
900
901 NTSTATUS
902 NTAPI
903 HidRegisterMinidriver(
904 IN PHID_MINIDRIVER_REGISTRATION MinidriverRegistration)
905 {
906 NTSTATUS Status;
907 PHIDCLASS_DRIVER_EXTENSION DriverExtension;
908
909 /* check if the version matches */
910 if (MinidriverRegistration->Revision > HID_REVISION)
911 {
912 /* revision mismatch */
913 ASSERT(FALSE);
914 return STATUS_REVISION_MISMATCH;
915 }
916
917 /* now allocate the driver object extension */
918 Status = IoAllocateDriverObjectExtension(MinidriverRegistration->DriverObject, (PVOID)ClientIdentificationAddress, sizeof(HIDCLASS_DRIVER_EXTENSION), (PVOID*)&DriverExtension);
919 if (!NT_SUCCESS(Status))
920 {
921 /* failed to allocate driver extension */
922 ASSERT(FALSE);
923 return Status;
924 }
925
926 /* zero driver extension */
927 RtlZeroMemory(DriverExtension, sizeof(HIDCLASS_DRIVER_EXTENSION));
928
929 /* init driver extension */
930 DriverExtension->DriverObject = MinidriverRegistration->DriverObject;
931 DriverExtension->DeviceExtensionSize = MinidriverRegistration->DeviceExtensionSize;
932 DriverExtension->DevicesArePolled = MinidriverRegistration->DevicesArePolled;
933 DriverExtension->AddDevice = MinidriverRegistration->DriverObject->DriverExtension->AddDevice;
934 DriverExtension->DriverUnload = MinidriverRegistration->DriverObject->DriverUnload;
935
936 /* copy driver dispatch routines */
937 RtlCopyMemory(DriverExtension->MajorFunction, MinidriverRegistration->DriverObject->MajorFunction, sizeof(PDRIVER_DISPATCH) * (IRP_MJ_MAXIMUM_FUNCTION+1));
938
939 /* initialize lock */
940 KeInitializeSpinLock(&DriverExtension->Lock);
941
942 /* now replace dispatch routines */
943 DriverExtension->DriverObject->DriverExtension->AddDevice = HidClassAddDevice;
944 DriverExtension->DriverObject->DriverUnload = HidClassDriverUnload;
945 DriverExtension->DriverObject->MajorFunction[IRP_MJ_CREATE] = HidClassDispatch;
946 DriverExtension->DriverObject->MajorFunction[IRP_MJ_CLOSE] = HidClassDispatch;
947 DriverExtension->DriverObject->MajorFunction[IRP_MJ_READ] = HidClassDispatch;
948 DriverExtension->DriverObject->MajorFunction[IRP_MJ_WRITE] = HidClassDispatch;
949 DriverExtension->DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = HidClassDispatch;
950 DriverExtension->DriverObject->MajorFunction[IRP_MJ_INTERNAL_DEVICE_CONTROL] = HidClassDispatch;
951 DriverExtension->DriverObject->MajorFunction[IRP_MJ_POWER] = HidClassDispatch;
952 DriverExtension->DriverObject->MajorFunction[IRP_MJ_PNP] = HidClassDispatch;
953
954 /* done */
955 return STATUS_SUCCESS;
956 }