xref: /reactos/drivers/hid/mouhid/mouhid.c (revision 05c20641)
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 
141 
142 NTSTATUS
143 NTAPI
144 MouHid_Create(
145     IN PDEVICE_OBJECT DeviceObject,
146     IN PIRP Irp)
147 {
148     UNIMPLEMENTED
149     ASSERT(FALSE);
150     return STATUS_NOT_IMPLEMENTED;
151 }
152 
153 
154 NTSTATUS
155 NTAPI
156 MouHid_Close(
157     IN PDEVICE_OBJECT DeviceObject,
158     IN PIRP Irp)
159 {
160     UNIMPLEMENTED
161     ASSERT(FALSE);
162     return STATUS_NOT_IMPLEMENTED;
163 }
164 
165 NTSTATUS
166 NTAPI
167 MouHid_DeviceControl(
168     IN PDEVICE_OBJECT DeviceObject,
169     IN PIRP Irp)
170 {
171     PIO_STACK_LOCATION IoStack;
172     PMOUSE_ATTRIBUTES Attributes;
173     PMOUHID_DEVICE_EXTENSION DeviceExtension;
174     PCONNECT_DATA Data;
175 
176     /* get current stack location */
177     IoStack = IoGetCurrentIrpStackLocation(Irp);
178 
179     /* get device extension */
180     DeviceExtension = (PMOUHID_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
181 
182     /* handle requests */
183     if (IoStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_MOUSE_QUERY_ATTRIBUTES)
184     {
185          /* verify output buffer length */
186          if (IoStack->Parameters.DeviceIoControl.OutputBufferLength < sizeof(MOUSE_ATTRIBUTES))
187          {
188              /* invalid request */
189              Irp->IoStatus.Status = STATUS_BUFFER_TOO_SMALL;
190              IoCompleteRequest(Irp, IO_NO_INCREMENT);
191              return STATUS_BUFFER_TOO_SMALL;
192          }
193 
194          /* get output buffer */
195          Attributes = (PMOUSE_ATTRIBUTES)Irp->AssociatedIrp.SystemBuffer;
196 
197          /* type of mouse */
198          Attributes->MouseIdentifier = DeviceExtension->MouseIdentifier;
199 
200          /* number of buttons */
201          Attributes->NumberOfButtons = DeviceExtension->UsageListLength;
202 
203          /* sample rate not used for usb */
204          Attributes->SampleRate = 0;
205 
206          /* queue length */
207          Attributes->InputDataQueueLength = 2;
208 
209          /* complete request */
210          Irp->IoStatus.Information = sizeof(MOUSE_ATTRIBUTES);
211          Irp->IoStatus.Status = STATUS_SUCCESS;
212          IoCompleteRequest(Irp, IO_NO_INCREMENT);
213          return STATUS_SUCCESS;
214     }
215     else if (IoStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_INTERNAL_MOUSE_CONNECT)
216     {
217          /* verify input buffer length */
218          if (IoStack->Parameters.DeviceIoControl.InputBufferLength < sizeof(CONNECT_DATA))
219          {
220              /* invalid request */
221              Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
222              IoCompleteRequest(Irp, IO_NO_INCREMENT);
223              return STATUS_INVALID_PARAMETER;
224          }
225 
226          /* is it already connected */
227          if (DeviceExtension->ClassService)
228          {
229              /* already connected */
230              Irp->IoStatus.Status = STATUS_SHARING_VIOLATION;
231              IoCompleteRequest(Irp, IO_NO_INCREMENT);
232              return STATUS_SHARING_VIOLATION;
233          }
234 
235          /* get connect data */
236          Data = (PCONNECT_DATA)IoStack->Parameters.DeviceIoControl.Type3InputBuffer;
237 
238          /* store connect details */
239          DeviceExtension->ClassDeviceObject = Data->ClassDeviceObject;
240          DeviceExtension->ClassService = Data->ClassService;
241 
242          /* completed successfully */
243          Irp->IoStatus.Status = STATUS_SUCCESS;
244          IoCompleteRequest(Irp, IO_NO_INCREMENT);
245          return STATUS_SUCCESS;
246     }
247     else if (IoStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_INTERNAL_MOUSE_DISCONNECT)
248     {
249         /* not supported */
250         Irp->IoStatus.Status = STATUS_NOT_IMPLEMENTED;
251         IoCompleteRequest(Irp, IO_NO_INCREMENT);
252         return STATUS_NOT_IMPLEMENTED;
253     }
254     else if (IoStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_INTERNAL_MOUSE_ENABLE)
255     {
256         /* not supported */
257         Irp->IoStatus.Status = STATUS_NOT_SUPPORTED;
258         IoCompleteRequest(Irp, IO_NO_INCREMENT);
259         return STATUS_NOT_SUPPORTED;
260     }
261     else if (IoStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_INTERNAL_MOUSE_DISABLE)
262     {
263         /* not supported */
264         Irp->IoStatus.Status = STATUS_INVALID_DEVICE_REQUEST;
265         IoCompleteRequest(Irp, IO_NO_INCREMENT);
266         return STATUS_INVALID_DEVICE_REQUEST;
267     }
268 
269     /* unknown request not supported */
270     Irp->IoStatus.Status = STATUS_NOT_SUPPORTED;
271     IoCompleteRequest(Irp, IO_NO_INCREMENT);
272     return STATUS_NOT_SUPPORTED;
273 }
274 
275 NTSTATUS
276 NTAPI
277 MouHid_InternalDeviceControl(
278     IN PDEVICE_OBJECT DeviceObject,
279     IN PIRP Irp)
280 {
281     PMOUHID_DEVICE_EXTENSION DeviceExtension;
282 
283     /* get device extension */
284     DeviceExtension = (PMOUHID_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
285 
286     /* skip stack location */
287     IoSkipCurrentIrpStackLocation(Irp);
288 
289     /* pass and forget */
290     return IoCallDriver(DeviceExtension->NextDeviceObject, Irp);
291 }
292 
293 NTSTATUS
294 NTAPI
295 MouHid_Power(
296     IN PDEVICE_OBJECT DeviceObject,
297     IN PIRP Irp)
298 {
299     UNIMPLEMENTED
300     ASSERT(FALSE);
301     return STATUS_NOT_IMPLEMENTED;
302 }
303 
304 NTSTATUS
305 MouHid_SubmitRequest(
306     PDEVICE_OBJECT DeviceObject,
307     ULONG IoControlCode,
308     ULONG InputBufferSize,
309     PVOID InputBuffer,
310     ULONG OutputBufferSize,
311     PVOID OutputBuffer)
312 {
313     KEVENT Event;
314     PMOUHID_DEVICE_EXTENSION DeviceExtension;
315     PIRP Irp;
316     NTSTATUS Status;
317     IO_STATUS_BLOCK IoStatus;
318 
319     /* get device extension */
320     DeviceExtension = (PMOUHID_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
321 
322     /* init event */
323     KeInitializeEvent(&Event, NotificationEvent, FALSE);
324 
325     /* build request */
326     Irp = IoBuildDeviceIoControlRequest(IoControlCode, DeviceExtension->NextDeviceObject, InputBuffer, InputBufferSize, OutputBuffer, OutputBufferSize, FALSE, &Event, &IoStatus);
327     if (!Irp)
328     {
329         /* no memory */
330         return STATUS_INSUFFICIENT_RESOURCES;
331     }
332 
333     /* send request */
334     Status = IoCallDriver(DeviceExtension->NextDeviceObject, Irp);
335     if (Status == STATUS_PENDING)
336     {
337         /* wait for request to complete */
338         KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
339         Status = IoStatus.Status;
340     }
341 
342     /* done */
343     return Status;
344 }
345 
346 NTSTATUS
347 NTAPI
348 MouHid_StartDevice(
349     IN PDEVICE_OBJECT DeviceObject)
350 {
351     NTSTATUS Status;
352     ULONG Buttons;
353     HID_COLLECTION_INFORMATION Information;
354     PVOID PreparsedData;
355     HIDP_CAPS Capabilities;
356     ULONG ValueCapsLength;
357     HIDP_VALUE_CAPS ValueCaps;
358     PMOUHID_DEVICE_EXTENSION DeviceExtension;
359     PUSHORT Buffer;
360 
361     /* get device extension */
362     DeviceExtension = (PMOUHID_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
363 
364     /* query collection information */
365     Status = MouHid_SubmitRequest(DeviceObject, IOCTL_HID_GET_COLLECTION_INFORMATION, 0, NULL, sizeof(HID_COLLECTION_INFORMATION), &Information);
366     if (!NT_SUCCESS(Status))
367     {
368         /* failed to query collection information */
369         return Status;
370     }
371 
372     /* lets allocate space for preparsed data */
373     PreparsedData = ExAllocatePool(NonPagedPool, Information.DescriptorSize);
374     if (PreparsedData)
375     {
376         /* no memory */
377         return STATUS_INSUFFICIENT_RESOURCES;
378     }
379 
380     /* now obtain the preparsed data */
381     Status = MouHid_SubmitRequest(DeviceObject, IOCTL_HID_GET_DRIVER_CONFIG, 0, NULL, Information.DescriptorSize, PreparsedData);
382     if (!NT_SUCCESS(Status))
383     {
384         /* failed to get preparsed data */
385         ExFreePool(PreparsedData);
386         return Status;
387     }
388 
389     /* lets get the caps */
390     Status = HidP_GetCaps(PreparsedData, &Capabilities);
391     if (!NT_SUCCESS(Status))
392     {
393         /* failed to get capabilities */
394         ExFreePool(PreparsedData);
395         return Status;
396     }
397 
398     /* verify capabilities */
399     if (Capabilities.Usage != HID_USAGE_GENERIC_POINTER && Capabilities.Usage != HID_USAGE_GENERIC_MOUSE || Capabilities.UsagePage != HID_USAGE_PAGE_GENERIC)
400     {
401         /* not supported */
402         ExFreePool(PreparsedData);
403         return STATUS_UNSUCCESSFUL;
404     }
405 
406     /* init input report*/
407     DeviceExtension->ReportLength = Capabilities.InputReportByteLength;
408     ASSERT(DeviceExtension->ReportLength);
409     DeviceExtension->Report = (PUCHAR)ExAllocatePool(NonPagedPool, DeviceExtension->ReportLength);
410     ASSERT(DeviceExtension->Report);
411     RtlZeroMemory(DeviceExtension->Report, DeviceExtension->ReportLength);
412     DeviceExtension->ReportMDL = IoAllocateMdl(DeviceExtension->Report, DeviceExtension->ReportLength, FALSE, FALSE, NULL);
413     ASSERT(DeviceExtension->ReportMDL);
414 
415 
416     /* get max number of buttons */
417     Buttons = HidP_MaxUsageListLength(HidP_Input, HID_USAGE_PAGE_BUTTON, PreparsedData);
418     ASSERT(Buttons > 0);
419 
420     /* now allocate an array for those buttons */
421     Buffer = ExAllocatePool(NonPagedPool, sizeof(USAGE) * 4 * Buttons);
422     if (!Buffer)
423     {
424         /* no memory */
425         ExFreePool(PreparsedData);
426         return STATUS_INSUFFICIENT_RESOURCES;
427     }
428 
429     /* init usage lists */
430     RtlZeroMemory(Buffer, sizeof(USAGE) * 4 * Buttons);
431     DeviceExtension->CurrentUsageList = Buffer;
432     Buffer += Buttons;
433     DeviceExtension->PreviousUsageList = Buffer;
434     Buffer += Buttons;
435     DeviceExtension->MakeUsageList = Buffer;
436     Buffer += Buttons;
437     DeviceExtension->BreakUsageList = Buffer;
438 
439     /* store number of buttons */
440     DeviceExtension->UsageListLength = (USHORT)Buttons;
441 
442     /* store preparsed data */
443     DeviceExtension->PreparsedData = PreparsedData;
444 
445     ValueCapsLength = 1;
446     HidP_GetSpecificValueCaps(HidP_Input, HID_USAGE_PAGE_GENERIC, HIDP_LINK_COLLECTION_UNSPECIFIED, HID_USAGE_GENERIC_X, &ValueCaps, &ValueCapsLength, PreparsedData);
447 
448     ValueCapsLength = 1;
449     HidP_GetSpecificValueCaps(HidP_Input, HID_USAGE_PAGE_GENERIC, HIDP_LINK_COLLECTION_UNSPECIFIED, HID_USAGE_GENERIC_Y, &ValueCaps, &ValueCapsLength, PreparsedData);
450 
451     /* now check for wheel mouse support */
452     ValueCapsLength = 1;
453     Status = HidP_GetSpecificValueCaps(HidP_Input, HID_USAGE_PAGE_GENERIC, HIDP_LINK_COLLECTION_UNSPECIFIED, HID_USAGE_GENERIC_WHEEL, &ValueCaps, &ValueCapsLength, PreparsedData);
454     if (Status == HIDP_STATUS_SUCCESS )
455     {
456         /* mouse has wheel support */
457         DeviceExtension->MouseIdentifier = WHEELMOUSE_HID_HARDWARE;
458         DeviceExtension->WheelUsagePage = ValueCaps.UsagePage;
459     }
460     else
461     {
462         /* check if the mouse has z-axis */
463         ValueCapsLength = 1;
464         Status = HidP_GetSpecificValueCaps(HidP_Input, HID_USAGE_PAGE_GENERIC, HIDP_LINK_COLLECTION_UNSPECIFIED, HID_USAGE_GENERIC_Z, &ValueCaps, &ValueCapsLength, PreparsedData);
465         if (Status == HIDP_STATUS_SUCCESS && ValueCapsLength == 1)
466         {
467             /* wheel support */
468             DeviceExtension->MouseIdentifier = WHEELMOUSE_HID_HARDWARE;
469             DeviceExtension->WheelUsagePage = ValueCaps.UsagePage;
470         }
471     }
472 
473     /* completed successfully */
474     return STATUS_SUCCESS;
475 }
476 
477 NTSTATUS
478 NTAPI
479 MouHid_StartDeviceCompletion(
480     IN PDEVICE_OBJECT  DeviceObject,
481     IN PIRP  Irp,
482     IN PVOID  Context)
483 {
484     KeSetEvent((PKEVENT)Context, 0, FALSE);
485     return STATUS_MORE_PROCESSING_REQUIRED;
486 }
487 
488 NTSTATUS
489 NTAPI
490 MouHid_Pnp(
491     IN PDEVICE_OBJECT DeviceObject,
492     IN PIRP Irp)
493 {
494     PIO_STACK_LOCATION IoStack;
495     KEVENT Event;
496     NTSTATUS Status;
497     PMOUHID_DEVICE_EXTENSION DeviceExtension;
498 
499     /* get device extension */
500     DeviceExtension = (PMOUHID_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
501 
502     /* get current irp stack */
503     IoStack = IoGetCurrentIrpStackLocation(Irp);
504 
505     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)
506     {
507         /* indicate success */
508         Irp->IoStatus.Status = STATUS_SUCCESS;
509 
510         /* skip irp stack location */
511         IoSkipCurrentIrpStackLocation(Irp);
512 
513         /* dispatch to lower device */
514         return IoCallDriver(DeviceExtension->NextDeviceObject, Irp);
515     }
516     else if (IoStack->MinorFunction == IRP_MN_REMOVE_DEVICE)
517     {
518         /* FIXME synchronization */
519 
520         /* cancel irp */
521         IoCancelIrp(DeviceExtension->Irp);
522 
523         /* indicate success */
524         Irp->IoStatus.Status = STATUS_SUCCESS;
525 
526         /* skip irp stack location */
527         IoSkipCurrentIrpStackLocation(Irp);
528 
529         /* dispatch to lower device */
530         Status = IoCallDriver(DeviceExtension->NextDeviceObject, Irp);
531 
532         IoFreeIrp(DeviceExtension->Irp);
533         IoDetachDevice(DeviceExtension->NextDeviceObject);
534         IoDeleteDevice(DeviceObject);
535         return Status;
536     }
537     else if (IoStack->MinorFunction == IRP_MN_START_DEVICE)
538     {
539         /* init event */
540         KeInitializeEvent(&Event, NotificationEvent, FALSE);
541 
542         /* copy stack location */
543         IoCopyCurrentIrpStackLocationToNext (Irp);
544 
545         /* set completion routine */
546         IoSetCompletionRoutine(Irp, MouHid_StartDeviceCompletion, &Event, TRUE, TRUE, TRUE);
547         Irp->IoStatus.Status = 0;
548 
549         /* pass request */
550         Status = IoCallDriver(DeviceExtension->NextDeviceObject, Irp);
551         if (Status == STATUS_PENDING)
552         {
553             KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
554             Status = Irp->IoStatus.Status;
555         }
556 
557         if (!NT_SUCCESS(Status))
558         {
559             /* failed */
560             Irp->IoStatus.Status = Status;
561             IoCompleteRequest(Irp, IO_NO_INCREMENT);
562             return Status;
563         }
564 
565         /* lets start the device */
566         Status = MouHid_StartDevice(DeviceObject);
567         DPRINT1("MouHid_StartDevice %x\n", Status);
568 
569         /* complete request */
570         Irp->IoStatus.Status = Status;
571         IoCompleteRequest(Irp, IO_NO_INCREMENT);
572 
573         /* done */
574         return Status;
575     }
576     else
577     {
578         /* skip irp stack location */
579         IoSkipCurrentIrpStackLocation(Irp);
580 
581         /* dispatch to lower device */
582         return IoCallDriver(DeviceExtension->NextDeviceObject, Irp);
583     }
584 }
585 
586 NTSTATUS
587 NTAPI
588 MouHid_AddDevice(
589     IN PDRIVER_OBJECT DriverObject,
590     IN PDEVICE_OBJECT PhysicalDeviceObject)
591 {
592     NTSTATUS Status;
593     PDEVICE_OBJECT DeviceObject, NextDeviceObject;
594     PMOUHID_DEVICE_EXTENSION DeviceExtension;
595     POWER_STATE State;
596 
597     /* create device object */
598     Status = IoCreateDevice(DriverObject, sizeof(MOUHID_DEVICE_EXTENSION), NULL, FILE_DEVICE_MOUSE, 0, FALSE, &DeviceObject);
599     if (!NT_SUCCESS(Status))
600     {
601         /* failed to create device object */
602         return Status;
603     }
604 
605     /* now attach it */
606     NextDeviceObject = IoAttachDeviceToDeviceStack(DeviceObject, PhysicalDeviceObject);
607     if (!NextDeviceObject)
608     {
609         /* failed to attach */
610         IoDeleteDevice(DeviceObject);
611         return STATUS_DEVICE_NOT_CONNECTED;
612     }
613 
614     /* get device extension */
615     DeviceExtension = (PMOUHID_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
616 
617     /* zero extension */
618     RtlZeroMemory(DeviceExtension, sizeof(MOUHID_DEVICE_EXTENSION));
619 
620     /* init device extension */
621     DeviceExtension->MouseIdentifier = MOUSE_HID_HARDWARE;
622     DeviceExtension->WheelUsagePage = 0;
623     DeviceExtension->NextDeviceObject = NextDeviceObject;
624     KeInitializeEvent(&DeviceExtension->Event, NotificationEvent, FALSE);
625     DeviceExtension->Irp = IoAllocateIrp(NextDeviceObject->StackSize, FALSE);
626 
627     /* FIXME handle allocation error */
628     ASSERT(DeviceExtension->Irp);
629 
630     /* FIXME query parameter 'FlipFlopWheel', 'WheelScalingFactor' */
631 
632     /* set power state to D0 */
633     State.DeviceState =  PowerDeviceD0;
634     PoSetPowerState(DeviceObject, DevicePowerState, State);
635 
636     /* init device object */
637     DeviceObject->Flags |= DO_BUFFERED_IO | DO_POWER_PAGABLE;
638     DeviceObject->Flags  &= ~DO_DEVICE_INITIALIZING;
639 
640     /* completed successfully */
641     return STATUS_SUCCESS;
642 }
643 
644 VOID
645 NTAPI
646 MouHid_Unload(
647     IN PDRIVER_OBJECT DriverObject)
648 {
649     UNIMPLEMENTED
650     ASSERT(FALSE);
651 }
652 
653 
654 NTSTATUS
655 NTAPI
656 DriverEntry(
657     IN PDRIVER_OBJECT DriverObject,
658     IN PUNICODE_STRING RegPath)
659 {
660     /* FIXME check for parameters 'UseOnlyMice', 'TreatAbsoluteAsRelative', 'TreatAbsolutePointerAsAbsolute' */
661 
662     /* initialize driver object */
663     DriverObject->DriverUnload = MouHid_Unload;
664     DriverObject->DriverExtension->AddDevice = MouHid_AddDevice;
665     DriverObject->MajorFunction[IRP_MJ_CREATE] = MouHid_Create;
666     DriverObject->MajorFunction[IRP_MJ_CLOSE] = MouHid_Close;
667     DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = MouHid_DeviceControl;
668     DriverObject->MajorFunction[IRP_MJ_INTERNAL_DEVICE_CONTROL] = MouHid_InternalDeviceControl;
669     DriverObject->MajorFunction[IRP_MJ_POWER] = MouHid_Power;
670     DriverObject->MajorFunction[IRP_MJ_PNP] = MouHid_Pnp;
671     DriverObject->DriverUnload = MouHid_Unload;
672     DriverObject->DriverExtension->AddDevice = MouHid_AddDevice;
673 
674     /* done */
675     return STATUS_SUCCESS;
676 }
677