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