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