2 * PROJECT: ReactOS HID Stack
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: drivers/hid/mouhid/mouhid.c
5 * PURPOSE: Mouse HID Driver
7 * Michael Martin (michael.martin@reactos.org)
8 * Johannes Anderwald (johannes.anderwald@reactos.org)
13 static USHORT MouHid_ButtonUpFlags
[] =
16 MOUSE_LEFT_BUTTON_DOWN
,
17 MOUSE_RIGHT_BUTTON_DOWN
,
18 MOUSE_MIDDLE_BUTTON_DOWN
,
23 static USHORT MouHid_ButtonDownFlags
[] =
27 MOUSE_RIGHT_BUTTON_UP
,
28 MOUSE_MIDDLE_BUTTON_UP
,
35 IN PMOUHID_DEVICE_EXTENSION DeviceExtension
,
46 /* get scaled usage value x */
47 Status
= HidP_GetScaledUsageValue(HidP_Input
,
48 HID_USAGE_PAGE_GENERIC
,
49 HIDP_LINK_COLLECTION_UNSPECIFIED
,
52 DeviceExtension
->PreparsedData
,
53 DeviceExtension
->Report
,
54 DeviceExtension
->ReportLength
);
55 if (Status
!= HIDP_STATUS_SUCCESS
)
57 /* FIXME: handle more errors */
58 if (Status
== HIDP_STATUS_BAD_LOG_PHY_VALUES
)
60 /* FIXME: assume it operates in absolute mode */
61 DeviceExtension
->MouseAbsolute
= TRUE
;
63 /* get unscaled value */
64 Status
= HidP_GetUsageValue(HidP_Input
,
65 HID_USAGE_PAGE_GENERIC
,
66 HIDP_LINK_COLLECTION_UNSPECIFIED
,
69 DeviceExtension
->PreparsedData
,
70 DeviceExtension
->Report
,
71 DeviceExtension
->ReportLength
);
73 /* FIXME handle error */
74 ASSERT(Status
== HIDP_STATUS_SUCCESS
);
76 /* absolute pointing devices values need be in range 0 - 0xffff */
77 ASSERT(DeviceExtension
->ValueCapsX
.LogicalMax
> 0);
79 *LastX
= (ValueX
* 0xFFFF) / DeviceExtension
->ValueCapsX
.LogicalMax
;
83 /* get scaled usage value y */
84 Status
= HidP_GetScaledUsageValue(HidP_Input
,
85 HID_USAGE_PAGE_GENERIC
,
86 HIDP_LINK_COLLECTION_UNSPECIFIED
,
89 DeviceExtension
->PreparsedData
,
90 DeviceExtension
->Report
,
91 DeviceExtension
->ReportLength
);
92 if (Status
!= HIDP_STATUS_SUCCESS
)
94 // FIXME: handle more errors
95 if (Status
== HIDP_STATUS_BAD_LOG_PHY_VALUES
)
97 // assume it operates in absolute mode
98 DeviceExtension
->MouseAbsolute
= TRUE
;
100 // get unscaled value
101 Status
= HidP_GetUsageValue(HidP_Input
,
102 HID_USAGE_PAGE_GENERIC
,
103 HIDP_LINK_COLLECTION_UNSPECIFIED
,
106 DeviceExtension
->PreparsedData
,
107 DeviceExtension
->Report
,
108 DeviceExtension
->ReportLength
);
110 /* FIXME handle error */
111 ASSERT(Status
== HIDP_STATUS_SUCCESS
);
113 /* absolute pointing devices values need be in range 0 - 0xffff */
114 ASSERT(DeviceExtension
->ValueCapsY
.LogicalMax
);
115 *LastY
= (ValueY
* 0xFFFF) / DeviceExtension
->ValueCapsY
.LogicalMax
;
121 MouHid_GetButtonFlags(
122 IN PMOUHID_DEVICE_EXTENSION DeviceExtension
,
123 OUT PUSHORT ButtonFlags
,
130 ULONG CurrentUsageListLength
;
137 CurrentUsageListLength
= DeviceExtension
->UsageListLength
;
138 Status
= HidP_GetUsages(HidP_Input
,
139 HID_USAGE_PAGE_BUTTON
,
140 HIDP_LINK_COLLECTION_UNSPECIFIED
,
141 DeviceExtension
->CurrentUsageList
,
142 &CurrentUsageListLength
,
143 DeviceExtension
->PreparsedData
,
144 DeviceExtension
->Report
,
145 DeviceExtension
->ReportLength
);
146 if (Status
!= HIDP_STATUS_SUCCESS
)
148 DPRINT1("MouHid_GetButtonFlags failed to get usages with %x\n", Status
);
152 /* extract usage list difference */
153 Status
= HidP_UsageListDifference(DeviceExtension
->PreviousUsageList
,
154 DeviceExtension
->CurrentUsageList
,
155 DeviceExtension
->BreakUsageList
,
156 DeviceExtension
->MakeUsageList
,
157 DeviceExtension
->UsageListLength
);
158 if (Status
!= HIDP_STATUS_SUCCESS
)
160 DPRINT1("MouHid_GetButtonFlags failed to get usages with %x\n", Status
);
164 if (DeviceExtension
->UsageListLength
)
170 Usage
= DeviceExtension
->BreakUsageList
[Index
];
176 /* max 5 buttons supported */
177 *ButtonFlags
|= MouHid_ButtonDownFlags
[Usage
];
180 /* move to next index*/
182 }while(Index
< DeviceExtension
->UsageListLength
);
185 if (DeviceExtension
->UsageListLength
)
191 Usage
= DeviceExtension
->MakeUsageList
[Index
];
197 /* max 5 buttons supported */
198 *ButtonFlags
|= MouHid_ButtonUpFlags
[Usage
];
201 /* move to next index*/
203 }while(Index
< DeviceExtension
->UsageListLength
);
206 /* now switch the previous list with current list */
207 TempList
= DeviceExtension
->CurrentUsageList
;
208 DeviceExtension
->CurrentUsageList
= DeviceExtension
->PreviousUsageList
;
209 DeviceExtension
->PreviousUsageList
= TempList
;
211 if (DeviceExtension
->MouseAbsolute
)
213 // mouse operates absolute
214 *Flags
|= MOUSE_MOVE_ABSOLUTE
;
219 MouHid_DispatchInputData(
220 IN PMOUHID_DEVICE_EXTENSION DeviceExtension
,
221 IN PMOUSE_INPUT_DATA InputData
)
224 ULONG InputDataConsumed
;
226 if (!DeviceExtension
->ClassService
)
230 ASSERT(DeviceExtension
->ClassService
);
231 ASSERT(DeviceExtension
->ClassDeviceObject
);
234 KeRaiseIrql(DISPATCH_LEVEL
, &OldIrql
);
236 /* dispatch input data */
237 (*(PSERVICE_CALLBACK_ROUTINE
)DeviceExtension
->ClassService
)(DeviceExtension
->ClassDeviceObject
, InputData
, InputData
+ 1, &InputDataConsumed
);
239 /* lower irql to previous level */
240 KeLowerIrql(OldIrql
);
245 MouHid_ReadCompletion(
246 IN PDEVICE_OBJECT DeviceObject
,
250 PMOUHID_DEVICE_EXTENSION DeviceExtension
;
255 MOUSE_INPUT_DATA MouseInputData
;
258 /* get device extension */
259 DeviceExtension
= (PMOUHID_DEVICE_EXTENSION
)Context
;
261 if (Irp
->IoStatus
.Status
== STATUS_PRIVILEGE_NOT_HELD
||
262 Irp
->IoStatus
.Status
== STATUS_DEVICE_NOT_CONNECTED
||
263 Irp
->IoStatus
.Status
== STATUS_CANCELLED
||
264 DeviceExtension
->StopReadReport
)
266 /* failed to read or should be stopped*/
267 DPRINT1("[MOUHID] ReadCompletion terminating read Status %x\n", Irp
->IoStatus
.Status
);
269 /* report no longer active */
270 DeviceExtension
->ReadReportActive
= FALSE
;
272 /* request stopping of the report cycle */
273 DeviceExtension
->StopReadReport
= FALSE
;
275 /* signal completion event */
276 KeSetEvent(&DeviceExtension
->ReadCompletionEvent
, 0, 0);
277 return STATUS_MORE_PROCESSING_REQUIRED
;
280 /* get mouse change */
281 MouHid_GetButtonMove(DeviceExtension
, &LastX
, &LastY
);
283 /* get mouse change flags */
284 MouHid_GetButtonFlags(DeviceExtension
, &ButtonFlags
, &Flags
);
286 /* init input data */
287 RtlZeroMemory(&MouseInputData
, sizeof(MOUSE_INPUT_DATA
));
289 /* init input data */
290 MouseInputData
.ButtonFlags
= ButtonFlags
;
291 MouseInputData
.Flags
= Flags
;
292 MouseInputData
.LastX
= LastX
;
293 MouseInputData
.LastY
= LastY
;
295 /* detect mouse wheel change */
296 if (DeviceExtension
->MouseIdentifier
== WHEELMOUSE_HID_HARDWARE
)
300 Status
= HidP_GetScaledUsageValue(HidP_Input
,
301 HID_USAGE_PAGE_GENERIC
,
302 HIDP_LINK_COLLECTION_UNSPECIFIED
,
303 HID_USAGE_GENERIC_WHEEL
,
305 DeviceExtension
->PreparsedData
,
306 DeviceExtension
->Report
,
307 DeviceExtension
->ReportLength
);
308 if (Status
== HIDP_STATUS_SUCCESS
&& UsageValue
!= 0)
310 /* store wheel status */
311 MouseInputData
.ButtonFlags
|= MOUSE_WHEEL
;
312 MouseInputData
.ButtonData
= (USHORT
)(UsageValue
* WHEEL_DELTA
);
316 DPRINT("[MOUHID] failed to get wheel status with %x\n", Status
);
320 DPRINT("[MOUHID] ReportData %02x %02x %02x %02x %02x %02x %02x\n",
321 DeviceExtension
->Report
[0] & 0xFF,
322 DeviceExtension
->Report
[1] & 0xFF, DeviceExtension
->Report
[2] & 0xFF,
323 DeviceExtension
->Report
[3] & 0xFF, DeviceExtension
->Report
[4] & 0xFF,
324 DeviceExtension
->Report
[5] & 0xFF, DeviceExtension
->Report
[6] & 0xFF);
326 DPRINT("[MOUHID] LastX %ld LastY %ld Flags %x ButtonData %x\n", MouseInputData
.LastX
, MouseInputData
.LastY
, MouseInputData
.ButtonFlags
, MouseInputData
.ButtonData
);
328 /* dispatch mouse action */
329 MouHid_DispatchInputData(DeviceExtension
, &MouseInputData
);
332 MouHid_InitiateRead(DeviceExtension
);
334 /* stop completion */
335 return STATUS_MORE_PROCESSING_REQUIRED
;
340 IN PMOUHID_DEVICE_EXTENSION DeviceExtension
)
342 PIO_STACK_LOCATION IoStack
;
346 IoReuseIrp(DeviceExtension
->Irp
, STATUS_SUCCESS
);
349 DeviceExtension
->Irp
->MdlAddress
= DeviceExtension
->ReportMDL
;
351 /* get next stack location */
352 IoStack
= IoGetNextIrpStackLocation(DeviceExtension
->Irp
);
354 /* init stack location */
355 IoStack
->Parameters
.Read
.Length
= DeviceExtension
->ReportLength
;
356 IoStack
->Parameters
.Read
.Key
= 0;
357 IoStack
->Parameters
.Read
.ByteOffset
.QuadPart
= 0LL;
358 IoStack
->MajorFunction
= IRP_MJ_READ
;
359 IoStack
->FileObject
= DeviceExtension
->FileObject
;
361 /* set completion routine */
362 IoSetCompletionRoutine(DeviceExtension
->Irp
, MouHid_ReadCompletion
, DeviceExtension
, TRUE
, TRUE
, TRUE
);
365 DeviceExtension
->ReadReportActive
= TRUE
;
368 Status
= IoCallDriver(DeviceExtension
->NextDeviceObject
, DeviceExtension
->Irp
);
376 MouHid_CreateCompletion(
377 IN PDEVICE_OBJECT DeviceObject
,
381 KeSetEvent(Context
, 0, FALSE
);
382 return STATUS_MORE_PROCESSING_REQUIRED
;
389 IN PDEVICE_OBJECT DeviceObject
,
392 PIO_STACK_LOCATION IoStack
;
395 PMOUHID_DEVICE_EXTENSION DeviceExtension
;
397 DPRINT("MOUHID: IRP_MJ_CREATE\n");
399 /* get device extension */
400 DeviceExtension
= (PMOUHID_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
402 /* get stack location */
403 IoStack
= IoGetCurrentIrpStackLocation(Irp
);
405 /* copy stack location to next */
406 IoCopyCurrentIrpStackLocationToNext(Irp
);
409 KeInitializeEvent(&Event
, NotificationEvent
, FALSE
);
412 IoSetCompletionRoutine(Irp
, MouHid_CreateCompletion
, &Event
, TRUE
, TRUE
, TRUE
);
414 /* call lower driver */
415 Status
= IoCallDriver(DeviceExtension
->NextDeviceObject
, Irp
);
416 if (Status
== STATUS_PENDING
)
418 /* request pending */
419 KeWaitForSingleObject(&Event
, Executive
, KernelMode
, FALSE
, NULL
);
422 /* check for success */
423 if (!NT_SUCCESS(Status
))
426 Irp
->IoStatus
.Status
= Status
;
427 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
431 /* is the driver already in use */
432 if (DeviceExtension
->FileObject
== NULL
)
434 /* did the caller specify correct attributes */
435 ASSERT(IoStack
->Parameters
.Create
.SecurityContext
);
436 if (IoStack
->Parameters
.Create
.SecurityContext
->DesiredAccess
)
438 /* store file object */
439 DeviceExtension
->FileObject
= IoStack
->FileObject
;
442 KeResetEvent(&DeviceExtension
->ReadCompletionEvent
);
444 /* initiating read */
445 Status
= MouHid_InitiateRead(DeviceExtension
);
446 DPRINT("[MOUHID] MouHid_InitiateRead: status %x\n", Status
);
447 if (Status
== STATUS_PENDING
)
449 /* report irp is pending */
450 Status
= STATUS_SUCCESS
;
455 /* complete request */
456 Irp
->IoStatus
.Status
= Status
;
457 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
465 IN PDEVICE_OBJECT DeviceObject
,
468 PMOUHID_DEVICE_EXTENSION DeviceExtension
;
470 /* get device extension */
471 DeviceExtension
= (PMOUHID_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
473 DPRINT("[MOUHID] IRP_MJ_CLOSE ReadReportActive %x\n", DeviceExtension
->ReadReportActive
);
475 if (DeviceExtension
->ReadReportActive
)
477 /* request stopping of the report cycle */
478 DeviceExtension
->StopReadReport
= TRUE
;
480 /* wait until the reports have been read */
481 KeWaitForSingleObject(&DeviceExtension
->ReadCompletionEvent
, Executive
, KernelMode
, FALSE
, NULL
);
484 IoCancelIrp(DeviceExtension
->Irp
);
487 DPRINT("[MOUHID] IRP_MJ_CLOSE ReadReportActive %x\n", DeviceExtension
->ReadReportActive
);
489 /* remove file object */
490 DeviceExtension
->FileObject
= NULL
;
493 IoSkipCurrentIrpStackLocation(Irp
);
495 /* pass irp to down the stack */
496 return IoCallDriver(DeviceExtension
->NextDeviceObject
, Irp
);
501 MouHid_InternalDeviceControl(
502 IN PDEVICE_OBJECT DeviceObject
,
505 PIO_STACK_LOCATION IoStack
;
506 PMOUSE_ATTRIBUTES Attributes
;
507 PMOUHID_DEVICE_EXTENSION DeviceExtension
;
510 /* get current stack location */
511 IoStack
= IoGetCurrentIrpStackLocation(Irp
);
513 DPRINT("[MOUHID] InternalDeviceControl %x\n", IoStack
->Parameters
.DeviceIoControl
.IoControlCode
);
515 /* get device extension */
516 DeviceExtension
= (PMOUHID_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
518 /* handle requests */
519 switch (IoStack
->Parameters
.DeviceIoControl
.IoControlCode
)
521 case IOCTL_MOUSE_QUERY_ATTRIBUTES
:
522 /* verify output buffer length */
523 if (IoStack
->Parameters
.DeviceIoControl
.OutputBufferLength
< sizeof(MOUSE_ATTRIBUTES
))
525 /* invalid request */
526 DPRINT1("[MOUHID] IOCTL_MOUSE_QUERY_ATTRIBUTES Buffer too small\n");
527 Irp
->IoStatus
.Status
= STATUS_BUFFER_TOO_SMALL
;
528 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
529 return STATUS_BUFFER_TOO_SMALL
;
532 /* get output buffer */
533 Attributes
= (PMOUSE_ATTRIBUTES
)Irp
->AssociatedIrp
.SystemBuffer
;
536 Attributes
->MouseIdentifier
= DeviceExtension
->MouseIdentifier
;
538 /* number of buttons */
539 Attributes
->NumberOfButtons
= DeviceExtension
->UsageListLength
;
541 /* sample rate not used for usb */
542 Attributes
->SampleRate
= 0;
545 Attributes
->InputDataQueueLength
= 2;
547 DPRINT("[MOUHID] MouseIdentifier %x\n", Attributes
->MouseIdentifier
);
548 DPRINT("[MOUHID] NumberOfButtons %x\n", Attributes
->NumberOfButtons
);
549 DPRINT("[MOUHID] SampleRate %x\n", Attributes
->SampleRate
);
550 DPRINT("[MOUHID] InputDataQueueLength %x\n", Attributes
->InputDataQueueLength
);
552 /* complete request */
553 Irp
->IoStatus
.Information
= sizeof(MOUSE_ATTRIBUTES
);
554 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
555 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
556 return STATUS_SUCCESS
;
558 case IOCTL_INTERNAL_MOUSE_CONNECT
:
559 /* verify input buffer length */
560 if (IoStack
->Parameters
.DeviceIoControl
.InputBufferLength
< sizeof(CONNECT_DATA
))
562 /* invalid request */
563 Irp
->IoStatus
.Status
= STATUS_INVALID_PARAMETER
;
564 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
565 return STATUS_INVALID_PARAMETER
;
568 /* is it already connected */
569 if (DeviceExtension
->ClassService
)
571 /* already connected */
572 Irp
->IoStatus
.Status
= STATUS_SHARING_VIOLATION
;
573 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
574 return STATUS_SHARING_VIOLATION
;
577 /* get connect data */
578 Data
= (PCONNECT_DATA
)IoStack
->Parameters
.DeviceIoControl
.Type3InputBuffer
;
580 /* store connect details */
581 DeviceExtension
->ClassDeviceObject
= Data
->ClassDeviceObject
;
582 DeviceExtension
->ClassService
= Data
->ClassService
;
584 /* completed successfully */
585 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
586 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
587 return STATUS_SUCCESS
;
589 case IOCTL_INTERNAL_MOUSE_DISCONNECT
:
591 Irp
->IoStatus
.Status
= STATUS_NOT_IMPLEMENTED
;
592 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
593 return STATUS_NOT_IMPLEMENTED
;
595 case IOCTL_INTERNAL_MOUSE_ENABLE
:
597 Irp
->IoStatus
.Status
= STATUS_NOT_SUPPORTED
;
598 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
599 return STATUS_NOT_SUPPORTED
;
601 case IOCTL_INTERNAL_MOUSE_DISABLE
:
603 Irp
->IoStatus
.Status
= STATUS_INVALID_DEVICE_REQUEST
;
604 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
605 return STATUS_INVALID_DEVICE_REQUEST
;
608 DPRINT1("[MOUHID] Unknown DeviceControl %x\n", IoStack
->Parameters
.DeviceIoControl
.IoControlCode
);
609 /* unknown request not supported */
610 Irp
->IoStatus
.Status
= STATUS_NOT_SUPPORTED
;
611 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
612 return STATUS_NOT_SUPPORTED
;
617 MouHid_DeviceControl(
618 IN PDEVICE_OBJECT DeviceObject
,
621 PMOUHID_DEVICE_EXTENSION DeviceExtension
;
623 /* get device extension */
624 DeviceExtension
= (PMOUHID_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
626 /* skip stack location */
627 IoSkipCurrentIrpStackLocation(Irp
);
629 /* pass and forget */
630 return IoCallDriver(DeviceExtension
->NextDeviceObject
, Irp
);
636 IN PDEVICE_OBJECT DeviceObject
,
639 PMOUHID_DEVICE_EXTENSION DeviceExtension
;
641 DeviceExtension
= DeviceObject
->DeviceExtension
;
642 PoStartNextPowerIrp(Irp
);
643 IoSkipCurrentIrpStackLocation(Irp
);
644 return PoCallDriver(DeviceExtension
->NextDeviceObject
, Irp
);
649 MouHid_SystemControl(
650 IN PDEVICE_OBJECT DeviceObject
,
653 PMOUHID_DEVICE_EXTENSION DeviceExtension
;
655 DeviceExtension
= DeviceObject
->DeviceExtension
;
656 IoSkipCurrentIrpStackLocation(Irp
);
657 return IoCallDriver(DeviceExtension
->NextDeviceObject
, Irp
);
661 MouHid_SubmitRequest(
662 PDEVICE_OBJECT DeviceObject
,
664 ULONG InputBufferSize
,
666 ULONG OutputBufferSize
,
670 PMOUHID_DEVICE_EXTENSION DeviceExtension
;
673 IO_STATUS_BLOCK IoStatus
;
675 /* get device extension */
676 DeviceExtension
= (PMOUHID_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
679 KeInitializeEvent(&Event
, NotificationEvent
, FALSE
);
682 Irp
= IoBuildDeviceIoControlRequest(IoControlCode
,
683 DeviceExtension
->NextDeviceObject
,
694 return STATUS_INSUFFICIENT_RESOURCES
;
698 Status
= IoCallDriver(DeviceExtension
->NextDeviceObject
, Irp
);
699 if (Status
== STATUS_PENDING
)
701 /* wait for request to complete */
702 KeWaitForSingleObject(&Event
, Executive
, KernelMode
, FALSE
, NULL
);
703 Status
= IoStatus
.Status
;
713 IN PDEVICE_OBJECT DeviceObject
)
717 HID_COLLECTION_INFORMATION Information
;
719 HIDP_CAPS Capabilities
;
720 ULONG ValueCapsLength
;
721 HIDP_VALUE_CAPS ValueCaps
;
722 PMOUHID_DEVICE_EXTENSION DeviceExtension
;
725 /* get device extension */
726 DeviceExtension
= (PMOUHID_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
728 /* query collection information */
729 Status
= MouHid_SubmitRequest(DeviceObject
,
730 IOCTL_HID_GET_COLLECTION_INFORMATION
,
733 sizeof(HID_COLLECTION_INFORMATION
),
735 if (!NT_SUCCESS(Status
))
737 /* failed to query collection information */
738 DPRINT1("[MOUHID] failed to obtain collection information with %x\n", Status
);
742 /* lets allocate space for preparsed data */
743 PreparsedData
= ExAllocatePool(NonPagedPool
, Information
.DescriptorSize
);
747 DPRINT1("[MOUHID] no memory size %u\n", Information
.DescriptorSize
);
748 return STATUS_INSUFFICIENT_RESOURCES
;
751 /* now obtain the preparsed data */
752 Status
= MouHid_SubmitRequest(DeviceObject
,
753 IOCTL_HID_GET_COLLECTION_DESCRIPTOR
,
756 Information
.DescriptorSize
,
758 if (!NT_SUCCESS(Status
))
760 /* failed to get preparsed data */
761 DPRINT1("[MOUHID] failed to obtain collection information with %x\n", Status
);
762 ExFreePool(PreparsedData
);
766 /* lets get the caps */
767 Status
= HidP_GetCaps(PreparsedData
, &Capabilities
);
768 if (Status
!= HIDP_STATUS_SUCCESS
)
770 /* failed to get capabilities */
771 DPRINT1("[MOUHID] failed to obtain caps with %x\n", Status
);
772 ExFreePool(PreparsedData
);
776 DPRINT("[MOUHID] Usage %x UsagePage %x InputReportLength %lu\n", Capabilities
.Usage
, Capabilities
.UsagePage
, Capabilities
.InputReportByteLength
);
778 /* verify capabilities */
779 if ((Capabilities
.Usage
!= HID_USAGE_GENERIC_POINTER
&& Capabilities
.Usage
!= HID_USAGE_GENERIC_MOUSE
) || Capabilities
.UsagePage
!= HID_USAGE_PAGE_GENERIC
)
782 ExFreePool(PreparsedData
);
783 return STATUS_UNSUCCESSFUL
;
786 /* init input report*/
787 DeviceExtension
->ReportLength
= Capabilities
.InputReportByteLength
;
788 ASSERT(DeviceExtension
->ReportLength
);
789 DeviceExtension
->Report
= (PCHAR
)ExAllocatePool(NonPagedPool
, DeviceExtension
->ReportLength
);
790 ASSERT(DeviceExtension
->Report
);
791 RtlZeroMemory(DeviceExtension
->Report
, DeviceExtension
->ReportLength
);
794 DeviceExtension
->ReportMDL
= IoAllocateMdl(DeviceExtension
->Report
,
795 DeviceExtension
->ReportLength
,
799 ASSERT(DeviceExtension
->ReportMDL
);
802 MmBuildMdlForNonPagedPool(DeviceExtension
->ReportMDL
);
804 /* get max number of buttons */
805 Buttons
= HidP_MaxUsageListLength(HidP_Input
,
806 HID_USAGE_PAGE_BUTTON
,
808 DPRINT("[MOUHID] Buttons %lu\n", Buttons
);
811 /* now allocate an array for those buttons */
812 Buffer
= ExAllocatePool(NonPagedPool
, sizeof(USAGE
) * 4 * Buttons
);
816 ExFreePool(PreparsedData
);
817 return STATUS_INSUFFICIENT_RESOURCES
;
820 /* init usage lists */
821 RtlZeroMemory(Buffer
, sizeof(USAGE
) * 4 * Buttons
);
822 DeviceExtension
->CurrentUsageList
= Buffer
;
824 DeviceExtension
->PreviousUsageList
= Buffer
;
826 DeviceExtension
->MakeUsageList
= Buffer
;
828 DeviceExtension
->BreakUsageList
= Buffer
;
830 /* store number of buttons */
831 DeviceExtension
->UsageListLength
= (USHORT
)Buttons
;
833 /* store preparsed data */
834 DeviceExtension
->PreparsedData
= PreparsedData
;
837 HidP_GetSpecificValueCaps(HidP_Input
,
838 HID_USAGE_PAGE_GENERIC
,
839 HIDP_LINK_COLLECTION_UNSPECIFIED
,
841 &DeviceExtension
->ValueCapsX
,
846 HidP_GetSpecificValueCaps(HidP_Input
,
847 HID_USAGE_PAGE_GENERIC
,
848 HIDP_LINK_COLLECTION_UNSPECIFIED
,
850 &DeviceExtension
->ValueCapsY
,
854 /* now check for wheel mouse support */
856 Status
= HidP_GetSpecificValueCaps(HidP_Input
,
857 HID_USAGE_PAGE_GENERIC
,
858 HIDP_LINK_COLLECTION_UNSPECIFIED
,
859 HID_USAGE_GENERIC_WHEEL
,
863 if (Status
== HIDP_STATUS_SUCCESS
)
865 /* mouse has wheel support */
866 DeviceExtension
->MouseIdentifier
= WHEELMOUSE_HID_HARDWARE
;
867 DeviceExtension
->WheelUsagePage
= ValueCaps
.UsagePage
;
868 DPRINT("[MOUHID] mouse wheel support detected\n", Status
);
872 /* check if the mouse has z-axis */
874 Status
= HidP_GetSpecificValueCaps(HidP_Input
,
875 HID_USAGE_PAGE_GENERIC
,
876 HIDP_LINK_COLLECTION_UNSPECIFIED
,
881 if (Status
== HIDP_STATUS_SUCCESS
&& ValueCapsLength
== 1)
884 DeviceExtension
->MouseIdentifier
= WHEELMOUSE_HID_HARDWARE
;
885 DeviceExtension
->WheelUsagePage
= ValueCaps
.UsagePage
;
886 DPRINT("[MOUHID] mouse wheel support detected with z-axis\n", Status
);
890 /* completed successfully */
891 return STATUS_SUCCESS
;
896 MouHid_StartDeviceCompletion(
897 IN PDEVICE_OBJECT DeviceObject
,
901 KeSetEvent((PKEVENT
)Context
, 0, FALSE
);
902 return STATUS_MORE_PROCESSING_REQUIRED
;
907 MouHid_FreeResources(
908 IN PDEVICE_OBJECT DeviceObject
)
910 PMOUHID_DEVICE_EXTENSION DeviceExtension
;
912 /* get device extension */
913 DeviceExtension
= DeviceObject
->DeviceExtension
;
916 if (DeviceExtension
->PreparsedData
)
918 ExFreePool(DeviceExtension
->PreparsedData
);
919 DeviceExtension
->PreparsedData
= NULL
;
922 if (DeviceExtension
->CurrentUsageList
)
924 ExFreePool(DeviceExtension
->CurrentUsageList
);
925 DeviceExtension
->CurrentUsageList
= NULL
;
926 DeviceExtension
->PreviousUsageList
= NULL
;
927 DeviceExtension
->MakeUsageList
= NULL
;
928 DeviceExtension
->BreakUsageList
= NULL
;
931 if (DeviceExtension
->ReportMDL
)
933 IoFreeMdl(DeviceExtension
->ReportMDL
);
934 DeviceExtension
->ReportMDL
= NULL
;
937 if (DeviceExtension
->Report
)
939 ExFreePool(DeviceExtension
->Report
);
940 DeviceExtension
->Report
= NULL
;
943 return STATUS_SUCCESS
;
949 IN PDEVICE_OBJECT DeviceObject
,
952 PIO_STACK_LOCATION IoStack
;
953 PMOUHID_DEVICE_EXTENSION DeviceExtension
;
955 /* get device extension */
956 DeviceExtension
= (PMOUHID_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
958 /* skip current stack location */
959 IoSkipCurrentIrpStackLocation(Irp
);
961 /* get next stack location */
962 IoStack
= IoGetNextIrpStackLocation(Irp
);
964 /* change request to hid flush queue request */
965 IoStack
->MajorFunction
= IRP_MJ_DEVICE_CONTROL
;
966 IoStack
->Parameters
.DeviceIoControl
.IoControlCode
= IOCTL_HID_FLUSH_QUEUE
;
969 return IoCallDriver(DeviceExtension
->NextDeviceObject
, Irp
);
975 IN PDEVICE_OBJECT DeviceObject
,
978 PIO_STACK_LOCATION IoStack
;
981 PMOUHID_DEVICE_EXTENSION DeviceExtension
;
983 /* get device extension */
984 DeviceExtension
= (PMOUHID_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
986 /* get current irp stack */
987 IoStack
= IoGetCurrentIrpStackLocation(Irp
);
988 DPRINT("[MOUHID] IRP_MJ_PNP Request: %x\n", IoStack
->MinorFunction
);
990 switch (IoStack
->MinorFunction
)
992 case IRP_MN_STOP_DEVICE
:
993 case IRP_MN_SURPRISE_REMOVAL
:
995 MouHid_FreeResources(DeviceObject
);
996 case IRP_MN_CANCEL_REMOVE_DEVICE
:
997 case IRP_MN_QUERY_STOP_DEVICE
:
998 case IRP_MN_CANCEL_STOP_DEVICE
:
999 case IRP_MN_QUERY_REMOVE_DEVICE
:
1000 /* indicate success */
1001 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
1003 /* skip irp stack location */
1004 IoSkipCurrentIrpStackLocation(Irp
);
1006 /* dispatch to lower device */
1007 return IoCallDriver(DeviceExtension
->NextDeviceObject
, Irp
);
1009 case IRP_MN_REMOVE_DEVICE
:
1010 /* FIXME synchronization */
1013 DeviceExtension
->StopReadReport
= TRUE
;
1016 IoCancelIrp(DeviceExtension
->Irp
);
1018 /* free resources */
1019 MouHid_FreeResources(DeviceObject
);
1021 /* indicate success */
1022 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
1024 /* skip irp stack location */
1025 IoSkipCurrentIrpStackLocation(Irp
);
1027 /* dispatch to lower device */
1028 Status
= IoCallDriver(DeviceExtension
->NextDeviceObject
, Irp
);
1030 /* wait for completion of stop event */
1031 KeWaitForSingleObject(&DeviceExtension
->ReadCompletionEvent
, Executive
, KernelMode
, FALSE
, NULL
);
1034 IoFreeIrp(DeviceExtension
->Irp
);
1037 IoDetachDevice(DeviceExtension
->NextDeviceObject
);
1040 IoDeleteDevice(DeviceObject
);
1045 case IRP_MN_START_DEVICE
:
1047 KeInitializeEvent(&Event
, NotificationEvent
, FALSE
);
1049 /* copy stack location */
1050 IoCopyCurrentIrpStackLocationToNext (Irp
);
1052 /* set completion routine */
1053 IoSetCompletionRoutine(Irp
, MouHid_StartDeviceCompletion
, &Event
, TRUE
, TRUE
, TRUE
);
1054 Irp
->IoStatus
.Status
= 0;
1057 Status
= IoCallDriver(DeviceExtension
->NextDeviceObject
, Irp
);
1058 if (Status
== STATUS_PENDING
)
1060 KeWaitForSingleObject(&Event
, Executive
, KernelMode
, FALSE
, NULL
);
1061 Status
= Irp
->IoStatus
.Status
;
1064 if (!NT_SUCCESS(Status
))
1067 Irp
->IoStatus
.Status
= Status
;
1068 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
1072 /* lets start the device */
1073 Status
= MouHid_StartDevice(DeviceObject
);
1074 DPRINT("MouHid_StartDevice %x\n", Status
);
1076 /* complete request */
1077 Irp
->IoStatus
.Status
= Status
;
1078 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
1084 /* skip irp stack location */
1085 IoSkipCurrentIrpStackLocation(Irp
);
1087 /* dispatch to lower device */
1088 return IoCallDriver(DeviceExtension
->NextDeviceObject
, Irp
);
1095 IN PDRIVER_OBJECT DriverObject
,
1096 IN PDEVICE_OBJECT PhysicalDeviceObject
)
1099 PDEVICE_OBJECT DeviceObject
, NextDeviceObject
;
1100 PMOUHID_DEVICE_EXTENSION DeviceExtension
;
1103 /* create device object */
1104 Status
= IoCreateDevice(DriverObject
,
1105 sizeof(MOUHID_DEVICE_EXTENSION
),
1111 if (!NT_SUCCESS(Status
))
1113 /* failed to create device object */
1118 NextDeviceObject
= IoAttachDeviceToDeviceStack(DeviceObject
, PhysicalDeviceObject
);
1119 if (!NextDeviceObject
)
1121 /* failed to attach */
1122 IoDeleteDevice(DeviceObject
);
1123 return STATUS_DEVICE_NOT_CONNECTED
;
1126 /* get device extension */
1127 DeviceExtension
= (PMOUHID_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
1129 /* zero extension */
1130 RtlZeroMemory(DeviceExtension
, sizeof(MOUHID_DEVICE_EXTENSION
));
1132 /* init device extension */
1133 DeviceExtension
->MouseIdentifier
= MOUSE_HID_HARDWARE
;
1134 DeviceExtension
->WheelUsagePage
= 0;
1135 DeviceExtension
->NextDeviceObject
= NextDeviceObject
;
1136 KeInitializeEvent(&DeviceExtension
->ReadCompletionEvent
, NotificationEvent
, FALSE
);
1137 DeviceExtension
->Irp
= IoAllocateIrp(NextDeviceObject
->StackSize
, FALSE
);
1139 /* FIXME handle allocation error */
1140 ASSERT(DeviceExtension
->Irp
);
1142 /* FIXME query parameter 'FlipFlopWheel', 'WheelScalingFactor' */
1144 /* set power state to D0 */
1145 State
.DeviceState
= PowerDeviceD0
;
1146 PoSetPowerState(DeviceObject
, DevicePowerState
, State
);
1148 /* init device object */
1149 DeviceObject
->Flags
|= DO_BUFFERED_IO
| DO_POWER_PAGABLE
;
1150 DeviceObject
->Flags
&= ~DO_DEVICE_INITIALIZING
;
1152 /* completed successfully */
1153 return STATUS_SUCCESS
;
1159 IN PDRIVER_OBJECT DriverObject
)
1168 IN PDRIVER_OBJECT DriverObject
,
1169 IN PUNICODE_STRING RegPath
)
1171 /* FIXME check for parameters 'UseOnlyMice', 'TreatAbsoluteAsRelative', 'TreatAbsolutePointerAsAbsolute' */
1173 /* initialize driver object */
1174 DriverObject
->DriverUnload
= MouHid_Unload
;
1175 DriverObject
->DriverExtension
->AddDevice
= MouHid_AddDevice
;
1176 DriverObject
->MajorFunction
[IRP_MJ_CREATE
] = MouHid_Create
;
1177 DriverObject
->MajorFunction
[IRP_MJ_CLOSE
] = MouHid_Close
;
1178 DriverObject
->MajorFunction
[IRP_MJ_FLUSH_BUFFERS
] = MouHid_Flush
;
1179 DriverObject
->MajorFunction
[IRP_MJ_DEVICE_CONTROL
] = MouHid_DeviceControl
;
1180 DriverObject
->MajorFunction
[IRP_MJ_INTERNAL_DEVICE_CONTROL
] = MouHid_InternalDeviceControl
;
1181 DriverObject
->MajorFunction
[IRP_MJ_POWER
] = MouHid_Power
;
1182 DriverObject
->MajorFunction
[IRP_MJ_PNP
] = MouHid_Pnp
;
1183 DriverObject
->MajorFunction
[IRP_MJ_SYSTEM_CONTROL
] = MouHid_SystemControl
;
1184 DriverObject
->DriverUnload
= MouHid_Unload
;
1185 DriverObject
->DriverExtension
->AddDevice
= MouHid_AddDevice
;
1188 return STATUS_SUCCESS
;