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
,
36 IN PMOUHID_DEVICE_EXTENSION DeviceExtension
,
47 if (!DeviceExtension
->MouseAbsolute
)
49 /* get scaled usage value x */
50 Status
= HidP_GetScaledUsageValue(HidP_Input
,
51 HID_USAGE_PAGE_GENERIC
,
52 HIDP_LINK_COLLECTION_UNSPECIFIED
,
55 DeviceExtension
->PreparsedData
,
56 DeviceExtension
->Report
,
57 DeviceExtension
->ReportLength
);
59 if (Status
!= HIDP_STATUS_SUCCESS
)
61 /* FIXME: handle more errors */
62 if (Status
== HIDP_STATUS_BAD_LOG_PHY_VALUES
)
64 /* FIXME: assume it operates in absolute mode */
65 DeviceExtension
->MouseAbsolute
= TRUE
;
67 /* get unscaled value */
68 Status
= HidP_GetUsageValue(HidP_Input
,
69 HID_USAGE_PAGE_GENERIC
,
70 HIDP_LINK_COLLECTION_UNSPECIFIED
,
73 DeviceExtension
->PreparsedData
,
74 DeviceExtension
->Report
,
75 DeviceExtension
->ReportLength
);
77 /* FIXME handle error */
78 ASSERT(Status
== HIDP_STATUS_SUCCESS
);
80 /* absolute pointing devices values need be in range 0 - 0xffff */
81 ASSERT(DeviceExtension
->ValueCapsX
.LogicalMax
> 0);
82 ASSERT(DeviceExtension
->ValueCapsX
.LogicalMax
> DeviceExtension
->ValueCapsX
.LogicalMin
);
84 /* convert to logical range */
85 *LastX
= (ValueX
* VIRTUAL_SCREEN_SIZE_X
) / DeviceExtension
->ValueCapsX
.LogicalMax
;
91 /* get unscaled value */
92 Status
= HidP_GetUsageValue(HidP_Input
,
93 HID_USAGE_PAGE_GENERIC
,
94 HIDP_LINK_COLLECTION_UNSPECIFIED
,
97 DeviceExtension
->PreparsedData
,
98 DeviceExtension
->Report
,
99 DeviceExtension
->ReportLength
);
101 /* FIXME handle error */
102 ASSERT(Status
== HIDP_STATUS_SUCCESS
);
104 /* absolute pointing devices values need be in range 0 - 0xffff */
105 ASSERT(DeviceExtension
->ValueCapsX
.LogicalMax
> 0);
106 ASSERT(DeviceExtension
->ValueCapsX
.LogicalMax
> DeviceExtension
->ValueCapsX
.LogicalMin
);
108 /* convert to logical range */
109 *LastX
= (ValueX
* VIRTUAL_SCREEN_SIZE_X
) / DeviceExtension
->ValueCapsX
.LogicalMax
;
112 if (!DeviceExtension
->MouseAbsolute
)
114 /* get scaled usage value y */
115 Status
= HidP_GetScaledUsageValue(HidP_Input
,
116 HID_USAGE_PAGE_GENERIC
,
117 HIDP_LINK_COLLECTION_UNSPECIFIED
,
120 DeviceExtension
->PreparsedData
,
121 DeviceExtension
->Report
,
122 DeviceExtension
->ReportLength
);
124 if (Status
!= HIDP_STATUS_SUCCESS
)
126 // FIXME: handle more errors
127 if (Status
== HIDP_STATUS_BAD_LOG_PHY_VALUES
)
129 // assume it operates in absolute mode
130 DeviceExtension
->MouseAbsolute
= TRUE
;
132 // get unscaled value
133 Status
= HidP_GetUsageValue(HidP_Input
,
134 HID_USAGE_PAGE_GENERIC
,
135 HIDP_LINK_COLLECTION_UNSPECIFIED
,
138 DeviceExtension
->PreparsedData
,
139 DeviceExtension
->Report
,
140 DeviceExtension
->ReportLength
);
142 /* FIXME handle error */
143 ASSERT(Status
== HIDP_STATUS_SUCCESS
);
145 /* absolute pointing devices values need be in range 0 - 0xffff */
146 ASSERT(DeviceExtension
->ValueCapsY
.LogicalMax
> 0);
147 ASSERT(DeviceExtension
->ValueCapsY
.LogicalMax
> DeviceExtension
->ValueCapsY
.LogicalMin
);
149 /* convert to logical range */
150 *LastY
= (ValueY
* VIRTUAL_SCREEN_SIZE_Y
) / DeviceExtension
->ValueCapsY
.LogicalMax
;
156 // get unscaled value
157 Status
= HidP_GetUsageValue(HidP_Input
,
158 HID_USAGE_PAGE_GENERIC
,
159 HIDP_LINK_COLLECTION_UNSPECIFIED
,
162 DeviceExtension
->PreparsedData
,
163 DeviceExtension
->Report
,
164 DeviceExtension
->ReportLength
);
166 /* FIXME handle error */
167 ASSERT(Status
== HIDP_STATUS_SUCCESS
);
169 /* absolute pointing devices values need be in range 0 - 0xffff */
170 ASSERT(DeviceExtension
->ValueCapsY
.LogicalMax
> 0);
171 ASSERT(DeviceExtension
->ValueCapsY
.LogicalMax
> DeviceExtension
->ValueCapsY
.LogicalMin
);
173 /* convert to logical range */
174 *LastY
= (ValueY
* VIRTUAL_SCREEN_SIZE_Y
) / DeviceExtension
->ValueCapsY
.LogicalMax
;
179 MouHid_GetButtonFlags(
180 IN PMOUHID_DEVICE_EXTENSION DeviceExtension
,
181 OUT PUSHORT ButtonFlags
,
188 ULONG CurrentUsageListLength
;
195 CurrentUsageListLength
= DeviceExtension
->UsageListLength
;
196 Status
= HidP_GetUsages(HidP_Input
,
197 HID_USAGE_PAGE_BUTTON
,
198 HIDP_LINK_COLLECTION_UNSPECIFIED
,
199 DeviceExtension
->CurrentUsageList
,
200 &CurrentUsageListLength
,
201 DeviceExtension
->PreparsedData
,
202 DeviceExtension
->Report
,
203 DeviceExtension
->ReportLength
);
204 if (Status
!= HIDP_STATUS_SUCCESS
)
206 DPRINT1("MouHid_GetButtonFlags failed to get usages with %x\n", Status
);
210 /* extract usage list difference */
211 Status
= HidP_UsageListDifference(DeviceExtension
->PreviousUsageList
,
212 DeviceExtension
->CurrentUsageList
,
213 DeviceExtension
->BreakUsageList
,
214 DeviceExtension
->MakeUsageList
,
215 DeviceExtension
->UsageListLength
);
216 if (Status
!= HIDP_STATUS_SUCCESS
)
218 DPRINT1("MouHid_GetButtonFlags failed to get usages with %x\n", Status
);
222 if (DeviceExtension
->UsageListLength
)
228 Usage
= DeviceExtension
->BreakUsageList
[Index
];
234 /* max 5 buttons supported */
235 *ButtonFlags
|= MouHid_ButtonDownFlags
[Usage
];
238 /* move to next index*/
240 }while(Index
< DeviceExtension
->UsageListLength
);
243 if (DeviceExtension
->UsageListLength
)
249 Usage
= DeviceExtension
->MakeUsageList
[Index
];
255 /* max 5 buttons supported */
256 *ButtonFlags
|= MouHid_ButtonUpFlags
[Usage
];
259 /* move to next index*/
261 }while(Index
< DeviceExtension
->UsageListLength
);
264 /* now switch the previous list with current list */
265 TempList
= DeviceExtension
->CurrentUsageList
;
266 DeviceExtension
->CurrentUsageList
= DeviceExtension
->PreviousUsageList
;
267 DeviceExtension
->PreviousUsageList
= TempList
;
269 if (DeviceExtension
->MouseAbsolute
)
271 // mouse operates absolute
272 *Flags
|= MOUSE_MOVE_ABSOLUTE
;
277 MouHid_DispatchInputData(
278 IN PMOUHID_DEVICE_EXTENSION DeviceExtension
,
279 IN PMOUSE_INPUT_DATA InputData
)
282 ULONG InputDataConsumed
;
284 if (!DeviceExtension
->ClassService
)
288 ASSERT(DeviceExtension
->ClassService
);
289 ASSERT(DeviceExtension
->ClassDeviceObject
);
292 KeRaiseIrql(DISPATCH_LEVEL
, &OldIrql
);
294 /* dispatch input data */
295 (*(PSERVICE_CALLBACK_ROUTINE
)DeviceExtension
->ClassService
)(DeviceExtension
->ClassDeviceObject
, InputData
, InputData
+ 1, &InputDataConsumed
);
297 /* lower irql to previous level */
298 KeLowerIrql(OldIrql
);
303 MouHid_ReadCompletion(
304 IN PDEVICE_OBJECT DeviceObject
,
308 PMOUHID_DEVICE_EXTENSION DeviceExtension
;
313 MOUSE_INPUT_DATA MouseInputData
;
316 /* get device extension */
317 DeviceExtension
= Context
;
319 if (Irp
->IoStatus
.Status
== STATUS_PRIVILEGE_NOT_HELD
||
320 Irp
->IoStatus
.Status
== STATUS_DEVICE_NOT_CONNECTED
||
321 Irp
->IoStatus
.Status
== STATUS_CANCELLED
||
322 DeviceExtension
->StopReadReport
)
324 /* failed to read or should be stopped*/
325 DPRINT1("[MOUHID] ReadCompletion terminating read Status %x\n", Irp
->IoStatus
.Status
);
327 /* report no longer active */
328 DeviceExtension
->ReadReportActive
= FALSE
;
330 /* request stopping of the report cycle */
331 DeviceExtension
->StopReadReport
= FALSE
;
333 /* signal completion event */
334 KeSetEvent(&DeviceExtension
->ReadCompletionEvent
, 0, 0);
335 return STATUS_MORE_PROCESSING_REQUIRED
;
338 /* get mouse change */
339 MouHid_GetButtonMove(DeviceExtension
, &LastX
, &LastY
);
341 /* get mouse change flags */
342 MouHid_GetButtonFlags(DeviceExtension
, &ButtonFlags
, &Flags
);
344 /* init input data */
345 RtlZeroMemory(&MouseInputData
, sizeof(MOUSE_INPUT_DATA
));
347 /* init input data */
348 MouseInputData
.ButtonFlags
= ButtonFlags
;
349 MouseInputData
.Flags
= Flags
;
350 MouseInputData
.LastX
= LastX
;
351 MouseInputData
.LastY
= LastY
;
353 /* detect mouse wheel change */
354 if (DeviceExtension
->MouseIdentifier
== WHEELMOUSE_HID_HARDWARE
)
358 Status
= HidP_GetScaledUsageValue(HidP_Input
,
359 HID_USAGE_PAGE_GENERIC
,
360 HIDP_LINK_COLLECTION_UNSPECIFIED
,
361 HID_USAGE_GENERIC_WHEEL
,
363 DeviceExtension
->PreparsedData
,
364 DeviceExtension
->Report
,
365 DeviceExtension
->ReportLength
);
366 if (Status
== HIDP_STATUS_SUCCESS
&& UsageValue
!= 0)
368 /* store wheel status */
369 MouseInputData
.ButtonFlags
|= MOUSE_WHEEL
;
370 MouseInputData
.ButtonData
= (USHORT
)(UsageValue
* WHEEL_DELTA
);
374 DPRINT("[MOUHID] failed to get wheel status with %x\n", Status
);
378 DPRINT("[MOUHID] ReportData %02x %02x %02x %02x %02x %02x %02x\n",
379 DeviceExtension
->Report
[0] & 0xFF,
380 DeviceExtension
->Report
[1] & 0xFF, DeviceExtension
->Report
[2] & 0xFF,
381 DeviceExtension
->Report
[3] & 0xFF, DeviceExtension
->Report
[4] & 0xFF,
382 DeviceExtension
->Report
[5] & 0xFF, DeviceExtension
->Report
[6] & 0xFF);
384 DPRINT("[MOUHID] LastX %ld LastY %ld Flags %x ButtonFlags %x ButtonData %x\n", MouseInputData
.LastX
, MouseInputData
.LastY
, MouseInputData
.Flags
, MouseInputData
.ButtonFlags
, MouseInputData
.ButtonData
);
386 /* dispatch mouse action */
387 MouHid_DispatchInputData(DeviceExtension
, &MouseInputData
);
390 MouHid_InitiateRead(DeviceExtension
);
392 /* stop completion */
393 return STATUS_MORE_PROCESSING_REQUIRED
;
398 IN PMOUHID_DEVICE_EXTENSION DeviceExtension
)
400 PIO_STACK_LOCATION IoStack
;
404 IoReuseIrp(DeviceExtension
->Irp
, STATUS_SUCCESS
);
407 DeviceExtension
->Irp
->MdlAddress
= DeviceExtension
->ReportMDL
;
409 /* get next stack location */
410 IoStack
= IoGetNextIrpStackLocation(DeviceExtension
->Irp
);
412 /* init stack location */
413 IoStack
->Parameters
.Read
.Length
= DeviceExtension
->ReportLength
;
414 IoStack
->Parameters
.Read
.Key
= 0;
415 IoStack
->Parameters
.Read
.ByteOffset
.QuadPart
= 0LL;
416 IoStack
->MajorFunction
= IRP_MJ_READ
;
417 IoStack
->FileObject
= DeviceExtension
->FileObject
;
419 /* set completion routine */
420 IoSetCompletionRoutine(DeviceExtension
->Irp
, MouHid_ReadCompletion
, DeviceExtension
, TRUE
, TRUE
, TRUE
);
423 DeviceExtension
->ReadReportActive
= TRUE
;
426 Status
= IoCallDriver(DeviceExtension
->NextDeviceObject
, DeviceExtension
->Irp
);
434 MouHid_CreateCompletion(
435 IN PDEVICE_OBJECT DeviceObject
,
439 KeSetEvent(Context
, 0, FALSE
);
440 return STATUS_MORE_PROCESSING_REQUIRED
;
447 IN PDEVICE_OBJECT DeviceObject
,
450 PIO_STACK_LOCATION IoStack
;
453 PMOUHID_DEVICE_EXTENSION DeviceExtension
;
455 DPRINT("MOUHID: IRP_MJ_CREATE\n");
457 /* get device extension */
458 DeviceExtension
= DeviceObject
->DeviceExtension
;
460 /* get stack location */
461 IoStack
= IoGetCurrentIrpStackLocation(Irp
);
463 /* copy stack location to next */
464 IoCopyCurrentIrpStackLocationToNext(Irp
);
467 KeInitializeEvent(&Event
, NotificationEvent
, FALSE
);
470 IoSetCompletionRoutine(Irp
, MouHid_CreateCompletion
, &Event
, TRUE
, TRUE
, TRUE
);
472 /* call lower driver */
473 Status
= IoCallDriver(DeviceExtension
->NextDeviceObject
, Irp
);
474 if (Status
== STATUS_PENDING
)
476 /* request pending */
477 KeWaitForSingleObject(&Event
, Executive
, KernelMode
, FALSE
, NULL
);
480 /* check for success */
481 if (!NT_SUCCESS(Status
))
484 Irp
->IoStatus
.Status
= Status
;
485 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
489 /* is the driver already in use */
490 if (DeviceExtension
->FileObject
== NULL
)
492 /* did the caller specify correct attributes */
493 ASSERT(IoStack
->Parameters
.Create
.SecurityContext
);
494 if (IoStack
->Parameters
.Create
.SecurityContext
->DesiredAccess
)
496 /* store file object */
497 DeviceExtension
->FileObject
= IoStack
->FileObject
;
500 KeResetEvent(&DeviceExtension
->ReadCompletionEvent
);
502 /* initiating read */
503 Status
= MouHid_InitiateRead(DeviceExtension
);
504 DPRINT("[MOUHID] MouHid_InitiateRead: status %x\n", Status
);
505 if (Status
== STATUS_PENDING
)
507 /* report irp is pending */
508 Status
= STATUS_SUCCESS
;
513 /* complete request */
514 Irp
->IoStatus
.Status
= Status
;
515 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
523 IN PDEVICE_OBJECT DeviceObject
,
526 PMOUHID_DEVICE_EXTENSION DeviceExtension
;
528 /* get device extension */
529 DeviceExtension
= DeviceObject
->DeviceExtension
;
531 DPRINT("[MOUHID] IRP_MJ_CLOSE ReadReportActive %x\n", DeviceExtension
->ReadReportActive
);
533 if (DeviceExtension
->ReadReportActive
)
535 /* request stopping of the report cycle */
536 DeviceExtension
->StopReadReport
= TRUE
;
538 /* wait until the reports have been read */
539 KeWaitForSingleObject(&DeviceExtension
->ReadCompletionEvent
, Executive
, KernelMode
, FALSE
, NULL
);
542 IoCancelIrp(DeviceExtension
->Irp
);
545 DPRINT("[MOUHID] IRP_MJ_CLOSE ReadReportActive %x\n", DeviceExtension
->ReadReportActive
);
547 /* remove file object */
548 DeviceExtension
->FileObject
= NULL
;
551 IoSkipCurrentIrpStackLocation(Irp
);
553 /* pass irp to down the stack */
554 return IoCallDriver(DeviceExtension
->NextDeviceObject
, Irp
);
559 MouHid_InternalDeviceControl(
560 IN PDEVICE_OBJECT DeviceObject
,
563 PIO_STACK_LOCATION IoStack
;
564 PMOUSE_ATTRIBUTES Attributes
;
565 PMOUHID_DEVICE_EXTENSION DeviceExtension
;
568 /* get current stack location */
569 IoStack
= IoGetCurrentIrpStackLocation(Irp
);
571 DPRINT("[MOUHID] InternalDeviceControl %x\n", IoStack
->Parameters
.DeviceIoControl
.IoControlCode
);
573 /* get device extension */
574 DeviceExtension
= DeviceObject
->DeviceExtension
;
576 /* handle requests */
577 switch (IoStack
->Parameters
.DeviceIoControl
.IoControlCode
)
579 case IOCTL_MOUSE_QUERY_ATTRIBUTES
:
580 /* verify output buffer length */
581 if (IoStack
->Parameters
.DeviceIoControl
.OutputBufferLength
< sizeof(MOUSE_ATTRIBUTES
))
583 /* invalid request */
584 DPRINT1("[MOUHID] IOCTL_MOUSE_QUERY_ATTRIBUTES Buffer too small\n");
585 Irp
->IoStatus
.Status
= STATUS_BUFFER_TOO_SMALL
;
586 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
587 return STATUS_BUFFER_TOO_SMALL
;
590 /* get output buffer */
591 Attributes
= Irp
->AssociatedIrp
.SystemBuffer
;
594 Attributes
->MouseIdentifier
= DeviceExtension
->MouseIdentifier
;
596 /* number of buttons */
597 Attributes
->NumberOfButtons
= DeviceExtension
->UsageListLength
;
599 /* sample rate not used for usb */
600 Attributes
->SampleRate
= 0;
603 Attributes
->InputDataQueueLength
= 2;
605 DPRINT("[MOUHID] MouseIdentifier %x\n", Attributes
->MouseIdentifier
);
606 DPRINT("[MOUHID] NumberOfButtons %x\n", Attributes
->NumberOfButtons
);
607 DPRINT("[MOUHID] SampleRate %x\n", Attributes
->SampleRate
);
608 DPRINT("[MOUHID] InputDataQueueLength %x\n", Attributes
->InputDataQueueLength
);
610 /* complete request */
611 Irp
->IoStatus
.Information
= sizeof(MOUSE_ATTRIBUTES
);
612 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
613 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
614 return STATUS_SUCCESS
;
616 case IOCTL_INTERNAL_MOUSE_CONNECT
:
617 /* verify input buffer length */
618 if (IoStack
->Parameters
.DeviceIoControl
.InputBufferLength
< sizeof(CONNECT_DATA
))
620 /* invalid request */
621 Irp
->IoStatus
.Status
= STATUS_INVALID_PARAMETER
;
622 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
623 return STATUS_INVALID_PARAMETER
;
626 /* is it already connected */
627 if (DeviceExtension
->ClassService
)
629 /* already connected */
630 Irp
->IoStatus
.Status
= STATUS_SHARING_VIOLATION
;
631 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
632 return STATUS_SHARING_VIOLATION
;
635 /* get connect data */
636 Data
= IoStack
->Parameters
.DeviceIoControl
.Type3InputBuffer
;
638 /* store connect details */
639 DeviceExtension
->ClassDeviceObject
= Data
->ClassDeviceObject
;
640 DeviceExtension
->ClassService
= Data
->ClassService
;
642 /* completed successfully */
643 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
644 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
645 return STATUS_SUCCESS
;
647 case IOCTL_INTERNAL_MOUSE_DISCONNECT
:
649 Irp
->IoStatus
.Status
= STATUS_NOT_IMPLEMENTED
;
650 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
651 return STATUS_NOT_IMPLEMENTED
;
653 case IOCTL_INTERNAL_MOUSE_ENABLE
:
655 Irp
->IoStatus
.Status
= STATUS_NOT_SUPPORTED
;
656 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
657 return STATUS_NOT_SUPPORTED
;
659 case IOCTL_INTERNAL_MOUSE_DISABLE
:
661 Irp
->IoStatus
.Status
= STATUS_INVALID_DEVICE_REQUEST
;
662 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
663 return STATUS_INVALID_DEVICE_REQUEST
;
666 DPRINT1("[MOUHID] Unknown DeviceControl %x\n", IoStack
->Parameters
.DeviceIoControl
.IoControlCode
);
667 /* unknown request not supported */
668 Irp
->IoStatus
.Status
= STATUS_NOT_SUPPORTED
;
669 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
670 return STATUS_NOT_SUPPORTED
;
675 MouHid_DeviceControl(
676 IN PDEVICE_OBJECT DeviceObject
,
679 PMOUHID_DEVICE_EXTENSION DeviceExtension
;
681 /* get device extension */
682 DeviceExtension
= DeviceObject
->DeviceExtension
;
684 /* skip stack location */
685 IoSkipCurrentIrpStackLocation(Irp
);
687 /* pass and forget */
688 return IoCallDriver(DeviceExtension
->NextDeviceObject
, Irp
);
694 IN PDEVICE_OBJECT DeviceObject
,
697 PMOUHID_DEVICE_EXTENSION DeviceExtension
;
699 DeviceExtension
= DeviceObject
->DeviceExtension
;
700 PoStartNextPowerIrp(Irp
);
701 IoSkipCurrentIrpStackLocation(Irp
);
702 return PoCallDriver(DeviceExtension
->NextDeviceObject
, Irp
);
707 MouHid_SystemControl(
708 IN PDEVICE_OBJECT DeviceObject
,
711 PMOUHID_DEVICE_EXTENSION DeviceExtension
;
713 DeviceExtension
= DeviceObject
->DeviceExtension
;
714 IoSkipCurrentIrpStackLocation(Irp
);
715 return IoCallDriver(DeviceExtension
->NextDeviceObject
, Irp
);
719 MouHid_SubmitRequest(
720 PDEVICE_OBJECT DeviceObject
,
722 ULONG InputBufferSize
,
724 ULONG OutputBufferSize
,
728 PMOUHID_DEVICE_EXTENSION DeviceExtension
;
731 IO_STATUS_BLOCK IoStatus
;
733 /* get device extension */
734 DeviceExtension
= DeviceObject
->DeviceExtension
;
737 KeInitializeEvent(&Event
, NotificationEvent
, FALSE
);
740 Irp
= IoBuildDeviceIoControlRequest(IoControlCode
,
741 DeviceExtension
->NextDeviceObject
,
752 return STATUS_INSUFFICIENT_RESOURCES
;
756 Status
= IoCallDriver(DeviceExtension
->NextDeviceObject
, Irp
);
757 if (Status
== STATUS_PENDING
)
759 /* wait for request to complete */
760 KeWaitForSingleObject(&Event
, Executive
, KernelMode
, FALSE
, NULL
);
761 Status
= IoStatus
.Status
;
771 IN PDEVICE_OBJECT DeviceObject
)
775 HID_COLLECTION_INFORMATION Information
;
777 HIDP_CAPS Capabilities
;
778 USHORT ValueCapsLength
;
779 HIDP_VALUE_CAPS ValueCaps
;
780 PMOUHID_DEVICE_EXTENSION DeviceExtension
;
783 /* get device extension */
784 DeviceExtension
= DeviceObject
->DeviceExtension
;
786 /* query collection information */
787 Status
= MouHid_SubmitRequest(DeviceObject
,
788 IOCTL_HID_GET_COLLECTION_INFORMATION
,
791 sizeof(HID_COLLECTION_INFORMATION
),
793 if (!NT_SUCCESS(Status
))
795 /* failed to query collection information */
796 DPRINT1("[MOUHID] failed to obtain collection information with %x\n", Status
);
800 /* lets allocate space for preparsed data */
801 PreparsedData
= ExAllocatePoolWithTag(NonPagedPool
, Information
.DescriptorSize
, MOUHID_TAG
);
805 DPRINT1("[MOUHID] no memory size %u\n", Information
.DescriptorSize
);
806 return STATUS_INSUFFICIENT_RESOURCES
;
809 /* now obtain the preparsed data */
810 Status
= MouHid_SubmitRequest(DeviceObject
,
811 IOCTL_HID_GET_COLLECTION_DESCRIPTOR
,
814 Information
.DescriptorSize
,
816 if (!NT_SUCCESS(Status
))
818 /* failed to get preparsed data */
819 DPRINT1("[MOUHID] failed to obtain collection information with %x\n", Status
);
820 ExFreePoolWithTag(PreparsedData
, MOUHID_TAG
);
824 /* lets get the caps */
825 Status
= HidP_GetCaps(PreparsedData
, &Capabilities
);
826 if (Status
!= HIDP_STATUS_SUCCESS
)
828 /* failed to get capabilities */
829 DPRINT1("[MOUHID] failed to obtain caps with %x\n", Status
);
830 ExFreePoolWithTag(PreparsedData
, MOUHID_TAG
);
834 DPRINT("[MOUHID] Usage %x UsagePage %x InputReportLength %lu\n", Capabilities
.Usage
, Capabilities
.UsagePage
, Capabilities
.InputReportByteLength
);
836 /* verify capabilities */
837 if ((Capabilities
.Usage
!= HID_USAGE_GENERIC_POINTER
&& Capabilities
.Usage
!= HID_USAGE_GENERIC_MOUSE
) || Capabilities
.UsagePage
!= HID_USAGE_PAGE_GENERIC
)
840 ExFreePoolWithTag(PreparsedData
, MOUHID_TAG
);
841 return STATUS_UNSUCCESSFUL
;
844 /* init input report */
845 DeviceExtension
->ReportLength
= Capabilities
.InputReportByteLength
;
846 ASSERT(DeviceExtension
->ReportLength
);
847 DeviceExtension
->Report
= ExAllocatePoolWithTag(NonPagedPool
, DeviceExtension
->ReportLength
, MOUHID_TAG
);
848 ASSERT(DeviceExtension
->Report
);
849 RtlZeroMemory(DeviceExtension
->Report
, DeviceExtension
->ReportLength
);
852 DeviceExtension
->ReportMDL
= IoAllocateMdl(DeviceExtension
->Report
,
853 DeviceExtension
->ReportLength
,
857 ASSERT(DeviceExtension
->ReportMDL
);
860 MmBuildMdlForNonPagedPool(DeviceExtension
->ReportMDL
);
862 /* get max number of buttons */
863 Buttons
= HidP_MaxUsageListLength(HidP_Input
,
864 HID_USAGE_PAGE_BUTTON
,
866 DPRINT("[MOUHID] Buttons %lu\n", Buttons
);
869 /* now allocate an array for those buttons */
870 Buffer
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(USAGE
) * 4 * Buttons
, MOUHID_TAG
);
874 ExFreePoolWithTag(PreparsedData
, MOUHID_TAG
);
875 return STATUS_INSUFFICIENT_RESOURCES
;
877 DeviceExtension
->UsageListBuffer
= Buffer
;
879 /* init usage lists */
880 RtlZeroMemory(Buffer
, sizeof(USAGE
) * 4 * Buttons
);
881 DeviceExtension
->CurrentUsageList
= Buffer
;
883 DeviceExtension
->PreviousUsageList
= Buffer
;
885 DeviceExtension
->MakeUsageList
= Buffer
;
887 DeviceExtension
->BreakUsageList
= Buffer
;
889 /* store number of buttons */
890 DeviceExtension
->UsageListLength
= (USHORT
)Buttons
;
892 /* store preparsed data */
893 DeviceExtension
->PreparsedData
= PreparsedData
;
896 HidP_GetSpecificValueCaps(HidP_Input
,
897 HID_USAGE_PAGE_GENERIC
,
898 HIDP_LINK_COLLECTION_UNSPECIFIED
,
900 &DeviceExtension
->ValueCapsX
,
905 HidP_GetSpecificValueCaps(HidP_Input
,
906 HID_USAGE_PAGE_GENERIC
,
907 HIDP_LINK_COLLECTION_UNSPECIFIED
,
909 &DeviceExtension
->ValueCapsY
,
913 /* now check for wheel mouse support */
915 Status
= HidP_GetSpecificValueCaps(HidP_Input
,
916 HID_USAGE_PAGE_GENERIC
,
917 HIDP_LINK_COLLECTION_UNSPECIFIED
,
918 HID_USAGE_GENERIC_WHEEL
,
922 if (Status
== HIDP_STATUS_SUCCESS
)
924 /* mouse has wheel support */
925 DeviceExtension
->MouseIdentifier
= WHEELMOUSE_HID_HARDWARE
;
926 DeviceExtension
->WheelUsagePage
= ValueCaps
.UsagePage
;
927 DPRINT("[MOUHID] mouse wheel support detected\n", Status
);
931 /* check if the mouse has z-axis */
933 Status
= HidP_GetSpecificValueCaps(HidP_Input
,
934 HID_USAGE_PAGE_GENERIC
,
935 HIDP_LINK_COLLECTION_UNSPECIFIED
,
940 if (Status
== HIDP_STATUS_SUCCESS
&& ValueCapsLength
== 1)
943 DeviceExtension
->MouseIdentifier
= WHEELMOUSE_HID_HARDWARE
;
944 DeviceExtension
->WheelUsagePage
= ValueCaps
.UsagePage
;
945 DPRINT("[MOUHID] mouse wheel support detected with z-axis\n", Status
);
949 /* check if mice is absolute */
950 if (DeviceExtension
->ValueCapsY
.LogicalMax
> DeviceExtension
->ValueCapsY
.LogicalMin
||
951 DeviceExtension
->ValueCapsX
.LogicalMax
> DeviceExtension
->ValueCapsX
.LogicalMin
)
953 /* mice is absolute */
954 DeviceExtension
->MouseAbsolute
= TRUE
;
957 /* completed successfully */
958 return STATUS_SUCCESS
;
963 MouHid_StartDeviceCompletion(
964 IN PDEVICE_OBJECT DeviceObject
,
968 KeSetEvent(Context
, 0, FALSE
);
969 return STATUS_MORE_PROCESSING_REQUIRED
;
974 MouHid_FreeResources(
975 IN PDEVICE_OBJECT DeviceObject
)
977 PMOUHID_DEVICE_EXTENSION DeviceExtension
;
979 /* get device extension */
980 DeviceExtension
= DeviceObject
->DeviceExtension
;
983 if (DeviceExtension
->PreparsedData
)
985 ExFreePoolWithTag(DeviceExtension
->PreparsedData
, MOUHID_TAG
);
986 DeviceExtension
->PreparsedData
= NULL
;
989 if (DeviceExtension
->UsageListBuffer
)
991 ExFreePoolWithTag(DeviceExtension
->UsageListBuffer
, MOUHID_TAG
);
992 DeviceExtension
->UsageListBuffer
= NULL
;
993 DeviceExtension
->CurrentUsageList
= NULL
;
994 DeviceExtension
->PreviousUsageList
= NULL
;
995 DeviceExtension
->MakeUsageList
= NULL
;
996 DeviceExtension
->BreakUsageList
= NULL
;
999 if (DeviceExtension
->ReportMDL
)
1001 IoFreeMdl(DeviceExtension
->ReportMDL
);
1002 DeviceExtension
->ReportMDL
= NULL
;
1005 if (DeviceExtension
->Report
)
1007 ExFreePoolWithTag(DeviceExtension
->Report
, MOUHID_TAG
);
1008 DeviceExtension
->Report
= NULL
;
1011 return STATUS_SUCCESS
;
1017 IN PDEVICE_OBJECT DeviceObject
,
1020 PIO_STACK_LOCATION IoStack
;
1021 PMOUHID_DEVICE_EXTENSION DeviceExtension
;
1023 /* get device extension */
1024 DeviceExtension
= DeviceObject
->DeviceExtension
;
1026 /* skip current stack location */
1027 IoSkipCurrentIrpStackLocation(Irp
);
1029 /* get next stack location */
1030 IoStack
= IoGetNextIrpStackLocation(Irp
);
1032 /* change request to hid flush queue request */
1033 IoStack
->MajorFunction
= IRP_MJ_DEVICE_CONTROL
;
1034 IoStack
->Parameters
.DeviceIoControl
.IoControlCode
= IOCTL_HID_FLUSH_QUEUE
;
1037 return IoCallDriver(DeviceExtension
->NextDeviceObject
, Irp
);
1043 IN PDEVICE_OBJECT DeviceObject
,
1046 PIO_STACK_LOCATION IoStack
;
1049 PMOUHID_DEVICE_EXTENSION DeviceExtension
;
1051 /* get device extension */
1052 DeviceExtension
= DeviceObject
->DeviceExtension
;
1054 /* get current irp stack */
1055 IoStack
= IoGetCurrentIrpStackLocation(Irp
);
1056 DPRINT("[MOUHID] IRP_MJ_PNP Request: %x\n", IoStack
->MinorFunction
);
1058 switch (IoStack
->MinorFunction
)
1060 case IRP_MN_STOP_DEVICE
:
1061 case IRP_MN_SURPRISE_REMOVAL
:
1062 /* free resources */
1063 MouHid_FreeResources(DeviceObject
);
1064 case IRP_MN_CANCEL_REMOVE_DEVICE
:
1065 case IRP_MN_QUERY_STOP_DEVICE
:
1066 case IRP_MN_CANCEL_STOP_DEVICE
:
1067 case IRP_MN_QUERY_REMOVE_DEVICE
:
1068 /* indicate success */
1069 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
1071 /* skip irp stack location */
1072 IoSkipCurrentIrpStackLocation(Irp
);
1074 /* dispatch to lower device */
1075 return IoCallDriver(DeviceExtension
->NextDeviceObject
, Irp
);
1077 case IRP_MN_REMOVE_DEVICE
:
1078 /* FIXME synchronization */
1081 DeviceExtension
->StopReadReport
= TRUE
;
1084 IoCancelIrp(DeviceExtension
->Irp
);
1086 /* free resources */
1087 MouHid_FreeResources(DeviceObject
);
1089 /* indicate success */
1090 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
1092 /* skip irp stack location */
1093 IoSkipCurrentIrpStackLocation(Irp
);
1095 /* dispatch to lower device */
1096 Status
= IoCallDriver(DeviceExtension
->NextDeviceObject
, Irp
);
1098 /* wait for completion of stop event */
1099 KeWaitForSingleObject(&DeviceExtension
->ReadCompletionEvent
, Executive
, KernelMode
, FALSE
, NULL
);
1102 IoFreeIrp(DeviceExtension
->Irp
);
1105 IoDetachDevice(DeviceExtension
->NextDeviceObject
);
1108 IoDeleteDevice(DeviceObject
);
1113 case IRP_MN_START_DEVICE
:
1115 KeInitializeEvent(&Event
, NotificationEvent
, FALSE
);
1117 /* copy stack location */
1118 IoCopyCurrentIrpStackLocationToNext (Irp
);
1120 /* set completion routine */
1121 IoSetCompletionRoutine(Irp
, MouHid_StartDeviceCompletion
, &Event
, TRUE
, TRUE
, TRUE
);
1122 Irp
->IoStatus
.Status
= 0;
1125 Status
= IoCallDriver(DeviceExtension
->NextDeviceObject
, Irp
);
1126 if (Status
== STATUS_PENDING
)
1128 KeWaitForSingleObject(&Event
, Executive
, KernelMode
, FALSE
, NULL
);
1129 Status
= Irp
->IoStatus
.Status
;
1132 if (!NT_SUCCESS(Status
))
1135 Irp
->IoStatus
.Status
= Status
;
1136 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
1140 /* lets start the device */
1141 Status
= MouHid_StartDevice(DeviceObject
);
1142 DPRINT("MouHid_StartDevice %x\n", Status
);
1144 /* complete request */
1145 Irp
->IoStatus
.Status
= Status
;
1146 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
1152 /* skip irp stack location */
1153 IoSkipCurrentIrpStackLocation(Irp
);
1155 /* dispatch to lower device */
1156 return IoCallDriver(DeviceExtension
->NextDeviceObject
, Irp
);
1163 IN PDRIVER_OBJECT DriverObject
,
1164 IN PDEVICE_OBJECT PhysicalDeviceObject
)
1167 PDEVICE_OBJECT DeviceObject
, NextDeviceObject
;
1168 PMOUHID_DEVICE_EXTENSION DeviceExtension
;
1171 /* create device object */
1172 Status
= IoCreateDevice(DriverObject
,
1173 sizeof(MOUHID_DEVICE_EXTENSION
),
1179 if (!NT_SUCCESS(Status
))
1181 /* failed to create device object */
1186 NextDeviceObject
= IoAttachDeviceToDeviceStack(DeviceObject
, PhysicalDeviceObject
);
1187 if (!NextDeviceObject
)
1189 /* failed to attach */
1190 IoDeleteDevice(DeviceObject
);
1191 return STATUS_DEVICE_NOT_CONNECTED
;
1194 /* get device extension */
1195 DeviceExtension
= DeviceObject
->DeviceExtension
;
1197 /* zero extension */
1198 RtlZeroMemory(DeviceExtension
, sizeof(MOUHID_DEVICE_EXTENSION
));
1200 /* init device extension */
1201 DeviceExtension
->MouseIdentifier
= MOUSE_HID_HARDWARE
;
1202 DeviceExtension
->WheelUsagePage
= 0;
1203 DeviceExtension
->NextDeviceObject
= NextDeviceObject
;
1204 KeInitializeEvent(&DeviceExtension
->ReadCompletionEvent
, NotificationEvent
, FALSE
);
1205 DeviceExtension
->Irp
= IoAllocateIrp(NextDeviceObject
->StackSize
, FALSE
);
1207 /* FIXME handle allocation error */
1208 ASSERT(DeviceExtension
->Irp
);
1210 /* FIXME query parameter 'FlipFlopWheel', 'WheelScalingFactor' */
1212 /* set power state to D0 */
1213 State
.DeviceState
= PowerDeviceD0
;
1214 PoSetPowerState(DeviceObject
, DevicePowerState
, State
);
1216 /* init device object */
1217 DeviceObject
->Flags
|= DO_BUFFERED_IO
| DO_POWER_PAGABLE
;
1218 DeviceObject
->Flags
&= ~DO_DEVICE_INITIALIZING
;
1220 /* completed successfully */
1221 return STATUS_SUCCESS
;
1227 IN PDRIVER_OBJECT DriverObject
)
1236 IN PDRIVER_OBJECT DriverObject
,
1237 IN PUNICODE_STRING RegPath
)
1239 /* FIXME check for parameters 'UseOnlyMice', 'TreatAbsoluteAsRelative', 'TreatAbsolutePointerAsAbsolute' */
1241 /* initialize driver object */
1242 DriverObject
->MajorFunction
[IRP_MJ_CREATE
] = MouHid_Create
;
1243 DriverObject
->MajorFunction
[IRP_MJ_CLOSE
] = MouHid_Close
;
1244 DriverObject
->MajorFunction
[IRP_MJ_FLUSH_BUFFERS
] = MouHid_Flush
;
1245 DriverObject
->MajorFunction
[IRP_MJ_DEVICE_CONTROL
] = MouHid_DeviceControl
;
1246 DriverObject
->MajorFunction
[IRP_MJ_INTERNAL_DEVICE_CONTROL
] = MouHid_InternalDeviceControl
;
1247 DriverObject
->MajorFunction
[IRP_MJ_POWER
] = MouHid_Power
;
1248 DriverObject
->MajorFunction
[IRP_MJ_PNP
] = MouHid_Pnp
;
1249 DriverObject
->MajorFunction
[IRP_MJ_SYSTEM_CONTROL
] = MouHid_SystemControl
;
1250 DriverObject
->DriverUnload
= MouHid_Unload
;
1251 DriverObject
->DriverExtension
->AddDevice
= MouHid_AddDevice
;
1254 return STATUS_SUCCESS
;