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