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