[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 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_ButtonDownFlags[] =
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 %ld LastY %ld 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 DPRINT1("[MOUHID] DeviceControl %x\n", IoStack->Parameters.DeviceIoControl.IoControlCode);
416
417 /* get device extension */
418 DeviceExtension = (PMOUHID_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
419
420 /* handle requests */
421 if (IoStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_MOUSE_QUERY_ATTRIBUTES)
422 {
423 /* verify output buffer length */
424 if (IoStack->Parameters.DeviceIoControl.OutputBufferLength < sizeof(MOUSE_ATTRIBUTES))
425 {
426 /* invalid request */
427 Irp->IoStatus.Status = STATUS_BUFFER_TOO_SMALL;
428 IoCompleteRequest(Irp, IO_NO_INCREMENT);
429 return STATUS_BUFFER_TOO_SMALL;
430 }
431
432 /* get output buffer */
433 Attributes = (PMOUSE_ATTRIBUTES)Irp->AssociatedIrp.SystemBuffer;
434
435 /* type of mouse */
436 Attributes->MouseIdentifier = DeviceExtension->MouseIdentifier;
437
438 /* number of buttons */
439 Attributes->NumberOfButtons = DeviceExtension->UsageListLength;
440
441 /* sample rate not used for usb */
442 Attributes->SampleRate = 0;
443
444 /* queue length */
445 Attributes->InputDataQueueLength = 2;
446
447 /* complete request */
448 Irp->IoStatus.Information = sizeof(MOUSE_ATTRIBUTES);
449 Irp->IoStatus.Status = STATUS_SUCCESS;
450 IoCompleteRequest(Irp, IO_NO_INCREMENT);
451 return STATUS_SUCCESS;
452 }
453 else if (IoStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_INTERNAL_MOUSE_CONNECT)
454 {
455 /* verify input buffer length */
456 if (IoStack->Parameters.DeviceIoControl.InputBufferLength < sizeof(CONNECT_DATA))
457 {
458 /* invalid request */
459 Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
460 IoCompleteRequest(Irp, IO_NO_INCREMENT);
461 return STATUS_INVALID_PARAMETER;
462 }
463
464 /* is it already connected */
465 if (DeviceExtension->ClassService)
466 {
467 /* already connected */
468 Irp->IoStatus.Status = STATUS_SHARING_VIOLATION;
469 IoCompleteRequest(Irp, IO_NO_INCREMENT);
470 return STATUS_SHARING_VIOLATION;
471 }
472
473 /* get connect data */
474 Data = (PCONNECT_DATA)IoStack->Parameters.DeviceIoControl.Type3InputBuffer;
475
476 /* store connect details */
477 DeviceExtension->ClassDeviceObject = Data->ClassDeviceObject;
478 DeviceExtension->ClassService = Data->ClassService;
479
480 /* completed successfully */
481 Irp->IoStatus.Status = STATUS_SUCCESS;
482 IoCompleteRequest(Irp, IO_NO_INCREMENT);
483 return STATUS_SUCCESS;
484 }
485 else if (IoStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_INTERNAL_MOUSE_DISCONNECT)
486 {
487 /* not supported */
488 Irp->IoStatus.Status = STATUS_NOT_IMPLEMENTED;
489 IoCompleteRequest(Irp, IO_NO_INCREMENT);
490 return STATUS_NOT_IMPLEMENTED;
491 }
492 else if (IoStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_INTERNAL_MOUSE_ENABLE)
493 {
494 /* not supported */
495 Irp->IoStatus.Status = STATUS_NOT_SUPPORTED;
496 IoCompleteRequest(Irp, IO_NO_INCREMENT);
497 return STATUS_NOT_SUPPORTED;
498 }
499 else if (IoStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_INTERNAL_MOUSE_DISABLE)
500 {
501 /* not supported */
502 Irp->IoStatus.Status = STATUS_INVALID_DEVICE_REQUEST;
503 IoCompleteRequest(Irp, IO_NO_INCREMENT);
504 return STATUS_INVALID_DEVICE_REQUEST;
505 }
506
507 /* unknown request not supported */
508 Irp->IoStatus.Status = STATUS_NOT_SUPPORTED;
509 IoCompleteRequest(Irp, IO_NO_INCREMENT);
510 return STATUS_NOT_SUPPORTED;
511 }
512
513 NTSTATUS
514 NTAPI
515 MouHid_InternalDeviceControl(
516 IN PDEVICE_OBJECT DeviceObject,
517 IN PIRP Irp)
518 {
519 PMOUHID_DEVICE_EXTENSION DeviceExtension;
520
521 /* get device extension */
522 DeviceExtension = (PMOUHID_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
523
524 /* skip stack location */
525 IoSkipCurrentIrpStackLocation(Irp);
526
527 /* pass and forget */
528 return IoCallDriver(DeviceExtension->NextDeviceObject, Irp);
529 }
530
531 NTSTATUS
532 NTAPI
533 MouHid_Power(
534 IN PDEVICE_OBJECT DeviceObject,
535 IN PIRP Irp)
536 {
537 UNIMPLEMENTED
538 ASSERT(FALSE);
539 return STATUS_NOT_IMPLEMENTED;
540 }
541
542 NTSTATUS
543 MouHid_SubmitRequest(
544 PDEVICE_OBJECT DeviceObject,
545 ULONG IoControlCode,
546 ULONG InputBufferSize,
547 PVOID InputBuffer,
548 ULONG OutputBufferSize,
549 PVOID OutputBuffer)
550 {
551 KEVENT Event;
552 PMOUHID_DEVICE_EXTENSION DeviceExtension;
553 PIRP Irp;
554 NTSTATUS Status;
555 IO_STATUS_BLOCK IoStatus;
556
557 /* get device extension */
558 DeviceExtension = (PMOUHID_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
559
560 /* init event */
561 KeInitializeEvent(&Event, NotificationEvent, FALSE);
562
563 /* build request */
564 Irp = IoBuildDeviceIoControlRequest(IoControlCode, DeviceExtension->NextDeviceObject, InputBuffer, InputBufferSize, OutputBuffer, OutputBufferSize, FALSE, &Event, &IoStatus);
565 if (!Irp)
566 {
567 /* no memory */
568 return STATUS_INSUFFICIENT_RESOURCES;
569 }
570
571 /* send request */
572 Status = IoCallDriver(DeviceExtension->NextDeviceObject, Irp);
573 if (Status == STATUS_PENDING)
574 {
575 /* wait for request to complete */
576 KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
577 Status = IoStatus.Status;
578 }
579
580 /* done */
581 return Status;
582 }
583
584 NTSTATUS
585 NTAPI
586 MouHid_StartDevice(
587 IN PDEVICE_OBJECT DeviceObject)
588 {
589 NTSTATUS Status;
590 ULONG Buttons;
591 HID_COLLECTION_INFORMATION Information;
592 PVOID PreparsedData;
593 HIDP_CAPS Capabilities;
594 ULONG ValueCapsLength;
595 HIDP_VALUE_CAPS ValueCaps;
596 PMOUHID_DEVICE_EXTENSION DeviceExtension;
597 PUSHORT Buffer;
598
599 /* get device extension */
600 DeviceExtension = (PMOUHID_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
601
602 /* query collection information */
603 Status = MouHid_SubmitRequest(DeviceObject, IOCTL_HID_GET_COLLECTION_INFORMATION, 0, NULL, sizeof(HID_COLLECTION_INFORMATION), &Information);
604 if (!NT_SUCCESS(Status))
605 {
606 /* failed to query collection information */
607 DPRINT1("[MOUHID] failed to obtain collection information with %x\n", Status);
608 return Status;
609 }
610
611 /* lets allocate space for preparsed data */
612 PreparsedData = ExAllocatePool(NonPagedPool, Information.DescriptorSize);
613 if (!PreparsedData)
614 {
615 /* no memory */
616 DPRINT1("[MOUHID] no memory size %u\n", Information.DescriptorSize);
617 return STATUS_INSUFFICIENT_RESOURCES;
618 }
619
620 /* now obtain the preparsed data */
621 Status = MouHid_SubmitRequest(DeviceObject, IOCTL_HID_GET_COLLECTION_DESCRIPTOR, 0, NULL, Information.DescriptorSize, PreparsedData);
622 if (!NT_SUCCESS(Status))
623 {
624 /* failed to get preparsed data */
625 DPRINT1("[MOUHID] failed to obtain collection information with %x\n", Status);
626 ExFreePool(PreparsedData);
627 return Status;
628 }
629
630 /* lets get the caps */
631 Status = HidP_GetCaps(PreparsedData, &Capabilities);
632 if (!NT_SUCCESS(Status))
633 {
634 /* failed to get capabilities */
635 DPRINT1("[MOUHID] failed to obtain caps with %x\n", Status);
636 ExFreePool(PreparsedData);
637 return Status;
638 }
639
640 DPRINT1("[MOUHID] Usage %x UsagePage %x\n", Capabilities.Usage, Capabilities.UsagePage, Capabilities.InputReportByteLength);
641
642 /* verify capabilities */
643 if (Capabilities.Usage != HID_USAGE_GENERIC_POINTER && Capabilities.Usage != HID_USAGE_GENERIC_MOUSE || Capabilities.UsagePage != HID_USAGE_PAGE_GENERIC)
644 {
645 /* not supported */
646 ExFreePool(PreparsedData);
647 return STATUS_UNSUCCESSFUL;
648 }
649
650 /* init input report*/
651 DeviceExtension->ReportLength = Capabilities.InputReportByteLength;
652 ASSERT(DeviceExtension->ReportLength);
653 DeviceExtension->Report = (PUCHAR)ExAllocatePool(NonPagedPool, DeviceExtension->ReportLength);
654 ASSERT(DeviceExtension->Report);
655 RtlZeroMemory(DeviceExtension->Report, DeviceExtension->ReportLength);
656
657 /* build mdl */
658 DeviceExtension->ReportMDL = IoAllocateMdl(DeviceExtension->Report, DeviceExtension->ReportLength, FALSE, FALSE, NULL);
659 ASSERT(DeviceExtension->ReportMDL);
660
661 /* init mdl */
662 MmBuildMdlForNonPagedPool(DeviceExtension->ReportMDL);
663
664 /* get max number of buttons */
665 Buttons = HidP_MaxUsageListLength(HidP_Input, HID_USAGE_PAGE_BUTTON, PreparsedData);
666 DPRINT1("[MOUHID] Buttons %lu\n", Buttons);
667 ASSERT(Buttons > 0);
668
669 /* now allocate an array for those buttons */
670 Buffer = ExAllocatePool(NonPagedPool, sizeof(USAGE) * 4 * Buttons);
671 if (!Buffer)
672 {
673 /* no memory */
674 ExFreePool(PreparsedData);
675 return STATUS_INSUFFICIENT_RESOURCES;
676 }
677
678 /* init usage lists */
679 RtlZeroMemory(Buffer, sizeof(USAGE) * 4 * Buttons);
680 DeviceExtension->CurrentUsageList = Buffer;
681 Buffer += Buttons;
682 DeviceExtension->PreviousUsageList = Buffer;
683 Buffer += Buttons;
684 DeviceExtension->MakeUsageList = Buffer;
685 Buffer += Buttons;
686 DeviceExtension->BreakUsageList = Buffer;
687
688 /* store number of buttons */
689 DeviceExtension->UsageListLength = (USHORT)Buttons;
690
691 /* store preparsed data */
692 DeviceExtension->PreparsedData = PreparsedData;
693
694 ValueCapsLength = 1;
695 HidP_GetSpecificValueCaps(HidP_Input, HID_USAGE_PAGE_GENERIC, HIDP_LINK_COLLECTION_UNSPECIFIED, HID_USAGE_GENERIC_X, &ValueCaps, &ValueCapsLength, PreparsedData);
696
697 ValueCapsLength = 1;
698 HidP_GetSpecificValueCaps(HidP_Input, HID_USAGE_PAGE_GENERIC, HIDP_LINK_COLLECTION_UNSPECIFIED, HID_USAGE_GENERIC_Y, &ValueCaps, &ValueCapsLength, PreparsedData);
699
700 /* now check for wheel mouse support */
701 ValueCapsLength = 1;
702 Status = HidP_GetSpecificValueCaps(HidP_Input, HID_USAGE_PAGE_GENERIC, HIDP_LINK_COLLECTION_UNSPECIFIED, HID_USAGE_GENERIC_WHEEL, &ValueCaps, &ValueCapsLength, PreparsedData);
703 if (Status == HIDP_STATUS_SUCCESS )
704 {
705 /* mouse has wheel support */
706 DeviceExtension->MouseIdentifier = WHEELMOUSE_HID_HARDWARE;
707 DeviceExtension->WheelUsagePage = ValueCaps.UsagePage;
708 DPRINT1("[MOUHID] mouse wheel support detected\n", Status);
709 }
710 else
711 {
712 /* check if the mouse has z-axis */
713 ValueCapsLength = 1;
714 Status = HidP_GetSpecificValueCaps(HidP_Input, HID_USAGE_PAGE_GENERIC, HIDP_LINK_COLLECTION_UNSPECIFIED, HID_USAGE_GENERIC_Z, &ValueCaps, &ValueCapsLength, PreparsedData);
715 if (Status == HIDP_STATUS_SUCCESS && ValueCapsLength == 1)
716 {
717 /* wheel support */
718 DeviceExtension->MouseIdentifier = WHEELMOUSE_HID_HARDWARE;
719 DeviceExtension->WheelUsagePage = ValueCaps.UsagePage;
720 DPRINT1("[MOUHID] mouse wheel support detected with z-axis\n", Status);
721 }
722 }
723
724 /* completed successfully */
725 return STATUS_SUCCESS;
726 }
727
728 NTSTATUS
729 NTAPI
730 MouHid_StartDeviceCompletion(
731 IN PDEVICE_OBJECT DeviceObject,
732 IN PIRP Irp,
733 IN PVOID Context)
734 {
735 KeSetEvent((PKEVENT)Context, 0, FALSE);
736 return STATUS_MORE_PROCESSING_REQUIRED;
737 }
738
739 NTSTATUS
740 NTAPI
741 MouHid_Pnp(
742 IN PDEVICE_OBJECT DeviceObject,
743 IN PIRP Irp)
744 {
745 PIO_STACK_LOCATION IoStack;
746 KEVENT Event;
747 NTSTATUS Status;
748 PMOUHID_DEVICE_EXTENSION DeviceExtension;
749
750 /* get device extension */
751 DeviceExtension = (PMOUHID_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
752
753 /* get current irp stack */
754 IoStack = IoGetCurrentIrpStackLocation(Irp);
755 DPRINT1("[MOUHID] IRP_MJ_PNP Request: %x\n", IoStack->MinorFunction);
756
757 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)
758 {
759 /* indicate success */
760 Irp->IoStatus.Status = STATUS_SUCCESS;
761
762 /* skip irp stack location */
763 IoSkipCurrentIrpStackLocation(Irp);
764
765 /* dispatch to lower device */
766 return IoCallDriver(DeviceExtension->NextDeviceObject, Irp);
767 }
768 else if (IoStack->MinorFunction == IRP_MN_REMOVE_DEVICE)
769 {
770 /* FIXME synchronization */
771
772 /* cancel irp */
773 IoCancelIrp(DeviceExtension->Irp);
774
775 /* indicate success */
776 Irp->IoStatus.Status = STATUS_SUCCESS;
777
778 /* skip irp stack location */
779 IoSkipCurrentIrpStackLocation(Irp);
780
781 /* dispatch to lower device */
782 Status = IoCallDriver(DeviceExtension->NextDeviceObject, Irp);
783
784 IoFreeIrp(DeviceExtension->Irp);
785 IoDetachDevice(DeviceExtension->NextDeviceObject);
786 IoDeleteDevice(DeviceObject);
787 return Status;
788 }
789 else if (IoStack->MinorFunction == IRP_MN_START_DEVICE)
790 {
791 /* init event */
792 KeInitializeEvent(&Event, NotificationEvent, FALSE);
793
794 /* copy stack location */
795 IoCopyCurrentIrpStackLocationToNext (Irp);
796
797 /* set completion routine */
798 IoSetCompletionRoutine(Irp, MouHid_StartDeviceCompletion, &Event, TRUE, TRUE, TRUE);
799 Irp->IoStatus.Status = 0;
800
801 /* pass request */
802 Status = IoCallDriver(DeviceExtension->NextDeviceObject, Irp);
803 if (Status == STATUS_PENDING)
804 {
805 KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
806 Status = Irp->IoStatus.Status;
807 }
808
809 if (!NT_SUCCESS(Status))
810 {
811 /* failed */
812 Irp->IoStatus.Status = Status;
813 IoCompleteRequest(Irp, IO_NO_INCREMENT);
814 return Status;
815 }
816
817 /* lets start the device */
818 Status = MouHid_StartDevice(DeviceObject);
819 DPRINT1("MouHid_StartDevice %x\n", Status);
820
821 /* complete request */
822 Irp->IoStatus.Status = Status;
823 IoCompleteRequest(Irp, IO_NO_INCREMENT);
824
825 /* done */
826 return Status;
827 }
828 else
829 {
830 /* skip irp stack location */
831 IoSkipCurrentIrpStackLocation(Irp);
832
833 /* dispatch to lower device */
834 return IoCallDriver(DeviceExtension->NextDeviceObject, Irp);
835 }
836 }
837
838 NTSTATUS
839 NTAPI
840 MouHid_AddDevice(
841 IN PDRIVER_OBJECT DriverObject,
842 IN PDEVICE_OBJECT PhysicalDeviceObject)
843 {
844 NTSTATUS Status;
845 PDEVICE_OBJECT DeviceObject, NextDeviceObject;
846 PMOUHID_DEVICE_EXTENSION DeviceExtension;
847 POWER_STATE State;
848
849 /* create device object */
850 Status = IoCreateDevice(DriverObject, sizeof(MOUHID_DEVICE_EXTENSION), NULL, FILE_DEVICE_MOUSE, 0, FALSE, &DeviceObject);
851 if (!NT_SUCCESS(Status))
852 {
853 /* failed to create device object */
854 return Status;
855 }
856
857 /* now attach it */
858 NextDeviceObject = IoAttachDeviceToDeviceStack(DeviceObject, PhysicalDeviceObject);
859 if (!NextDeviceObject)
860 {
861 /* failed to attach */
862 IoDeleteDevice(DeviceObject);
863 return STATUS_DEVICE_NOT_CONNECTED;
864 }
865
866 /* get device extension */
867 DeviceExtension = (PMOUHID_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
868
869 /* zero extension */
870 RtlZeroMemory(DeviceExtension, sizeof(MOUHID_DEVICE_EXTENSION));
871
872 /* init device extension */
873 DeviceExtension->MouseIdentifier = MOUSE_HID_HARDWARE;
874 DeviceExtension->WheelUsagePage = 0;
875 DeviceExtension->NextDeviceObject = NextDeviceObject;
876 KeInitializeEvent(&DeviceExtension->ReadCompletionEvent, NotificationEvent, FALSE);
877 DeviceExtension->Irp = IoAllocateIrp(NextDeviceObject->StackSize, FALSE);
878
879 /* FIXME handle allocation error */
880 ASSERT(DeviceExtension->Irp);
881
882 /* FIXME query parameter 'FlipFlopWheel', 'WheelScalingFactor' */
883
884 /* set power state to D0 */
885 State.DeviceState = PowerDeviceD0;
886 PoSetPowerState(DeviceObject, DevicePowerState, State);
887
888 /* init device object */
889 DeviceObject->Flags |= DO_BUFFERED_IO | DO_POWER_PAGABLE;
890 DeviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
891
892 /* completed successfully */
893 return STATUS_SUCCESS;
894 }
895
896 VOID
897 NTAPI
898 MouHid_Unload(
899 IN PDRIVER_OBJECT DriverObject)
900 {
901 UNIMPLEMENTED
902 }
903
904
905 NTSTATUS
906 NTAPI
907 DriverEntry(
908 IN PDRIVER_OBJECT DriverObject,
909 IN PUNICODE_STRING RegPath)
910 {
911 /* FIXME check for parameters 'UseOnlyMice', 'TreatAbsoluteAsRelative', 'TreatAbsolutePointerAsAbsolute' */
912
913 /* initialize driver object */
914 DriverObject->DriverUnload = MouHid_Unload;
915 DriverObject->DriverExtension->AddDevice = MouHid_AddDevice;
916 DriverObject->MajorFunction[IRP_MJ_CREATE] = MouHid_Create;
917 DriverObject->MajorFunction[IRP_MJ_CLOSE] = MouHid_Close;
918 DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = MouHid_DeviceControl;
919 DriverObject->MajorFunction[IRP_MJ_INTERNAL_DEVICE_CONTROL] = MouHid_InternalDeviceControl;
920 DriverObject->MajorFunction[IRP_MJ_POWER] = MouHid_Power;
921 DriverObject->MajorFunction[IRP_MJ_PNP] = MouHid_Pnp;
922 DriverObject->DriverUnload = MouHid_Unload;
923 DriverObject->DriverExtension->AddDevice = MouHid_AddDevice;
924
925 /* done */
926 return STATUS_SUCCESS;
927 }