[HIDCLASS] Implement IRP_MJ_WRITE
[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 PIO_STACK_LOCATION IoStack;
805 PHIDCLASS_COMMON_DEVICE_EXTENSION CommonDeviceExtension;
806 PIRP SubIrp;
807 KEVENT Event;
808 IO_STATUS_BLOCK IoStatusBlock;
809 HID_XFER_PACKET XferPacket;
810 NTSTATUS Status;
811 ULONG Length;
812
813 IoStack = IoGetCurrentIrpStackLocation(Irp);
814 Length = IoStack->Parameters.Write.Length;
815 if (Length < 1)
816 {
817 Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
818 IoCompleteRequest(Irp, IO_NO_INCREMENT);
819 return STATUS_INVALID_PARAMETER;
820 }
821
822 RtlZeroMemory(&XferPacket, sizeof(XferPacket));
823 XferPacket.reportBufferLen = Length;
824 XferPacket.reportBuffer = Irp->UserBuffer;
825 XferPacket.reportId = XferPacket.reportBuffer[0];
826
827 CommonDeviceExtension = DeviceObject->DeviceExtension;
828 SubIrp = IoBuildDeviceIoControlRequest(
829 IOCTL_HID_WRITE_REPORT,
830 CommonDeviceExtension->HidDeviceExtension.NextDeviceObject,
831 NULL, 0,
832 NULL, 0,
833 TRUE,
834 &Event,
835 &IoStatusBlock);
836 if (!SubIrp)
837 {
838 Irp->IoStatus.Status = STATUS_NO_MEMORY;
839 IoCompleteRequest(Irp, IO_NO_INCREMENT);
840 return STATUS_NOT_IMPLEMENTED;
841 }
842 SubIrp->UserBuffer = &XferPacket;
843 KeInitializeEvent(&Event, SynchronizationEvent, FALSE);
844 Status = IoCallDriver(CommonDeviceExtension->HidDeviceExtension.NextDeviceObject, SubIrp);
845 if (Status == STATUS_PENDING)
846 {
847 KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
848 Status = IoStatusBlock.Status;
849 }
850 Irp->IoStatus.Status = Status;
851 IoCompleteRequest(Irp, IO_NO_INCREMENT);
852 return Status;
853 }
854
855 NTSTATUS
856 NTAPI
857 HidClass_DeviceControl(
858 IN PDEVICE_OBJECT DeviceObject,
859 IN PIRP Irp)
860 {
861 PIO_STACK_LOCATION IoStack;
862 PHIDCLASS_COMMON_DEVICE_EXTENSION CommonDeviceExtension;
863 PHID_COLLECTION_INFORMATION CollectionInformation;
864 PHIDP_COLLECTION_DESC CollectionDescription;
865 PHIDCLASS_PDO_DEVICE_EXTENSION PDODeviceExtension;
866
867 //
868 // get device extension
869 //
870 CommonDeviceExtension = DeviceObject->DeviceExtension;
871
872 //
873 // only PDO are supported
874 //
875 if (CommonDeviceExtension->IsFDO)
876 {
877 //
878 // invalid request
879 //
880 DPRINT1("[HIDCLASS] DeviceControl Irp for FDO arrived\n");
881 Irp->IoStatus.Status = STATUS_INVALID_PARAMETER_1;
882 IoCompleteRequest(Irp, IO_NO_INCREMENT);
883 return STATUS_INVALID_PARAMETER_1;
884 }
885
886 ASSERT(CommonDeviceExtension->IsFDO == FALSE);
887
888 //
889 // get pdo device extension
890 //
891 PDODeviceExtension = DeviceObject->DeviceExtension;
892
893 //
894 // get stack location
895 //
896 IoStack = IoGetCurrentIrpStackLocation(Irp);
897
898 switch (IoStack->Parameters.DeviceIoControl.IoControlCode)
899 {
900 case IOCTL_HID_GET_COLLECTION_INFORMATION:
901 {
902 //
903 // check if output buffer is big enough
904 //
905 if (IoStack->Parameters.DeviceIoControl.OutputBufferLength < sizeof(HID_COLLECTION_INFORMATION))
906 {
907 //
908 // invalid buffer size
909 //
910 Irp->IoStatus.Status = STATUS_INVALID_BUFFER_SIZE;
911 IoCompleteRequest(Irp, IO_NO_INCREMENT);
912 return STATUS_INVALID_BUFFER_SIZE;
913 }
914
915 //
916 // get output buffer
917 //
918 CollectionInformation = Irp->AssociatedIrp.SystemBuffer;
919 ASSERT(CollectionInformation);
920
921 //
922 // get collection description
923 //
924 CollectionDescription = HidClassPDO_GetCollectionDescription(&CommonDeviceExtension->DeviceDescription,
925 PDODeviceExtension->CollectionNumber);
926 ASSERT(CollectionDescription);
927
928 //
929 // init result buffer
930 //
931 CollectionInformation->DescriptorSize = CollectionDescription->PreparsedDataLength;
932 CollectionInformation->Polled = CommonDeviceExtension->DriverExtension->DevicesArePolled;
933 CollectionInformation->VendorID = CommonDeviceExtension->Attributes.VendorID;
934 CollectionInformation->ProductID = CommonDeviceExtension->Attributes.ProductID;
935 CollectionInformation->VersionNumber = CommonDeviceExtension->Attributes.VersionNumber;
936
937 //
938 // complete request
939 //
940 Irp->IoStatus.Information = sizeof(HID_COLLECTION_INFORMATION);
941 Irp->IoStatus.Status = STATUS_SUCCESS;
942 IoCompleteRequest(Irp, IO_NO_INCREMENT);
943 return STATUS_SUCCESS;
944 }
945 case IOCTL_HID_GET_COLLECTION_DESCRIPTOR:
946 {
947 //
948 // get collection description
949 //
950 CollectionDescription = HidClassPDO_GetCollectionDescription(&CommonDeviceExtension->DeviceDescription,
951 PDODeviceExtension->CollectionNumber);
952 ASSERT(CollectionDescription);
953
954 //
955 // check if output buffer is big enough
956 //
957 if (IoStack->Parameters.DeviceIoControl.OutputBufferLength < CollectionDescription->PreparsedDataLength)
958 {
959 //
960 // invalid buffer size
961 //
962 Irp->IoStatus.Status = STATUS_INVALID_BUFFER_SIZE;
963 IoCompleteRequest(Irp, IO_NO_INCREMENT);
964 return STATUS_INVALID_BUFFER_SIZE;
965 }
966
967 //
968 // copy result
969 //
970 ASSERT(Irp->UserBuffer);
971 RtlCopyMemory(Irp->UserBuffer, CollectionDescription->PreparsedData, CollectionDescription->PreparsedDataLength);
972
973 //
974 // complete request
975 //
976 Irp->IoStatus.Information = CollectionDescription->PreparsedDataLength;
977 Irp->IoStatus.Status = STATUS_SUCCESS;
978 IoCompleteRequest(Irp, IO_NO_INCREMENT);
979 return STATUS_SUCCESS;
980 }
981 case IOCTL_HID_GET_FEATURE:
982 {
983 PIRP SubIrp;
984 KEVENT Event;
985 IO_STATUS_BLOCK IoStatusBlock;
986 HID_XFER_PACKET XferPacket;
987 NTSTATUS Status;
988 PHIDP_REPORT_IDS ReportDescription;
989
990 if (IoStack->Parameters.DeviceIoControl.InputBufferLength < 1)
991 {
992 Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
993 IoCompleteRequest(Irp, IO_NO_INCREMENT);
994 return STATUS_INVALID_PARAMETER;
995 }
996 ReportDescription = HidClassPDO_GetReportDescriptionByReportID(&PDODeviceExtension->Common.DeviceDescription, ((PUCHAR)Irp->AssociatedIrp.SystemBuffer)[0]);
997 if (!ReportDescription || IoStack->Parameters.DeviceIoControl.OutputBufferLength < ReportDescription->FeatureLength)
998 {
999 Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
1000 IoCompleteRequest(Irp, IO_NO_INCREMENT);
1001 return STATUS_INVALID_PARAMETER;
1002 }
1003
1004 RtlZeroMemory(&XferPacket, sizeof(XferPacket));
1005 XferPacket.reportBufferLen = ReportDescription->FeatureLength;
1006 XferPacket.reportBuffer = MmGetSystemAddressForMdlSafe(Irp->MdlAddress, NormalPagePriority);
1007 XferPacket.reportId = ((PUCHAR)Irp->AssociatedIrp.SystemBuffer)[0];
1008 if (!XferPacket.reportBuffer)
1009 {
1010 Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
1011 IoCompleteRequest(Irp, IO_NO_INCREMENT);
1012 return STATUS_INSUFFICIENT_RESOURCES;
1013 }
1014
1015 SubIrp = IoBuildDeviceIoControlRequest(
1016 IOCTL_HID_GET_FEATURE,
1017 CommonDeviceExtension->HidDeviceExtension.NextDeviceObject,
1018 NULL, 0,
1019 NULL, 0,
1020 TRUE,
1021 &Event,
1022 &IoStatusBlock);
1023 if (!SubIrp)
1024 {
1025 Irp->IoStatus.Status = STATUS_NO_MEMORY;
1026 IoCompleteRequest(Irp, IO_NO_INCREMENT);
1027 return STATUS_NOT_IMPLEMENTED;
1028 }
1029 SubIrp->UserBuffer = &XferPacket;
1030 KeInitializeEvent(&Event, SynchronizationEvent, FALSE);
1031 Status = IoCallDriver(CommonDeviceExtension->HidDeviceExtension.NextDeviceObject, SubIrp);
1032 if (Status == STATUS_PENDING)
1033 {
1034 KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
1035 Status = IoStatusBlock.Status;
1036 }
1037 Irp->IoStatus.Status = Status;
1038 IoCompleteRequest(Irp, IO_NO_INCREMENT);
1039 return Status;
1040 }
1041 case IOCTL_HID_SET_FEATURE:
1042 {
1043 PIRP SubIrp;
1044 KEVENT Event;
1045 IO_STATUS_BLOCK IoStatusBlock;
1046 HID_XFER_PACKET XferPacket;
1047 NTSTATUS Status;
1048 PHIDP_REPORT_IDS ReportDescription;
1049
1050 if (IoStack->Parameters.DeviceIoControl.InputBufferLength < 1)
1051 {
1052 Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
1053 IoCompleteRequest(Irp, IO_NO_INCREMENT);
1054 return STATUS_INVALID_PARAMETER;
1055 }
1056 ReportDescription = HidClassPDO_GetReportDescriptionByReportID(&PDODeviceExtension->Common.DeviceDescription, ((PUCHAR)Irp->AssociatedIrp.SystemBuffer)[0]);
1057 if (!ReportDescription || IoStack->Parameters.DeviceIoControl.InputBufferLength < ReportDescription->FeatureLength)
1058 {
1059 Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
1060 IoCompleteRequest(Irp, IO_NO_INCREMENT);
1061 return STATUS_INVALID_PARAMETER;
1062 }
1063
1064 RtlZeroMemory(&XferPacket, sizeof(XferPacket));
1065 XferPacket.reportBufferLen = ReportDescription->FeatureLength;
1066 XferPacket.reportBuffer = Irp->AssociatedIrp.SystemBuffer;
1067 XferPacket.reportId = XferPacket.reportBuffer[0];
1068
1069 SubIrp = IoBuildDeviceIoControlRequest(
1070 IOCTL_HID_SET_FEATURE,
1071 CommonDeviceExtension->HidDeviceExtension.NextDeviceObject,
1072 NULL, 0,
1073 NULL, 0,
1074 TRUE,
1075 &Event,
1076 &IoStatusBlock);
1077 if (!SubIrp)
1078 {
1079 Irp->IoStatus.Status = STATUS_NO_MEMORY;
1080 IoCompleteRequest(Irp, IO_NO_INCREMENT);
1081 return STATUS_NOT_IMPLEMENTED;
1082 }
1083 SubIrp->UserBuffer = &XferPacket;
1084 KeInitializeEvent(&Event, SynchronizationEvent, FALSE);
1085 Status = IoCallDriver(CommonDeviceExtension->HidDeviceExtension.NextDeviceObject, SubIrp);
1086 if (Status == STATUS_PENDING)
1087 {
1088 KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
1089 Status = IoStatusBlock.Status;
1090 }
1091 Irp->IoStatus.Status = Status;
1092 IoCompleteRequest(Irp, IO_NO_INCREMENT);
1093 return Status;
1094 }
1095 default:
1096 {
1097 DPRINT1("[HIDCLASS] DeviceControl IoControlCode 0x%x not implemented\n", IoStack->Parameters.DeviceIoControl.IoControlCode);
1098 Irp->IoStatus.Status = STATUS_NOT_IMPLEMENTED;
1099 IoCompleteRequest(Irp, IO_NO_INCREMENT);
1100 return STATUS_NOT_IMPLEMENTED;
1101 }
1102 }
1103 }
1104
1105 NTSTATUS
1106 NTAPI
1107 HidClass_InternalDeviceControl(
1108 IN PDEVICE_OBJECT DeviceObject,
1109 IN PIRP Irp)
1110 {
1111 UNIMPLEMENTED;
1112 ASSERT(FALSE);
1113 Irp->IoStatus.Status = STATUS_NOT_IMPLEMENTED;
1114 IoCompleteRequest(Irp, IO_NO_INCREMENT);
1115 return STATUS_NOT_IMPLEMENTED;
1116 }
1117
1118 NTSTATUS
1119 NTAPI
1120 HidClass_Power(
1121 IN PDEVICE_OBJECT DeviceObject,
1122 IN PIRP Irp)
1123 {
1124 PHIDCLASS_COMMON_DEVICE_EXTENSION CommonDeviceExtension;
1125 CommonDeviceExtension = DeviceObject->DeviceExtension;
1126
1127 if (CommonDeviceExtension->IsFDO)
1128 {
1129 IoCopyCurrentIrpStackLocationToNext(Irp);
1130 return HidClassFDO_DispatchRequest(DeviceObject, Irp);
1131 }
1132 else
1133 {
1134 Irp->IoStatus.Status = STATUS_SUCCESS;
1135 PoStartNextPowerIrp(Irp);
1136 IoCompleteRequest(Irp, IO_NO_INCREMENT);
1137 return STATUS_SUCCESS;
1138 }
1139 }
1140
1141 NTSTATUS
1142 NTAPI
1143 HidClass_PnP(
1144 IN PDEVICE_OBJECT DeviceObject,
1145 IN PIRP Irp)
1146 {
1147 PHIDCLASS_COMMON_DEVICE_EXTENSION CommonDeviceExtension;
1148
1149 //
1150 // get common device extension
1151 //
1152 CommonDeviceExtension = DeviceObject->DeviceExtension;
1153
1154 //
1155 // check type of device object
1156 //
1157 if (CommonDeviceExtension->IsFDO)
1158 {
1159 //
1160 // handle request
1161 //
1162 return HidClassFDO_PnP(DeviceObject, Irp);
1163 }
1164 else
1165 {
1166 //
1167 // handle request
1168 //
1169 return HidClassPDO_PnP(DeviceObject, Irp);
1170 }
1171 }
1172
1173 NTSTATUS
1174 NTAPI
1175 HidClass_DispatchDefault(
1176 IN PDEVICE_OBJECT DeviceObject,
1177 IN PIRP Irp)
1178 {
1179 PHIDCLASS_COMMON_DEVICE_EXTENSION CommonDeviceExtension;
1180
1181 //
1182 // get common device extension
1183 //
1184 CommonDeviceExtension = DeviceObject->DeviceExtension;
1185
1186 //
1187 // FIXME: support PDO
1188 //
1189 ASSERT(CommonDeviceExtension->IsFDO == TRUE);
1190
1191 //
1192 // skip current irp stack location
1193 //
1194 IoSkipCurrentIrpStackLocation(Irp);
1195
1196 //
1197 // dispatch to lower device object
1198 //
1199 return IoCallDriver(CommonDeviceExtension->HidDeviceExtension.NextDeviceObject, Irp);
1200 }
1201
1202 NTSTATUS
1203 NTAPI
1204 HidClassDispatch(
1205 IN PDEVICE_OBJECT DeviceObject,
1206 IN PIRP Irp)
1207 {
1208 PIO_STACK_LOCATION IoStack;
1209
1210 //
1211 // get current stack location
1212 //
1213 IoStack = IoGetCurrentIrpStackLocation(Irp);
1214 DPRINT("[HIDCLASS] Dispatch Major %x Minor %x\n", IoStack->MajorFunction, IoStack->MinorFunction);
1215
1216 //
1217 // dispatch request based on major function
1218 //
1219 switch (IoStack->MajorFunction)
1220 {
1221 case IRP_MJ_CREATE:
1222 return HidClass_Create(DeviceObject, Irp);
1223 case IRP_MJ_CLOSE:
1224 return HidClass_Close(DeviceObject, Irp);
1225 case IRP_MJ_READ:
1226 return HidClass_Read(DeviceObject, Irp);
1227 case IRP_MJ_WRITE:
1228 return HidClass_Write(DeviceObject, Irp);
1229 case IRP_MJ_DEVICE_CONTROL:
1230 return HidClass_DeviceControl(DeviceObject, Irp);
1231 case IRP_MJ_INTERNAL_DEVICE_CONTROL:
1232 return HidClass_InternalDeviceControl(DeviceObject, Irp);
1233 case IRP_MJ_POWER:
1234 return HidClass_Power(DeviceObject, Irp);
1235 case IRP_MJ_PNP:
1236 return HidClass_PnP(DeviceObject, Irp);
1237 default:
1238 return HidClass_DispatchDefault(DeviceObject, Irp);
1239 }
1240 }
1241
1242 NTSTATUS
1243 NTAPI
1244 HidRegisterMinidriver(
1245 IN PHID_MINIDRIVER_REGISTRATION MinidriverRegistration)
1246 {
1247 NTSTATUS Status;
1248 PHIDCLASS_DRIVER_EXTENSION DriverExtension;
1249
1250 /* check if the version matches */
1251 if (MinidriverRegistration->Revision > HID_REVISION)
1252 {
1253 /* revision mismatch */
1254 ASSERT(FALSE);
1255 return STATUS_REVISION_MISMATCH;
1256 }
1257
1258 /* now allocate the driver object extension */
1259 Status = IoAllocateDriverObjectExtension(MinidriverRegistration->DriverObject,
1260 ClientIdentificationAddress,
1261 sizeof(HIDCLASS_DRIVER_EXTENSION),
1262 (PVOID *)&DriverExtension);
1263 if (!NT_SUCCESS(Status))
1264 {
1265 /* failed to allocate driver extension */
1266 ASSERT(FALSE);
1267 return Status;
1268 }
1269
1270 /* zero driver extension */
1271 RtlZeroMemory(DriverExtension, sizeof(HIDCLASS_DRIVER_EXTENSION));
1272
1273 /* init driver extension */
1274 DriverExtension->DriverObject = MinidriverRegistration->DriverObject;
1275 DriverExtension->DeviceExtensionSize = MinidriverRegistration->DeviceExtensionSize;
1276 DriverExtension->DevicesArePolled = MinidriverRegistration->DevicesArePolled;
1277 DriverExtension->AddDevice = MinidriverRegistration->DriverObject->DriverExtension->AddDevice;
1278 DriverExtension->DriverUnload = MinidriverRegistration->DriverObject->DriverUnload;
1279
1280 /* copy driver dispatch routines */
1281 RtlCopyMemory(DriverExtension->MajorFunction,
1282 MinidriverRegistration->DriverObject->MajorFunction,
1283 sizeof(PDRIVER_DISPATCH) * (IRP_MJ_MAXIMUM_FUNCTION + 1));
1284
1285 /* initialize lock */
1286 KeInitializeSpinLock(&DriverExtension->Lock);
1287
1288 /* now replace dispatch routines */
1289 DriverExtension->DriverObject->DriverExtension->AddDevice = HidClassAddDevice;
1290 DriverExtension->DriverObject->DriverUnload = HidClassDriverUnload;
1291 DriverExtension->DriverObject->MajorFunction[IRP_MJ_CREATE] = HidClassDispatch;
1292 DriverExtension->DriverObject->MajorFunction[IRP_MJ_CLOSE] = HidClassDispatch;
1293 DriverExtension->DriverObject->MajorFunction[IRP_MJ_READ] = HidClassDispatch;
1294 DriverExtension->DriverObject->MajorFunction[IRP_MJ_WRITE] = HidClassDispatch;
1295 DriverExtension->DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = HidClassDispatch;
1296 DriverExtension->DriverObject->MajorFunction[IRP_MJ_INTERNAL_DEVICE_CONTROL] = HidClassDispatch;
1297 DriverExtension->DriverObject->MajorFunction[IRP_MJ_POWER] = HidClassDispatch;
1298 DriverExtension->DriverObject->MajorFunction[IRP_MJ_PNP] = HidClassDispatch;
1299
1300 /* done */
1301 return STATUS_SUCCESS;
1302 }