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