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