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
[] =
15 MOUSE_LEFT_BUTTON_DOWN
,
16 MOUSE_RIGHT_BUTTON_DOWN
,
17 MOUSE_MIDDLE_BUTTON_DOWN
,
22 static USHORT MouHid_ButtonDownFlags
[] =
25 MOUSE_RIGHT_BUTTON_UP
,
26 MOUSE_MIDDLE_BUTTON_UP
,
33 IN PMOUHID_DEVICE_EXTENSION DeviceExtension
,
43 /* get scaled usage value x */
44 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
);
45 /* FIXME handle error */
46 ASSERT(Status
== HIDP_STATUS_SUCCESS
);
48 /* get scaled usage value y */
49 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
);
50 /* FIXME handle error */
51 ASSERT(Status
== HIDP_STATUS_SUCCESS
);
57 MouHid_GetButtonFlags(
58 IN PMOUHID_DEVICE_EXTENSION DeviceExtension
,
59 OUT PUSHORT ButtonFlags
)
65 ULONG CurrentUsageListLength
;
71 CurrentUsageListLength
= DeviceExtension
->UsageListLength
;
72 Status
= HidP_GetUsages(HidP_Input
, HID_USAGE_PAGE_BUTTON
, HIDP_LINK_COLLECTION_UNSPECIFIED
, DeviceExtension
->CurrentUsageList
, &CurrentUsageListLength
, DeviceExtension
->PreparsedData
, DeviceExtension
->Report
, DeviceExtension
->ReportLength
);
73 if (Status
!= HIDP_STATUS_SUCCESS
)
75 DPRINT1("MouHid_GetButtonFlags failed to get usages with %x\n", Status
);
79 /* extract usage list difference */
80 Status
= HidP_UsageListDifference(DeviceExtension
->PreviousUsageList
, DeviceExtension
->CurrentUsageList
, DeviceExtension
->BreakUsageList
, DeviceExtension
->MakeUsageList
, DeviceExtension
->UsageListLength
);
81 if (Status
!= HIDP_STATUS_SUCCESS
)
83 DPRINT1("MouHid_GetButtonFlags failed to get usages with %x\n", Status
);
87 if (DeviceExtension
->UsageListLength
)
93 Usage
= DeviceExtension
->BreakUsageList
[Index
];
99 /* max 5 buttons supported */
100 *ButtonFlags
|= MouHid_ButtonDownFlags
[Usage
];
103 /* move to next index*/
105 }while(Index
< DeviceExtension
->UsageListLength
);
108 if (DeviceExtension
->UsageListLength
)
114 Usage
= DeviceExtension
->MakeUsageList
[Index
];
120 /* max 5 buttons supported */
121 *ButtonFlags
|= MouHid_ButtonUpFlags
[Usage
];
124 /* move to next index*/
126 }while(Index
< DeviceExtension
->UsageListLength
);
129 /* now switch the previous list with current list */
130 TempList
= DeviceExtension
->CurrentUsageList
;
131 DeviceExtension
->CurrentUsageList
= DeviceExtension
->PreviousUsageList
;
132 DeviceExtension
->PreviousUsageList
= TempList
;
136 MouHid_DispatchInputData(
137 IN PMOUHID_DEVICE_EXTENSION DeviceExtension
,
138 IN PMOUSE_INPUT_DATA InputData
)
141 ULONG InputDataConsumed
;
143 if (!DeviceExtension
->ClassService
)
147 ASSERT(DeviceExtension
->ClassService
);
148 ASSERT(DeviceExtension
->ClassDeviceObject
);
151 KeRaiseIrql(DISPATCH_LEVEL
, &OldIrql
);
153 /* dispatch input data */
154 (*(PSERVICE_CALLBACK_ROUTINE
)DeviceExtension
->ClassService
)(DeviceExtension
->ClassDeviceObject
, InputData
, InputData
+ 1, &InputDataConsumed
);
156 /* lower irql to previous level */
157 KeLowerIrql(OldIrql
);
162 MouHid_ReadCompletion(
163 IN PDEVICE_OBJECT DeviceObject
,
167 PMOUHID_DEVICE_EXTENSION DeviceExtension
;
172 MOUSE_INPUT_DATA MouseInputData
;
174 /* get device extension */
175 DeviceExtension
= (PMOUHID_DEVICE_EXTENSION
)Context
;
177 if (Irp
->IoStatus
.Status
== STATUS_PRIVILEGE_NOT_HELD
||
178 Irp
->IoStatus
.Status
== STATUS_DEVICE_NOT_CONNECTED
||
179 Irp
->IoStatus
.Status
== STATUS_CANCELLED
||
180 DeviceExtension
->StopReadReport
)
182 /* failed to read or should be stopped*/
183 DPRINT1("[MOUHID] ReadCompletion terminating read Status %x\n", Irp
->IoStatus
.Status
);
185 /* report no longer active */
186 DeviceExtension
->ReadReportActive
= FALSE
;
188 /* request stopping of the report cycle */
189 DeviceExtension
->StopReadReport
= FALSE
;
191 /* signal completion event */
192 KeSetEvent(&DeviceExtension
->ReadCompletionEvent
, 0, 0);
193 return STATUS_MORE_PROCESSING_REQUIRED
;
196 /* get mouse change flags */
197 MouHid_GetButtonFlags(DeviceExtension
, &ButtonFlags
);
199 /* get mouse change */
200 MouHid_GetButtonMove(DeviceExtension
, &LastX
, &LastY
);
202 /* init input data */
203 RtlZeroMemory(&MouseInputData
, sizeof(MOUSE_INPUT_DATA
));
205 /* init input data */
206 MouseInputData
.ButtonFlags
= ButtonFlags
;
207 MouseInputData
.LastX
= LastX
;
208 MouseInputData
.LastY
= LastY
;
210 /* detect mouse wheel change */
211 if (DeviceExtension
->MouseIdentifier
== WHEELMOUSE_HID_HARDWARE
)
215 Status
= HidP_GetScaledUsageValue(HidP_Input
, HID_USAGE_PAGE_GENERIC
, HIDP_LINK_COLLECTION_UNSPECIFIED
, HID_USAGE_GENERIC_WHEEL
, &UsageValue
, DeviceExtension
->PreparsedData
, DeviceExtension
->Report
, DeviceExtension
->ReportLength
);
216 if (Status
== HIDP_STATUS_SUCCESS
)
218 /* store wheel status */
219 MouseInputData
.ButtonFlags
|= MOUSE_WHEEL
;
220 MouseInputData
.ButtonData
= (USHORT
)UsageValue
; /* FIXME */
224 DPRINT1("[MOUHID] failed to get wheel status with %x\n", Status
);
228 DPRINT1("[MOUHID] LastX %ld LastY %ld Flags %x ButtonData %x\n", MouseInputData
.LastX
, MouseInputData
.LastY
, MouseInputData
.ButtonFlags
, MouseInputData
.ButtonData
);
230 /* dispatch mouse action */
231 MouHid_DispatchInputData(DeviceExtension
, &MouseInputData
);
234 MouHid_InitiateRead(DeviceExtension
);
236 /* stop completion */
237 return STATUS_MORE_PROCESSING_REQUIRED
;
242 IN PMOUHID_DEVICE_EXTENSION DeviceExtension
)
244 PIO_STACK_LOCATION IoStack
;
248 IoReuseIrp(DeviceExtension
->Irp
, STATUS_SUCCESS
);
251 DeviceExtension
->Irp
->MdlAddress
= DeviceExtension
->ReportMDL
;
253 /* get next stack location */
254 IoStack
= IoGetNextIrpStackLocation(DeviceExtension
->Irp
);
256 /* init stack location */
257 IoStack
->Parameters
.Read
.Length
= DeviceExtension
->ReportLength
;
258 IoStack
->Parameters
.Read
.Key
= 0;
259 IoStack
->Parameters
.Read
.ByteOffset
.QuadPart
= 0LL;
260 IoStack
->MajorFunction
= IRP_MJ_READ
;
261 IoStack
->FileObject
= DeviceExtension
->FileObject
;
263 /* set completion routine */
264 IoSetCompletionRoutine(DeviceExtension
->Irp
, MouHid_ReadCompletion
, DeviceExtension
, TRUE
, TRUE
, TRUE
);
267 DeviceExtension
->ReadReportActive
= TRUE
;
270 Status
= IoCallDriver(DeviceExtension
->NextDeviceObject
, DeviceExtension
->Irp
);
278 MouHid_CreateCompletion(
279 IN PDEVICE_OBJECT DeviceObject
,
283 KeSetEvent((PKEVENT
)Context
, 0, FALSE
);
284 return STATUS_MORE_PROCESSING_REQUIRED
;
291 IN PDEVICE_OBJECT DeviceObject
,
294 PIO_STACK_LOCATION IoStack
;
297 PMOUHID_DEVICE_EXTENSION DeviceExtension
;
299 DPRINT1("MOUHID: IRP_MJ_CREATE\n");
301 /* get device extension */
302 DeviceExtension
= (PMOUHID_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
304 /* get stack location */
305 IoStack
= IoGetCurrentIrpStackLocation(Irp
);
307 /* copy stack location to next */
308 IoCopyCurrentIrpStackLocationToNext(Irp
);
311 KeInitializeEvent(&Event
, NotificationEvent
, FALSE
);
314 IoSetCompletionRoutine(Irp
, MouHid_CreateCompletion
, &Event
, TRUE
, TRUE
, TRUE
);
316 /* call lower driver */
317 Status
= IoCallDriver(DeviceExtension
->NextDeviceObject
, Irp
);
318 if (Status
== STATUS_PENDING
)
320 /* request pending */
321 KeWaitForSingleObject(&Event
, Executive
, KernelMode
, FALSE
, NULL
);
324 /* check for success */
325 if (!NT_SUCCESS(Status
))
328 Irp
->IoStatus
.Status
= Status
;
329 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
333 /* is the driver already in use */
334 if (DeviceExtension
->FileObject
== NULL
)
336 /* did the caller specify correct attributes */
337 ASSERT(IoStack
->Parameters
.Create
.SecurityContext
);
338 if (IoStack
->Parameters
.Create
.SecurityContext
->DesiredAccess
)
340 /* store file object */
341 DeviceExtension
->FileObject
= IoStack
->FileObject
;
344 KeResetEvent(&DeviceExtension
->ReadCompletionEvent
);
346 /* initiating read */
347 Status
= MouHid_InitiateRead(DeviceExtension
);
348 DPRINT1("[MOUHID] MouHid_InitiateRead: status %x\n", Status
);
349 if (Status
== STATUS_PENDING
)
351 /* report irp is pending */
352 Status
= STATUS_SUCCESS
;
357 /* complete request */
358 Irp
->IoStatus
.Status
= Status
;
359 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
367 IN PDEVICE_OBJECT DeviceObject
,
370 PMOUHID_DEVICE_EXTENSION DeviceExtension
;
372 /* get device extension */
373 DeviceExtension
= (PMOUHID_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
375 DPRINT("[MOUHID] IRP_MJ_CLOSE ReadReportActive %x\n", DeviceExtension
->ReadReportActive
);
377 if (DeviceExtension
->ReadReportActive
)
379 /* request stopping of the report cycle */
380 DeviceExtension
->StopReadReport
= TRUE
;
382 /* wait until the reports have been read */
383 KeWaitForSingleObject(&DeviceExtension
->ReadCompletionEvent
, Executive
, KernelMode
, FALSE
, NULL
);
386 IoCancelIrp(DeviceExtension
->Irp
);
389 DPRINT("[MOUHID] IRP_MJ_CLOSE ReadReportActive %x\n", DeviceExtension
->ReadReportActive
);
391 /* remove file object */
392 DeviceExtension
->FileObject
= NULL
;
395 IoSkipCurrentIrpStackLocation(Irp
);
397 /* pass irp to down the stack */
398 return IoCallDriver(DeviceExtension
->NextDeviceObject
, Irp
);
403 MouHid_DeviceControl(
404 IN PDEVICE_OBJECT DeviceObject
,
407 PIO_STACK_LOCATION IoStack
;
408 PMOUSE_ATTRIBUTES Attributes
;
409 PMOUHID_DEVICE_EXTENSION DeviceExtension
;
412 /* get current stack location */
413 IoStack
= IoGetCurrentIrpStackLocation(Irp
);
415 DPRINT1("[MOUHID] DeviceControl %x\n", IoStack
->Parameters
.DeviceIoControl
.IoControlCode
);
417 /* get device extension */
418 DeviceExtension
= (PMOUHID_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
420 /* handle requests */
421 if (IoStack
->Parameters
.DeviceIoControl
.IoControlCode
== IOCTL_MOUSE_QUERY_ATTRIBUTES
)
423 /* verify output buffer length */
424 if (IoStack
->Parameters
.DeviceIoControl
.OutputBufferLength
< sizeof(MOUSE_ATTRIBUTES
))
426 /* invalid request */
427 Irp
->IoStatus
.Status
= STATUS_BUFFER_TOO_SMALL
;
428 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
429 return STATUS_BUFFER_TOO_SMALL
;
432 /* get output buffer */
433 Attributes
= (PMOUSE_ATTRIBUTES
)Irp
->AssociatedIrp
.SystemBuffer
;
436 Attributes
->MouseIdentifier
= DeviceExtension
->MouseIdentifier
;
438 /* number of buttons */
439 Attributes
->NumberOfButtons
= DeviceExtension
->UsageListLength
;
441 /* sample rate not used for usb */
442 Attributes
->SampleRate
= 0;
445 Attributes
->InputDataQueueLength
= 2;
447 /* complete request */
448 Irp
->IoStatus
.Information
= sizeof(MOUSE_ATTRIBUTES
);
449 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
450 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
451 return STATUS_SUCCESS
;
453 else if (IoStack
->Parameters
.DeviceIoControl
.IoControlCode
== IOCTL_INTERNAL_MOUSE_CONNECT
)
455 /* verify input buffer length */
456 if (IoStack
->Parameters
.DeviceIoControl
.InputBufferLength
< sizeof(CONNECT_DATA
))
458 /* invalid request */
459 Irp
->IoStatus
.Status
= STATUS_INVALID_PARAMETER
;
460 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
461 return STATUS_INVALID_PARAMETER
;
464 /* is it already connected */
465 if (DeviceExtension
->ClassService
)
467 /* already connected */
468 Irp
->IoStatus
.Status
= STATUS_SHARING_VIOLATION
;
469 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
470 return STATUS_SHARING_VIOLATION
;
473 /* get connect data */
474 Data
= (PCONNECT_DATA
)IoStack
->Parameters
.DeviceIoControl
.Type3InputBuffer
;
476 /* store connect details */
477 DeviceExtension
->ClassDeviceObject
= Data
->ClassDeviceObject
;
478 DeviceExtension
->ClassService
= Data
->ClassService
;
480 /* completed successfully */
481 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
482 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
483 return STATUS_SUCCESS
;
485 else if (IoStack
->Parameters
.DeviceIoControl
.IoControlCode
== IOCTL_INTERNAL_MOUSE_DISCONNECT
)
488 Irp
->IoStatus
.Status
= STATUS_NOT_IMPLEMENTED
;
489 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
490 return STATUS_NOT_IMPLEMENTED
;
492 else if (IoStack
->Parameters
.DeviceIoControl
.IoControlCode
== IOCTL_INTERNAL_MOUSE_ENABLE
)
495 Irp
->IoStatus
.Status
= STATUS_NOT_SUPPORTED
;
496 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
497 return STATUS_NOT_SUPPORTED
;
499 else if (IoStack
->Parameters
.DeviceIoControl
.IoControlCode
== IOCTL_INTERNAL_MOUSE_DISABLE
)
502 Irp
->IoStatus
.Status
= STATUS_INVALID_DEVICE_REQUEST
;
503 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
504 return STATUS_INVALID_DEVICE_REQUEST
;
507 /* unknown request not supported */
508 Irp
->IoStatus
.Status
= STATUS_NOT_SUPPORTED
;
509 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
510 return STATUS_NOT_SUPPORTED
;
515 MouHid_InternalDeviceControl(
516 IN PDEVICE_OBJECT DeviceObject
,
519 PMOUHID_DEVICE_EXTENSION DeviceExtension
;
521 /* get device extension */
522 DeviceExtension
= (PMOUHID_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
524 /* skip stack location */
525 IoSkipCurrentIrpStackLocation(Irp
);
527 /* pass and forget */
528 return IoCallDriver(DeviceExtension
->NextDeviceObject
, Irp
);
534 IN PDEVICE_OBJECT DeviceObject
,
539 return STATUS_NOT_IMPLEMENTED
;
543 MouHid_SubmitRequest(
544 PDEVICE_OBJECT DeviceObject
,
546 ULONG InputBufferSize
,
548 ULONG OutputBufferSize
,
552 PMOUHID_DEVICE_EXTENSION DeviceExtension
;
555 IO_STATUS_BLOCK IoStatus
;
557 /* get device extension */
558 DeviceExtension
= (PMOUHID_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
561 KeInitializeEvent(&Event
, NotificationEvent
, FALSE
);
564 Irp
= IoBuildDeviceIoControlRequest(IoControlCode
, DeviceExtension
->NextDeviceObject
, InputBuffer
, InputBufferSize
, OutputBuffer
, OutputBufferSize
, FALSE
, &Event
, &IoStatus
);
568 return STATUS_INSUFFICIENT_RESOURCES
;
572 Status
= IoCallDriver(DeviceExtension
->NextDeviceObject
, Irp
);
573 if (Status
== STATUS_PENDING
)
575 /* wait for request to complete */
576 KeWaitForSingleObject(&Event
, Executive
, KernelMode
, FALSE
, NULL
);
577 Status
= IoStatus
.Status
;
587 IN PDEVICE_OBJECT DeviceObject
)
591 HID_COLLECTION_INFORMATION Information
;
593 HIDP_CAPS Capabilities
;
594 ULONG ValueCapsLength
;
595 HIDP_VALUE_CAPS ValueCaps
;
596 PMOUHID_DEVICE_EXTENSION DeviceExtension
;
599 /* get device extension */
600 DeviceExtension
= (PMOUHID_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
602 /* query collection information */
603 Status
= MouHid_SubmitRequest(DeviceObject
, IOCTL_HID_GET_COLLECTION_INFORMATION
, 0, NULL
, sizeof(HID_COLLECTION_INFORMATION
), &Information
);
604 if (!NT_SUCCESS(Status
))
606 /* failed to query collection information */
607 DPRINT1("[MOUHID] failed to obtain collection information with %x\n", Status
);
611 /* lets allocate space for preparsed data */
612 PreparsedData
= ExAllocatePool(NonPagedPool
, Information
.DescriptorSize
);
616 DPRINT1("[MOUHID] no memory size %u\n", Information
.DescriptorSize
);
617 return STATUS_INSUFFICIENT_RESOURCES
;
620 /* now obtain the preparsed data */
621 Status
= MouHid_SubmitRequest(DeviceObject
, IOCTL_HID_GET_COLLECTION_DESCRIPTOR
, 0, NULL
, Information
.DescriptorSize
, PreparsedData
);
622 if (!NT_SUCCESS(Status
))
624 /* failed to get preparsed data */
625 DPRINT1("[MOUHID] failed to obtain collection information with %x\n", Status
);
626 ExFreePool(PreparsedData
);
630 /* lets get the caps */
631 Status
= HidP_GetCaps(PreparsedData
, &Capabilities
);
632 if (!NT_SUCCESS(Status
))
634 /* failed to get capabilities */
635 DPRINT1("[MOUHID] failed to obtain caps with %x\n", Status
);
636 ExFreePool(PreparsedData
);
640 DPRINT1("[MOUHID] Usage %x UsagePage %x\n", Capabilities
.Usage
, Capabilities
.UsagePage
, Capabilities
.InputReportByteLength
);
642 /* verify capabilities */
643 if (Capabilities
.Usage
!= HID_USAGE_GENERIC_POINTER
&& Capabilities
.Usage
!= HID_USAGE_GENERIC_MOUSE
|| Capabilities
.UsagePage
!= HID_USAGE_PAGE_GENERIC
)
646 ExFreePool(PreparsedData
);
647 return STATUS_UNSUCCESSFUL
;
650 /* init input report*/
651 DeviceExtension
->ReportLength
= Capabilities
.InputReportByteLength
;
652 ASSERT(DeviceExtension
->ReportLength
);
653 DeviceExtension
->Report
= (PUCHAR
)ExAllocatePool(NonPagedPool
, DeviceExtension
->ReportLength
);
654 ASSERT(DeviceExtension
->Report
);
655 RtlZeroMemory(DeviceExtension
->Report
, DeviceExtension
->ReportLength
);
658 DeviceExtension
->ReportMDL
= IoAllocateMdl(DeviceExtension
->Report
, DeviceExtension
->ReportLength
, FALSE
, FALSE
, NULL
);
659 ASSERT(DeviceExtension
->ReportMDL
);
662 MmBuildMdlForNonPagedPool(DeviceExtension
->ReportMDL
);
664 /* get max number of buttons */
665 Buttons
= HidP_MaxUsageListLength(HidP_Input
, HID_USAGE_PAGE_BUTTON
, PreparsedData
);
666 DPRINT1("[MOUHID] Buttons %lu\n", Buttons
);
669 /* now allocate an array for those buttons */
670 Buffer
= ExAllocatePool(NonPagedPool
, sizeof(USAGE
) * 4 * Buttons
);
674 ExFreePool(PreparsedData
);
675 return STATUS_INSUFFICIENT_RESOURCES
;
678 /* init usage lists */
679 RtlZeroMemory(Buffer
, sizeof(USAGE
) * 4 * Buttons
);
680 DeviceExtension
->CurrentUsageList
= Buffer
;
682 DeviceExtension
->PreviousUsageList
= Buffer
;
684 DeviceExtension
->MakeUsageList
= Buffer
;
686 DeviceExtension
->BreakUsageList
= Buffer
;
688 /* store number of buttons */
689 DeviceExtension
->UsageListLength
= (USHORT
)Buttons
;
691 /* store preparsed data */
692 DeviceExtension
->PreparsedData
= PreparsedData
;
695 HidP_GetSpecificValueCaps(HidP_Input
, HID_USAGE_PAGE_GENERIC
, HIDP_LINK_COLLECTION_UNSPECIFIED
, HID_USAGE_GENERIC_X
, &ValueCaps
, &ValueCapsLength
, PreparsedData
);
698 HidP_GetSpecificValueCaps(HidP_Input
, HID_USAGE_PAGE_GENERIC
, HIDP_LINK_COLLECTION_UNSPECIFIED
, HID_USAGE_GENERIC_Y
, &ValueCaps
, &ValueCapsLength
, PreparsedData
);
700 /* now check for wheel mouse support */
702 Status
= HidP_GetSpecificValueCaps(HidP_Input
, HID_USAGE_PAGE_GENERIC
, HIDP_LINK_COLLECTION_UNSPECIFIED
, HID_USAGE_GENERIC_WHEEL
, &ValueCaps
, &ValueCapsLength
, PreparsedData
);
703 if (Status
== HIDP_STATUS_SUCCESS
)
705 /* mouse has wheel support */
706 DeviceExtension
->MouseIdentifier
= WHEELMOUSE_HID_HARDWARE
;
707 DeviceExtension
->WheelUsagePage
= ValueCaps
.UsagePage
;
708 DPRINT1("[MOUHID] mouse wheel support detected\n", Status
);
712 /* check if the mouse has z-axis */
714 Status
= HidP_GetSpecificValueCaps(HidP_Input
, HID_USAGE_PAGE_GENERIC
, HIDP_LINK_COLLECTION_UNSPECIFIED
, HID_USAGE_GENERIC_Z
, &ValueCaps
, &ValueCapsLength
, PreparsedData
);
715 if (Status
== HIDP_STATUS_SUCCESS
&& ValueCapsLength
== 1)
718 DeviceExtension
->MouseIdentifier
= WHEELMOUSE_HID_HARDWARE
;
719 DeviceExtension
->WheelUsagePage
= ValueCaps
.UsagePage
;
720 DPRINT1("[MOUHID] mouse wheel support detected with z-axis\n", Status
);
724 /* completed successfully */
725 return STATUS_SUCCESS
;
730 MouHid_StartDeviceCompletion(
731 IN PDEVICE_OBJECT DeviceObject
,
735 KeSetEvent((PKEVENT
)Context
, 0, FALSE
);
736 return STATUS_MORE_PROCESSING_REQUIRED
;
742 IN PDEVICE_OBJECT DeviceObject
,
745 PIO_STACK_LOCATION IoStack
;
748 PMOUHID_DEVICE_EXTENSION DeviceExtension
;
750 /* get device extension */
751 DeviceExtension
= (PMOUHID_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
753 /* get current irp stack */
754 IoStack
= IoGetCurrentIrpStackLocation(Irp
);
755 DPRINT1("[MOUHID] IRP_MJ_PNP Request: %x\n", IoStack
->MinorFunction
);
757 if (IoStack
->MinorFunction
== IRP_MN_STOP_DEVICE
|| IoStack
->MinorFunction
== IRP_MN_CANCEL_REMOVE_DEVICE
|| IoStack
->MinorFunction
== IRP_MN_QUERY_STOP_DEVICE
|| IoStack
->MinorFunction
== IRP_MN_CANCEL_STOP_DEVICE
)
759 /* indicate success */
760 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
762 /* skip irp stack location */
763 IoSkipCurrentIrpStackLocation(Irp
);
765 /* dispatch to lower device */
766 return IoCallDriver(DeviceExtension
->NextDeviceObject
, Irp
);
768 else if (IoStack
->MinorFunction
== IRP_MN_REMOVE_DEVICE
)
770 /* FIXME synchronization */
773 IoCancelIrp(DeviceExtension
->Irp
);
775 /* indicate success */
776 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
778 /* skip irp stack location */
779 IoSkipCurrentIrpStackLocation(Irp
);
781 /* dispatch to lower device */
782 Status
= IoCallDriver(DeviceExtension
->NextDeviceObject
, Irp
);
784 IoFreeIrp(DeviceExtension
->Irp
);
785 IoDetachDevice(DeviceExtension
->NextDeviceObject
);
786 IoDeleteDevice(DeviceObject
);
789 else if (IoStack
->MinorFunction
== IRP_MN_START_DEVICE
)
792 KeInitializeEvent(&Event
, NotificationEvent
, FALSE
);
794 /* copy stack location */
795 IoCopyCurrentIrpStackLocationToNext (Irp
);
797 /* set completion routine */
798 IoSetCompletionRoutine(Irp
, MouHid_StartDeviceCompletion
, &Event
, TRUE
, TRUE
, TRUE
);
799 Irp
->IoStatus
.Status
= 0;
802 Status
= IoCallDriver(DeviceExtension
->NextDeviceObject
, Irp
);
803 if (Status
== STATUS_PENDING
)
805 KeWaitForSingleObject(&Event
, Executive
, KernelMode
, FALSE
, NULL
);
806 Status
= Irp
->IoStatus
.Status
;
809 if (!NT_SUCCESS(Status
))
812 Irp
->IoStatus
.Status
= Status
;
813 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
817 /* lets start the device */
818 Status
= MouHid_StartDevice(DeviceObject
);
819 DPRINT1("MouHid_StartDevice %x\n", Status
);
821 /* complete request */
822 Irp
->IoStatus
.Status
= Status
;
823 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
830 /* skip irp stack location */
831 IoSkipCurrentIrpStackLocation(Irp
);
833 /* dispatch to lower device */
834 return IoCallDriver(DeviceExtension
->NextDeviceObject
, Irp
);
841 IN PDRIVER_OBJECT DriverObject
,
842 IN PDEVICE_OBJECT PhysicalDeviceObject
)
845 PDEVICE_OBJECT DeviceObject
, NextDeviceObject
;
846 PMOUHID_DEVICE_EXTENSION DeviceExtension
;
849 /* create device object */
850 Status
= IoCreateDevice(DriverObject
, sizeof(MOUHID_DEVICE_EXTENSION
), NULL
, FILE_DEVICE_MOUSE
, 0, FALSE
, &DeviceObject
);
851 if (!NT_SUCCESS(Status
))
853 /* failed to create device object */
858 NextDeviceObject
= IoAttachDeviceToDeviceStack(DeviceObject
, PhysicalDeviceObject
);
859 if (!NextDeviceObject
)
861 /* failed to attach */
862 IoDeleteDevice(DeviceObject
);
863 return STATUS_DEVICE_NOT_CONNECTED
;
866 /* get device extension */
867 DeviceExtension
= (PMOUHID_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
870 RtlZeroMemory(DeviceExtension
, sizeof(MOUHID_DEVICE_EXTENSION
));
872 /* init device extension */
873 DeviceExtension
->MouseIdentifier
= MOUSE_HID_HARDWARE
;
874 DeviceExtension
->WheelUsagePage
= 0;
875 DeviceExtension
->NextDeviceObject
= NextDeviceObject
;
876 KeInitializeEvent(&DeviceExtension
->ReadCompletionEvent
, NotificationEvent
, FALSE
);
877 DeviceExtension
->Irp
= IoAllocateIrp(NextDeviceObject
->StackSize
, FALSE
);
879 /* FIXME handle allocation error */
880 ASSERT(DeviceExtension
->Irp
);
882 /* FIXME query parameter 'FlipFlopWheel', 'WheelScalingFactor' */
884 /* set power state to D0 */
885 State
.DeviceState
= PowerDeviceD0
;
886 PoSetPowerState(DeviceObject
, DevicePowerState
, State
);
888 /* init device object */
889 DeviceObject
->Flags
|= DO_BUFFERED_IO
| DO_POWER_PAGABLE
;
890 DeviceObject
->Flags
&= ~DO_DEVICE_INITIALIZING
;
892 /* completed successfully */
893 return STATUS_SUCCESS
;
899 IN PDRIVER_OBJECT DriverObject
)
908 IN PDRIVER_OBJECT DriverObject
,
909 IN PUNICODE_STRING RegPath
)
911 /* FIXME check for parameters 'UseOnlyMice', 'TreatAbsoluteAsRelative', 'TreatAbsolutePointerAsAbsolute' */
913 /* initialize driver object */
914 DriverObject
->DriverUnload
= MouHid_Unload
;
915 DriverObject
->DriverExtension
->AddDevice
= MouHid_AddDevice
;
916 DriverObject
->MajorFunction
[IRP_MJ_CREATE
] = MouHid_Create
;
917 DriverObject
->MajorFunction
[IRP_MJ_CLOSE
] = MouHid_Close
;
918 DriverObject
->MajorFunction
[IRP_MJ_DEVICE_CONTROL
] = MouHid_DeviceControl
;
919 DriverObject
->MajorFunction
[IRP_MJ_INTERNAL_DEVICE_CONTROL
] = MouHid_InternalDeviceControl
;
920 DriverObject
->MajorFunction
[IRP_MJ_POWER
] = MouHid_Power
;
921 DriverObject
->MajorFunction
[IRP_MJ_PNP
] = MouHid_Pnp
;
922 DriverObject
->DriverUnload
= MouHid_Unload
;
923 DriverObject
->DriverExtension
->AddDevice
= MouHid_AddDevice
;
926 return STATUS_SUCCESS
;