xref: /reactos/drivers/hid/mouhid/mouhid.c (revision 7eead935)
1 /*
2  * PROJECT:     ReactOS HID Stack
3  * LICENSE:     GPL - See COPYING in the top level directory
4  * FILE:        drivers/hid/mouhid/mouhid.c
5  * PURPOSE:     Mouse HID Driver
6  * PROGRAMMERS:
7  *              Michael Martin (michael.martin@reactos.org)
8  *              Johannes Anderwald (johannes.anderwald@reactos.org)
9  */
10 
11 #include "mouhid.h"
12 
13 static USHORT MouHid_ButtonUpFlags[] =
14 {
15     0xFF, /* unused */
16     MOUSE_LEFT_BUTTON_DOWN,
17     MOUSE_RIGHT_BUTTON_DOWN,
18     MOUSE_MIDDLE_BUTTON_DOWN,
19     MOUSE_BUTTON_4_DOWN,
20     MOUSE_BUTTON_5_DOWN
21 };
22 
23 static USHORT MouHid_ButtonDownFlags[] =
24 {
25     0xFF, /* unused */
26     MOUSE_LEFT_BUTTON_UP,
27     MOUSE_RIGHT_BUTTON_UP,
28     MOUSE_MIDDLE_BUTTON_UP,
29     MOUSE_BUTTON_4_UP,
30     MOUSE_BUTTON_5_UP
31 };
32 
33 
34 VOID
35 MouHid_GetButtonMove(
36     IN PMOUHID_DEVICE_EXTENSION DeviceExtension,
37     OUT PLONG LastX,
38     OUT PLONG LastY)
39 {
40     NTSTATUS Status;
41     ULONG ValueX, ValueY;
42 
43     /* init result */
44     *LastX = 0;
45     *LastY = 0;
46 
47     if (!DeviceExtension->MouseAbsolute)
48     {
49         /* get scaled usage value x */
50         Status =  HidP_GetScaledUsageValue(HidP_Input,
51                                        HID_USAGE_PAGE_GENERIC,
52                                        HIDP_LINK_COLLECTION_UNSPECIFIED,
53                                        HID_USAGE_GENERIC_X,
54                                        LastX,
55                                        DeviceExtension->PreparsedData,
56                                        DeviceExtension->Report,
57                                        DeviceExtension->ReportLength);
58 
59         if (Status != HIDP_STATUS_SUCCESS)
60         {
61             /* FIXME: handle more errors */
62             if (Status == HIDP_STATUS_BAD_LOG_PHY_VALUES)
63             {
64                 /* FIXME: assume it operates in absolute mode */
65                 DeviceExtension->MouseAbsolute = TRUE;
66 
67                 /* get unscaled value */
68                 Status = HidP_GetUsageValue(HidP_Input,
69                                         HID_USAGE_PAGE_GENERIC,
70                                         HIDP_LINK_COLLECTION_UNSPECIFIED,
71                                         HID_USAGE_GENERIC_X,
72                                         &ValueX,
73                                         DeviceExtension->PreparsedData,
74                                         DeviceExtension->Report,
75                                         DeviceExtension->ReportLength);
76 
77                 /* FIXME handle error */
78                 ASSERT(Status == HIDP_STATUS_SUCCESS);
79 
80                 /* absolute pointing devices values need be in range 0 - 0xffff */
81                 ASSERT(DeviceExtension->ValueCapsX.LogicalMax > 0);
82                 ASSERT(DeviceExtension->ValueCapsX.LogicalMax > DeviceExtension->ValueCapsX.LogicalMin);
83 
84                 /* convert to logical range */
85                 *LastX = (ValueX * VIRTUAL_SCREEN_SIZE_X) / DeviceExtension->ValueCapsX.LogicalMax;
86             }
87         }
88     }
89     else
90     {
91         /* get unscaled value */
92         Status = HidP_GetUsageValue(HidP_Input,
93                                     HID_USAGE_PAGE_GENERIC,
94                                     HIDP_LINK_COLLECTION_UNSPECIFIED,
95                                     HID_USAGE_GENERIC_X,
96                                     &ValueX,
97                                     DeviceExtension->PreparsedData,
98                                     DeviceExtension->Report,
99                                     DeviceExtension->ReportLength);
100 
101         /* FIXME handle error */
102         ASSERT(Status == HIDP_STATUS_SUCCESS);
103 
104         /* absolute pointing devices values need be in range 0 - 0xffff */
105         ASSERT(DeviceExtension->ValueCapsX.LogicalMax > 0);
106         ASSERT(DeviceExtension->ValueCapsX.LogicalMax > DeviceExtension->ValueCapsX.LogicalMin);
107 
108         /* convert to logical range */
109         *LastX = (ValueX * VIRTUAL_SCREEN_SIZE_X) / DeviceExtension->ValueCapsX.LogicalMax;
110     }
111 
112     if (!DeviceExtension->MouseAbsolute)
113     {
114         /* get scaled usage value y */
115         Status =  HidP_GetScaledUsageValue(HidP_Input,
116                                        HID_USAGE_PAGE_GENERIC,
117                                        HIDP_LINK_COLLECTION_UNSPECIFIED,
118                                        HID_USAGE_GENERIC_Y,
119                                        LastY,
120                                        DeviceExtension->PreparsedData,
121                                        DeviceExtension->Report,
122                                        DeviceExtension->ReportLength);
123 
124         if (Status != HIDP_STATUS_SUCCESS)
125         {
126             // FIXME: handle more errors
127             if (Status == HIDP_STATUS_BAD_LOG_PHY_VALUES)
128             {
129                 // assume it operates in absolute mode
130                 DeviceExtension->MouseAbsolute = TRUE;
131 
132                 // get unscaled value
133                 Status = HidP_GetUsageValue(HidP_Input,
134                                         HID_USAGE_PAGE_GENERIC,
135                                         HIDP_LINK_COLLECTION_UNSPECIFIED,
136                                         HID_USAGE_GENERIC_Y,
137                                         &ValueY,
138                                         DeviceExtension->PreparsedData,
139                                         DeviceExtension->Report,
140                                         DeviceExtension->ReportLength);
141 
142                 /* FIXME handle error */
143                 ASSERT(Status == HIDP_STATUS_SUCCESS);
144 
145                 /* absolute pointing devices values need be in range 0 - 0xffff */
146                 ASSERT(DeviceExtension->ValueCapsY.LogicalMax > 0);
147                 ASSERT(DeviceExtension->ValueCapsY.LogicalMax > DeviceExtension->ValueCapsY.LogicalMin);
148 
149                 /* convert to logical range */
150                 *LastY = (ValueY * VIRTUAL_SCREEN_SIZE_Y) / DeviceExtension->ValueCapsY.LogicalMax;
151             }
152         }
153     }
154     else
155     {
156         // get unscaled value
157         Status = HidP_GetUsageValue(HidP_Input,
158                                 HID_USAGE_PAGE_GENERIC,
159                                 HIDP_LINK_COLLECTION_UNSPECIFIED,
160                                 HID_USAGE_GENERIC_Y,
161                                 &ValueY,
162                                 DeviceExtension->PreparsedData,
163                                 DeviceExtension->Report,
164                                 DeviceExtension->ReportLength);
165 
166         /* FIXME handle error */
167         ASSERT(Status == HIDP_STATUS_SUCCESS);
168 
169         /* absolute pointing devices values need be in range 0 - 0xffff */
170         ASSERT(DeviceExtension->ValueCapsY.LogicalMax > 0);
171         ASSERT(DeviceExtension->ValueCapsY.LogicalMax > DeviceExtension->ValueCapsY.LogicalMin);
172 
173         /* convert to logical range */
174         *LastY = (ValueY * VIRTUAL_SCREEN_SIZE_Y) / DeviceExtension->ValueCapsY.LogicalMax;
175     }
176 }
177 
178 VOID
179 MouHid_GetButtonFlags(
180     IN PMOUHID_DEVICE_EXTENSION DeviceExtension,
181     OUT PUSHORT ButtonFlags,
182     OUT PUSHORT Flags)
183 {
184     NTSTATUS Status;
185     USAGE Usage;
186     ULONG Index;
187     PUSAGE TempList;
188     ULONG CurrentUsageListLength;
189 
190     /* init flags */
191     *ButtonFlags = 0;
192     *Flags = 0;
193 
194     /* get usages */
195     CurrentUsageListLength = DeviceExtension->UsageListLength;
196     Status = HidP_GetUsages(HidP_Input,
197                             HID_USAGE_PAGE_BUTTON,
198                             HIDP_LINK_COLLECTION_UNSPECIFIED,
199                             DeviceExtension->CurrentUsageList,
200                             &CurrentUsageListLength,
201                             DeviceExtension->PreparsedData,
202                             DeviceExtension->Report,
203                             DeviceExtension->ReportLength);
204     if (Status != HIDP_STATUS_SUCCESS)
205     {
206         DPRINT1("MouHid_GetButtonFlags failed to get usages with %x\n", Status);
207         return;
208     }
209 
210     /* extract usage list difference */
211     Status = HidP_UsageListDifference(DeviceExtension->PreviousUsageList,
212                                       DeviceExtension->CurrentUsageList,
213                                       DeviceExtension->BreakUsageList,
214                                       DeviceExtension->MakeUsageList,
215                                       DeviceExtension->UsageListLength);
216     if (Status != HIDP_STATUS_SUCCESS)
217     {
218         DPRINT1("MouHid_GetButtonFlags failed to get usages with %x\n", Status);
219         return;
220     }
221 
222     if (DeviceExtension->UsageListLength)
223     {
224         Index = 0;
225         do
226         {
227             /* get usage */
228             Usage = DeviceExtension->BreakUsageList[Index];
229             if (!Usage)
230                 break;
231 
232             if (Usage <= 5)
233             {
234                 /* max 5 buttons supported */
235                 *ButtonFlags |= MouHid_ButtonDownFlags[Usage];
236             }
237 
238             /* move to next index*/
239             Index++;
240         }while(Index < DeviceExtension->UsageListLength);
241     }
242 
243     if (DeviceExtension->UsageListLength)
244     {
245         Index = 0;
246         do
247         {
248             /* get usage */
249             Usage = DeviceExtension->MakeUsageList[Index];
250             if (!Usage)
251                 break;
252 
253             if (Usage <= 5)
254             {
255                 /* max 5 buttons supported */
256                 *ButtonFlags |= MouHid_ButtonUpFlags[Usage];
257             }
258 
259             /* move to next index*/
260             Index++;
261         }while(Index < DeviceExtension->UsageListLength);
262     }
263 
264     /* now switch the previous list with current list */
265     TempList = DeviceExtension->CurrentUsageList;
266     DeviceExtension->CurrentUsageList = DeviceExtension->PreviousUsageList;
267     DeviceExtension->PreviousUsageList = TempList;
268 
269     if (DeviceExtension->MouseAbsolute)
270     {
271         // mouse operates absolute
272         *Flags |= MOUSE_MOVE_ABSOLUTE;
273     }
274 }
275 
276 VOID
277 MouHid_DispatchInputData(
278     IN PMOUHID_DEVICE_EXTENSION DeviceExtension,
279     IN PMOUSE_INPUT_DATA InputData)
280 {
281     KIRQL OldIrql;
282     ULONG InputDataConsumed;
283 
284     if (!DeviceExtension->ClassService)
285         return;
286 
287     /* sanity check */
288     ASSERT(DeviceExtension->ClassService);
289     ASSERT(DeviceExtension->ClassDeviceObject);
290 
291     /* raise irql */
292     KeRaiseIrql(DISPATCH_LEVEL, &OldIrql);
293 
294     /* dispatch input data */
295     (*(PSERVICE_CALLBACK_ROUTINE)DeviceExtension->ClassService)(DeviceExtension->ClassDeviceObject, InputData, InputData + 1, &InputDataConsumed);
296 
297     /* lower irql to previous level */
298     KeLowerIrql(OldIrql);
299 }
300 
301 NTSTATUS
302 NTAPI
303 MouHid_ReadCompletion(
304     IN PDEVICE_OBJECT  DeviceObject,
305     IN PIRP  Irp,
306     IN PVOID  Context)
307 {
308     PMOUHID_DEVICE_EXTENSION DeviceExtension;
309     USHORT ButtonFlags;
310     LONG UsageValue;
311     NTSTATUS Status;
312     LONG LastX, LastY;
313     MOUSE_INPUT_DATA MouseInputData;
314     USHORT Flags;
315 
316     /* get device extension */
317     DeviceExtension = Context;
318 
319     if (Irp->IoStatus.Status == STATUS_PRIVILEGE_NOT_HELD ||
320         Irp->IoStatus.Status == STATUS_DEVICE_NOT_CONNECTED ||
321         Irp->IoStatus.Status == STATUS_CANCELLED ||
322         DeviceExtension->StopReadReport)
323     {
324         /* failed to read or should be stopped*/
325         DPRINT1("[MOUHID] ReadCompletion terminating read Status %x\n", Irp->IoStatus.Status);
326 
327         /* report no longer active */
328         DeviceExtension->ReadReportActive = FALSE;
329 
330         /* request stopping of the report cycle */
331         DeviceExtension->StopReadReport = FALSE;
332 
333         /* signal completion event */
334         KeSetEvent(&DeviceExtension->ReadCompletionEvent, 0, 0);
335         return STATUS_MORE_PROCESSING_REQUIRED;
336     }
337 
338     /* get mouse change */
339     MouHid_GetButtonMove(DeviceExtension, &LastX, &LastY);
340 
341     /* get mouse change flags */
342     MouHid_GetButtonFlags(DeviceExtension, &ButtonFlags, &Flags);
343 
344     /* init input data */
345     RtlZeroMemory(&MouseInputData, sizeof(MOUSE_INPUT_DATA));
346 
347     /* init input data */
348     MouseInputData.ButtonFlags = ButtonFlags;
349     MouseInputData.Flags = Flags;
350     MouseInputData.LastX = LastX;
351     MouseInputData.LastY = LastY;
352 
353     /* detect mouse wheel change */
354     if (DeviceExtension->MouseIdentifier == WHEELMOUSE_HID_HARDWARE)
355     {
356         /* get usage */
357         UsageValue = 0;
358         Status = HidP_GetScaledUsageValue(HidP_Input,
359                                           HID_USAGE_PAGE_GENERIC,
360                                           HIDP_LINK_COLLECTION_UNSPECIFIED,
361                                           HID_USAGE_GENERIC_WHEEL,
362                                           &UsageValue,
363                                           DeviceExtension->PreparsedData,
364                                           DeviceExtension->Report,
365                                           DeviceExtension->ReportLength);
366         if (Status == HIDP_STATUS_SUCCESS && UsageValue != 0)
367         {
368             /* store wheel status */
369             MouseInputData.ButtonFlags |= MOUSE_WHEEL;
370             MouseInputData.ButtonData = (USHORT)(UsageValue * WHEEL_DELTA);
371         }
372         else
373         {
374             DPRINT("[MOUHID] failed to get wheel status with %x\n", Status);
375         }
376     }
377 
378     DPRINT("[MOUHID] ReportData %02x %02x %02x %02x %02x %02x %02x\n",
379         DeviceExtension->Report[0] & 0xFF,
380         DeviceExtension->Report[1] & 0xFF, DeviceExtension->Report[2] & 0xFF,
381         DeviceExtension->Report[3] & 0xFF, DeviceExtension->Report[4] & 0xFF,
382         DeviceExtension->Report[5] & 0xFF, DeviceExtension->Report[6] & 0xFF);
383 
384     DPRINT("[MOUHID] LastX %ld LastY %ld Flags %x ButtonFlags %x ButtonData %x\n", MouseInputData.LastX, MouseInputData.LastY, MouseInputData.Flags, MouseInputData.ButtonFlags, MouseInputData.ButtonData);
385 
386     /* dispatch mouse action */
387     MouHid_DispatchInputData(DeviceExtension, &MouseInputData);
388 
389     /* re-init read */
390     MouHid_InitiateRead(DeviceExtension);
391 
392     /* stop completion */
393     return STATUS_MORE_PROCESSING_REQUIRED;
394 }
395 
396 NTSTATUS
397 MouHid_InitiateRead(
398     IN PMOUHID_DEVICE_EXTENSION DeviceExtension)
399 {
400     PIO_STACK_LOCATION IoStack;
401     NTSTATUS Status;
402 
403     /* re-use irp */
404     IoReuseIrp(DeviceExtension->Irp, STATUS_SUCCESS);
405 
406     /* init irp */
407     DeviceExtension->Irp->MdlAddress = DeviceExtension->ReportMDL;
408 
409     /* get next stack location */
410     IoStack = IoGetNextIrpStackLocation(DeviceExtension->Irp);
411 
412     /* init stack location */
413     IoStack->Parameters.Read.Length = DeviceExtension->ReportLength;
414     IoStack->Parameters.Read.Key = 0;
415     IoStack->Parameters.Read.ByteOffset.QuadPart = 0LL;
416     IoStack->MajorFunction = IRP_MJ_READ;
417     IoStack->FileObject = DeviceExtension->FileObject;
418 
419     /* set completion routine */
420     IoSetCompletionRoutine(DeviceExtension->Irp, MouHid_ReadCompletion, DeviceExtension, TRUE, TRUE, TRUE);
421 
422     /* read is active */
423     DeviceExtension->ReadReportActive = TRUE;
424 
425     /* start the read */
426     Status = IoCallDriver(DeviceExtension->NextDeviceObject, DeviceExtension->Irp);
427 
428     /* done */
429     return Status;
430 }
431 
432 NTSTATUS
433 NTAPI
434 MouHid_CreateCompletion(
435     IN PDEVICE_OBJECT  DeviceObject,
436     IN PIRP  Irp,
437     IN PVOID  Context)
438 {
439     KeSetEvent(Context, 0, FALSE);
440     return STATUS_MORE_PROCESSING_REQUIRED;
441 }
442 
443 
444 NTSTATUS
445 NTAPI
446 MouHid_Create(
447     IN PDEVICE_OBJECT DeviceObject,
448     IN PIRP Irp)
449 {
450     PIO_STACK_LOCATION IoStack;
451     NTSTATUS Status;
452     KEVENT Event;
453     PMOUHID_DEVICE_EXTENSION DeviceExtension;
454 
455     DPRINT("MOUHID: IRP_MJ_CREATE\n");
456 
457     /* get device extension */
458     DeviceExtension = DeviceObject->DeviceExtension;
459 
460     /* get stack location */
461     IoStack = IoGetCurrentIrpStackLocation(Irp);
462 
463     /* copy stack location to next */
464     IoCopyCurrentIrpStackLocationToNext(Irp);
465 
466     /* init event */
467     KeInitializeEvent(&Event, NotificationEvent, FALSE);
468 
469     /* prepare irp */
470     IoSetCompletionRoutine(Irp, MouHid_CreateCompletion, &Event, TRUE, TRUE, TRUE);
471 
472     /* call lower driver */
473     Status = IoCallDriver(DeviceExtension->NextDeviceObject, Irp);
474     if (Status == STATUS_PENDING)
475     {
476         /* request pending */
477         KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
478     }
479 
480     /* check for success */
481     if (!NT_SUCCESS(Status))
482     {
483         /* failed */
484         Irp->IoStatus.Status = Status;
485         IoCompleteRequest(Irp, IO_NO_INCREMENT);
486         return Status;
487     }
488 
489     /* is the driver already in use */
490     if (DeviceExtension->FileObject == NULL)
491     {
492          /* did the caller specify correct attributes */
493          ASSERT(IoStack->Parameters.Create.SecurityContext);
494          if (IoStack->Parameters.Create.SecurityContext->DesiredAccess)
495          {
496              /* store file object */
497              DeviceExtension->FileObject = IoStack->FileObject;
498 
499              /* reset event */
500              KeClearEvent(&DeviceExtension->ReadCompletionEvent);
501 
502              /* initiating read */
503              Status = MouHid_InitiateRead(DeviceExtension);
504              DPRINT("[MOUHID] MouHid_InitiateRead: status %x\n", Status);
505              if (Status == STATUS_PENDING)
506              {
507                  /* report irp is pending */
508                  Status = STATUS_SUCCESS;
509              }
510          }
511     }
512 
513     /* complete request */
514     Irp->IoStatus.Status = Status;
515     IoCompleteRequest(Irp, IO_NO_INCREMENT);
516     return Status;
517 }
518 
519 
520 NTSTATUS
521 NTAPI
522 MouHid_Close(
523     IN PDEVICE_OBJECT DeviceObject,
524     IN PIRP Irp)
525 {
526     PMOUHID_DEVICE_EXTENSION DeviceExtension;
527 
528     /* get device extension */
529     DeviceExtension = DeviceObject->DeviceExtension;
530 
531     DPRINT("[MOUHID] IRP_MJ_CLOSE ReadReportActive %x\n", DeviceExtension->ReadReportActive);
532 
533     if (DeviceExtension->ReadReportActive)
534     {
535         /* request stopping of the report cycle */
536         DeviceExtension->StopReadReport = TRUE;
537 
538         /* wait until the reports have been read */
539         KeWaitForSingleObject(&DeviceExtension->ReadCompletionEvent, Executive, KernelMode, FALSE, NULL);
540 
541         /* cancel irp */
542         IoCancelIrp(DeviceExtension->Irp);
543     }
544 
545     DPRINT("[MOUHID] IRP_MJ_CLOSE ReadReportActive %x\n", DeviceExtension->ReadReportActive);
546 
547     /* remove file object */
548     DeviceExtension->FileObject = NULL;
549 
550     /* skip location */
551     IoSkipCurrentIrpStackLocation(Irp);
552 
553     /* pass irp to down the stack */
554     return IoCallDriver(DeviceExtension->NextDeviceObject, Irp);
555 }
556 
557 NTSTATUS
558 NTAPI
559 MouHid_InternalDeviceControl(
560     IN PDEVICE_OBJECT DeviceObject,
561     IN PIRP Irp)
562 {
563     PIO_STACK_LOCATION IoStack;
564     PMOUSE_ATTRIBUTES Attributes;
565     PMOUHID_DEVICE_EXTENSION DeviceExtension;
566     PCONNECT_DATA Data;
567 
568     /* get current stack location */
569     IoStack = IoGetCurrentIrpStackLocation(Irp);
570 
571     DPRINT("[MOUHID] InternalDeviceControl %x\n", IoStack->Parameters.DeviceIoControl.IoControlCode);
572 
573     /* get device extension */
574     DeviceExtension = DeviceObject->DeviceExtension;
575 
576     /* handle requests */
577     switch (IoStack->Parameters.DeviceIoControl.IoControlCode)
578     {
579     case IOCTL_MOUSE_QUERY_ATTRIBUTES:
580          /* verify output buffer length */
581          if (IoStack->Parameters.DeviceIoControl.OutputBufferLength < sizeof(MOUSE_ATTRIBUTES))
582          {
583              /* invalid request */
584              DPRINT1("[MOUHID] IOCTL_MOUSE_QUERY_ATTRIBUTES Buffer too small\n");
585              Irp->IoStatus.Status = STATUS_BUFFER_TOO_SMALL;
586              IoCompleteRequest(Irp, IO_NO_INCREMENT);
587              return STATUS_BUFFER_TOO_SMALL;
588          }
589 
590          /* get output buffer */
591          Attributes = Irp->AssociatedIrp.SystemBuffer;
592 
593          /* type of mouse */
594          Attributes->MouseIdentifier = DeviceExtension->MouseIdentifier;
595 
596          /* number of buttons */
597          Attributes->NumberOfButtons = DeviceExtension->UsageListLength;
598 
599          /* sample rate not used for usb */
600          Attributes->SampleRate = 0;
601 
602          /* queue length */
603          Attributes->InputDataQueueLength = 2;
604 
605          DPRINT("[MOUHID] MouseIdentifier %x\n", Attributes->MouseIdentifier);
606          DPRINT("[MOUHID] NumberOfButtons %x\n", Attributes->NumberOfButtons);
607          DPRINT("[MOUHID] SampleRate %x\n", Attributes->SampleRate);
608          DPRINT("[MOUHID] InputDataQueueLength %x\n", Attributes->InputDataQueueLength);
609 
610          /* complete request */
611          Irp->IoStatus.Information = sizeof(MOUSE_ATTRIBUTES);
612          Irp->IoStatus.Status = STATUS_SUCCESS;
613          IoCompleteRequest(Irp, IO_NO_INCREMENT);
614          return STATUS_SUCCESS;
615 
616     case IOCTL_INTERNAL_MOUSE_CONNECT:
617          /* verify input buffer length */
618          if (IoStack->Parameters.DeviceIoControl.InputBufferLength < sizeof(CONNECT_DATA))
619          {
620              /* invalid request */
621              Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
622              IoCompleteRequest(Irp, IO_NO_INCREMENT);
623              return STATUS_INVALID_PARAMETER;
624          }
625 
626          /* is it already connected */
627          if (DeviceExtension->ClassService)
628          {
629              /* already connected */
630              Irp->IoStatus.Status = STATUS_SHARING_VIOLATION;
631              IoCompleteRequest(Irp, IO_NO_INCREMENT);
632              return STATUS_SHARING_VIOLATION;
633          }
634 
635          /* get connect data */
636          Data = IoStack->Parameters.DeviceIoControl.Type3InputBuffer;
637 
638          /* store connect details */
639          DeviceExtension->ClassDeviceObject = Data->ClassDeviceObject;
640          DeviceExtension->ClassService = Data->ClassService;
641 
642          /* completed successfully */
643          Irp->IoStatus.Status = STATUS_SUCCESS;
644          IoCompleteRequest(Irp, IO_NO_INCREMENT);
645          return STATUS_SUCCESS;
646 
647     case IOCTL_INTERNAL_MOUSE_DISCONNECT:
648         /* not supported */
649         Irp->IoStatus.Status = STATUS_NOT_IMPLEMENTED;
650         IoCompleteRequest(Irp, IO_NO_INCREMENT);
651         return STATUS_NOT_IMPLEMENTED;
652 
653     case IOCTL_INTERNAL_MOUSE_ENABLE:
654         /* not supported */
655         Irp->IoStatus.Status = STATUS_NOT_SUPPORTED;
656         IoCompleteRequest(Irp, IO_NO_INCREMENT);
657         return STATUS_NOT_SUPPORTED;
658 
659     case IOCTL_INTERNAL_MOUSE_DISABLE:
660         /* not supported */
661         Irp->IoStatus.Status = STATUS_INVALID_DEVICE_REQUEST;
662         IoCompleteRequest(Irp, IO_NO_INCREMENT);
663         return STATUS_INVALID_DEVICE_REQUEST;
664     }
665 
666     DPRINT1("[MOUHID] Unknown DeviceControl %x\n", IoStack->Parameters.DeviceIoControl.IoControlCode);
667     /* unknown request not supported */
668     Irp->IoStatus.Status = STATUS_NOT_SUPPORTED;
669     IoCompleteRequest(Irp, IO_NO_INCREMENT);
670     return STATUS_NOT_SUPPORTED;
671 }
672 
673 NTSTATUS
674 NTAPI
675 MouHid_DeviceControl(
676     IN PDEVICE_OBJECT DeviceObject,
677     IN PIRP Irp)
678 {
679     PMOUHID_DEVICE_EXTENSION DeviceExtension;
680 
681     /* get device extension */
682     DeviceExtension = DeviceObject->DeviceExtension;
683 
684     /* skip stack location */
685     IoSkipCurrentIrpStackLocation(Irp);
686 
687     /* pass and forget */
688     return IoCallDriver(DeviceExtension->NextDeviceObject, Irp);
689 }
690 
691 NTSTATUS
692 NTAPI
693 MouHid_Power(
694     IN PDEVICE_OBJECT DeviceObject,
695     IN PIRP Irp)
696 {
697     PMOUHID_DEVICE_EXTENSION DeviceExtension;
698 
699     DeviceExtension = DeviceObject->DeviceExtension;
700     PoStartNextPowerIrp(Irp);
701     IoSkipCurrentIrpStackLocation(Irp);
702     return PoCallDriver(DeviceExtension->NextDeviceObject, Irp);
703 }
704 
705 NTSTATUS
706 NTAPI
707 MouHid_SystemControl(
708     IN PDEVICE_OBJECT DeviceObject,
709     IN PIRP Irp)
710 {
711     PMOUHID_DEVICE_EXTENSION DeviceExtension;
712 
713     DeviceExtension = DeviceObject->DeviceExtension;
714     IoSkipCurrentIrpStackLocation(Irp);
715     return IoCallDriver(DeviceExtension->NextDeviceObject, Irp);
716 }
717 
718 NTSTATUS
719 MouHid_SubmitRequest(
720     PDEVICE_OBJECT DeviceObject,
721     ULONG IoControlCode,
722     ULONG InputBufferSize,
723     PVOID InputBuffer,
724     ULONG OutputBufferSize,
725     PVOID OutputBuffer)
726 {
727     KEVENT Event;
728     PMOUHID_DEVICE_EXTENSION DeviceExtension;
729     PIRP Irp;
730     NTSTATUS Status;
731     IO_STATUS_BLOCK IoStatus;
732 
733     /* get device extension */
734     DeviceExtension = DeviceObject->DeviceExtension;
735 
736     /* init event */
737     KeInitializeEvent(&Event, NotificationEvent, FALSE);
738 
739     /* build request */
740     Irp = IoBuildDeviceIoControlRequest(IoControlCode,
741                                         DeviceExtension->NextDeviceObject,
742                                         InputBuffer,
743                                         InputBufferSize,
744                                         OutputBuffer,
745                                         OutputBufferSize,
746                                         FALSE,
747                                         &Event,
748                                         &IoStatus);
749     if (!Irp)
750     {
751         /* no memory */
752         return STATUS_INSUFFICIENT_RESOURCES;
753     }
754 
755     /* send request */
756     Status = IoCallDriver(DeviceExtension->NextDeviceObject, Irp);
757     if (Status == STATUS_PENDING)
758     {
759         /* wait for request to complete */
760         KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
761         Status = IoStatus.Status;
762     }
763 
764     /* done */
765     return Status;
766 }
767 
768 NTSTATUS
769 NTAPI
770 MouHid_StartDevice(
771     IN PDEVICE_OBJECT DeviceObject)
772 {
773     NTSTATUS Status;
774     ULONG Buttons;
775     HID_COLLECTION_INFORMATION Information;
776     PVOID PreparsedData;
777     HIDP_CAPS Capabilities;
778     USHORT ValueCapsLength;
779     HIDP_VALUE_CAPS ValueCaps;
780     PMOUHID_DEVICE_EXTENSION DeviceExtension;
781     PUSAGE Buffer;
782 
783     /* get device extension */
784     DeviceExtension = DeviceObject->DeviceExtension;
785 
786     /* query collection information */
787     Status = MouHid_SubmitRequest(DeviceObject,
788                                   IOCTL_HID_GET_COLLECTION_INFORMATION,
789                                   0,
790                                   NULL,
791                                   sizeof(HID_COLLECTION_INFORMATION),
792                                   &Information);
793     if (!NT_SUCCESS(Status))
794     {
795         /* failed to query collection information */
796         DPRINT1("[MOUHID] failed to obtain collection information with %x\n", Status);
797         return Status;
798     }
799 
800     /* lets allocate space for preparsed data */
801     PreparsedData = ExAllocatePoolWithTag(NonPagedPool, Information.DescriptorSize, MOUHID_TAG);
802     if (!PreparsedData)
803     {
804         /* no memory */
805         DPRINT1("[MOUHID] no memory size %u\n", Information.DescriptorSize);
806         return STATUS_INSUFFICIENT_RESOURCES;
807     }
808 
809     /* now obtain the preparsed data */
810     Status = MouHid_SubmitRequest(DeviceObject,
811                                   IOCTL_HID_GET_COLLECTION_DESCRIPTOR,
812                                   0,
813                                   NULL,
814                                   Information.DescriptorSize,
815                                   PreparsedData);
816     if (!NT_SUCCESS(Status))
817     {
818         /* failed to get preparsed data */
819         DPRINT1("[MOUHID] failed to obtain collection information with %x\n", Status);
820         ExFreePoolWithTag(PreparsedData, MOUHID_TAG);
821         return Status;
822     }
823 
824     /* lets get the caps */
825     Status = HidP_GetCaps(PreparsedData, &Capabilities);
826     if (Status != HIDP_STATUS_SUCCESS)
827     {
828         /* failed to get capabilities */
829         DPRINT1("[MOUHID] failed to obtain caps with %x\n", Status);
830         ExFreePoolWithTag(PreparsedData, MOUHID_TAG);
831         return Status;
832     }
833 
834     DPRINT("[MOUHID] Usage %x UsagePage %x InputReportLength %lu\n", Capabilities.Usage, Capabilities.UsagePage, Capabilities.InputReportByteLength);
835 
836     /* verify capabilities */
837     if ((Capabilities.Usage != HID_USAGE_GENERIC_POINTER && Capabilities.Usage != HID_USAGE_GENERIC_MOUSE) || Capabilities.UsagePage != HID_USAGE_PAGE_GENERIC)
838     {
839         /* not supported */
840         ExFreePoolWithTag(PreparsedData, MOUHID_TAG);
841         return STATUS_UNSUCCESSFUL;
842     }
843 
844     /* init input report */
845     DeviceExtension->ReportLength = Capabilities.InputReportByteLength;
846     ASSERT(DeviceExtension->ReportLength);
847     DeviceExtension->Report = ExAllocatePoolWithTag(NonPagedPool, DeviceExtension->ReportLength, MOUHID_TAG);
848     ASSERT(DeviceExtension->Report);
849     RtlZeroMemory(DeviceExtension->Report, DeviceExtension->ReportLength);
850 
851     /* build mdl */
852     DeviceExtension->ReportMDL = IoAllocateMdl(DeviceExtension->Report,
853                                                DeviceExtension->ReportLength,
854                                                FALSE,
855                                                FALSE,
856                                                NULL);
857     ASSERT(DeviceExtension->ReportMDL);
858 
859     /* init mdl */
860     MmBuildMdlForNonPagedPool(DeviceExtension->ReportMDL);
861 
862     /* get max number of buttons */
863     Buttons = HidP_MaxUsageListLength(HidP_Input,
864                                       HID_USAGE_PAGE_BUTTON,
865                                       PreparsedData);
866     DPRINT("[MOUHID] Buttons %lu\n", Buttons);
867     ASSERT(Buttons > 0);
868 
869     /* now allocate an array for those buttons */
870     Buffer = ExAllocatePoolWithTag(NonPagedPool, sizeof(USAGE) * 4 * Buttons, MOUHID_TAG);
871     if (!Buffer)
872     {
873         /* no memory */
874         ExFreePoolWithTag(PreparsedData, MOUHID_TAG);
875         return STATUS_INSUFFICIENT_RESOURCES;
876     }
877     DeviceExtension->UsageListBuffer = Buffer;
878 
879     /* init usage lists */
880     RtlZeroMemory(Buffer, sizeof(USAGE) * 4 * Buttons);
881     DeviceExtension->CurrentUsageList = Buffer;
882     Buffer += Buttons;
883     DeviceExtension->PreviousUsageList = Buffer;
884     Buffer += Buttons;
885     DeviceExtension->MakeUsageList = Buffer;
886     Buffer += Buttons;
887     DeviceExtension->BreakUsageList = Buffer;
888 
889     /* store number of buttons */
890     DeviceExtension->UsageListLength = (USHORT)Buttons;
891 
892     /* store preparsed data */
893     DeviceExtension->PreparsedData = PreparsedData;
894 
895     ValueCapsLength = 1;
896     HidP_GetSpecificValueCaps(HidP_Input,
897                               HID_USAGE_PAGE_GENERIC,
898                               HIDP_LINK_COLLECTION_UNSPECIFIED,
899                               HID_USAGE_GENERIC_X,
900                               &DeviceExtension->ValueCapsX,
901                               &ValueCapsLength,
902                               PreparsedData);
903 
904     ValueCapsLength = 1;
905     HidP_GetSpecificValueCaps(HidP_Input,
906                               HID_USAGE_PAGE_GENERIC,
907                               HIDP_LINK_COLLECTION_UNSPECIFIED,
908                               HID_USAGE_GENERIC_Y,
909                               &DeviceExtension->ValueCapsY,
910                               &ValueCapsLength,
911                               PreparsedData);
912 
913     /* now check for wheel mouse support */
914     ValueCapsLength = 1;
915     Status = HidP_GetSpecificValueCaps(HidP_Input,
916                                        HID_USAGE_PAGE_GENERIC,
917                                        HIDP_LINK_COLLECTION_UNSPECIFIED,
918                                        HID_USAGE_GENERIC_WHEEL,
919                                        &ValueCaps,
920                                        &ValueCapsLength,
921                                        PreparsedData);
922     if (Status == HIDP_STATUS_SUCCESS )
923     {
924         /* mouse has wheel support */
925         DeviceExtension->MouseIdentifier = WHEELMOUSE_HID_HARDWARE;
926         DeviceExtension->WheelUsagePage = ValueCaps.UsagePage;
927         DPRINT("[MOUHID] mouse wheel support detected\n", Status);
928     }
929     else
930     {
931         /* check if the mouse has z-axis */
932         ValueCapsLength = 1;
933         Status = HidP_GetSpecificValueCaps(HidP_Input,
934                                            HID_USAGE_PAGE_GENERIC,
935                                            HIDP_LINK_COLLECTION_UNSPECIFIED,
936                                            HID_USAGE_GENERIC_Z,
937                                            &ValueCaps,
938                                            &ValueCapsLength,
939                                            PreparsedData);
940         if (Status == HIDP_STATUS_SUCCESS && ValueCapsLength == 1)
941         {
942             /* wheel support */
943             DeviceExtension->MouseIdentifier = WHEELMOUSE_HID_HARDWARE;
944             DeviceExtension->WheelUsagePage = ValueCaps.UsagePage;
945             DPRINT("[MOUHID] mouse wheel support detected with z-axis\n", Status);
946         }
947     }
948 
949     /* check if mice is absolute */
950     if (DeviceExtension->ValueCapsY.IsAbsolute &&
951         DeviceExtension->ValueCapsX.IsAbsolute)
952     {
953         /* mice is absolute */
954         DeviceExtension->MouseAbsolute = TRUE;
955     }
956 
957     /* completed successfully */
958     return STATUS_SUCCESS;
959 }
960 
961 NTSTATUS
962 NTAPI
963 MouHid_StartDeviceCompletion(
964     IN PDEVICE_OBJECT  DeviceObject,
965     IN PIRP  Irp,
966     IN PVOID  Context)
967 {
968     KeSetEvent(Context, 0, FALSE);
969     return STATUS_MORE_PROCESSING_REQUIRED;
970 }
971 
972 NTSTATUS
973 NTAPI
974 MouHid_FreeResources(
975     IN PDEVICE_OBJECT DeviceObject)
976 {
977     PMOUHID_DEVICE_EXTENSION DeviceExtension;
978 
979     /* get device extension */
980     DeviceExtension = DeviceObject->DeviceExtension;
981 
982     /* free resources */
983     if (DeviceExtension->PreparsedData)
984     {
985         ExFreePoolWithTag(DeviceExtension->PreparsedData, MOUHID_TAG);
986         DeviceExtension->PreparsedData = NULL;
987     }
988 
989     if (DeviceExtension->UsageListBuffer)
990     {
991         ExFreePoolWithTag(DeviceExtension->UsageListBuffer, MOUHID_TAG);
992         DeviceExtension->UsageListBuffer = NULL;
993         DeviceExtension->CurrentUsageList = NULL;
994         DeviceExtension->PreviousUsageList = NULL;
995         DeviceExtension->MakeUsageList = NULL;
996         DeviceExtension->BreakUsageList = NULL;
997     }
998 
999     if (DeviceExtension->ReportMDL)
1000     {
1001         IoFreeMdl(DeviceExtension->ReportMDL);
1002         DeviceExtension->ReportMDL = NULL;
1003     }
1004 
1005     if (DeviceExtension->Report)
1006     {
1007         ExFreePoolWithTag(DeviceExtension->Report, MOUHID_TAG);
1008         DeviceExtension->Report = NULL;
1009     }
1010 
1011     return STATUS_SUCCESS;
1012 }
1013 
1014 NTSTATUS
1015 NTAPI
1016 MouHid_Flush(
1017     IN PDEVICE_OBJECT DeviceObject,
1018     IN PIRP Irp)
1019 {
1020     PIO_STACK_LOCATION IoStack;
1021     PMOUHID_DEVICE_EXTENSION DeviceExtension;
1022 
1023     /* get device extension */
1024     DeviceExtension = DeviceObject->DeviceExtension;
1025 
1026     /* skip current stack location */
1027     IoSkipCurrentIrpStackLocation(Irp);
1028 
1029     /* get next stack location */
1030     IoStack = IoGetNextIrpStackLocation(Irp);
1031 
1032     /* change request to hid flush queue request */
1033     IoStack->MajorFunction = IRP_MJ_DEVICE_CONTROL;
1034     IoStack->Parameters.DeviceIoControl.IoControlCode = IOCTL_HID_FLUSH_QUEUE;
1035 
1036     /* call device */
1037     return IoCallDriver(DeviceExtension->NextDeviceObject, Irp);
1038 }
1039 
1040 NTSTATUS
1041 NTAPI
1042 MouHid_Pnp(
1043     IN PDEVICE_OBJECT DeviceObject,
1044     IN PIRP Irp)
1045 {
1046     PIO_STACK_LOCATION IoStack;
1047     KEVENT Event;
1048     NTSTATUS Status;
1049     PMOUHID_DEVICE_EXTENSION DeviceExtension;
1050 
1051     /* get device extension */
1052     DeviceExtension = DeviceObject->DeviceExtension;
1053 
1054     /* get current irp stack */
1055     IoStack = IoGetCurrentIrpStackLocation(Irp);
1056     DPRINT("[MOUHID] IRP_MJ_PNP Request: %x\n", IoStack->MinorFunction);
1057 
1058     switch (IoStack->MinorFunction)
1059     {
1060     case IRP_MN_STOP_DEVICE:
1061     case IRP_MN_SURPRISE_REMOVAL:
1062         /* free resources */
1063         MouHid_FreeResources(DeviceObject);
1064     case IRP_MN_CANCEL_REMOVE_DEVICE:
1065     case IRP_MN_QUERY_STOP_DEVICE:
1066     case IRP_MN_CANCEL_STOP_DEVICE:
1067     case IRP_MN_QUERY_REMOVE_DEVICE:
1068         /* indicate success */
1069         Irp->IoStatus.Status = STATUS_SUCCESS;
1070 
1071         /* skip irp stack location */
1072         IoSkipCurrentIrpStackLocation(Irp);
1073 
1074         /* dispatch to lower device */
1075         return IoCallDriver(DeviceExtension->NextDeviceObject, Irp);
1076 
1077     case IRP_MN_REMOVE_DEVICE:
1078         /* FIXME synchronization */
1079 
1080         /* request stop */
1081         DeviceExtension->StopReadReport = TRUE;
1082 
1083         /* cancel irp */
1084         IoCancelIrp(DeviceExtension->Irp);
1085 
1086         /* free resources */
1087         MouHid_FreeResources(DeviceObject);
1088 
1089         /* indicate success */
1090         Irp->IoStatus.Status = STATUS_SUCCESS;
1091 
1092         /* skip irp stack location */
1093         IoSkipCurrentIrpStackLocation(Irp);
1094 
1095         /* dispatch to lower device */
1096         Status = IoCallDriver(DeviceExtension->NextDeviceObject, Irp);
1097 
1098         /* wait for completion of stop event */
1099         KeWaitForSingleObject(&DeviceExtension->ReadCompletionEvent, Executive, KernelMode, FALSE, NULL);
1100 
1101         /* free irp */
1102         IoFreeIrp(DeviceExtension->Irp);
1103 
1104         /* detach device */
1105         IoDetachDevice(DeviceExtension->NextDeviceObject);
1106 
1107         /* delete device */
1108         IoDeleteDevice(DeviceObject);
1109 
1110         /* done */
1111         return Status;
1112 
1113     case IRP_MN_START_DEVICE:
1114         /* init event */
1115         KeInitializeEvent(&Event, NotificationEvent, FALSE);
1116 
1117         /* copy stack location */
1118         IoCopyCurrentIrpStackLocationToNext (Irp);
1119 
1120         /* set completion routine */
1121         IoSetCompletionRoutine(Irp, MouHid_StartDeviceCompletion, &Event, TRUE, TRUE, TRUE);
1122         Irp->IoStatus.Status = 0;
1123 
1124         /* pass request */
1125         Status = IoCallDriver(DeviceExtension->NextDeviceObject, Irp);
1126         if (Status == STATUS_PENDING)
1127         {
1128             KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
1129             Status = Irp->IoStatus.Status;
1130         }
1131 
1132         if (!NT_SUCCESS(Status))
1133         {
1134             /* failed */
1135             Irp->IoStatus.Status = Status;
1136             IoCompleteRequest(Irp, IO_NO_INCREMENT);
1137             return Status;
1138         }
1139 
1140         /* lets start the device */
1141         Status = MouHid_StartDevice(DeviceObject);
1142         DPRINT("MouHid_StartDevice %x\n", Status);
1143 
1144         /* complete request */
1145         Irp->IoStatus.Status = Status;
1146         IoCompleteRequest(Irp, IO_NO_INCREMENT);
1147 
1148         /* done */
1149         return Status;
1150 
1151     default:
1152         /* skip irp stack location */
1153         IoSkipCurrentIrpStackLocation(Irp);
1154 
1155         /* dispatch to lower device */
1156         return IoCallDriver(DeviceExtension->NextDeviceObject, Irp);
1157     }
1158 }
1159 
1160 NTSTATUS
1161 NTAPI
1162 MouHid_AddDevice(
1163     IN PDRIVER_OBJECT DriverObject,
1164     IN PDEVICE_OBJECT PhysicalDeviceObject)
1165 {
1166     NTSTATUS Status;
1167     PDEVICE_OBJECT DeviceObject, NextDeviceObject;
1168     PMOUHID_DEVICE_EXTENSION DeviceExtension;
1169     POWER_STATE State;
1170 
1171     /* create device object */
1172     Status = IoCreateDevice(DriverObject,
1173                             sizeof(MOUHID_DEVICE_EXTENSION),
1174                             NULL,
1175                             FILE_DEVICE_MOUSE,
1176                             0,
1177                             FALSE,
1178                             &DeviceObject);
1179     if (!NT_SUCCESS(Status))
1180     {
1181         /* failed to create device object */
1182         return Status;
1183     }
1184 
1185     /* now attach it */
1186     NextDeviceObject = IoAttachDeviceToDeviceStack(DeviceObject, PhysicalDeviceObject);
1187     if (!NextDeviceObject)
1188     {
1189         /* failed to attach */
1190         IoDeleteDevice(DeviceObject);
1191         return STATUS_DEVICE_NOT_CONNECTED;
1192     }
1193 
1194     /* get device extension */
1195     DeviceExtension = DeviceObject->DeviceExtension;
1196 
1197     /* zero extension */
1198     RtlZeroMemory(DeviceExtension, sizeof(MOUHID_DEVICE_EXTENSION));
1199 
1200     /* init device extension */
1201     DeviceExtension->MouseIdentifier = MOUSE_HID_HARDWARE;
1202     DeviceExtension->WheelUsagePage = 0;
1203     DeviceExtension->NextDeviceObject = NextDeviceObject;
1204     KeInitializeEvent(&DeviceExtension->ReadCompletionEvent, NotificationEvent, FALSE);
1205     DeviceExtension->Irp = IoAllocateIrp(NextDeviceObject->StackSize, FALSE);
1206 
1207     /* FIXME handle allocation error */
1208     ASSERT(DeviceExtension->Irp);
1209 
1210     /* FIXME query parameter 'FlipFlopWheel', 'WheelScalingFactor' */
1211 
1212     /* set power state to D0 */
1213     State.DeviceState =  PowerDeviceD0;
1214     PoSetPowerState(DeviceObject, DevicePowerState, State);
1215 
1216     /* init device object */
1217     DeviceObject->Flags |= DO_BUFFERED_IO | DO_POWER_PAGABLE;
1218     DeviceObject->Flags  &= ~DO_DEVICE_INITIALIZING;
1219 
1220     /* completed successfully */
1221     return STATUS_SUCCESS;
1222 }
1223 
1224 VOID
1225 NTAPI
1226 MouHid_Unload(
1227     IN PDRIVER_OBJECT DriverObject)
1228 {
1229     UNIMPLEMENTED;
1230 }
1231 
1232 
1233 NTSTATUS
1234 NTAPI
1235 DriverEntry(
1236     IN PDRIVER_OBJECT DriverObject,
1237     IN PUNICODE_STRING RegPath)
1238 {
1239     /* FIXME check for parameters 'UseOnlyMice', 'TreatAbsoluteAsRelative', 'TreatAbsolutePointerAsAbsolute' */
1240 
1241     /* initialize driver object */
1242     DriverObject->MajorFunction[IRP_MJ_CREATE] = MouHid_Create;
1243     DriverObject->MajorFunction[IRP_MJ_CLOSE] = MouHid_Close;
1244     DriverObject->MajorFunction[IRP_MJ_FLUSH_BUFFERS] = MouHid_Flush;
1245     DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = MouHid_DeviceControl;
1246     DriverObject->MajorFunction[IRP_MJ_INTERNAL_DEVICE_CONTROL] = MouHid_InternalDeviceControl;
1247     DriverObject->MajorFunction[IRP_MJ_POWER] = MouHid_Power;
1248     DriverObject->MajorFunction[IRP_MJ_PNP] = MouHid_Pnp;
1249     DriverObject->MajorFunction[IRP_MJ_SYSTEM_CONTROL] = MouHid_SystemControl;
1250     DriverObject->DriverUnload = MouHid_Unload;
1251     DriverObject->DriverExtension->AddDevice = MouHid_AddDevice;
1252 
1253     /* done */
1254     return STATUS_SUCCESS;
1255 }
1256