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
,
45 /* get scaled usage value x */
46 Status
= HidP_GetScaledUsageValue(HidP_Input
, HID_USAGE_PAGE_GENERIC
, HIDP_LINK_COLLECTION_UNSPECIFIED
, HID_USAGE_GENERIC_X
, (PLONG
)LastX
, DeviceExtension
->PreparsedData
, DeviceExtension
->Report
, DeviceExtension
->ReportLength
);
47 /* FIXME handle error */
48 ASSERT(Status
== HIDP_STATUS_SUCCESS
);
50 /* get scaled usage value y */
51 Status
= HidP_GetScaledUsageValue(HidP_Input
, HID_USAGE_PAGE_GENERIC
, HIDP_LINK_COLLECTION_UNSPECIFIED
, HID_USAGE_GENERIC_Y
, (PLONG
)LastY
, DeviceExtension
->PreparsedData
, DeviceExtension
->Report
, DeviceExtension
->ReportLength
);
52 /* FIXME handle error */
53 ASSERT(Status
== HIDP_STATUS_SUCCESS
);
59 MouHid_GetButtonFlags(
60 IN PMOUHID_DEVICE_EXTENSION DeviceExtension
,
61 OUT PUSHORT ButtonFlags
)
67 ULONG CurrentUsageListLength
;
73 CurrentUsageListLength
= DeviceExtension
->UsageListLength
;
74 Status
= HidP_GetUsages(HidP_Input
, HID_USAGE_PAGE_BUTTON
, HIDP_LINK_COLLECTION_UNSPECIFIED
, DeviceExtension
->CurrentUsageList
, &CurrentUsageListLength
, DeviceExtension
->PreparsedData
, DeviceExtension
->Report
, DeviceExtension
->ReportLength
);
75 if (Status
!= HIDP_STATUS_SUCCESS
)
77 DPRINT1("MouHid_GetButtonFlags failed to get usages with %x\n", Status
);
81 /* extract usage list difference */
82 Status
= HidP_UsageListDifference(DeviceExtension
->PreviousUsageList
, DeviceExtension
->CurrentUsageList
, DeviceExtension
->BreakUsageList
, DeviceExtension
->MakeUsageList
, DeviceExtension
->UsageListLength
);
83 if (Status
!= HIDP_STATUS_SUCCESS
)
85 DPRINT1("MouHid_GetButtonFlags failed to get usages with %x\n", Status
);
89 if (DeviceExtension
->UsageListLength
)
95 Usage
= DeviceExtension
->BreakUsageList
[Index
];
101 /* max 5 buttons supported */
102 *ButtonFlags
|= MouHid_ButtonDownFlags
[Usage
];
105 /* move to next index*/
107 }while(Index
< DeviceExtension
->UsageListLength
);
110 if (DeviceExtension
->UsageListLength
)
116 Usage
= DeviceExtension
->MakeUsageList
[Index
];
122 /* max 5 buttons supported */
123 *ButtonFlags
|= MouHid_ButtonUpFlags
[Usage
];
126 /* move to next index*/
128 }while(Index
< DeviceExtension
->UsageListLength
);
131 /* now switch the previous list with current list */
132 TempList
= DeviceExtension
->CurrentUsageList
;
133 DeviceExtension
->CurrentUsageList
= DeviceExtension
->PreviousUsageList
;
134 DeviceExtension
->PreviousUsageList
= TempList
;
138 MouHid_DispatchInputData(
139 IN PMOUHID_DEVICE_EXTENSION DeviceExtension
,
140 IN PMOUSE_INPUT_DATA InputData
)
143 ULONG InputDataConsumed
;
145 if (!DeviceExtension
->ClassService
)
149 ASSERT(DeviceExtension
->ClassService
);
150 ASSERT(DeviceExtension
->ClassDeviceObject
);
153 KeRaiseIrql(DISPATCH_LEVEL
, &OldIrql
);
155 /* dispatch input data */
156 (*(PSERVICE_CALLBACK_ROUTINE
)DeviceExtension
->ClassService
)(DeviceExtension
->ClassDeviceObject
, InputData
, InputData
+ 1, &InputDataConsumed
);
158 /* lower irql to previous level */
159 KeLowerIrql(OldIrql
);
164 MouHid_ReadCompletion(
165 IN PDEVICE_OBJECT DeviceObject
,
169 PMOUHID_DEVICE_EXTENSION DeviceExtension
;
174 MOUSE_INPUT_DATA MouseInputData
;
176 /* get device extension */
177 DeviceExtension
= (PMOUHID_DEVICE_EXTENSION
)Context
;
179 if (Irp
->IoStatus
.Status
== STATUS_PRIVILEGE_NOT_HELD
||
180 Irp
->IoStatus
.Status
== STATUS_DEVICE_NOT_CONNECTED
||
181 Irp
->IoStatus
.Status
== STATUS_CANCELLED
||
182 DeviceExtension
->StopReadReport
)
184 /* failed to read or should be stopped*/
185 DPRINT1("[MOUHID] ReadCompletion terminating read Status %x\n", Irp
->IoStatus
.Status
);
187 /* report no longer active */
188 DeviceExtension
->ReadReportActive
= FALSE
;
190 /* request stopping of the report cycle */
191 DeviceExtension
->StopReadReport
= FALSE
;
193 /* signal completion event */
194 KeSetEvent(&DeviceExtension
->ReadCompletionEvent
, 0, 0);
195 return STATUS_MORE_PROCESSING_REQUIRED
;
198 /* get mouse change flags */
199 MouHid_GetButtonFlags(DeviceExtension
, &ButtonFlags
);
201 /* get mouse change */
202 MouHid_GetButtonMove(DeviceExtension
, &LastX
, &LastY
);
204 /* init input data */
205 RtlZeroMemory(&MouseInputData
, sizeof(MOUSE_INPUT_DATA
));
207 /* init input data */
208 MouseInputData
.ButtonFlags
= ButtonFlags
;
209 MouseInputData
.LastX
= LastX
;
210 MouseInputData
.LastY
= LastY
;
212 /* detect mouse wheel change */
213 if (DeviceExtension
->MouseIdentifier
== WHEELMOUSE_HID_HARDWARE
)
217 Status
= HidP_GetScaledUsageValue(HidP_Input
, HID_USAGE_PAGE_GENERIC
, HIDP_LINK_COLLECTION_UNSPECIFIED
, HID_USAGE_GENERIC_WHEEL
, &UsageValue
, DeviceExtension
->PreparsedData
, DeviceExtension
->Report
, DeviceExtension
->ReportLength
);
218 if (Status
== HIDP_STATUS_SUCCESS
&& UsageValue
!= 0)
220 /* store wheel status */
221 MouseInputData
.ButtonFlags
|= MOUSE_WHEEL
;
222 MouseInputData
.ButtonData
= (USHORT
)(UsageValue
* WHEEL_DELTA
);
226 DPRINT("[MOUHID] failed to get wheel status with %x\n", Status
);
230 DPRINT("[MOUHID] LastX %ld LastY %ld Flags %x ButtonData %x\n", MouseInputData
.LastX
, MouseInputData
.LastY
, MouseInputData
.ButtonFlags
, MouseInputData
.ButtonData
);
232 /* dispatch mouse action */
233 MouHid_DispatchInputData(DeviceExtension
, &MouseInputData
);
236 MouHid_InitiateRead(DeviceExtension
);
238 /* stop completion */
239 return STATUS_MORE_PROCESSING_REQUIRED
;
244 IN PMOUHID_DEVICE_EXTENSION DeviceExtension
)
246 PIO_STACK_LOCATION IoStack
;
250 IoReuseIrp(DeviceExtension
->Irp
, STATUS_SUCCESS
);
253 DeviceExtension
->Irp
->MdlAddress
= DeviceExtension
->ReportMDL
;
255 /* get next stack location */
256 IoStack
= IoGetNextIrpStackLocation(DeviceExtension
->Irp
);
258 /* init stack location */
259 IoStack
->Parameters
.Read
.Length
= DeviceExtension
->ReportLength
;
260 IoStack
->Parameters
.Read
.Key
= 0;
261 IoStack
->Parameters
.Read
.ByteOffset
.QuadPart
= 0LL;
262 IoStack
->MajorFunction
= IRP_MJ_READ
;
263 IoStack
->FileObject
= DeviceExtension
->FileObject
;
265 /* set completion routine */
266 IoSetCompletionRoutine(DeviceExtension
->Irp
, MouHid_ReadCompletion
, DeviceExtension
, TRUE
, TRUE
, TRUE
);
269 DeviceExtension
->ReadReportActive
= TRUE
;
272 Status
= IoCallDriver(DeviceExtension
->NextDeviceObject
, DeviceExtension
->Irp
);
280 MouHid_CreateCompletion(
281 IN PDEVICE_OBJECT DeviceObject
,
285 KeSetEvent((PKEVENT
)Context
, 0, FALSE
);
286 return STATUS_MORE_PROCESSING_REQUIRED
;
293 IN PDEVICE_OBJECT DeviceObject
,
296 PIO_STACK_LOCATION IoStack
;
299 PMOUHID_DEVICE_EXTENSION DeviceExtension
;
301 DPRINT1("MOUHID: IRP_MJ_CREATE\n");
303 /* get device extension */
304 DeviceExtension
= (PMOUHID_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
306 /* get stack location */
307 IoStack
= IoGetCurrentIrpStackLocation(Irp
);
309 /* copy stack location to next */
310 IoCopyCurrentIrpStackLocationToNext(Irp
);
313 KeInitializeEvent(&Event
, NotificationEvent
, FALSE
);
316 IoSetCompletionRoutine(Irp
, MouHid_CreateCompletion
, &Event
, TRUE
, TRUE
, TRUE
);
318 /* call lower driver */
319 Status
= IoCallDriver(DeviceExtension
->NextDeviceObject
, Irp
);
320 if (Status
== STATUS_PENDING
)
322 /* request pending */
323 KeWaitForSingleObject(&Event
, Executive
, KernelMode
, FALSE
, NULL
);
326 /* check for success */
327 if (!NT_SUCCESS(Status
))
330 Irp
->IoStatus
.Status
= Status
;
331 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
335 /* is the driver already in use */
336 if (DeviceExtension
->FileObject
== NULL
)
338 /* did the caller specify correct attributes */
339 ASSERT(IoStack
->Parameters
.Create
.SecurityContext
);
340 if (IoStack
->Parameters
.Create
.SecurityContext
->DesiredAccess
)
342 /* store file object */
343 DeviceExtension
->FileObject
= IoStack
->FileObject
;
346 KeResetEvent(&DeviceExtension
->ReadCompletionEvent
);
348 /* initiating read */
349 Status
= MouHid_InitiateRead(DeviceExtension
);
350 DPRINT1("[MOUHID] MouHid_InitiateRead: status %x\n", Status
);
351 if (Status
== STATUS_PENDING
)
353 /* report irp is pending */
354 Status
= STATUS_SUCCESS
;
359 /* complete request */
360 Irp
->IoStatus
.Status
= Status
;
361 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
369 IN PDEVICE_OBJECT DeviceObject
,
372 PMOUHID_DEVICE_EXTENSION DeviceExtension
;
374 /* get device extension */
375 DeviceExtension
= (PMOUHID_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
377 DPRINT("[MOUHID] IRP_MJ_CLOSE ReadReportActive %x\n", DeviceExtension
->ReadReportActive
);
379 if (DeviceExtension
->ReadReportActive
)
381 /* request stopping of the report cycle */
382 DeviceExtension
->StopReadReport
= TRUE
;
384 /* wait until the reports have been read */
385 KeWaitForSingleObject(&DeviceExtension
->ReadCompletionEvent
, Executive
, KernelMode
, FALSE
, NULL
);
388 IoCancelIrp(DeviceExtension
->Irp
);
391 DPRINT("[MOUHID] IRP_MJ_CLOSE ReadReportActive %x\n", DeviceExtension
->ReadReportActive
);
393 /* remove file object */
394 DeviceExtension
->FileObject
= NULL
;
397 IoSkipCurrentIrpStackLocation(Irp
);
399 /* pass irp to down the stack */
400 return IoCallDriver(DeviceExtension
->NextDeviceObject
, Irp
);
405 MouHid_InternalDeviceControl(
406 IN PDEVICE_OBJECT DeviceObject
,
409 PIO_STACK_LOCATION IoStack
;
410 PMOUSE_ATTRIBUTES Attributes
;
411 PMOUHID_DEVICE_EXTENSION DeviceExtension
;
414 /* get current stack location */
415 IoStack
= IoGetCurrentIrpStackLocation(Irp
);
417 DPRINT1("[MOUHID] InternalDeviceControl %x\n", IoStack
->Parameters
.DeviceIoControl
.IoControlCode
);
419 /* get device extension */
420 DeviceExtension
= (PMOUHID_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
422 /* handle requests */
423 if (IoStack
->Parameters
.DeviceIoControl
.IoControlCode
== IOCTL_MOUSE_QUERY_ATTRIBUTES
)
425 /* verify output buffer length */
426 if (IoStack
->Parameters
.DeviceIoControl
.OutputBufferLength
< sizeof(MOUSE_ATTRIBUTES
))
428 /* invalid request */
429 DPRINT1("[MOUHID] IOCTL_MOUSE_QUERY_ATTRIBUTES Buffer too small\n");
430 Irp
->IoStatus
.Status
= STATUS_BUFFER_TOO_SMALL
;
431 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
432 return STATUS_BUFFER_TOO_SMALL
;
435 /* get output buffer */
436 Attributes
= (PMOUSE_ATTRIBUTES
)Irp
->AssociatedIrp
.SystemBuffer
;
439 Attributes
->MouseIdentifier
= DeviceExtension
->MouseIdentifier
;
441 /* number of buttons */
442 Attributes
->NumberOfButtons
= DeviceExtension
->UsageListLength
;
444 /* sample rate not used for usb */
445 Attributes
->SampleRate
= 0;
448 Attributes
->InputDataQueueLength
= 2;
450 DPRINT1("[MOUHID] MouseIdentifier %x\n", Attributes
->MouseIdentifier
);
451 DPRINT1("[MOUHID] NumberOfButtons %x\n", Attributes
->NumberOfButtons
);
452 DPRINT1("[MOUHID] SampleRate %x\n", Attributes
->SampleRate
);
453 DPRINT1("[MOUHID] InputDataQueueLength %x\n", Attributes
->InputDataQueueLength
);
455 /* complete request */
456 Irp
->IoStatus
.Information
= sizeof(MOUSE_ATTRIBUTES
);
457 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
458 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
459 return STATUS_SUCCESS
;
461 else if (IoStack
->Parameters
.DeviceIoControl
.IoControlCode
== IOCTL_INTERNAL_MOUSE_CONNECT
)
463 /* verify input buffer length */
464 if (IoStack
->Parameters
.DeviceIoControl
.InputBufferLength
< sizeof(CONNECT_DATA
))
466 /* invalid request */
467 Irp
->IoStatus
.Status
= STATUS_INVALID_PARAMETER
;
468 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
469 return STATUS_INVALID_PARAMETER
;
472 /* is it already connected */
473 if (DeviceExtension
->ClassService
)
475 /* already connected */
476 Irp
->IoStatus
.Status
= STATUS_SHARING_VIOLATION
;
477 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
478 return STATUS_SHARING_VIOLATION
;
481 /* get connect data */
482 Data
= (PCONNECT_DATA
)IoStack
->Parameters
.DeviceIoControl
.Type3InputBuffer
;
484 /* store connect details */
485 DeviceExtension
->ClassDeviceObject
= Data
->ClassDeviceObject
;
486 DeviceExtension
->ClassService
= Data
->ClassService
;
488 /* completed successfully */
489 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
490 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
491 return STATUS_SUCCESS
;
493 else if (IoStack
->Parameters
.DeviceIoControl
.IoControlCode
== IOCTL_INTERNAL_MOUSE_DISCONNECT
)
496 Irp
->IoStatus
.Status
= STATUS_NOT_IMPLEMENTED
;
497 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
498 return STATUS_NOT_IMPLEMENTED
;
500 else if (IoStack
->Parameters
.DeviceIoControl
.IoControlCode
== IOCTL_INTERNAL_MOUSE_ENABLE
)
503 Irp
->IoStatus
.Status
= STATUS_NOT_SUPPORTED
;
504 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
505 return STATUS_NOT_SUPPORTED
;
507 else if (IoStack
->Parameters
.DeviceIoControl
.IoControlCode
== IOCTL_INTERNAL_MOUSE_DISABLE
)
510 Irp
->IoStatus
.Status
= STATUS_INVALID_DEVICE_REQUEST
;
511 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
512 return STATUS_INVALID_DEVICE_REQUEST
;
515 DPRINT1("[MOUHID] Unknown DeviceControl %x\n", IoStack
->Parameters
.DeviceIoControl
.IoControlCode
);
516 /* unknown request not supported */
517 Irp
->IoStatus
.Status
= STATUS_NOT_SUPPORTED
;
518 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
519 return STATUS_NOT_SUPPORTED
;
524 MouHid_DeviceControl(
525 IN PDEVICE_OBJECT DeviceObject
,
528 PMOUHID_DEVICE_EXTENSION DeviceExtension
;
530 /* get device extension */
531 DeviceExtension
= (PMOUHID_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
533 /* skip stack location */
534 IoSkipCurrentIrpStackLocation(Irp
);
536 /* pass and forget */
537 return IoCallDriver(DeviceExtension
->NextDeviceObject
, Irp
);
543 IN PDEVICE_OBJECT DeviceObject
,
547 return STATUS_NOT_IMPLEMENTED
;
551 MouHid_SubmitRequest(
552 PDEVICE_OBJECT DeviceObject
,
554 ULONG InputBufferSize
,
556 ULONG OutputBufferSize
,
560 PMOUHID_DEVICE_EXTENSION DeviceExtension
;
563 IO_STATUS_BLOCK IoStatus
;
565 /* get device extension */
566 DeviceExtension
= (PMOUHID_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
569 KeInitializeEvent(&Event
, NotificationEvent
, FALSE
);
572 Irp
= IoBuildDeviceIoControlRequest(IoControlCode
, DeviceExtension
->NextDeviceObject
, InputBuffer
, InputBufferSize
, OutputBuffer
, OutputBufferSize
, FALSE
, &Event
, &IoStatus
);
576 return STATUS_INSUFFICIENT_RESOURCES
;
580 Status
= IoCallDriver(DeviceExtension
->NextDeviceObject
, Irp
);
581 if (Status
== STATUS_PENDING
)
583 /* wait for request to complete */
584 KeWaitForSingleObject(&Event
, Executive
, KernelMode
, FALSE
, NULL
);
585 Status
= IoStatus
.Status
;
595 IN PDEVICE_OBJECT DeviceObject
)
599 HID_COLLECTION_INFORMATION Information
;
601 HIDP_CAPS Capabilities
;
602 ULONG ValueCapsLength
;
603 HIDP_VALUE_CAPS ValueCaps
;
604 PMOUHID_DEVICE_EXTENSION DeviceExtension
;
607 /* get device extension */
608 DeviceExtension
= (PMOUHID_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
610 /* query collection information */
611 Status
= MouHid_SubmitRequest(DeviceObject
, IOCTL_HID_GET_COLLECTION_INFORMATION
, 0, NULL
, sizeof(HID_COLLECTION_INFORMATION
), &Information
);
612 if (!NT_SUCCESS(Status
))
614 /* failed to query collection information */
615 DPRINT1("[MOUHID] failed to obtain collection information with %x\n", Status
);
619 /* lets allocate space for preparsed data */
620 PreparsedData
= ExAllocatePool(NonPagedPool
, Information
.DescriptorSize
);
624 DPRINT1("[MOUHID] no memory size %u\n", Information
.DescriptorSize
);
625 return STATUS_INSUFFICIENT_RESOURCES
;
628 /* now obtain the preparsed data */
629 Status
= MouHid_SubmitRequest(DeviceObject
, IOCTL_HID_GET_COLLECTION_DESCRIPTOR
, 0, NULL
, Information
.DescriptorSize
, PreparsedData
);
630 if (!NT_SUCCESS(Status
))
632 /* failed to get preparsed data */
633 DPRINT1("[MOUHID] failed to obtain collection information with %x\n", Status
);
634 ExFreePool(PreparsedData
);
638 /* lets get the caps */
639 Status
= HidP_GetCaps(PreparsedData
, &Capabilities
);
640 if (Status
!= HIDP_STATUS_SUCCESS
)
642 /* failed to get capabilities */
643 DPRINT1("[MOUHID] failed to obtain caps with %x\n", Status
);
644 ExFreePool(PreparsedData
);
648 DPRINT1("[MOUHID] Usage %x UsagePage %x InputReportLength %lu\n", Capabilities
.Usage
, Capabilities
.UsagePage
, Capabilities
.InputReportByteLength
);
650 /* verify capabilities */
651 if ((Capabilities
.Usage
!= HID_USAGE_GENERIC_POINTER
&& Capabilities
.Usage
!= HID_USAGE_GENERIC_MOUSE
) || Capabilities
.UsagePage
!= HID_USAGE_PAGE_GENERIC
)
654 ExFreePool(PreparsedData
);
655 return STATUS_UNSUCCESSFUL
;
658 /* init input report*/
659 DeviceExtension
->ReportLength
= Capabilities
.InputReportByteLength
;
660 ASSERT(DeviceExtension
->ReportLength
);
661 DeviceExtension
->Report
= (PCHAR
)ExAllocatePool(NonPagedPool
, DeviceExtension
->ReportLength
);
662 ASSERT(DeviceExtension
->Report
);
663 RtlZeroMemory(DeviceExtension
->Report
, DeviceExtension
->ReportLength
);
666 DeviceExtension
->ReportMDL
= IoAllocateMdl(DeviceExtension
->Report
, DeviceExtension
->ReportLength
, FALSE
, FALSE
, NULL
);
667 ASSERT(DeviceExtension
->ReportMDL
);
670 MmBuildMdlForNonPagedPool(DeviceExtension
->ReportMDL
);
672 /* get max number of buttons */
673 Buttons
= HidP_MaxUsageListLength(HidP_Input
, HID_USAGE_PAGE_BUTTON
, PreparsedData
);
674 DPRINT1("[MOUHID] Buttons %lu\n", Buttons
);
677 /* now allocate an array for those buttons */
678 Buffer
= ExAllocatePool(NonPagedPool
, sizeof(USAGE
) * 4 * Buttons
);
682 ExFreePool(PreparsedData
);
683 return STATUS_INSUFFICIENT_RESOURCES
;
686 /* init usage lists */
687 RtlZeroMemory(Buffer
, sizeof(USAGE
) * 4 * Buttons
);
688 DeviceExtension
->CurrentUsageList
= Buffer
;
690 DeviceExtension
->PreviousUsageList
= Buffer
;
692 DeviceExtension
->MakeUsageList
= Buffer
;
694 DeviceExtension
->BreakUsageList
= Buffer
;
696 /* store number of buttons */
697 DeviceExtension
->UsageListLength
= (USHORT
)Buttons
;
699 /* store preparsed data */
700 DeviceExtension
->PreparsedData
= PreparsedData
;
703 HidP_GetSpecificValueCaps(HidP_Input
, HID_USAGE_PAGE_GENERIC
, HIDP_LINK_COLLECTION_UNSPECIFIED
, HID_USAGE_GENERIC_X
, &ValueCaps
, &ValueCapsLength
, PreparsedData
);
706 HidP_GetSpecificValueCaps(HidP_Input
, HID_USAGE_PAGE_GENERIC
, HIDP_LINK_COLLECTION_UNSPECIFIED
, HID_USAGE_GENERIC_Y
, &ValueCaps
, &ValueCapsLength
, PreparsedData
);
708 /* now check for wheel mouse support */
710 Status
= HidP_GetSpecificValueCaps(HidP_Input
, HID_USAGE_PAGE_GENERIC
, HIDP_LINK_COLLECTION_UNSPECIFIED
, HID_USAGE_GENERIC_WHEEL
, &ValueCaps
, &ValueCapsLength
, PreparsedData
);
711 if (Status
== HIDP_STATUS_SUCCESS
)
713 /* mouse has wheel support */
714 DeviceExtension
->MouseIdentifier
= WHEELMOUSE_HID_HARDWARE
;
715 DeviceExtension
->WheelUsagePage
= ValueCaps
.UsagePage
;
716 DPRINT1("[MOUHID] mouse wheel support detected\n", Status
);
720 /* check if the mouse has z-axis */
722 Status
= HidP_GetSpecificValueCaps(HidP_Input
, HID_USAGE_PAGE_GENERIC
, HIDP_LINK_COLLECTION_UNSPECIFIED
, HID_USAGE_GENERIC_Z
, &ValueCaps
, &ValueCapsLength
, PreparsedData
);
723 if (Status
== HIDP_STATUS_SUCCESS
&& ValueCapsLength
== 1)
726 DeviceExtension
->MouseIdentifier
= WHEELMOUSE_HID_HARDWARE
;
727 DeviceExtension
->WheelUsagePage
= ValueCaps
.UsagePage
;
728 DPRINT1("[MOUHID] mouse wheel support detected with z-axis\n", Status
);
732 /* completed successfully */
733 return STATUS_SUCCESS
;
738 MouHid_StartDeviceCompletion(
739 IN PDEVICE_OBJECT DeviceObject
,
743 KeSetEvent((PKEVENT
)Context
, 0, FALSE
);
744 return STATUS_MORE_PROCESSING_REQUIRED
;
750 IN PDEVICE_OBJECT DeviceObject
,
753 PIO_STACK_LOCATION IoStack
;
754 PMOUHID_DEVICE_EXTENSION DeviceExtension
;
756 /* get device extension */
757 DeviceExtension
= (PMOUHID_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
759 /* skip current stack location */
760 IoSkipCurrentIrpStackLocation(Irp
);
762 /* get next stack location */
763 IoStack
= IoGetNextIrpStackLocation(Irp
);
765 /* change request to hid flush queue request */
766 IoStack
->MajorFunction
= IRP_MJ_DEVICE_CONTROL
;
767 IoStack
->Parameters
.DeviceIoControl
.IoControlCode
= IOCTL_HID_FLUSH_QUEUE
;
770 return IoCallDriver(DeviceExtension
->NextDeviceObject
, Irp
);
776 IN PDEVICE_OBJECT DeviceObject
,
779 PIO_STACK_LOCATION IoStack
;
782 PMOUHID_DEVICE_EXTENSION DeviceExtension
;
784 /* get device extension */
785 DeviceExtension
= (PMOUHID_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
787 /* get current irp stack */
788 IoStack
= IoGetCurrentIrpStackLocation(Irp
);
789 DPRINT1("[MOUHID] IRP_MJ_PNP Request: %x\n", IoStack
->MinorFunction
);
791 if (IoStack
->MinorFunction
== IRP_MN_STOP_DEVICE
||
792 IoStack
->MinorFunction
== IRP_MN_CANCEL_REMOVE_DEVICE
||
793 IoStack
->MinorFunction
== IRP_MN_QUERY_STOP_DEVICE
||
794 IoStack
->MinorFunction
== IRP_MN_CANCEL_STOP_DEVICE
||
795 IoStack
->MinorFunction
== IRP_MN_QUERY_REMOVE_DEVICE
)
797 /* indicate success */
798 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
800 /* skip irp stack location */
801 IoSkipCurrentIrpStackLocation(Irp
);
803 /* dispatch to lower device */
804 return IoCallDriver(DeviceExtension
->NextDeviceObject
, Irp
);
806 else if (IoStack
->MinorFunction
== IRP_MN_REMOVE_DEVICE
)
808 /* FIXME synchronization */
811 IoCancelIrp(DeviceExtension
->Irp
);
813 /* indicate success */
814 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
816 /* skip irp stack location */
817 IoSkipCurrentIrpStackLocation(Irp
);
819 /* dispatch to lower device */
820 Status
= IoCallDriver(DeviceExtension
->NextDeviceObject
, Irp
);
822 IoFreeIrp(DeviceExtension
->Irp
);
823 IoDetachDevice(DeviceExtension
->NextDeviceObject
);
824 IoDeleteDevice(DeviceObject
);
827 else if (IoStack
->MinorFunction
== IRP_MN_START_DEVICE
)
830 KeInitializeEvent(&Event
, NotificationEvent
, FALSE
);
832 /* copy stack location */
833 IoCopyCurrentIrpStackLocationToNext (Irp
);
835 /* set completion routine */
836 IoSetCompletionRoutine(Irp
, MouHid_StartDeviceCompletion
, &Event
, TRUE
, TRUE
, TRUE
);
837 Irp
->IoStatus
.Status
= 0;
840 Status
= IoCallDriver(DeviceExtension
->NextDeviceObject
, Irp
);
841 if (Status
== STATUS_PENDING
)
843 KeWaitForSingleObject(&Event
, Executive
, KernelMode
, FALSE
, NULL
);
844 Status
= Irp
->IoStatus
.Status
;
847 if (!NT_SUCCESS(Status
))
850 Irp
->IoStatus
.Status
= Status
;
851 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
855 /* lets start the device */
856 Status
= MouHid_StartDevice(DeviceObject
);
857 DPRINT1("MouHid_StartDevice %x\n", Status
);
859 /* complete request */
860 Irp
->IoStatus
.Status
= Status
;
861 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
868 /* skip irp stack location */
869 IoSkipCurrentIrpStackLocation(Irp
);
871 /* dispatch to lower device */
872 return IoCallDriver(DeviceExtension
->NextDeviceObject
, Irp
);
879 IN PDRIVER_OBJECT DriverObject
,
880 IN PDEVICE_OBJECT PhysicalDeviceObject
)
883 PDEVICE_OBJECT DeviceObject
, NextDeviceObject
;
884 PMOUHID_DEVICE_EXTENSION DeviceExtension
;
887 /* create device object */
888 Status
= IoCreateDevice(DriverObject
, sizeof(MOUHID_DEVICE_EXTENSION
), NULL
, FILE_DEVICE_MOUSE
, 0, FALSE
, &DeviceObject
);
889 if (!NT_SUCCESS(Status
))
891 /* failed to create device object */
896 NextDeviceObject
= IoAttachDeviceToDeviceStack(DeviceObject
, PhysicalDeviceObject
);
897 if (!NextDeviceObject
)
899 /* failed to attach */
900 IoDeleteDevice(DeviceObject
);
901 return STATUS_DEVICE_NOT_CONNECTED
;
904 /* get device extension */
905 DeviceExtension
= (PMOUHID_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
908 RtlZeroMemory(DeviceExtension
, sizeof(MOUHID_DEVICE_EXTENSION
));
910 /* init device extension */
911 DeviceExtension
->MouseIdentifier
= MOUSE_HID_HARDWARE
;
912 DeviceExtension
->WheelUsagePage
= 0;
913 DeviceExtension
->NextDeviceObject
= NextDeviceObject
;
914 KeInitializeEvent(&DeviceExtension
->ReadCompletionEvent
, NotificationEvent
, FALSE
);
915 DeviceExtension
->Irp
= IoAllocateIrp(NextDeviceObject
->StackSize
, FALSE
);
917 /* FIXME handle allocation error */
918 ASSERT(DeviceExtension
->Irp
);
920 /* FIXME query parameter 'FlipFlopWheel', 'WheelScalingFactor' */
922 /* set power state to D0 */
923 State
.DeviceState
= PowerDeviceD0
;
924 PoSetPowerState(DeviceObject
, DevicePowerState
, State
);
926 /* init device object */
927 DeviceObject
->Flags
|= DO_BUFFERED_IO
| DO_POWER_PAGABLE
;
928 DeviceObject
->Flags
&= ~DO_DEVICE_INITIALIZING
;
930 /* completed successfully */
931 return STATUS_SUCCESS
;
937 IN PDRIVER_OBJECT DriverObject
)
946 IN PDRIVER_OBJECT DriverObject
,
947 IN PUNICODE_STRING RegPath
)
949 /* FIXME check for parameters 'UseOnlyMice', 'TreatAbsoluteAsRelative', 'TreatAbsolutePointerAsAbsolute' */
951 /* initialize driver object */
952 DriverObject
->DriverUnload
= MouHid_Unload
;
953 DriverObject
->DriverExtension
->AddDevice
= MouHid_AddDevice
;
954 DriverObject
->MajorFunction
[IRP_MJ_CREATE
] = MouHid_Create
;
955 DriverObject
->MajorFunction
[IRP_MJ_CLOSE
] = MouHid_Close
;
956 DriverObject
->MajorFunction
[IRP_MJ_FLUSH_BUFFERS
] = MouHid_Flush
;
957 DriverObject
->MajorFunction
[IRP_MJ_DEVICE_CONTROL
] = MouHid_DeviceControl
;
958 DriverObject
->MajorFunction
[IRP_MJ_INTERNAL_DEVICE_CONTROL
] = MouHid_InternalDeviceControl
;
959 DriverObject
->MajorFunction
[IRP_MJ_POWER
] = MouHid_Power
;
960 DriverObject
->MajorFunction
[IRP_MJ_PNP
] = MouHid_Pnp
;
961 DriverObject
->DriverUnload
= MouHid_Unload
;
962 DriverObject
->DriverExtension
->AddDevice
= MouHid_AddDevice
;
965 return STATUS_SUCCESS
;