Sync with trunk r58740.
[reactos.git] / drivers / hid / mouhid / mouhid.c
1 /*
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
6 * PROGRAMMERS:
7 * Michael Martin (michael.martin@reactos.org)
8 * Johannes Anderwald (johannes.anderwald@reactos.org)
9 */
10
11 #include "mouhid.h"
12
13 static USHORT MouHid_ButtonUpFlags[] =
14 {
15 0xFF, /* unused */
16 MOUSE_LEFT_BUTTON_DOWN,
17 MOUSE_RIGHT_BUTTON_DOWN,
18 MOUSE_MIDDLE_BUTTON_DOWN,
19 MOUSE_BUTTON_4_DOWN,
20 MOUSE_BUTTON_5_DOWN
21 };
22
23 static USHORT MouHid_ButtonDownFlags[] =
24 {
25 0xFF, /* unused */
26 MOUSE_LEFT_BUTTON_UP,
27 MOUSE_RIGHT_BUTTON_UP,
28 MOUSE_MIDDLE_BUTTON_UP,
29 MOUSE_BUTTON_4_UP,
30 MOUSE_BUTTON_5_UP
31 };
32
33 VOID
34 MouHid_GetButtonMove(
35 IN PMOUHID_DEVICE_EXTENSION DeviceExtension,
36 OUT PLONG LastX,
37 OUT PLONG LastY)
38 {
39 NTSTATUS Status;
40 ULONG ValueX, ValueY;
41
42 /* init result */
43 *LastX = 0;
44 *LastY = 0;
45
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)
49 {
50 /* FIXME: handle more errors */
51 if (Status == HIDP_STATUS_BAD_LOG_PHY_VALUES)
52 {
53 /* FIXME: assume it operates in absolute mode */
54 DeviceExtension->MouseAbsolute = TRUE;
55
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);
58
59 /* FIXME handle error */
60 ASSERT(Status == HIDP_STATUS_SUCCESS);
61
62 /* absolute pointing devices values need be in range 0 - 0xffff */
63 ASSERT(DeviceExtension->ValueCapsX.LogicalMax > 0);
64
65 *LastX = (ValueX * 0xFFFF) / DeviceExtension->ValueCapsX.LogicalMax;
66 }
67 }
68
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)
72 {
73 // FIXME: handle more errors
74 if (Status == HIDP_STATUS_BAD_LOG_PHY_VALUES)
75 {
76 // assume it operates in absolute mode
77 DeviceExtension->MouseAbsolute = TRUE;
78
79 // get unscaled value
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);
81
82 /* FIXME handle error */
83 ASSERT(Status == HIDP_STATUS_SUCCESS);
84
85 /* absolute pointing devices values need be in range 0 - 0xffff */
86 ASSERT(DeviceExtension->ValueCapsY.LogicalMax);
87 *LastY = (ValueY * 0xFFFF) / DeviceExtension->ValueCapsY.LogicalMax;
88 }
89 }
90 }
91
92 VOID
93 MouHid_GetButtonFlags(
94 IN PMOUHID_DEVICE_EXTENSION DeviceExtension,
95 OUT PUSHORT ButtonFlags,
96 OUT PUSHORT Flags)
97 {
98 NTSTATUS Status;
99 USAGE Usage;
100 ULONG Index;
101 PUSAGE TempList;
102 ULONG CurrentUsageListLength;
103
104 /* init flags */
105 *ButtonFlags = 0;
106 *Flags = 0;
107
108 /* get usages */
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)
112 {
113 DPRINT1("MouHid_GetButtonFlags failed to get usages with %x\n", Status);
114 return;
115 }
116
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)
120 {
121 DPRINT1("MouHid_GetButtonFlags failed to get usages with %x\n", Status);
122 return;
123 }
124
125 if (DeviceExtension->UsageListLength)
126 {
127 Index = 0;
128 do
129 {
130 /* get usage */
131 Usage = DeviceExtension->BreakUsageList[Index];
132 if (!Usage)
133 break;
134
135 if (Usage <= 5)
136 {
137 /* max 5 buttons supported */
138 *ButtonFlags |= MouHid_ButtonDownFlags[Usage];
139 }
140
141 /* move to next index*/
142 Index++;
143 }while(Index < DeviceExtension->UsageListLength);
144 }
145
146 if (DeviceExtension->UsageListLength)
147 {
148 Index = 0;
149 do
150 {
151 /* get usage */
152 Usage = DeviceExtension->MakeUsageList[Index];
153 if (!Usage)
154 break;
155
156 if (Usage <= 5)
157 {
158 /* max 5 buttons supported */
159 *ButtonFlags |= MouHid_ButtonUpFlags[Usage];
160 }
161
162 /* move to next index*/
163 Index++;
164 }while(Index < DeviceExtension->UsageListLength);
165 }
166
167 /* now switch the previous list with current list */
168 TempList = DeviceExtension->CurrentUsageList;
169 DeviceExtension->CurrentUsageList = DeviceExtension->PreviousUsageList;
170 DeviceExtension->PreviousUsageList = TempList;
171
172 if (DeviceExtension->MouseAbsolute)
173 {
174 // mouse operates absolute
175 *Flags |= MOUSE_MOVE_ABSOLUTE;
176 }
177 }
178
179 VOID
180 MouHid_DispatchInputData(
181 IN PMOUHID_DEVICE_EXTENSION DeviceExtension,
182 IN PMOUSE_INPUT_DATA InputData)
183 {
184 KIRQL OldIrql;
185 ULONG InputDataConsumed;
186
187 if (!DeviceExtension->ClassService)
188 return;
189
190 /* sanity check */
191 ASSERT(DeviceExtension->ClassService);
192 ASSERT(DeviceExtension->ClassDeviceObject);
193
194 /* raise irql */
195 KeRaiseIrql(DISPATCH_LEVEL, &OldIrql);
196
197 /* dispatch input data */
198 (*(PSERVICE_CALLBACK_ROUTINE)DeviceExtension->ClassService)(DeviceExtension->ClassDeviceObject, InputData, InputData + 1, &InputDataConsumed);
199
200 /* lower irql to previous level */
201 KeLowerIrql(OldIrql);
202 }
203
204 NTSTATUS
205 NTAPI
206 MouHid_ReadCompletion(
207 IN PDEVICE_OBJECT DeviceObject,
208 IN PIRP Irp,
209 IN PVOID Context)
210 {
211 PMOUHID_DEVICE_EXTENSION DeviceExtension;
212 USHORT ButtonFlags;
213 LONG UsageValue;
214 NTSTATUS Status;
215 LONG LastX, LastY;
216 MOUSE_INPUT_DATA MouseInputData;
217 USHORT Flags;
218
219 /* get device extension */
220 DeviceExtension = (PMOUHID_DEVICE_EXTENSION)Context;
221
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)
226 {
227 /* failed to read or should be stopped*/
228 DPRINT1("[MOUHID] ReadCompletion terminating read Status %x\n", Irp->IoStatus.Status);
229
230 /* report no longer active */
231 DeviceExtension->ReadReportActive = FALSE;
232
233 /* request stopping of the report cycle */
234 DeviceExtension->StopReadReport = FALSE;
235
236 /* signal completion event */
237 KeSetEvent(&DeviceExtension->ReadCompletionEvent, 0, 0);
238 return STATUS_MORE_PROCESSING_REQUIRED;
239 }
240
241 /* get mouse change */
242 MouHid_GetButtonMove(DeviceExtension, &LastX, &LastY);
243
244 /* get mouse change flags */
245 MouHid_GetButtonFlags(DeviceExtension, &ButtonFlags, &Flags);
246
247 /* init input data */
248 RtlZeroMemory(&MouseInputData, sizeof(MOUSE_INPUT_DATA));
249
250 /* init input data */
251 MouseInputData.ButtonFlags = ButtonFlags;
252 MouseInputData.Flags = Flags;
253 MouseInputData.LastX = LastX;
254 MouseInputData.LastY = LastY;
255
256 /* detect mouse wheel change */
257 if (DeviceExtension->MouseIdentifier == WHEELMOUSE_HID_HARDWARE)
258 {
259 /* get usage */
260 UsageValue = 0;
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)
263 {
264 /* store wheel status */
265 MouseInputData.ButtonFlags |= MOUSE_WHEEL;
266 MouseInputData.ButtonData = (USHORT)(UsageValue * WHEEL_DELTA);
267 }
268 else
269 {
270 DPRINT("[MOUHID] failed to get wheel status with %x\n", Status);
271 }
272 }
273
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);
279
280 DPRINT("[MOUHID] LastX %ld LastY %ld Flags %x ButtonData %x\n", MouseInputData.LastX, MouseInputData.LastY, MouseInputData.ButtonFlags, MouseInputData.ButtonData);
281
282 /* dispatch mouse action */
283 MouHid_DispatchInputData(DeviceExtension, &MouseInputData);
284
285 /* re-init read */
286 MouHid_InitiateRead(DeviceExtension);
287
288 /* stop completion */
289 return STATUS_MORE_PROCESSING_REQUIRED;
290 }
291
292 NTSTATUS
293 MouHid_InitiateRead(
294 IN PMOUHID_DEVICE_EXTENSION DeviceExtension)
295 {
296 PIO_STACK_LOCATION IoStack;
297 NTSTATUS Status;
298
299 /* re-use irp */
300 IoReuseIrp(DeviceExtension->Irp, STATUS_SUCCESS);
301
302 /* init irp */
303 DeviceExtension->Irp->MdlAddress = DeviceExtension->ReportMDL;
304
305 /* get next stack location */
306 IoStack = IoGetNextIrpStackLocation(DeviceExtension->Irp);
307
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;
314
315 /* set completion routine */
316 IoSetCompletionRoutine(DeviceExtension->Irp, MouHid_ReadCompletion, DeviceExtension, TRUE, TRUE, TRUE);
317
318 /* read is active */
319 DeviceExtension->ReadReportActive = TRUE;
320
321 /* start the read */
322 Status = IoCallDriver(DeviceExtension->NextDeviceObject, DeviceExtension->Irp);
323
324 /* done */
325 return Status;
326 }
327
328 NTSTATUS
329 NTAPI
330 MouHid_CreateCompletion(
331 IN PDEVICE_OBJECT DeviceObject,
332 IN PIRP Irp,
333 IN PVOID Context)
334 {
335 KeSetEvent((PKEVENT)Context, 0, FALSE);
336 return STATUS_MORE_PROCESSING_REQUIRED;
337 }
338
339
340 NTSTATUS
341 NTAPI
342 MouHid_Create(
343 IN PDEVICE_OBJECT DeviceObject,
344 IN PIRP Irp)
345 {
346 PIO_STACK_LOCATION IoStack;
347 NTSTATUS Status;
348 KEVENT Event;
349 PMOUHID_DEVICE_EXTENSION DeviceExtension;
350
351 DPRINT("MOUHID: IRP_MJ_CREATE\n");
352
353 /* get device extension */
354 DeviceExtension = (PMOUHID_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
355
356 /* get stack location */
357 IoStack = IoGetCurrentIrpStackLocation(Irp);
358
359 /* copy stack location to next */
360 IoCopyCurrentIrpStackLocationToNext(Irp);
361
362 /* init event */
363 KeInitializeEvent(&Event, NotificationEvent, FALSE);
364
365 /* prepare irp */
366 IoSetCompletionRoutine(Irp, MouHid_CreateCompletion, &Event, TRUE, TRUE, TRUE);
367
368 /* call lower driver */
369 Status = IoCallDriver(DeviceExtension->NextDeviceObject, Irp);
370 if (Status == STATUS_PENDING)
371 {
372 /* request pending */
373 KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
374 }
375
376 /* check for success */
377 if (!NT_SUCCESS(Status))
378 {
379 /* failed */
380 Irp->IoStatus.Status = Status;
381 IoCompleteRequest(Irp, IO_NO_INCREMENT);
382 return Status;
383 }
384
385 /* is the driver already in use */
386 if (DeviceExtension->FileObject == NULL)
387 {
388 /* did the caller specify correct attributes */
389 ASSERT(IoStack->Parameters.Create.SecurityContext);
390 if (IoStack->Parameters.Create.SecurityContext->DesiredAccess)
391 {
392 /* store file object */
393 DeviceExtension->FileObject = IoStack->FileObject;
394
395 /* reset event */
396 KeResetEvent(&DeviceExtension->ReadCompletionEvent);
397
398 /* initiating read */
399 Status = MouHid_InitiateRead(DeviceExtension);
400 DPRINT("[MOUHID] MouHid_InitiateRead: status %x\n", Status);
401 if (Status == STATUS_PENDING)
402 {
403 /* report irp is pending */
404 Status = STATUS_SUCCESS;
405 }
406 }
407 }
408
409 /* complete request */
410 Irp->IoStatus.Status = Status;
411 IoCompleteRequest(Irp, IO_NO_INCREMENT);
412 return Status;
413 }
414
415
416 NTSTATUS
417 NTAPI
418 MouHid_Close(
419 IN PDEVICE_OBJECT DeviceObject,
420 IN PIRP Irp)
421 {
422 PMOUHID_DEVICE_EXTENSION DeviceExtension;
423
424 /* get device extension */
425 DeviceExtension = (PMOUHID_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
426
427 DPRINT("[MOUHID] IRP_MJ_CLOSE ReadReportActive %x\n", DeviceExtension->ReadReportActive);
428
429 if (DeviceExtension->ReadReportActive)
430 {
431 /* request stopping of the report cycle */
432 DeviceExtension->StopReadReport = TRUE;
433
434 /* wait until the reports have been read */
435 KeWaitForSingleObject(&DeviceExtension->ReadCompletionEvent, Executive, KernelMode, FALSE, NULL);
436
437 /* cancel irp */
438 IoCancelIrp(DeviceExtension->Irp);
439 }
440
441 DPRINT("[MOUHID] IRP_MJ_CLOSE ReadReportActive %x\n", DeviceExtension->ReadReportActive);
442
443 /* remove file object */
444 DeviceExtension->FileObject = NULL;
445
446 /* skip location */
447 IoSkipCurrentIrpStackLocation(Irp);
448
449 /* pass irp to down the stack */
450 return IoCallDriver(DeviceExtension->NextDeviceObject, Irp);
451 }
452
453 NTSTATUS
454 NTAPI
455 MouHid_InternalDeviceControl(
456 IN PDEVICE_OBJECT DeviceObject,
457 IN PIRP Irp)
458 {
459 PIO_STACK_LOCATION IoStack;
460 PMOUSE_ATTRIBUTES Attributes;
461 PMOUHID_DEVICE_EXTENSION DeviceExtension;
462 PCONNECT_DATA Data;
463
464 /* get current stack location */
465 IoStack = IoGetCurrentIrpStackLocation(Irp);
466
467 DPRINT("[MOUHID] InternalDeviceControl %x\n", IoStack->Parameters.DeviceIoControl.IoControlCode);
468
469 /* get device extension */
470 DeviceExtension = (PMOUHID_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
471
472 /* handle requests */
473 if (IoStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_MOUSE_QUERY_ATTRIBUTES)
474 {
475 /* verify output buffer length */
476 if (IoStack->Parameters.DeviceIoControl.OutputBufferLength < sizeof(MOUSE_ATTRIBUTES))
477 {
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;
483 }
484
485 /* get output buffer */
486 Attributes = (PMOUSE_ATTRIBUTES)Irp->AssociatedIrp.SystemBuffer;
487
488 /* type of mouse */
489 Attributes->MouseIdentifier = DeviceExtension->MouseIdentifier;
490
491 /* number of buttons */
492 Attributes->NumberOfButtons = DeviceExtension->UsageListLength;
493
494 /* sample rate not used for usb */
495 Attributes->SampleRate = 0;
496
497 /* queue length */
498 Attributes->InputDataQueueLength = 2;
499
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);
504
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;
510 }
511 else if (IoStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_INTERNAL_MOUSE_CONNECT)
512 {
513 /* verify input buffer length */
514 if (IoStack->Parameters.DeviceIoControl.InputBufferLength < sizeof(CONNECT_DATA))
515 {
516 /* invalid request */
517 Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
518 IoCompleteRequest(Irp, IO_NO_INCREMENT);
519 return STATUS_INVALID_PARAMETER;
520 }
521
522 /* is it already connected */
523 if (DeviceExtension->ClassService)
524 {
525 /* already connected */
526 Irp->IoStatus.Status = STATUS_SHARING_VIOLATION;
527 IoCompleteRequest(Irp, IO_NO_INCREMENT);
528 return STATUS_SHARING_VIOLATION;
529 }
530
531 /* get connect data */
532 Data = (PCONNECT_DATA)IoStack->Parameters.DeviceIoControl.Type3InputBuffer;
533
534 /* store connect details */
535 DeviceExtension->ClassDeviceObject = Data->ClassDeviceObject;
536 DeviceExtension->ClassService = Data->ClassService;
537
538 /* completed successfully */
539 Irp->IoStatus.Status = STATUS_SUCCESS;
540 IoCompleteRequest(Irp, IO_NO_INCREMENT);
541 return STATUS_SUCCESS;
542 }
543 else if (IoStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_INTERNAL_MOUSE_DISCONNECT)
544 {
545 /* not supported */
546 Irp->IoStatus.Status = STATUS_NOT_IMPLEMENTED;
547 IoCompleteRequest(Irp, IO_NO_INCREMENT);
548 return STATUS_NOT_IMPLEMENTED;
549 }
550 else if (IoStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_INTERNAL_MOUSE_ENABLE)
551 {
552 /* not supported */
553 Irp->IoStatus.Status = STATUS_NOT_SUPPORTED;
554 IoCompleteRequest(Irp, IO_NO_INCREMENT);
555 return STATUS_NOT_SUPPORTED;
556 }
557 else if (IoStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_INTERNAL_MOUSE_DISABLE)
558 {
559 /* not supported */
560 Irp->IoStatus.Status = STATUS_INVALID_DEVICE_REQUEST;
561 IoCompleteRequest(Irp, IO_NO_INCREMENT);
562 return STATUS_INVALID_DEVICE_REQUEST;
563 }
564
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;
570 }
571
572 NTSTATUS
573 NTAPI
574 MouHid_DeviceControl(
575 IN PDEVICE_OBJECT DeviceObject,
576 IN PIRP Irp)
577 {
578 PMOUHID_DEVICE_EXTENSION DeviceExtension;
579
580 /* get device extension */
581 DeviceExtension = (PMOUHID_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
582
583 /* skip stack location */
584 IoSkipCurrentIrpStackLocation(Irp);
585
586 /* pass and forget */
587 return IoCallDriver(DeviceExtension->NextDeviceObject, Irp);
588 }
589
590 NTSTATUS
591 NTAPI
592 MouHid_Power(
593 IN PDEVICE_OBJECT DeviceObject,
594 IN PIRP Irp)
595 {
596 UNIMPLEMENTED
597 return STATUS_NOT_IMPLEMENTED;
598 }
599
600 NTSTATUS
601 MouHid_SubmitRequest(
602 PDEVICE_OBJECT DeviceObject,
603 ULONG IoControlCode,
604 ULONG InputBufferSize,
605 PVOID InputBuffer,
606 ULONG OutputBufferSize,
607 PVOID OutputBuffer)
608 {
609 KEVENT Event;
610 PMOUHID_DEVICE_EXTENSION DeviceExtension;
611 PIRP Irp;
612 NTSTATUS Status;
613 IO_STATUS_BLOCK IoStatus;
614
615 /* get device extension */
616 DeviceExtension = (PMOUHID_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
617
618 /* init event */
619 KeInitializeEvent(&Event, NotificationEvent, FALSE);
620
621 /* build request */
622 Irp = IoBuildDeviceIoControlRequest(IoControlCode, DeviceExtension->NextDeviceObject, InputBuffer, InputBufferSize, OutputBuffer, OutputBufferSize, FALSE, &Event, &IoStatus);
623 if (!Irp)
624 {
625 /* no memory */
626 return STATUS_INSUFFICIENT_RESOURCES;
627 }
628
629 /* send request */
630 Status = IoCallDriver(DeviceExtension->NextDeviceObject, Irp);
631 if (Status == STATUS_PENDING)
632 {
633 /* wait for request to complete */
634 KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
635 Status = IoStatus.Status;
636 }
637
638 /* done */
639 return Status;
640 }
641
642 NTSTATUS
643 NTAPI
644 MouHid_StartDevice(
645 IN PDEVICE_OBJECT DeviceObject)
646 {
647 NTSTATUS Status;
648 ULONG Buttons;
649 HID_COLLECTION_INFORMATION Information;
650 PVOID PreparsedData;
651 HIDP_CAPS Capabilities;
652 ULONG ValueCapsLength;
653 HIDP_VALUE_CAPS ValueCaps;
654 PMOUHID_DEVICE_EXTENSION DeviceExtension;
655 PUSHORT Buffer;
656
657 /* get device extension */
658 DeviceExtension = (PMOUHID_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
659
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))
663 {
664 /* failed to query collection information */
665 DPRINT1("[MOUHID] failed to obtain collection information with %x\n", Status);
666 return Status;
667 }
668
669 /* lets allocate space for preparsed data */
670 PreparsedData = ExAllocatePool(NonPagedPool, Information.DescriptorSize);
671 if (!PreparsedData)
672 {
673 /* no memory */
674 DPRINT1("[MOUHID] no memory size %u\n", Information.DescriptorSize);
675 return STATUS_INSUFFICIENT_RESOURCES;
676 }
677
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))
681 {
682 /* failed to get preparsed data */
683 DPRINT1("[MOUHID] failed to obtain collection information with %x\n", Status);
684 ExFreePool(PreparsedData);
685 return Status;
686 }
687
688 /* lets get the caps */
689 Status = HidP_GetCaps(PreparsedData, &Capabilities);
690 if (Status != HIDP_STATUS_SUCCESS)
691 {
692 /* failed to get capabilities */
693 DPRINT1("[MOUHID] failed to obtain caps with %x\n", Status);
694 ExFreePool(PreparsedData);
695 return Status;
696 }
697
698 DPRINT("[MOUHID] Usage %x UsagePage %x InputReportLength %lu\n", Capabilities.Usage, Capabilities.UsagePage, Capabilities.InputReportByteLength);
699
700 /* verify capabilities */
701 if ((Capabilities.Usage != HID_USAGE_GENERIC_POINTER && Capabilities.Usage != HID_USAGE_GENERIC_MOUSE) || Capabilities.UsagePage != HID_USAGE_PAGE_GENERIC)
702 {
703 /* not supported */
704 ExFreePool(PreparsedData);
705 return STATUS_UNSUCCESSFUL;
706 }
707
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);
714
715 /* build mdl */
716 DeviceExtension->ReportMDL = IoAllocateMdl(DeviceExtension->Report, DeviceExtension->ReportLength, FALSE, FALSE, NULL);
717 ASSERT(DeviceExtension->ReportMDL);
718
719 /* init mdl */
720 MmBuildMdlForNonPagedPool(DeviceExtension->ReportMDL);
721
722 /* get max number of buttons */
723 Buttons = HidP_MaxUsageListLength(HidP_Input, HID_USAGE_PAGE_BUTTON, PreparsedData);
724 DPRINT("[MOUHID] Buttons %lu\n", Buttons);
725 ASSERT(Buttons > 0);
726
727 /* now allocate an array for those buttons */
728 Buffer = ExAllocatePool(NonPagedPool, sizeof(USAGE) * 4 * Buttons);
729 if (!Buffer)
730 {
731 /* no memory */
732 ExFreePool(PreparsedData);
733 return STATUS_INSUFFICIENT_RESOURCES;
734 }
735
736 /* init usage lists */
737 RtlZeroMemory(Buffer, sizeof(USAGE) * 4 * Buttons);
738 DeviceExtension->CurrentUsageList = Buffer;
739 Buffer += Buttons;
740 DeviceExtension->PreviousUsageList = Buffer;
741 Buffer += Buttons;
742 DeviceExtension->MakeUsageList = Buffer;
743 Buffer += Buttons;
744 DeviceExtension->BreakUsageList = Buffer;
745
746 /* store number of buttons */
747 DeviceExtension->UsageListLength = (USHORT)Buttons;
748
749 /* store preparsed data */
750 DeviceExtension->PreparsedData = PreparsedData;
751
752 ValueCapsLength = 1;
753 HidP_GetSpecificValueCaps(HidP_Input, HID_USAGE_PAGE_GENERIC, HIDP_LINK_COLLECTION_UNSPECIFIED, HID_USAGE_GENERIC_X, &DeviceExtension->ValueCapsX, &ValueCapsLength, PreparsedData);
754
755 ValueCapsLength = 1;
756 HidP_GetSpecificValueCaps(HidP_Input, HID_USAGE_PAGE_GENERIC, HIDP_LINK_COLLECTION_UNSPECIFIED, HID_USAGE_GENERIC_Y, &DeviceExtension->ValueCapsY, &ValueCapsLength, PreparsedData);
757
758 /* now check for wheel mouse support */
759 ValueCapsLength = 1;
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 )
762 {
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);
767 }
768 else
769 {
770 /* check if the mouse has z-axis */
771 ValueCapsLength = 1;
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)
774 {
775 /* wheel support */
776 DeviceExtension->MouseIdentifier = WHEELMOUSE_HID_HARDWARE;
777 DeviceExtension->WheelUsagePage = ValueCaps.UsagePage;
778 DPRINT("[MOUHID] mouse wheel support detected with z-axis\n", Status);
779 }
780 }
781
782 /* completed successfully */
783 return STATUS_SUCCESS;
784 }
785
786 NTSTATUS
787 NTAPI
788 MouHid_StartDeviceCompletion(
789 IN PDEVICE_OBJECT DeviceObject,
790 IN PIRP Irp,
791 IN PVOID Context)
792 {
793 KeSetEvent((PKEVENT)Context, 0, FALSE);
794 return STATUS_MORE_PROCESSING_REQUIRED;
795 }
796
797 NTSTATUS
798 NTAPI
799 MouHid_Flush(
800 IN PDEVICE_OBJECT DeviceObject,
801 IN PIRP Irp)
802 {
803 PIO_STACK_LOCATION IoStack;
804 PMOUHID_DEVICE_EXTENSION DeviceExtension;
805
806 /* get device extension */
807 DeviceExtension = (PMOUHID_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
808
809 /* skip current stack location */
810 IoSkipCurrentIrpStackLocation(Irp);
811
812 /* get next stack location */
813 IoStack = IoGetNextIrpStackLocation(Irp);
814
815 /* change request to hid flush queue request */
816 IoStack->MajorFunction = IRP_MJ_DEVICE_CONTROL;
817 IoStack->Parameters.DeviceIoControl.IoControlCode = IOCTL_HID_FLUSH_QUEUE;
818
819 /* call device */
820 return IoCallDriver(DeviceExtension->NextDeviceObject, Irp);
821 }
822
823 NTSTATUS
824 NTAPI
825 MouHid_Pnp(
826 IN PDEVICE_OBJECT DeviceObject,
827 IN PIRP Irp)
828 {
829 PIO_STACK_LOCATION IoStack;
830 KEVENT Event;
831 NTSTATUS Status;
832 PMOUHID_DEVICE_EXTENSION DeviceExtension;
833
834 /* get device extension */
835 DeviceExtension = (PMOUHID_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
836
837 /* get current irp stack */
838 IoStack = IoGetCurrentIrpStackLocation(Irp);
839 DPRINT("[MOUHID] IRP_MJ_PNP Request: %x\n", IoStack->MinorFunction);
840
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)
846 {
847 /* indicate success */
848 Irp->IoStatus.Status = STATUS_SUCCESS;
849
850 /* skip irp stack location */
851 IoSkipCurrentIrpStackLocation(Irp);
852
853 /* dispatch to lower device */
854 return IoCallDriver(DeviceExtension->NextDeviceObject, Irp);
855 }
856 else if (IoStack->MinorFunction == IRP_MN_REMOVE_DEVICE)
857 {
858 /* FIXME synchronization */
859
860 /* request stop */
861 DeviceExtension->StopReadReport = TRUE;
862
863 /* cancel irp */
864 IoCancelIrp(DeviceExtension->Irp);
865
866 /* indicate success */
867 Irp->IoStatus.Status = STATUS_SUCCESS;
868
869 /* skip irp stack location */
870 IoSkipCurrentIrpStackLocation(Irp);
871
872 /* dispatch to lower device */
873 Status = IoCallDriver(DeviceExtension->NextDeviceObject, Irp);
874
875 /* wait for completion of stop event */
876 KeWaitForSingleObject(&DeviceExtension->ReadCompletionEvent, Executive, KernelMode, FALSE, NULL);
877
878 /* free irp */
879 IoFreeIrp(DeviceExtension->Irp);
880
881 /* detach device */
882 IoDetachDevice(DeviceExtension->NextDeviceObject);
883
884 /* delete device */
885 IoDeleteDevice(DeviceObject);
886
887 /* done */
888 return Status;
889 }
890 else if (IoStack->MinorFunction == IRP_MN_START_DEVICE)
891 {
892 /* init event */
893 KeInitializeEvent(&Event, NotificationEvent, FALSE);
894
895 /* copy stack location */
896 IoCopyCurrentIrpStackLocationToNext (Irp);
897
898 /* set completion routine */
899 IoSetCompletionRoutine(Irp, MouHid_StartDeviceCompletion, &Event, TRUE, TRUE, TRUE);
900 Irp->IoStatus.Status = 0;
901
902 /* pass request */
903 Status = IoCallDriver(DeviceExtension->NextDeviceObject, Irp);
904 if (Status == STATUS_PENDING)
905 {
906 KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
907 Status = Irp->IoStatus.Status;
908 }
909
910 if (!NT_SUCCESS(Status))
911 {
912 /* failed */
913 Irp->IoStatus.Status = Status;
914 IoCompleteRequest(Irp, IO_NO_INCREMENT);
915 return Status;
916 }
917
918 /* lets start the device */
919 Status = MouHid_StartDevice(DeviceObject);
920 DPRINT("MouHid_StartDevice %x\n", Status);
921
922 /* complete request */
923 Irp->IoStatus.Status = Status;
924 IoCompleteRequest(Irp, IO_NO_INCREMENT);
925
926 /* done */
927 return Status;
928 }
929 else
930 {
931 /* skip irp stack location */
932 IoSkipCurrentIrpStackLocation(Irp);
933
934 /* dispatch to lower device */
935 return IoCallDriver(DeviceExtension->NextDeviceObject, Irp);
936 }
937 }
938
939 NTSTATUS
940 NTAPI
941 MouHid_AddDevice(
942 IN PDRIVER_OBJECT DriverObject,
943 IN PDEVICE_OBJECT PhysicalDeviceObject)
944 {
945 NTSTATUS Status;
946 PDEVICE_OBJECT DeviceObject, NextDeviceObject;
947 PMOUHID_DEVICE_EXTENSION DeviceExtension;
948 POWER_STATE State;
949
950 /* create device object */
951 Status = IoCreateDevice(DriverObject, sizeof(MOUHID_DEVICE_EXTENSION), NULL, FILE_DEVICE_MOUSE, 0, FALSE, &DeviceObject);
952 if (!NT_SUCCESS(Status))
953 {
954 /* failed to create device object */
955 return Status;
956 }
957
958 /* now attach it */
959 NextDeviceObject = IoAttachDeviceToDeviceStack(DeviceObject, PhysicalDeviceObject);
960 if (!NextDeviceObject)
961 {
962 /* failed to attach */
963 IoDeleteDevice(DeviceObject);
964 return STATUS_DEVICE_NOT_CONNECTED;
965 }
966
967 /* get device extension */
968 DeviceExtension = (PMOUHID_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
969
970 /* zero extension */
971 RtlZeroMemory(DeviceExtension, sizeof(MOUHID_DEVICE_EXTENSION));
972
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);
979
980 /* FIXME handle allocation error */
981 ASSERT(DeviceExtension->Irp);
982
983 /* FIXME query parameter 'FlipFlopWheel', 'WheelScalingFactor' */
984
985 /* set power state to D0 */
986 State.DeviceState = PowerDeviceD0;
987 PoSetPowerState(DeviceObject, DevicePowerState, State);
988
989 /* init device object */
990 DeviceObject->Flags |= DO_BUFFERED_IO | DO_POWER_PAGABLE;
991 DeviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
992
993 /* completed successfully */
994 return STATUS_SUCCESS;
995 }
996
997 VOID
998 NTAPI
999 MouHid_Unload(
1000 IN PDRIVER_OBJECT DriverObject)
1001 {
1002 UNIMPLEMENTED
1003 }
1004
1005
1006 NTSTATUS
1007 NTAPI
1008 DriverEntry(
1009 IN PDRIVER_OBJECT DriverObject,
1010 IN PUNICODE_STRING RegPath)
1011 {
1012 /* FIXME check for parameters 'UseOnlyMice', 'TreatAbsoluteAsRelative', 'TreatAbsolutePointerAsAbsolute' */
1013
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;
1026
1027 /* done */
1028 return STATUS_SUCCESS;
1029 }