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
, HID_USAGE_PAGE_GENERIC
, HIDP_LINK_COLLECTION_UNSPECIFIED
, HID_USAGE_GENERIC_X
, (PLONG
)LastX
, DeviceExtension
->PreparsedData
, DeviceExtension
->Report
, DeviceExtension
->ReportLength
);
48 if (Status
!= HIDP_STATUS_SUCCESS
)
50 /* FIXME: handle more errors */
51 if (Status
== HIDP_STATUS_BAD_LOG_PHY_VALUES
)
53 /* FIXME: assume it operates in absolute mode */
54 DeviceExtension
->MouseAbsolute
= TRUE
;
56 /* get unscaled value */
57 Status
= HidP_GetUsageValue(HidP_Input
, HID_USAGE_PAGE_GENERIC
, HIDP_LINK_COLLECTION_UNSPECIFIED
, HID_USAGE_GENERIC_X
, (PULONG
)&ValueX
, DeviceExtension
->PreparsedData
, DeviceExtension
->Report
, DeviceExtension
->ReportLength
);
59 /* FIXME handle error */
60 ASSERT(Status
== HIDP_STATUS_SUCCESS
);
62 /* absolute pointing devices values need be in range 0 - 0xffff */
63 ASSERT(DeviceExtension
->ValueCapsX
.LogicalMax
> 0);
65 *LastX
= (ValueX
* 0xFFFF) / DeviceExtension
->ValueCapsX
.LogicalMax
;
69 /* get scaled usage value y */
70 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
);
71 if (Status
!= HIDP_STATUS_SUCCESS
)
73 // FIXME: handle more errors
74 if (Status
== HIDP_STATUS_BAD_LOG_PHY_VALUES
)
76 // assume it operates in absolute mode
77 DeviceExtension
->MouseAbsolute
= TRUE
;
80 Status
= HidP_GetUsageValue(HidP_Input
, HID_USAGE_PAGE_GENERIC
, HIDP_LINK_COLLECTION_UNSPECIFIED
, HID_USAGE_GENERIC_Y
, (PULONG
)&ValueY
, DeviceExtension
->PreparsedData
, DeviceExtension
->Report
, DeviceExtension
->ReportLength
);
82 /* FIXME handle error */
83 ASSERT(Status
== HIDP_STATUS_SUCCESS
);
85 /* absolute pointing devices values need be in range 0 - 0xffff */
86 ASSERT(DeviceExtension
->ValueCapsY
.LogicalMax
);
87 *LastY
= (ValueY
* 0xFFFF) / DeviceExtension
->ValueCapsY
.LogicalMax
;
93 MouHid_GetButtonFlags(
94 IN PMOUHID_DEVICE_EXTENSION DeviceExtension
,
95 OUT PUSHORT ButtonFlags
,
102 ULONG CurrentUsageListLength
;
109 CurrentUsageListLength
= DeviceExtension
->UsageListLength
;
110 Status
= HidP_GetUsages(HidP_Input
, HID_USAGE_PAGE_BUTTON
, HIDP_LINK_COLLECTION_UNSPECIFIED
, DeviceExtension
->CurrentUsageList
, &CurrentUsageListLength
, DeviceExtension
->PreparsedData
, DeviceExtension
->Report
, DeviceExtension
->ReportLength
);
111 if (Status
!= HIDP_STATUS_SUCCESS
)
113 DPRINT1("MouHid_GetButtonFlags failed to get usages with %x\n", Status
);
117 /* extract usage list difference */
118 Status
= HidP_UsageListDifference(DeviceExtension
->PreviousUsageList
, DeviceExtension
->CurrentUsageList
, DeviceExtension
->BreakUsageList
, DeviceExtension
->MakeUsageList
, DeviceExtension
->UsageListLength
);
119 if (Status
!= HIDP_STATUS_SUCCESS
)
121 DPRINT1("MouHid_GetButtonFlags failed to get usages with %x\n", Status
);
125 if (DeviceExtension
->UsageListLength
)
131 Usage
= DeviceExtension
->BreakUsageList
[Index
];
137 /* max 5 buttons supported */
138 *ButtonFlags
|= MouHid_ButtonDownFlags
[Usage
];
141 /* move to next index*/
143 }while(Index
< DeviceExtension
->UsageListLength
);
146 if (DeviceExtension
->UsageListLength
)
152 Usage
= DeviceExtension
->MakeUsageList
[Index
];
158 /* max 5 buttons supported */
159 *ButtonFlags
|= MouHid_ButtonUpFlags
[Usage
];
162 /* move to next index*/
164 }while(Index
< DeviceExtension
->UsageListLength
);
167 /* now switch the previous list with current list */
168 TempList
= DeviceExtension
->CurrentUsageList
;
169 DeviceExtension
->CurrentUsageList
= DeviceExtension
->PreviousUsageList
;
170 DeviceExtension
->PreviousUsageList
= TempList
;
172 if (DeviceExtension
->MouseAbsolute
)
174 // mouse operates absolute
175 *Flags
|= MOUSE_MOVE_ABSOLUTE
;
180 MouHid_DispatchInputData(
181 IN PMOUHID_DEVICE_EXTENSION DeviceExtension
,
182 IN PMOUSE_INPUT_DATA InputData
)
185 ULONG InputDataConsumed
;
187 if (!DeviceExtension
->ClassService
)
191 ASSERT(DeviceExtension
->ClassService
);
192 ASSERT(DeviceExtension
->ClassDeviceObject
);
195 KeRaiseIrql(DISPATCH_LEVEL
, &OldIrql
);
197 /* dispatch input data */
198 (*(PSERVICE_CALLBACK_ROUTINE
)DeviceExtension
->ClassService
)(DeviceExtension
->ClassDeviceObject
, InputData
, InputData
+ 1, &InputDataConsumed
);
200 /* lower irql to previous level */
201 KeLowerIrql(OldIrql
);
206 MouHid_ReadCompletion(
207 IN PDEVICE_OBJECT DeviceObject
,
211 PMOUHID_DEVICE_EXTENSION DeviceExtension
;
216 MOUSE_INPUT_DATA MouseInputData
;
219 /* get device extension */
220 DeviceExtension
= (PMOUHID_DEVICE_EXTENSION
)Context
;
222 if (Irp
->IoStatus
.Status
== STATUS_PRIVILEGE_NOT_HELD
||
223 Irp
->IoStatus
.Status
== STATUS_DEVICE_NOT_CONNECTED
||
224 Irp
->IoStatus
.Status
== STATUS_CANCELLED
||
225 DeviceExtension
->StopReadReport
)
227 /* failed to read or should be stopped*/
228 DPRINT1("[MOUHID] ReadCompletion terminating read Status %x\n", Irp
->IoStatus
.Status
);
230 /* report no longer active */
231 DeviceExtension
->ReadReportActive
= FALSE
;
233 /* request stopping of the report cycle */
234 DeviceExtension
->StopReadReport
= FALSE
;
236 /* signal completion event */
237 KeSetEvent(&DeviceExtension
->ReadCompletionEvent
, 0, 0);
238 return STATUS_MORE_PROCESSING_REQUIRED
;
241 /* get mouse change */
242 MouHid_GetButtonMove(DeviceExtension
, &LastX
, &LastY
);
244 /* get mouse change flags */
245 MouHid_GetButtonFlags(DeviceExtension
, &ButtonFlags
, &Flags
);
247 /* init input data */
248 RtlZeroMemory(&MouseInputData
, sizeof(MOUSE_INPUT_DATA
));
250 /* init input data */
251 MouseInputData
.ButtonFlags
= ButtonFlags
;
252 MouseInputData
.Flags
= Flags
;
253 MouseInputData
.LastX
= LastX
;
254 MouseInputData
.LastY
= LastY
;
256 /* detect mouse wheel change */
257 if (DeviceExtension
->MouseIdentifier
== WHEELMOUSE_HID_HARDWARE
)
261 Status
= HidP_GetScaledUsageValue(HidP_Input
, HID_USAGE_PAGE_GENERIC
, HIDP_LINK_COLLECTION_UNSPECIFIED
, HID_USAGE_GENERIC_WHEEL
, &UsageValue
, DeviceExtension
->PreparsedData
, DeviceExtension
->Report
, DeviceExtension
->ReportLength
);
262 if (Status
== HIDP_STATUS_SUCCESS
&& UsageValue
!= 0)
264 /* store wheel status */
265 MouseInputData
.ButtonFlags
|= MOUSE_WHEEL
;
266 MouseInputData
.ButtonData
= (USHORT
)(UsageValue
* WHEEL_DELTA
);
270 DPRINT("[MOUHID] failed to get wheel status with %x\n", Status
);
274 DPRINT("[MOUHID] ReportData %02x %02x %02x %02x %02x %02x %02x\n",
275 DeviceExtension
->Report
[0] & 0xFF,
276 DeviceExtension
->Report
[1] & 0xFF, DeviceExtension
->Report
[2] & 0xFF,
277 DeviceExtension
->Report
[3] & 0xFF, DeviceExtension
->Report
[4] & 0xFF,
278 DeviceExtension
->Report
[5] & 0xFF, DeviceExtension
->Report
[6] & 0xFF);
280 DPRINT("[MOUHID] LastX %ld LastY %ld Flags %x ButtonData %x\n", MouseInputData
.LastX
, MouseInputData
.LastY
, MouseInputData
.ButtonFlags
, MouseInputData
.ButtonData
);
282 /* dispatch mouse action */
283 MouHid_DispatchInputData(DeviceExtension
, &MouseInputData
);
286 MouHid_InitiateRead(DeviceExtension
);
288 /* stop completion */
289 return STATUS_MORE_PROCESSING_REQUIRED
;
294 IN PMOUHID_DEVICE_EXTENSION DeviceExtension
)
296 PIO_STACK_LOCATION IoStack
;
300 IoReuseIrp(DeviceExtension
->Irp
, STATUS_SUCCESS
);
303 DeviceExtension
->Irp
->MdlAddress
= DeviceExtension
->ReportMDL
;
305 /* get next stack location */
306 IoStack
= IoGetNextIrpStackLocation(DeviceExtension
->Irp
);
308 /* init stack location */
309 IoStack
->Parameters
.Read
.Length
= DeviceExtension
->ReportLength
;
310 IoStack
->Parameters
.Read
.Key
= 0;
311 IoStack
->Parameters
.Read
.ByteOffset
.QuadPart
= 0LL;
312 IoStack
->MajorFunction
= IRP_MJ_READ
;
313 IoStack
->FileObject
= DeviceExtension
->FileObject
;
315 /* set completion routine */
316 IoSetCompletionRoutine(DeviceExtension
->Irp
, MouHid_ReadCompletion
, DeviceExtension
, TRUE
, TRUE
, TRUE
);
319 DeviceExtension
->ReadReportActive
= TRUE
;
322 Status
= IoCallDriver(DeviceExtension
->NextDeviceObject
, DeviceExtension
->Irp
);
330 MouHid_CreateCompletion(
331 IN PDEVICE_OBJECT DeviceObject
,
335 KeSetEvent((PKEVENT
)Context
, 0, FALSE
);
336 return STATUS_MORE_PROCESSING_REQUIRED
;
343 IN PDEVICE_OBJECT DeviceObject
,
346 PIO_STACK_LOCATION IoStack
;
349 PMOUHID_DEVICE_EXTENSION DeviceExtension
;
351 DPRINT("MOUHID: IRP_MJ_CREATE\n");
353 /* get device extension */
354 DeviceExtension
= (PMOUHID_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
356 /* get stack location */
357 IoStack
= IoGetCurrentIrpStackLocation(Irp
);
359 /* copy stack location to next */
360 IoCopyCurrentIrpStackLocationToNext(Irp
);
363 KeInitializeEvent(&Event
, NotificationEvent
, FALSE
);
366 IoSetCompletionRoutine(Irp
, MouHid_CreateCompletion
, &Event
, TRUE
, TRUE
, TRUE
);
368 /* call lower driver */
369 Status
= IoCallDriver(DeviceExtension
->NextDeviceObject
, Irp
);
370 if (Status
== STATUS_PENDING
)
372 /* request pending */
373 KeWaitForSingleObject(&Event
, Executive
, KernelMode
, FALSE
, NULL
);
376 /* check for success */
377 if (!NT_SUCCESS(Status
))
380 Irp
->IoStatus
.Status
= Status
;
381 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
385 /* is the driver already in use */
386 if (DeviceExtension
->FileObject
== NULL
)
388 /* did the caller specify correct attributes */
389 ASSERT(IoStack
->Parameters
.Create
.SecurityContext
);
390 if (IoStack
->Parameters
.Create
.SecurityContext
->DesiredAccess
)
392 /* store file object */
393 DeviceExtension
->FileObject
= IoStack
->FileObject
;
396 KeResetEvent(&DeviceExtension
->ReadCompletionEvent
);
398 /* initiating read */
399 Status
= MouHid_InitiateRead(DeviceExtension
);
400 DPRINT("[MOUHID] MouHid_InitiateRead: status %x\n", Status
);
401 if (Status
== STATUS_PENDING
)
403 /* report irp is pending */
404 Status
= STATUS_SUCCESS
;
409 /* complete request */
410 Irp
->IoStatus
.Status
= Status
;
411 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
419 IN PDEVICE_OBJECT DeviceObject
,
422 PMOUHID_DEVICE_EXTENSION DeviceExtension
;
424 /* get device extension */
425 DeviceExtension
= (PMOUHID_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
427 DPRINT("[MOUHID] IRP_MJ_CLOSE ReadReportActive %x\n", DeviceExtension
->ReadReportActive
);
429 if (DeviceExtension
->ReadReportActive
)
431 /* request stopping of the report cycle */
432 DeviceExtension
->StopReadReport
= TRUE
;
434 /* wait until the reports have been read */
435 KeWaitForSingleObject(&DeviceExtension
->ReadCompletionEvent
, Executive
, KernelMode
, FALSE
, NULL
);
438 IoCancelIrp(DeviceExtension
->Irp
);
441 DPRINT("[MOUHID] IRP_MJ_CLOSE ReadReportActive %x\n", DeviceExtension
->ReadReportActive
);
443 /* remove file object */
444 DeviceExtension
->FileObject
= NULL
;
447 IoSkipCurrentIrpStackLocation(Irp
);
449 /* pass irp to down the stack */
450 return IoCallDriver(DeviceExtension
->NextDeviceObject
, Irp
);
455 MouHid_InternalDeviceControl(
456 IN PDEVICE_OBJECT DeviceObject
,
459 PIO_STACK_LOCATION IoStack
;
460 PMOUSE_ATTRIBUTES Attributes
;
461 PMOUHID_DEVICE_EXTENSION DeviceExtension
;
464 /* get current stack location */
465 IoStack
= IoGetCurrentIrpStackLocation(Irp
);
467 DPRINT("[MOUHID] InternalDeviceControl %x\n", IoStack
->Parameters
.DeviceIoControl
.IoControlCode
);
469 /* get device extension */
470 DeviceExtension
= (PMOUHID_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
472 /* handle requests */
473 if (IoStack
->Parameters
.DeviceIoControl
.IoControlCode
== IOCTL_MOUSE_QUERY_ATTRIBUTES
)
475 /* verify output buffer length */
476 if (IoStack
->Parameters
.DeviceIoControl
.OutputBufferLength
< sizeof(MOUSE_ATTRIBUTES
))
478 /* invalid request */
479 DPRINT1("[MOUHID] IOCTL_MOUSE_QUERY_ATTRIBUTES Buffer too small\n");
480 Irp
->IoStatus
.Status
= STATUS_BUFFER_TOO_SMALL
;
481 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
482 return STATUS_BUFFER_TOO_SMALL
;
485 /* get output buffer */
486 Attributes
= (PMOUSE_ATTRIBUTES
)Irp
->AssociatedIrp
.SystemBuffer
;
489 Attributes
->MouseIdentifier
= DeviceExtension
->MouseIdentifier
;
491 /* number of buttons */
492 Attributes
->NumberOfButtons
= DeviceExtension
->UsageListLength
;
494 /* sample rate not used for usb */
495 Attributes
->SampleRate
= 0;
498 Attributes
->InputDataQueueLength
= 2;
500 DPRINT("[MOUHID] MouseIdentifier %x\n", Attributes
->MouseIdentifier
);
501 DPRINT("[MOUHID] NumberOfButtons %x\n", Attributes
->NumberOfButtons
);
502 DPRINT("[MOUHID] SampleRate %x\n", Attributes
->SampleRate
);
503 DPRINT("[MOUHID] InputDataQueueLength %x\n", Attributes
->InputDataQueueLength
);
505 /* complete request */
506 Irp
->IoStatus
.Information
= sizeof(MOUSE_ATTRIBUTES
);
507 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
508 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
509 return STATUS_SUCCESS
;
511 else if (IoStack
->Parameters
.DeviceIoControl
.IoControlCode
== IOCTL_INTERNAL_MOUSE_CONNECT
)
513 /* verify input buffer length */
514 if (IoStack
->Parameters
.DeviceIoControl
.InputBufferLength
< sizeof(CONNECT_DATA
))
516 /* invalid request */
517 Irp
->IoStatus
.Status
= STATUS_INVALID_PARAMETER
;
518 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
519 return STATUS_INVALID_PARAMETER
;
522 /* is it already connected */
523 if (DeviceExtension
->ClassService
)
525 /* already connected */
526 Irp
->IoStatus
.Status
= STATUS_SHARING_VIOLATION
;
527 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
528 return STATUS_SHARING_VIOLATION
;
531 /* get connect data */
532 Data
= (PCONNECT_DATA
)IoStack
->Parameters
.DeviceIoControl
.Type3InputBuffer
;
534 /* store connect details */
535 DeviceExtension
->ClassDeviceObject
= Data
->ClassDeviceObject
;
536 DeviceExtension
->ClassService
= Data
->ClassService
;
538 /* completed successfully */
539 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
540 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
541 return STATUS_SUCCESS
;
543 else if (IoStack
->Parameters
.DeviceIoControl
.IoControlCode
== IOCTL_INTERNAL_MOUSE_DISCONNECT
)
546 Irp
->IoStatus
.Status
= STATUS_NOT_IMPLEMENTED
;
547 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
548 return STATUS_NOT_IMPLEMENTED
;
550 else if (IoStack
->Parameters
.DeviceIoControl
.IoControlCode
== IOCTL_INTERNAL_MOUSE_ENABLE
)
553 Irp
->IoStatus
.Status
= STATUS_NOT_SUPPORTED
;
554 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
555 return STATUS_NOT_SUPPORTED
;
557 else if (IoStack
->Parameters
.DeviceIoControl
.IoControlCode
== IOCTL_INTERNAL_MOUSE_DISABLE
)
560 Irp
->IoStatus
.Status
= STATUS_INVALID_DEVICE_REQUEST
;
561 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
562 return STATUS_INVALID_DEVICE_REQUEST
;
565 DPRINT1("[MOUHID] Unknown DeviceControl %x\n", IoStack
->Parameters
.DeviceIoControl
.IoControlCode
);
566 /* unknown request not supported */
567 Irp
->IoStatus
.Status
= STATUS_NOT_SUPPORTED
;
568 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
569 return STATUS_NOT_SUPPORTED
;
574 MouHid_DeviceControl(
575 IN PDEVICE_OBJECT DeviceObject
,
578 PMOUHID_DEVICE_EXTENSION DeviceExtension
;
580 /* get device extension */
581 DeviceExtension
= (PMOUHID_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
583 /* skip stack location */
584 IoSkipCurrentIrpStackLocation(Irp
);
586 /* pass and forget */
587 return IoCallDriver(DeviceExtension
->NextDeviceObject
, Irp
);
593 IN PDEVICE_OBJECT DeviceObject
,
597 return STATUS_NOT_IMPLEMENTED
;
601 MouHid_SubmitRequest(
602 PDEVICE_OBJECT DeviceObject
,
604 ULONG InputBufferSize
,
606 ULONG OutputBufferSize
,
610 PMOUHID_DEVICE_EXTENSION DeviceExtension
;
613 IO_STATUS_BLOCK IoStatus
;
615 /* get device extension */
616 DeviceExtension
= (PMOUHID_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
619 KeInitializeEvent(&Event
, NotificationEvent
, FALSE
);
622 Irp
= IoBuildDeviceIoControlRequest(IoControlCode
, DeviceExtension
->NextDeviceObject
, InputBuffer
, InputBufferSize
, OutputBuffer
, OutputBufferSize
, FALSE
, &Event
, &IoStatus
);
626 return STATUS_INSUFFICIENT_RESOURCES
;
630 Status
= IoCallDriver(DeviceExtension
->NextDeviceObject
, Irp
);
631 if (Status
== STATUS_PENDING
)
633 /* wait for request to complete */
634 KeWaitForSingleObject(&Event
, Executive
, KernelMode
, FALSE
, NULL
);
635 Status
= IoStatus
.Status
;
645 IN PDEVICE_OBJECT DeviceObject
)
649 HID_COLLECTION_INFORMATION Information
;
651 HIDP_CAPS Capabilities
;
652 ULONG ValueCapsLength
;
653 HIDP_VALUE_CAPS ValueCaps
;
654 PMOUHID_DEVICE_EXTENSION DeviceExtension
;
657 /* get device extension */
658 DeviceExtension
= (PMOUHID_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
660 /* query collection information */
661 Status
= MouHid_SubmitRequest(DeviceObject
, IOCTL_HID_GET_COLLECTION_INFORMATION
, 0, NULL
, sizeof(HID_COLLECTION_INFORMATION
), &Information
);
662 if (!NT_SUCCESS(Status
))
664 /* failed to query collection information */
665 DPRINT1("[MOUHID] failed to obtain collection information with %x\n", Status
);
669 /* lets allocate space for preparsed data */
670 PreparsedData
= ExAllocatePool(NonPagedPool
, Information
.DescriptorSize
);
674 DPRINT1("[MOUHID] no memory size %u\n", Information
.DescriptorSize
);
675 return STATUS_INSUFFICIENT_RESOURCES
;
678 /* now obtain the preparsed data */
679 Status
= MouHid_SubmitRequest(DeviceObject
, IOCTL_HID_GET_COLLECTION_DESCRIPTOR
, 0, NULL
, Information
.DescriptorSize
, PreparsedData
);
680 if (!NT_SUCCESS(Status
))
682 /* failed to get preparsed data */
683 DPRINT1("[MOUHID] failed to obtain collection information with %x\n", Status
);
684 ExFreePool(PreparsedData
);
688 /* lets get the caps */
689 Status
= HidP_GetCaps(PreparsedData
, &Capabilities
);
690 if (Status
!= HIDP_STATUS_SUCCESS
)
692 /* failed to get capabilities */
693 DPRINT1("[MOUHID] failed to obtain caps with %x\n", Status
);
694 ExFreePool(PreparsedData
);
698 DPRINT("[MOUHID] Usage %x UsagePage %x InputReportLength %lu\n", Capabilities
.Usage
, Capabilities
.UsagePage
, Capabilities
.InputReportByteLength
);
700 /* verify capabilities */
701 if ((Capabilities
.Usage
!= HID_USAGE_GENERIC_POINTER
&& Capabilities
.Usage
!= HID_USAGE_GENERIC_MOUSE
) || Capabilities
.UsagePage
!= HID_USAGE_PAGE_GENERIC
)
704 ExFreePool(PreparsedData
);
705 return STATUS_UNSUCCESSFUL
;
708 /* init input report*/
709 DeviceExtension
->ReportLength
= Capabilities
.InputReportByteLength
;
710 ASSERT(DeviceExtension
->ReportLength
);
711 DeviceExtension
->Report
= (PCHAR
)ExAllocatePool(NonPagedPool
, DeviceExtension
->ReportLength
);
712 ASSERT(DeviceExtension
->Report
);
713 RtlZeroMemory(DeviceExtension
->Report
, DeviceExtension
->ReportLength
);
716 DeviceExtension
->ReportMDL
= IoAllocateMdl(DeviceExtension
->Report
, DeviceExtension
->ReportLength
, FALSE
, FALSE
, NULL
);
717 ASSERT(DeviceExtension
->ReportMDL
);
720 MmBuildMdlForNonPagedPool(DeviceExtension
->ReportMDL
);
722 /* get max number of buttons */
723 Buttons
= HidP_MaxUsageListLength(HidP_Input
, HID_USAGE_PAGE_BUTTON
, PreparsedData
);
724 DPRINT("[MOUHID] Buttons %lu\n", Buttons
);
727 /* now allocate an array for those buttons */
728 Buffer
= ExAllocatePool(NonPagedPool
, sizeof(USAGE
) * 4 * Buttons
);
732 ExFreePool(PreparsedData
);
733 return STATUS_INSUFFICIENT_RESOURCES
;
736 /* init usage lists */
737 RtlZeroMemory(Buffer
, sizeof(USAGE
) * 4 * Buttons
);
738 DeviceExtension
->CurrentUsageList
= Buffer
;
740 DeviceExtension
->PreviousUsageList
= Buffer
;
742 DeviceExtension
->MakeUsageList
= Buffer
;
744 DeviceExtension
->BreakUsageList
= Buffer
;
746 /* store number of buttons */
747 DeviceExtension
->UsageListLength
= (USHORT
)Buttons
;
749 /* store preparsed data */
750 DeviceExtension
->PreparsedData
= PreparsedData
;
753 HidP_GetSpecificValueCaps(HidP_Input
, HID_USAGE_PAGE_GENERIC
, HIDP_LINK_COLLECTION_UNSPECIFIED
, HID_USAGE_GENERIC_X
, &DeviceExtension
->ValueCapsX
, &ValueCapsLength
, PreparsedData
);
756 HidP_GetSpecificValueCaps(HidP_Input
, HID_USAGE_PAGE_GENERIC
, HIDP_LINK_COLLECTION_UNSPECIFIED
, HID_USAGE_GENERIC_Y
, &DeviceExtension
->ValueCapsY
, &ValueCapsLength
, PreparsedData
);
758 /* now check for wheel mouse support */
760 Status
= HidP_GetSpecificValueCaps(HidP_Input
, HID_USAGE_PAGE_GENERIC
, HIDP_LINK_COLLECTION_UNSPECIFIED
, HID_USAGE_GENERIC_WHEEL
, &ValueCaps
, &ValueCapsLength
, PreparsedData
);
761 if (Status
== HIDP_STATUS_SUCCESS
)
763 /* mouse has wheel support */
764 DeviceExtension
->MouseIdentifier
= WHEELMOUSE_HID_HARDWARE
;
765 DeviceExtension
->WheelUsagePage
= ValueCaps
.UsagePage
;
766 DPRINT("[MOUHID] mouse wheel support detected\n", Status
);
770 /* check if the mouse has z-axis */
772 Status
= HidP_GetSpecificValueCaps(HidP_Input
, HID_USAGE_PAGE_GENERIC
, HIDP_LINK_COLLECTION_UNSPECIFIED
, HID_USAGE_GENERIC_Z
, &ValueCaps
, &ValueCapsLength
, PreparsedData
);
773 if (Status
== HIDP_STATUS_SUCCESS
&& ValueCapsLength
== 1)
776 DeviceExtension
->MouseIdentifier
= WHEELMOUSE_HID_HARDWARE
;
777 DeviceExtension
->WheelUsagePage
= ValueCaps
.UsagePage
;
778 DPRINT("[MOUHID] mouse wheel support detected with z-axis\n", Status
);
782 /* completed successfully */
783 return STATUS_SUCCESS
;
788 MouHid_StartDeviceCompletion(
789 IN PDEVICE_OBJECT DeviceObject
,
793 KeSetEvent((PKEVENT
)Context
, 0, FALSE
);
794 return STATUS_MORE_PROCESSING_REQUIRED
;
800 IN PDEVICE_OBJECT DeviceObject
,
803 PIO_STACK_LOCATION IoStack
;
804 PMOUHID_DEVICE_EXTENSION DeviceExtension
;
806 /* get device extension */
807 DeviceExtension
= (PMOUHID_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
809 /* skip current stack location */
810 IoSkipCurrentIrpStackLocation(Irp
);
812 /* get next stack location */
813 IoStack
= IoGetNextIrpStackLocation(Irp
);
815 /* change request to hid flush queue request */
816 IoStack
->MajorFunction
= IRP_MJ_DEVICE_CONTROL
;
817 IoStack
->Parameters
.DeviceIoControl
.IoControlCode
= IOCTL_HID_FLUSH_QUEUE
;
820 return IoCallDriver(DeviceExtension
->NextDeviceObject
, Irp
);
826 IN PDEVICE_OBJECT DeviceObject
,
829 PIO_STACK_LOCATION IoStack
;
832 PMOUHID_DEVICE_EXTENSION DeviceExtension
;
834 /* get device extension */
835 DeviceExtension
= (PMOUHID_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
837 /* get current irp stack */
838 IoStack
= IoGetCurrentIrpStackLocation(Irp
);
839 DPRINT("[MOUHID] IRP_MJ_PNP Request: %x\n", IoStack
->MinorFunction
);
841 if (IoStack
->MinorFunction
== IRP_MN_STOP_DEVICE
||
842 IoStack
->MinorFunction
== IRP_MN_CANCEL_REMOVE_DEVICE
||
843 IoStack
->MinorFunction
== IRP_MN_QUERY_STOP_DEVICE
||
844 IoStack
->MinorFunction
== IRP_MN_CANCEL_STOP_DEVICE
||
845 IoStack
->MinorFunction
== IRP_MN_QUERY_REMOVE_DEVICE
)
847 /* indicate success */
848 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
850 /* skip irp stack location */
851 IoSkipCurrentIrpStackLocation(Irp
);
853 /* dispatch to lower device */
854 return IoCallDriver(DeviceExtension
->NextDeviceObject
, Irp
);
856 else if (IoStack
->MinorFunction
== IRP_MN_REMOVE_DEVICE
)
858 /* FIXME synchronization */
861 DeviceExtension
->StopReadReport
= TRUE
;
864 IoCancelIrp(DeviceExtension
->Irp
);
866 /* indicate success */
867 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
869 /* skip irp stack location */
870 IoSkipCurrentIrpStackLocation(Irp
);
872 /* dispatch to lower device */
873 Status
= IoCallDriver(DeviceExtension
->NextDeviceObject
, Irp
);
875 /* wait for completion of stop event */
876 KeWaitForSingleObject(&DeviceExtension
->ReadCompletionEvent
, Executive
, KernelMode
, FALSE
, NULL
);
879 IoFreeIrp(DeviceExtension
->Irp
);
882 IoDetachDevice(DeviceExtension
->NextDeviceObject
);
885 IoDeleteDevice(DeviceObject
);
890 else if (IoStack
->MinorFunction
== IRP_MN_START_DEVICE
)
893 KeInitializeEvent(&Event
, NotificationEvent
, FALSE
);
895 /* copy stack location */
896 IoCopyCurrentIrpStackLocationToNext (Irp
);
898 /* set completion routine */
899 IoSetCompletionRoutine(Irp
, MouHid_StartDeviceCompletion
, &Event
, TRUE
, TRUE
, TRUE
);
900 Irp
->IoStatus
.Status
= 0;
903 Status
= IoCallDriver(DeviceExtension
->NextDeviceObject
, Irp
);
904 if (Status
== STATUS_PENDING
)
906 KeWaitForSingleObject(&Event
, Executive
, KernelMode
, FALSE
, NULL
);
907 Status
= Irp
->IoStatus
.Status
;
910 if (!NT_SUCCESS(Status
))
913 Irp
->IoStatus
.Status
= Status
;
914 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
918 /* lets start the device */
919 Status
= MouHid_StartDevice(DeviceObject
);
920 DPRINT("MouHid_StartDevice %x\n", Status
);
922 /* complete request */
923 Irp
->IoStatus
.Status
= Status
;
924 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
931 /* skip irp stack location */
932 IoSkipCurrentIrpStackLocation(Irp
);
934 /* dispatch to lower device */
935 return IoCallDriver(DeviceExtension
->NextDeviceObject
, Irp
);
942 IN PDRIVER_OBJECT DriverObject
,
943 IN PDEVICE_OBJECT PhysicalDeviceObject
)
946 PDEVICE_OBJECT DeviceObject
, NextDeviceObject
;
947 PMOUHID_DEVICE_EXTENSION DeviceExtension
;
950 /* create device object */
951 Status
= IoCreateDevice(DriverObject
, sizeof(MOUHID_DEVICE_EXTENSION
), NULL
, FILE_DEVICE_MOUSE
, 0, FALSE
, &DeviceObject
);
952 if (!NT_SUCCESS(Status
))
954 /* failed to create device object */
959 NextDeviceObject
= IoAttachDeviceToDeviceStack(DeviceObject
, PhysicalDeviceObject
);
960 if (!NextDeviceObject
)
962 /* failed to attach */
963 IoDeleteDevice(DeviceObject
);
964 return STATUS_DEVICE_NOT_CONNECTED
;
967 /* get device extension */
968 DeviceExtension
= (PMOUHID_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
971 RtlZeroMemory(DeviceExtension
, sizeof(MOUHID_DEVICE_EXTENSION
));
973 /* init device extension */
974 DeviceExtension
->MouseIdentifier
= MOUSE_HID_HARDWARE
;
975 DeviceExtension
->WheelUsagePage
= 0;
976 DeviceExtension
->NextDeviceObject
= NextDeviceObject
;
977 KeInitializeEvent(&DeviceExtension
->ReadCompletionEvent
, NotificationEvent
, FALSE
);
978 DeviceExtension
->Irp
= IoAllocateIrp(NextDeviceObject
->StackSize
, FALSE
);
980 /* FIXME handle allocation error */
981 ASSERT(DeviceExtension
->Irp
);
983 /* FIXME query parameter 'FlipFlopWheel', 'WheelScalingFactor' */
985 /* set power state to D0 */
986 State
.DeviceState
= PowerDeviceD0
;
987 PoSetPowerState(DeviceObject
, DevicePowerState
, State
);
989 /* init device object */
990 DeviceObject
->Flags
|= DO_BUFFERED_IO
| DO_POWER_PAGABLE
;
991 DeviceObject
->Flags
&= ~DO_DEVICE_INITIALIZING
;
993 /* completed successfully */
994 return STATUS_SUCCESS
;
1000 IN PDRIVER_OBJECT DriverObject
)
1009 IN PDRIVER_OBJECT DriverObject
,
1010 IN PUNICODE_STRING RegPath
)
1012 /* FIXME check for parameters 'UseOnlyMice', 'TreatAbsoluteAsRelative', 'TreatAbsolutePointerAsAbsolute' */
1014 /* initialize driver object */
1015 DriverObject
->DriverUnload
= MouHid_Unload
;
1016 DriverObject
->DriverExtension
->AddDevice
= MouHid_AddDevice
;
1017 DriverObject
->MajorFunction
[IRP_MJ_CREATE
] = MouHid_Create
;
1018 DriverObject
->MajorFunction
[IRP_MJ_CLOSE
] = MouHid_Close
;
1019 DriverObject
->MajorFunction
[IRP_MJ_FLUSH_BUFFERS
] = MouHid_Flush
;
1020 DriverObject
->MajorFunction
[IRP_MJ_DEVICE_CONTROL
] = MouHid_DeviceControl
;
1021 DriverObject
->MajorFunction
[IRP_MJ_INTERNAL_DEVICE_CONTROL
] = MouHid_InternalDeviceControl
;
1022 DriverObject
->MajorFunction
[IRP_MJ_POWER
] = MouHid_Power
;
1023 DriverObject
->MajorFunction
[IRP_MJ_PNP
] = MouHid_Pnp
;
1024 DriverObject
->DriverUnload
= MouHid_Unload
;
1025 DriverObject
->DriverExtension
->AddDevice
= MouHid_AddDevice
;
1028 return STATUS_SUCCESS
;