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
)
101 ULONG CurrentUsageListLength
;
107 CurrentUsageListLength
= DeviceExtension
->UsageListLength
;
108 Status
= HidP_GetUsages(HidP_Input
, HID_USAGE_PAGE_BUTTON
, HIDP_LINK_COLLECTION_UNSPECIFIED
, DeviceExtension
->CurrentUsageList
, &CurrentUsageListLength
, DeviceExtension
->PreparsedData
, DeviceExtension
->Report
, DeviceExtension
->ReportLength
);
109 if (Status
!= HIDP_STATUS_SUCCESS
)
111 DPRINT1("MouHid_GetButtonFlags failed to get usages with %x\n", Status
);
115 /* extract usage list difference */
116 Status
= HidP_UsageListDifference(DeviceExtension
->PreviousUsageList
, DeviceExtension
->CurrentUsageList
, DeviceExtension
->BreakUsageList
, DeviceExtension
->MakeUsageList
, DeviceExtension
->UsageListLength
);
117 if (Status
!= HIDP_STATUS_SUCCESS
)
119 DPRINT1("MouHid_GetButtonFlags failed to get usages with %x\n", Status
);
123 if (DeviceExtension
->UsageListLength
)
129 Usage
= DeviceExtension
->BreakUsageList
[Index
];
135 /* max 5 buttons supported */
136 *ButtonFlags
|= MouHid_ButtonDownFlags
[Usage
];
139 /* move to next index*/
141 }while(Index
< DeviceExtension
->UsageListLength
);
144 if (DeviceExtension
->UsageListLength
)
150 Usage
= DeviceExtension
->MakeUsageList
[Index
];
156 /* max 5 buttons supported */
157 *ButtonFlags
|= MouHid_ButtonUpFlags
[Usage
];
160 /* move to next index*/
162 }while(Index
< DeviceExtension
->UsageListLength
);
165 /* now switch the previous list with current list */
166 TempList
= DeviceExtension
->CurrentUsageList
;
167 DeviceExtension
->CurrentUsageList
= DeviceExtension
->PreviousUsageList
;
168 DeviceExtension
->PreviousUsageList
= TempList
;
170 if (DeviceExtension
->MouseAbsolute
)
172 // mouse operates absolute
173 *ButtonFlags
|= MOUSE_MOVE_ABSOLUTE
;
178 MouHid_DispatchInputData(
179 IN PMOUHID_DEVICE_EXTENSION DeviceExtension
,
180 IN PMOUSE_INPUT_DATA InputData
)
183 ULONG InputDataConsumed
;
185 if (!DeviceExtension
->ClassService
)
189 ASSERT(DeviceExtension
->ClassService
);
190 ASSERT(DeviceExtension
->ClassDeviceObject
);
193 KeRaiseIrql(DISPATCH_LEVEL
, &OldIrql
);
195 /* dispatch input data */
196 (*(PSERVICE_CALLBACK_ROUTINE
)DeviceExtension
->ClassService
)(DeviceExtension
->ClassDeviceObject
, InputData
, InputData
+ 1, &InputDataConsumed
);
198 /* lower irql to previous level */
199 KeLowerIrql(OldIrql
);
204 MouHid_ReadCompletion(
205 IN PDEVICE_OBJECT DeviceObject
,
209 PMOUHID_DEVICE_EXTENSION DeviceExtension
;
214 MOUSE_INPUT_DATA MouseInputData
;
216 /* get device extension */
217 DeviceExtension
= (PMOUHID_DEVICE_EXTENSION
)Context
;
219 if (Irp
->IoStatus
.Status
== STATUS_PRIVILEGE_NOT_HELD
||
220 Irp
->IoStatus
.Status
== STATUS_DEVICE_NOT_CONNECTED
||
221 Irp
->IoStatus
.Status
== STATUS_CANCELLED
||
222 DeviceExtension
->StopReadReport
)
224 /* failed to read or should be stopped*/
225 DPRINT1("[MOUHID] ReadCompletion terminating read Status %x\n", Irp
->IoStatus
.Status
);
227 /* report no longer active */
228 DeviceExtension
->ReadReportActive
= FALSE
;
230 /* request stopping of the report cycle */
231 DeviceExtension
->StopReadReport
= FALSE
;
233 /* signal completion event */
234 KeSetEvent(&DeviceExtension
->ReadCompletionEvent
, 0, 0);
235 return STATUS_MORE_PROCESSING_REQUIRED
;
238 /* get mouse change */
239 MouHid_GetButtonMove(DeviceExtension
, &LastX
, &LastY
);
241 /* get mouse change flags */
242 MouHid_GetButtonFlags(DeviceExtension
, &ButtonFlags
);
244 /* init input data */
245 RtlZeroMemory(&MouseInputData
, sizeof(MOUSE_INPUT_DATA
));
247 /* init input data */
248 MouseInputData
.ButtonFlags
= ButtonFlags
;
249 MouseInputData
.LastX
= LastX
;
250 MouseInputData
.LastY
= LastY
;
252 /* detect mouse wheel change */
253 if (DeviceExtension
->MouseIdentifier
== WHEELMOUSE_HID_HARDWARE
)
257 Status
= HidP_GetScaledUsageValue(HidP_Input
, HID_USAGE_PAGE_GENERIC
, HIDP_LINK_COLLECTION_UNSPECIFIED
, HID_USAGE_GENERIC_WHEEL
, &UsageValue
, DeviceExtension
->PreparsedData
, DeviceExtension
->Report
, DeviceExtension
->ReportLength
);
258 if (Status
== HIDP_STATUS_SUCCESS
&& UsageValue
!= 0)
260 /* store wheel status */
261 MouseInputData
.ButtonFlags
|= MOUSE_WHEEL
;
262 MouseInputData
.ButtonData
= (USHORT
)(UsageValue
* WHEEL_DELTA
);
266 DPRINT("[MOUHID] failed to get wheel status with %x\n", Status
);
270 DPRINT("[MOUHID] ReportData %02x %02x %02x %02x %02x %02x %02x\n",
271 DeviceExtension
->Report
[0] & 0xFF,
272 DeviceExtension
->Report
[1] & 0xFF, DeviceExtension
->Report
[2] & 0xFF,
273 DeviceExtension
->Report
[3] & 0xFF, DeviceExtension
->Report
[4] & 0xFF,
274 DeviceExtension
->Report
[5] & 0xFF, DeviceExtension
->Report
[6] & 0xFF);
276 DPRINT("[MOUHID] LastX %ld LastY %ld Flags %x ButtonData %x\n", MouseInputData
.LastX
, MouseInputData
.LastY
, MouseInputData
.ButtonFlags
, MouseInputData
.ButtonData
);
278 /* dispatch mouse action */
279 MouHid_DispatchInputData(DeviceExtension
, &MouseInputData
);
282 MouHid_InitiateRead(DeviceExtension
);
284 /* stop completion */
285 return STATUS_MORE_PROCESSING_REQUIRED
;
290 IN PMOUHID_DEVICE_EXTENSION DeviceExtension
)
292 PIO_STACK_LOCATION IoStack
;
296 IoReuseIrp(DeviceExtension
->Irp
, STATUS_SUCCESS
);
299 DeviceExtension
->Irp
->MdlAddress
= DeviceExtension
->ReportMDL
;
301 /* get next stack location */
302 IoStack
= IoGetNextIrpStackLocation(DeviceExtension
->Irp
);
304 /* init stack location */
305 IoStack
->Parameters
.Read
.Length
= DeviceExtension
->ReportLength
;
306 IoStack
->Parameters
.Read
.Key
= 0;
307 IoStack
->Parameters
.Read
.ByteOffset
.QuadPart
= 0LL;
308 IoStack
->MajorFunction
= IRP_MJ_READ
;
309 IoStack
->FileObject
= DeviceExtension
->FileObject
;
311 /* set completion routine */
312 IoSetCompletionRoutine(DeviceExtension
->Irp
, MouHid_ReadCompletion
, DeviceExtension
, TRUE
, TRUE
, TRUE
);
315 DeviceExtension
->ReadReportActive
= TRUE
;
318 Status
= IoCallDriver(DeviceExtension
->NextDeviceObject
, DeviceExtension
->Irp
);
326 MouHid_CreateCompletion(
327 IN PDEVICE_OBJECT DeviceObject
,
331 KeSetEvent((PKEVENT
)Context
, 0, FALSE
);
332 return STATUS_MORE_PROCESSING_REQUIRED
;
339 IN PDEVICE_OBJECT DeviceObject
,
342 PIO_STACK_LOCATION IoStack
;
345 PMOUHID_DEVICE_EXTENSION DeviceExtension
;
347 DPRINT("MOUHID: IRP_MJ_CREATE\n");
349 /* get device extension */
350 DeviceExtension
= (PMOUHID_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
352 /* get stack location */
353 IoStack
= IoGetCurrentIrpStackLocation(Irp
);
355 /* copy stack location to next */
356 IoCopyCurrentIrpStackLocationToNext(Irp
);
359 KeInitializeEvent(&Event
, NotificationEvent
, FALSE
);
362 IoSetCompletionRoutine(Irp
, MouHid_CreateCompletion
, &Event
, TRUE
, TRUE
, TRUE
);
364 /* call lower driver */
365 Status
= IoCallDriver(DeviceExtension
->NextDeviceObject
, Irp
);
366 if (Status
== STATUS_PENDING
)
368 /* request pending */
369 KeWaitForSingleObject(&Event
, Executive
, KernelMode
, FALSE
, NULL
);
372 /* check for success */
373 if (!NT_SUCCESS(Status
))
376 Irp
->IoStatus
.Status
= Status
;
377 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
381 /* is the driver already in use */
382 if (DeviceExtension
->FileObject
== NULL
)
384 /* did the caller specify correct attributes */
385 ASSERT(IoStack
->Parameters
.Create
.SecurityContext
);
386 if (IoStack
->Parameters
.Create
.SecurityContext
->DesiredAccess
)
388 /* store file object */
389 DeviceExtension
->FileObject
= IoStack
->FileObject
;
392 KeResetEvent(&DeviceExtension
->ReadCompletionEvent
);
394 /* initiating read */
395 Status
= MouHid_InitiateRead(DeviceExtension
);
396 DPRINT("[MOUHID] MouHid_InitiateRead: status %x\n", Status
);
397 if (Status
== STATUS_PENDING
)
399 /* report irp is pending */
400 Status
= STATUS_SUCCESS
;
405 /* complete request */
406 Irp
->IoStatus
.Status
= Status
;
407 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
415 IN PDEVICE_OBJECT DeviceObject
,
418 PMOUHID_DEVICE_EXTENSION DeviceExtension
;
420 /* get device extension */
421 DeviceExtension
= (PMOUHID_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
423 DPRINT("[MOUHID] IRP_MJ_CLOSE ReadReportActive %x\n", DeviceExtension
->ReadReportActive
);
425 if (DeviceExtension
->ReadReportActive
)
427 /* request stopping of the report cycle */
428 DeviceExtension
->StopReadReport
= TRUE
;
430 /* wait until the reports have been read */
431 KeWaitForSingleObject(&DeviceExtension
->ReadCompletionEvent
, Executive
, KernelMode
, FALSE
, NULL
);
434 IoCancelIrp(DeviceExtension
->Irp
);
437 DPRINT("[MOUHID] IRP_MJ_CLOSE ReadReportActive %x\n", DeviceExtension
->ReadReportActive
);
439 /* remove file object */
440 DeviceExtension
->FileObject
= NULL
;
443 IoSkipCurrentIrpStackLocation(Irp
);
445 /* pass irp to down the stack */
446 return IoCallDriver(DeviceExtension
->NextDeviceObject
, Irp
);
451 MouHid_InternalDeviceControl(
452 IN PDEVICE_OBJECT DeviceObject
,
455 PIO_STACK_LOCATION IoStack
;
456 PMOUSE_ATTRIBUTES Attributes
;
457 PMOUHID_DEVICE_EXTENSION DeviceExtension
;
460 /* get current stack location */
461 IoStack
= IoGetCurrentIrpStackLocation(Irp
);
463 DPRINT("[MOUHID] InternalDeviceControl %x\n", IoStack
->Parameters
.DeviceIoControl
.IoControlCode
);
465 /* get device extension */
466 DeviceExtension
= (PMOUHID_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
468 /* handle requests */
469 if (IoStack
->Parameters
.DeviceIoControl
.IoControlCode
== IOCTL_MOUSE_QUERY_ATTRIBUTES
)
471 /* verify output buffer length */
472 if (IoStack
->Parameters
.DeviceIoControl
.OutputBufferLength
< sizeof(MOUSE_ATTRIBUTES
))
474 /* invalid request */
475 DPRINT1("[MOUHID] IOCTL_MOUSE_QUERY_ATTRIBUTES Buffer too small\n");
476 Irp
->IoStatus
.Status
= STATUS_BUFFER_TOO_SMALL
;
477 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
478 return STATUS_BUFFER_TOO_SMALL
;
481 /* get output buffer */
482 Attributes
= (PMOUSE_ATTRIBUTES
)Irp
->AssociatedIrp
.SystemBuffer
;
485 Attributes
->MouseIdentifier
= DeviceExtension
->MouseIdentifier
;
487 /* number of buttons */
488 Attributes
->NumberOfButtons
= DeviceExtension
->UsageListLength
;
490 /* sample rate not used for usb */
491 Attributes
->SampleRate
= 0;
494 Attributes
->InputDataQueueLength
= 2;
496 DPRINT("[MOUHID] MouseIdentifier %x\n", Attributes
->MouseIdentifier
);
497 DPRINT("[MOUHID] NumberOfButtons %x\n", Attributes
->NumberOfButtons
);
498 DPRINT("[MOUHID] SampleRate %x\n", Attributes
->SampleRate
);
499 DPRINT("[MOUHID] InputDataQueueLength %x\n", Attributes
->InputDataQueueLength
);
501 /* complete request */
502 Irp
->IoStatus
.Information
= sizeof(MOUSE_ATTRIBUTES
);
503 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
504 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
505 return STATUS_SUCCESS
;
507 else if (IoStack
->Parameters
.DeviceIoControl
.IoControlCode
== IOCTL_INTERNAL_MOUSE_CONNECT
)
509 /* verify input buffer length */
510 if (IoStack
->Parameters
.DeviceIoControl
.InputBufferLength
< sizeof(CONNECT_DATA
))
512 /* invalid request */
513 Irp
->IoStatus
.Status
= STATUS_INVALID_PARAMETER
;
514 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
515 return STATUS_INVALID_PARAMETER
;
518 /* is it already connected */
519 if (DeviceExtension
->ClassService
)
521 /* already connected */
522 Irp
->IoStatus
.Status
= STATUS_SHARING_VIOLATION
;
523 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
524 return STATUS_SHARING_VIOLATION
;
527 /* get connect data */
528 Data
= (PCONNECT_DATA
)IoStack
->Parameters
.DeviceIoControl
.Type3InputBuffer
;
530 /* store connect details */
531 DeviceExtension
->ClassDeviceObject
= Data
->ClassDeviceObject
;
532 DeviceExtension
->ClassService
= Data
->ClassService
;
534 /* completed successfully */
535 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
536 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
537 return STATUS_SUCCESS
;
539 else if (IoStack
->Parameters
.DeviceIoControl
.IoControlCode
== IOCTL_INTERNAL_MOUSE_DISCONNECT
)
542 Irp
->IoStatus
.Status
= STATUS_NOT_IMPLEMENTED
;
543 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
544 return STATUS_NOT_IMPLEMENTED
;
546 else if (IoStack
->Parameters
.DeviceIoControl
.IoControlCode
== IOCTL_INTERNAL_MOUSE_ENABLE
)
549 Irp
->IoStatus
.Status
= STATUS_NOT_SUPPORTED
;
550 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
551 return STATUS_NOT_SUPPORTED
;
553 else if (IoStack
->Parameters
.DeviceIoControl
.IoControlCode
== IOCTL_INTERNAL_MOUSE_DISABLE
)
556 Irp
->IoStatus
.Status
= STATUS_INVALID_DEVICE_REQUEST
;
557 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
558 return STATUS_INVALID_DEVICE_REQUEST
;
561 DPRINT1("[MOUHID] Unknown DeviceControl %x\n", IoStack
->Parameters
.DeviceIoControl
.IoControlCode
);
562 /* unknown request not supported */
563 Irp
->IoStatus
.Status
= STATUS_NOT_SUPPORTED
;
564 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
565 return STATUS_NOT_SUPPORTED
;
570 MouHid_DeviceControl(
571 IN PDEVICE_OBJECT DeviceObject
,
574 PMOUHID_DEVICE_EXTENSION DeviceExtension
;
576 /* get device extension */
577 DeviceExtension
= (PMOUHID_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
579 /* skip stack location */
580 IoSkipCurrentIrpStackLocation(Irp
);
582 /* pass and forget */
583 return IoCallDriver(DeviceExtension
->NextDeviceObject
, Irp
);
589 IN PDEVICE_OBJECT DeviceObject
,
593 return STATUS_NOT_IMPLEMENTED
;
597 MouHid_SubmitRequest(
598 PDEVICE_OBJECT DeviceObject
,
600 ULONG InputBufferSize
,
602 ULONG OutputBufferSize
,
606 PMOUHID_DEVICE_EXTENSION DeviceExtension
;
609 IO_STATUS_BLOCK IoStatus
;
611 /* get device extension */
612 DeviceExtension
= (PMOUHID_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
615 KeInitializeEvent(&Event
, NotificationEvent
, FALSE
);
618 Irp
= IoBuildDeviceIoControlRequest(IoControlCode
, DeviceExtension
->NextDeviceObject
, InputBuffer
, InputBufferSize
, OutputBuffer
, OutputBufferSize
, FALSE
, &Event
, &IoStatus
);
622 return STATUS_INSUFFICIENT_RESOURCES
;
626 Status
= IoCallDriver(DeviceExtension
->NextDeviceObject
, Irp
);
627 if (Status
== STATUS_PENDING
)
629 /* wait for request to complete */
630 KeWaitForSingleObject(&Event
, Executive
, KernelMode
, FALSE
, NULL
);
631 Status
= IoStatus
.Status
;
641 IN PDEVICE_OBJECT DeviceObject
)
645 HID_COLLECTION_INFORMATION Information
;
647 HIDP_CAPS Capabilities
;
648 ULONG ValueCapsLength
;
649 HIDP_VALUE_CAPS ValueCaps
;
650 PMOUHID_DEVICE_EXTENSION DeviceExtension
;
653 /* get device extension */
654 DeviceExtension
= (PMOUHID_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
656 /* query collection information */
657 Status
= MouHid_SubmitRequest(DeviceObject
, IOCTL_HID_GET_COLLECTION_INFORMATION
, 0, NULL
, sizeof(HID_COLLECTION_INFORMATION
), &Information
);
658 if (!NT_SUCCESS(Status
))
660 /* failed to query collection information */
661 DPRINT1("[MOUHID] failed to obtain collection information with %x\n", Status
);
665 /* lets allocate space for preparsed data */
666 PreparsedData
= ExAllocatePool(NonPagedPool
, Information
.DescriptorSize
);
670 DPRINT1("[MOUHID] no memory size %u\n", Information
.DescriptorSize
);
671 return STATUS_INSUFFICIENT_RESOURCES
;
674 /* now obtain the preparsed data */
675 Status
= MouHid_SubmitRequest(DeviceObject
, IOCTL_HID_GET_COLLECTION_DESCRIPTOR
, 0, NULL
, Information
.DescriptorSize
, PreparsedData
);
676 if (!NT_SUCCESS(Status
))
678 /* failed to get preparsed data */
679 DPRINT1("[MOUHID] failed to obtain collection information with %x\n", Status
);
680 ExFreePool(PreparsedData
);
684 /* lets get the caps */
685 Status
= HidP_GetCaps(PreparsedData
, &Capabilities
);
686 if (Status
!= HIDP_STATUS_SUCCESS
)
688 /* failed to get capabilities */
689 DPRINT1("[MOUHID] failed to obtain caps with %x\n", Status
);
690 ExFreePool(PreparsedData
);
694 DPRINT("[MOUHID] Usage %x UsagePage %x InputReportLength %lu\n", Capabilities
.Usage
, Capabilities
.UsagePage
, Capabilities
.InputReportByteLength
);
696 /* verify capabilities */
697 if ((Capabilities
.Usage
!= HID_USAGE_GENERIC_POINTER
&& Capabilities
.Usage
!= HID_USAGE_GENERIC_MOUSE
) || Capabilities
.UsagePage
!= HID_USAGE_PAGE_GENERIC
)
700 ExFreePool(PreparsedData
);
701 return STATUS_UNSUCCESSFUL
;
704 /* init input report*/
705 DeviceExtension
->ReportLength
= Capabilities
.InputReportByteLength
;
706 ASSERT(DeviceExtension
->ReportLength
);
707 DeviceExtension
->Report
= (PCHAR
)ExAllocatePool(NonPagedPool
, DeviceExtension
->ReportLength
);
708 ASSERT(DeviceExtension
->Report
);
709 RtlZeroMemory(DeviceExtension
->Report
, DeviceExtension
->ReportLength
);
712 DeviceExtension
->ReportMDL
= IoAllocateMdl(DeviceExtension
->Report
, DeviceExtension
->ReportLength
, FALSE
, FALSE
, NULL
);
713 ASSERT(DeviceExtension
->ReportMDL
);
716 MmBuildMdlForNonPagedPool(DeviceExtension
->ReportMDL
);
718 /* get max number of buttons */
719 Buttons
= HidP_MaxUsageListLength(HidP_Input
, HID_USAGE_PAGE_BUTTON
, PreparsedData
);
720 DPRINT("[MOUHID] Buttons %lu\n", Buttons
);
723 /* now allocate an array for those buttons */
724 Buffer
= ExAllocatePool(NonPagedPool
, sizeof(USAGE
) * 4 * Buttons
);
728 ExFreePool(PreparsedData
);
729 return STATUS_INSUFFICIENT_RESOURCES
;
732 /* init usage lists */
733 RtlZeroMemory(Buffer
, sizeof(USAGE
) * 4 * Buttons
);
734 DeviceExtension
->CurrentUsageList
= Buffer
;
736 DeviceExtension
->PreviousUsageList
= Buffer
;
738 DeviceExtension
->MakeUsageList
= Buffer
;
740 DeviceExtension
->BreakUsageList
= Buffer
;
742 /* store number of buttons */
743 DeviceExtension
->UsageListLength
= (USHORT
)Buttons
;
745 /* store preparsed data */
746 DeviceExtension
->PreparsedData
= PreparsedData
;
749 HidP_GetSpecificValueCaps(HidP_Input
, HID_USAGE_PAGE_GENERIC
, HIDP_LINK_COLLECTION_UNSPECIFIED
, HID_USAGE_GENERIC_X
, &DeviceExtension
->ValueCapsX
, &ValueCapsLength
, PreparsedData
);
752 HidP_GetSpecificValueCaps(HidP_Input
, HID_USAGE_PAGE_GENERIC
, HIDP_LINK_COLLECTION_UNSPECIFIED
, HID_USAGE_GENERIC_Y
, &DeviceExtension
->ValueCapsY
, &ValueCapsLength
, PreparsedData
);
754 /* now check for wheel mouse support */
756 Status
= HidP_GetSpecificValueCaps(HidP_Input
, HID_USAGE_PAGE_GENERIC
, HIDP_LINK_COLLECTION_UNSPECIFIED
, HID_USAGE_GENERIC_WHEEL
, &ValueCaps
, &ValueCapsLength
, PreparsedData
);
757 if (Status
== HIDP_STATUS_SUCCESS
)
759 /* mouse has wheel support */
760 DeviceExtension
->MouseIdentifier
= WHEELMOUSE_HID_HARDWARE
;
761 DeviceExtension
->WheelUsagePage
= ValueCaps
.UsagePage
;
762 DPRINT("[MOUHID] mouse wheel support detected\n", Status
);
766 /* check if the mouse has z-axis */
768 Status
= HidP_GetSpecificValueCaps(HidP_Input
, HID_USAGE_PAGE_GENERIC
, HIDP_LINK_COLLECTION_UNSPECIFIED
, HID_USAGE_GENERIC_Z
, &ValueCaps
, &ValueCapsLength
, PreparsedData
);
769 if (Status
== HIDP_STATUS_SUCCESS
&& ValueCapsLength
== 1)
772 DeviceExtension
->MouseIdentifier
= WHEELMOUSE_HID_HARDWARE
;
773 DeviceExtension
->WheelUsagePage
= ValueCaps
.UsagePage
;
774 DPRINT("[MOUHID] mouse wheel support detected with z-axis\n", Status
);
778 /* completed successfully */
779 return STATUS_SUCCESS
;
784 MouHid_StartDeviceCompletion(
785 IN PDEVICE_OBJECT DeviceObject
,
789 KeSetEvent((PKEVENT
)Context
, 0, FALSE
);
790 return STATUS_MORE_PROCESSING_REQUIRED
;
796 IN PDEVICE_OBJECT DeviceObject
,
799 PIO_STACK_LOCATION IoStack
;
800 PMOUHID_DEVICE_EXTENSION DeviceExtension
;
802 /* get device extension */
803 DeviceExtension
= (PMOUHID_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
805 /* skip current stack location */
806 IoSkipCurrentIrpStackLocation(Irp
);
808 /* get next stack location */
809 IoStack
= IoGetNextIrpStackLocation(Irp
);
811 /* change request to hid flush queue request */
812 IoStack
->MajorFunction
= IRP_MJ_DEVICE_CONTROL
;
813 IoStack
->Parameters
.DeviceIoControl
.IoControlCode
= IOCTL_HID_FLUSH_QUEUE
;
816 return IoCallDriver(DeviceExtension
->NextDeviceObject
, Irp
);
822 IN PDEVICE_OBJECT DeviceObject
,
825 PIO_STACK_LOCATION IoStack
;
828 PMOUHID_DEVICE_EXTENSION DeviceExtension
;
830 /* get device extension */
831 DeviceExtension
= (PMOUHID_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
833 /* get current irp stack */
834 IoStack
= IoGetCurrentIrpStackLocation(Irp
);
835 DPRINT("[MOUHID] IRP_MJ_PNP Request: %x\n", IoStack
->MinorFunction
);
837 if (IoStack
->MinorFunction
== IRP_MN_STOP_DEVICE
||
838 IoStack
->MinorFunction
== IRP_MN_CANCEL_REMOVE_DEVICE
||
839 IoStack
->MinorFunction
== IRP_MN_QUERY_STOP_DEVICE
||
840 IoStack
->MinorFunction
== IRP_MN_CANCEL_STOP_DEVICE
||
841 IoStack
->MinorFunction
== IRP_MN_QUERY_REMOVE_DEVICE
)
843 /* indicate success */
844 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
846 /* skip irp stack location */
847 IoSkipCurrentIrpStackLocation(Irp
);
849 /* dispatch to lower device */
850 return IoCallDriver(DeviceExtension
->NextDeviceObject
, Irp
);
852 else if (IoStack
->MinorFunction
== IRP_MN_REMOVE_DEVICE
)
854 /* FIXME synchronization */
857 DeviceExtension
->StopReadReport
= TRUE
;
860 IoCancelIrp(DeviceExtension
->Irp
);
862 /* indicate success */
863 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
865 /* skip irp stack location */
866 IoSkipCurrentIrpStackLocation(Irp
);
868 /* dispatch to lower device */
869 Status
= IoCallDriver(DeviceExtension
->NextDeviceObject
, Irp
);
871 /* wait for completion of stop event */
872 KeWaitForSingleObject(&DeviceExtension
->ReadCompletionEvent
, Executive
, KernelMode
, FALSE
, NULL
);
875 IoFreeIrp(DeviceExtension
->Irp
);
878 IoDetachDevice(DeviceExtension
->NextDeviceObject
);
881 IoDeleteDevice(DeviceObject
);
886 else if (IoStack
->MinorFunction
== IRP_MN_START_DEVICE
)
889 KeInitializeEvent(&Event
, NotificationEvent
, FALSE
);
891 /* copy stack location */
892 IoCopyCurrentIrpStackLocationToNext (Irp
);
894 /* set completion routine */
895 IoSetCompletionRoutine(Irp
, MouHid_StartDeviceCompletion
, &Event
, TRUE
, TRUE
, TRUE
);
896 Irp
->IoStatus
.Status
= 0;
899 Status
= IoCallDriver(DeviceExtension
->NextDeviceObject
, Irp
);
900 if (Status
== STATUS_PENDING
)
902 KeWaitForSingleObject(&Event
, Executive
, KernelMode
, FALSE
, NULL
);
903 Status
= Irp
->IoStatus
.Status
;
906 if (!NT_SUCCESS(Status
))
909 Irp
->IoStatus
.Status
= Status
;
910 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
914 /* lets start the device */
915 Status
= MouHid_StartDevice(DeviceObject
);
916 DPRINT("MouHid_StartDevice %x\n", Status
);
918 /* complete request */
919 Irp
->IoStatus
.Status
= Status
;
920 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
927 /* skip irp stack location */
928 IoSkipCurrentIrpStackLocation(Irp
);
930 /* dispatch to lower device */
931 return IoCallDriver(DeviceExtension
->NextDeviceObject
, Irp
);
938 IN PDRIVER_OBJECT DriverObject
,
939 IN PDEVICE_OBJECT PhysicalDeviceObject
)
942 PDEVICE_OBJECT DeviceObject
, NextDeviceObject
;
943 PMOUHID_DEVICE_EXTENSION DeviceExtension
;
946 /* create device object */
947 Status
= IoCreateDevice(DriverObject
, sizeof(MOUHID_DEVICE_EXTENSION
), NULL
, FILE_DEVICE_MOUSE
, 0, FALSE
, &DeviceObject
);
948 if (!NT_SUCCESS(Status
))
950 /* failed to create device object */
955 NextDeviceObject
= IoAttachDeviceToDeviceStack(DeviceObject
, PhysicalDeviceObject
);
956 if (!NextDeviceObject
)
958 /* failed to attach */
959 IoDeleteDevice(DeviceObject
);
960 return STATUS_DEVICE_NOT_CONNECTED
;
963 /* get device extension */
964 DeviceExtension
= (PMOUHID_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
967 RtlZeroMemory(DeviceExtension
, sizeof(MOUHID_DEVICE_EXTENSION
));
969 /* init device extension */
970 DeviceExtension
->MouseIdentifier
= MOUSE_HID_HARDWARE
;
971 DeviceExtension
->WheelUsagePage
= 0;
972 DeviceExtension
->NextDeviceObject
= NextDeviceObject
;
973 KeInitializeEvent(&DeviceExtension
->ReadCompletionEvent
, NotificationEvent
, FALSE
);
974 DeviceExtension
->Irp
= IoAllocateIrp(NextDeviceObject
->StackSize
, FALSE
);
976 /* FIXME handle allocation error */
977 ASSERT(DeviceExtension
->Irp
);
979 /* FIXME query parameter 'FlipFlopWheel', 'WheelScalingFactor' */
981 /* set power state to D0 */
982 State
.DeviceState
= PowerDeviceD0
;
983 PoSetPowerState(DeviceObject
, DevicePowerState
, State
);
985 /* init device object */
986 DeviceObject
->Flags
|= DO_BUFFERED_IO
| DO_POWER_PAGABLE
;
987 DeviceObject
->Flags
&= ~DO_DEVICE_INITIALIZING
;
989 /* completed successfully */
990 return STATUS_SUCCESS
;
996 IN PDRIVER_OBJECT DriverObject
)
1005 IN PDRIVER_OBJECT DriverObject
,
1006 IN PUNICODE_STRING RegPath
)
1008 /* FIXME check for parameters 'UseOnlyMice', 'TreatAbsoluteAsRelative', 'TreatAbsolutePointerAsAbsolute' */
1010 /* initialize driver object */
1011 DriverObject
->DriverUnload
= MouHid_Unload
;
1012 DriverObject
->DriverExtension
->AddDevice
= MouHid_AddDevice
;
1013 DriverObject
->MajorFunction
[IRP_MJ_CREATE
] = MouHid_Create
;
1014 DriverObject
->MajorFunction
[IRP_MJ_CLOSE
] = MouHid_Close
;
1015 DriverObject
->MajorFunction
[IRP_MJ_FLUSH_BUFFERS
] = MouHid_Flush
;
1016 DriverObject
->MajorFunction
[IRP_MJ_DEVICE_CONTROL
] = MouHid_DeviceControl
;
1017 DriverObject
->MajorFunction
[IRP_MJ_INTERNAL_DEVICE_CONTROL
] = MouHid_InternalDeviceControl
;
1018 DriverObject
->MajorFunction
[IRP_MJ_POWER
] = MouHid_Power
;
1019 DriverObject
->MajorFunction
[IRP_MJ_PNP
] = MouHid_Pnp
;
1020 DriverObject
->DriverUnload
= MouHid_Unload
;
1021 DriverObject
->DriverExtension
->AddDevice
= MouHid_AddDevice
;
1024 return STATUS_SUCCESS
;