1 /** @file
2   USB Mouse Driver that manages USB mouse and produces Absolute Pointer Protocol.
3 
4 Copyright (c) 2004 - 2018, Intel Corporation. All rights reserved.<BR>
5 SPDX-License-Identifier: BSD-2-Clause-Patent
6 
7 **/
8 
9 #include "UsbMouseAbsolutePointer.h"
10 
11 EFI_DRIVER_BINDING_PROTOCOL gUsbMouseAbsolutePointerDriverBinding = {
12   USBMouseAbsolutePointerDriverBindingSupported,
13   USBMouseAbsolutePointerDriverBindingStart,
14   USBMouseAbsolutePointerDriverBindingStop,
15   0x1,
16   NULL,
17   NULL
18 };
19 
20 /**
21   Entrypoint of USB Mouse Absolute Pointer Driver.
22 
23   This function is the entrypoint of USB Mouse Driver. It installs Driver Binding
24   Protocols together with Component Name Protocols.
25 
26   @param  ImageHandle       The firmware allocated handle for the EFI image.
27   @param  SystemTable       A pointer to the EFI System Table.
28 
29   @retval EFI_SUCCESS       The entry point is executed successfully.
30 
31 **/
32 EFI_STATUS
33 EFIAPI
USBMouseAbsolutePointerDriverBindingEntryPoint(IN EFI_HANDLE ImageHandle,IN EFI_SYSTEM_TABLE * SystemTable)34 USBMouseAbsolutePointerDriverBindingEntryPoint (
35   IN EFI_HANDLE           ImageHandle,
36   IN EFI_SYSTEM_TABLE     *SystemTable
37   )
38 {
39   EFI_STATUS              Status;
40 
41   Status = EfiLibInstallDriverBindingComponentName2 (
42              ImageHandle,
43              SystemTable,
44              &gUsbMouseAbsolutePointerDriverBinding,
45              ImageHandle,
46              &gUsbMouseAbsolutePointerComponentName,
47              &gUsbMouseAbsolutePointerComponentName2
48              );
49   ASSERT_EFI_ERROR (Status);
50 
51   return EFI_SUCCESS;
52 }
53 
54 
55 /**
56   Check whether USB Mouse Absolute Pointer Driver supports this device.
57 
58   @param  This                   The driver binding protocol.
59   @param  Controller             The controller handle to check.
60   @param  RemainingDevicePath    The remaining device path.
61 
62   @retval EFI_SUCCESS            The driver supports this controller.
63   @retval other                  This device isn't supported.
64 
65 **/
66 EFI_STATUS
67 EFIAPI
USBMouseAbsolutePointerDriverBindingSupported(IN EFI_DRIVER_BINDING_PROTOCOL * This,IN EFI_HANDLE Controller,IN EFI_DEVICE_PATH_PROTOCOL * RemainingDevicePath)68 USBMouseAbsolutePointerDriverBindingSupported (
69   IN EFI_DRIVER_BINDING_PROTOCOL    *This,
70   IN EFI_HANDLE                     Controller,
71   IN EFI_DEVICE_PATH_PROTOCOL       *RemainingDevicePath
72   )
73 {
74   EFI_STATUS          Status;
75   EFI_USB_IO_PROTOCOL *UsbIo;
76 
77   Status = gBS->OpenProtocol (
78                   Controller,
79                   &gEfiUsbIoProtocolGuid,
80                   (VOID **) &UsbIo,
81                   This->DriverBindingHandle,
82                   Controller,
83                   EFI_OPEN_PROTOCOL_BY_DRIVER
84                   );
85   if (EFI_ERROR (Status)) {
86     return Status;
87   }
88 
89   //
90   // Use the USB I/O Protocol interface to check whether Controller is
91   // a mouse device that can be managed by this driver.
92   //
93   Status = EFI_SUCCESS;
94   if (!IsUsbMouse (UsbIo)) {
95     Status = EFI_UNSUPPORTED;
96   }
97 
98   gBS->CloseProtocol (
99         Controller,
100         &gEfiUsbIoProtocolGuid,
101         This->DriverBindingHandle,
102         Controller
103         );
104 
105   return Status;
106 }
107 
108 
109 /**
110   Starts the mouse device with this driver.
111 
112   This function consumes USB I/O Protocol, initializes USB mouse device,
113   installs Absolute Pointer Protocol, and submits Asynchronous Interrupt
114   Transfer to manage the USB mouse device.
115 
116   @param  This                  The driver binding instance.
117   @param  Controller            Handle of device to bind driver to.
118   @param  RemainingDevicePath   Optional parameter use to pick a specific child
119                                 device to start.
120 
121   @retval EFI_SUCCESS           This driver supports this device.
122   @retval EFI_UNSUPPORTED       This driver does not support this device.
123   @retval EFI_DEVICE_ERROR      This driver cannot be started due to device Error.
124   @retval EFI_OUT_OF_RESOURCES  Can't allocate memory resources.
125   @retval EFI_ALREADY_STARTED   This driver has been started.
126 
127 **/
128 EFI_STATUS
129 EFIAPI
USBMouseAbsolutePointerDriverBindingStart(IN EFI_DRIVER_BINDING_PROTOCOL * This,IN EFI_HANDLE Controller,IN EFI_DEVICE_PATH_PROTOCOL * RemainingDevicePath)130 USBMouseAbsolutePointerDriverBindingStart (
131   IN EFI_DRIVER_BINDING_PROTOCOL    *This,
132   IN EFI_HANDLE                     Controller,
133   IN EFI_DEVICE_PATH_PROTOCOL       *RemainingDevicePath
134   )
135 {
136   EFI_STATUS                     Status;
137   EFI_USB_IO_PROTOCOL            *UsbIo;
138   USB_MOUSE_ABSOLUTE_POINTER_DEV *UsbMouseAbsolutePointerDevice;
139   UINT8                          EndpointNumber;
140   EFI_USB_ENDPOINT_DESCRIPTOR    EndpointDescriptor;
141   UINT8                          Index;
142   UINT8                          EndpointAddr;
143   UINT8                          PollingInterval;
144   UINT8                          PacketSize;
145   BOOLEAN                        Found;
146   EFI_TPL                        OldTpl;
147 
148   OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
149   //
150   // Open USB I/O Protocol
151   //
152   Status = gBS->OpenProtocol (
153                   Controller,
154                   &gEfiUsbIoProtocolGuid,
155                   (VOID **) &UsbIo,
156                   This->DriverBindingHandle,
157                   Controller,
158                   EFI_OPEN_PROTOCOL_BY_DRIVER
159                   );
160   if (EFI_ERROR (Status)) {
161     goto ErrorExit1;
162   }
163 
164   UsbMouseAbsolutePointerDevice = AllocateZeroPool (sizeof (USB_MOUSE_ABSOLUTE_POINTER_DEV));
165   ASSERT (UsbMouseAbsolutePointerDevice != NULL);
166 
167   UsbMouseAbsolutePointerDevice->UsbIo     = UsbIo;
168   UsbMouseAbsolutePointerDevice->Signature = USB_MOUSE_ABSOLUTE_POINTER_DEV_SIGNATURE;
169 
170   //
171   // Get the Device Path Protocol on Controller's handle
172   //
173   Status = gBS->OpenProtocol (
174                   Controller,
175                   &gEfiDevicePathProtocolGuid,
176                   (VOID **) &UsbMouseAbsolutePointerDevice->DevicePath,
177                   This->DriverBindingHandle,
178                   Controller,
179                   EFI_OPEN_PROTOCOL_GET_PROTOCOL
180                   );
181 
182   if (EFI_ERROR (Status)) {
183     goto ErrorExit;
184   }
185 
186   //
187   // Report Status Code here since USB mouse will be detected next.
188   //
189   REPORT_STATUS_CODE_WITH_DEVICE_PATH (
190     EFI_PROGRESS_CODE,
191     (EFI_PERIPHERAL_MOUSE | EFI_P_PC_PRESENCE_DETECT),
192     UsbMouseAbsolutePointerDevice->DevicePath
193     );
194 
195   //
196   // Get interface & endpoint descriptor
197   //
198   UsbIo->UsbGetInterfaceDescriptor (
199            UsbIo,
200            &UsbMouseAbsolutePointerDevice->InterfaceDescriptor
201            );
202 
203   EndpointNumber = UsbMouseAbsolutePointerDevice->InterfaceDescriptor.NumEndpoints;
204 
205   //
206   // Traverse endpoints to find interrupt endpoint IN
207   //
208   Found = FALSE;
209   for (Index = 0; Index < EndpointNumber; Index++) {
210     UsbIo->UsbGetEndpointDescriptor (
211              UsbIo,
212              Index,
213              &EndpointDescriptor
214              );
215 
216     if (((EndpointDescriptor.Attributes & (BIT0 | BIT1)) == USB_ENDPOINT_INTERRUPT) &&
217         ((EndpointDescriptor.EndpointAddress & USB_ENDPOINT_DIR_IN) != 0)) {
218       //
219       // We only care interrupt endpoint here
220       //
221       CopyMem (&UsbMouseAbsolutePointerDevice->IntEndpointDescriptor, &EndpointDescriptor, sizeof(EndpointDescriptor));
222       Found = TRUE;
223       break;
224     }
225   }
226 
227   if (!Found) {
228     //
229     // Report Status Code to indicate that there is no USB mouse
230     //
231     REPORT_STATUS_CODE (
232       EFI_ERROR_CODE | EFI_ERROR_MINOR,
233       (EFI_PERIPHERAL_MOUSE | EFI_P_EC_NOT_DETECTED)
234       );
235     //
236     // No interrupt endpoint found, then return unsupported.
237     //
238     Status = EFI_UNSUPPORTED;
239     goto ErrorExit;
240   }
241 
242   //
243   // Report Status Code here since USB mouse has be detected.
244   //
245   REPORT_STATUS_CODE_WITH_DEVICE_PATH (
246     EFI_PROGRESS_CODE,
247     (EFI_PERIPHERAL_MOUSE | EFI_P_PC_DETECTED),
248     UsbMouseAbsolutePointerDevice->DevicePath
249     );
250 
251   Status = InitializeUsbMouseDevice (UsbMouseAbsolutePointerDevice);
252   if (EFI_ERROR (Status)) {
253     //
254     // Fail to initialize USB mouse device.
255     //
256     REPORT_STATUS_CODE_WITH_DEVICE_PATH (
257       EFI_ERROR_CODE | EFI_ERROR_MINOR,
258       (EFI_PERIPHERAL_MOUSE | EFI_P_EC_INTERFACE_ERROR),
259       UsbMouseAbsolutePointerDevice->DevicePath
260       );
261 
262     goto ErrorExit;
263   }
264 
265   //
266   // Initialize and install EFI Absolute Pointer Protocol.
267   //
268   UsbMouseAbsolutePointerDevice->AbsolutePointerProtocol.GetState = GetMouseAbsolutePointerState;
269   UsbMouseAbsolutePointerDevice->AbsolutePointerProtocol.Reset    = UsbMouseAbsolutePointerReset;
270   UsbMouseAbsolutePointerDevice->AbsolutePointerProtocol.Mode    = &UsbMouseAbsolutePointerDevice->Mode;
271 
272   Status = gBS->CreateEvent (
273                   EVT_NOTIFY_WAIT,
274                   TPL_NOTIFY,
275                   UsbMouseAbsolutePointerWaitForInput,
276                   UsbMouseAbsolutePointerDevice,
277                   &((UsbMouseAbsolutePointerDevice->AbsolutePointerProtocol).WaitForInput)
278                   );
279   if (EFI_ERROR (Status)) {
280     goto ErrorExit;
281   }
282 
283   Status = gBS->InstallProtocolInterface (
284                   &Controller,
285                   &gEfiAbsolutePointerProtocolGuid,
286                   EFI_NATIVE_INTERFACE,
287                   &UsbMouseAbsolutePointerDevice->AbsolutePointerProtocol
288                   );
289 
290   if (EFI_ERROR (Status)) {
291     goto ErrorExit;
292   }
293 
294   //
295   // The next step would be submitting Asynchronous Interrupt Transfer on this mouse device.
296   // After that we will be able to get key data from it. Thus this is deemed as
297   // the enable action of the mouse, so report status code accordingly.
298   //
299   REPORT_STATUS_CODE_WITH_DEVICE_PATH (
300     EFI_PROGRESS_CODE,
301     (EFI_PERIPHERAL_MOUSE | EFI_P_PC_ENABLE),
302     UsbMouseAbsolutePointerDevice->DevicePath
303     );
304 
305   //
306   // Submit Asynchronous Interrupt Transfer to manage this device.
307   //
308   EndpointAddr    = UsbMouseAbsolutePointerDevice->IntEndpointDescriptor.EndpointAddress;
309   PollingInterval = UsbMouseAbsolutePointerDevice->IntEndpointDescriptor.Interval;
310   PacketSize      = (UINT8) (UsbMouseAbsolutePointerDevice->IntEndpointDescriptor.MaxPacketSize);
311 
312   Status = UsbIo->UsbAsyncInterruptTransfer (
313                     UsbIo,
314                     EndpointAddr,
315                     TRUE,
316                     PollingInterval,
317                     PacketSize,
318                     OnMouseInterruptComplete,
319                     UsbMouseAbsolutePointerDevice
320                     );
321 
322   if (EFI_ERROR (Status)) {
323     //
324     // If submit error, uninstall that interface
325     //
326     gBS->UninstallProtocolInterface (
327            Controller,
328            &gEfiAbsolutePointerProtocolGuid,
329            &UsbMouseAbsolutePointerDevice->AbsolutePointerProtocol
330            );
331     goto ErrorExit;
332   }
333 
334   UsbMouseAbsolutePointerDevice->ControllerNameTable = NULL;
335   AddUnicodeString2 (
336     "eng",
337     gUsbMouseAbsolutePointerComponentName.SupportedLanguages,
338     &UsbMouseAbsolutePointerDevice->ControllerNameTable,
339     L"Generic Usb Mouse Absolute Pointer",
340       TRUE
341       );
342   AddUnicodeString2 (
343     "en",
344     gUsbMouseAbsolutePointerComponentName2.SupportedLanguages,
345     &UsbMouseAbsolutePointerDevice->ControllerNameTable,
346     L"Generic Usb Mouse Absolute Pointer",
347     FALSE
348     );
349 
350   gBS->RestoreTPL (OldTpl);
351   return EFI_SUCCESS;
352 
353 //
354 // Error handler
355 //
356 ErrorExit:
357   if (EFI_ERROR (Status)) {
358     gBS->CloseProtocol (
359           Controller,
360           &gEfiUsbIoProtocolGuid,
361           This->DriverBindingHandle,
362           Controller
363           );
364 
365     if (UsbMouseAbsolutePointerDevice != NULL) {
366       if ((UsbMouseAbsolutePointerDevice->AbsolutePointerProtocol).WaitForInput != NULL) {
367         gBS->CloseEvent ((UsbMouseAbsolutePointerDevice->AbsolutePointerProtocol).WaitForInput);
368       }
369 
370       FreePool (UsbMouseAbsolutePointerDevice);
371       UsbMouseAbsolutePointerDevice = NULL;
372     }
373   }
374 
375 ErrorExit1:
376   gBS->RestoreTPL (OldTpl);
377 
378   return Status;
379 }
380 
381 
382 /**
383   Stop the USB mouse device handled by this driver.
384 
385   @param  This                   The driver binding protocol.
386   @param  Controller             The controller to release.
387   @param  NumberOfChildren       The number of handles in ChildHandleBuffer.
388   @param  ChildHandleBuffer      The array of child handle.
389 
390   @retval EFI_SUCCESS            The device was stopped.
391   @retval EFI_UNSUPPORTED        Absolute Pointer Protocol is not installed on Controller.
392   @retval Others                 Fail to uninstall protocols attached on the device.
393 
394 **/
395 EFI_STATUS
396 EFIAPI
USBMouseAbsolutePointerDriverBindingStop(IN EFI_DRIVER_BINDING_PROTOCOL * This,IN EFI_HANDLE Controller,IN UINTN NumberOfChildren,IN EFI_HANDLE * ChildHandleBuffer)397 USBMouseAbsolutePointerDriverBindingStop (
398   IN  EFI_DRIVER_BINDING_PROTOCOL   *This,
399   IN  EFI_HANDLE                    Controller,
400   IN  UINTN                         NumberOfChildren,
401   IN  EFI_HANDLE                    *ChildHandleBuffer
402   )
403 {
404   EFI_STATUS                      Status;
405   USB_MOUSE_ABSOLUTE_POINTER_DEV  *UsbMouseAbsolutePointerDevice;
406   EFI_ABSOLUTE_POINTER_PROTOCOL   *AbsolutePointerProtocol;
407   EFI_USB_IO_PROTOCOL             *UsbIo;
408 
409   Status = gBS->OpenProtocol (
410                   Controller,
411                   &gEfiAbsolutePointerProtocolGuid,
412                   (VOID **) &AbsolutePointerProtocol,
413                   This->DriverBindingHandle,
414                   Controller,
415                   EFI_OPEN_PROTOCOL_GET_PROTOCOL
416                   );
417 
418   if (EFI_ERROR (Status)) {
419     return EFI_UNSUPPORTED;
420   }
421 
422   UsbMouseAbsolutePointerDevice = USB_MOUSE_ABSOLUTE_POINTER_DEV_FROM_MOUSE_PROTOCOL (AbsolutePointerProtocol);
423 
424   UsbIo = UsbMouseAbsolutePointerDevice->UsbIo;
425 
426   //
427   // The key data input from this device will be disabled.
428   //
429   REPORT_STATUS_CODE_WITH_DEVICE_PATH (
430     EFI_PROGRESS_CODE,
431     (EFI_PERIPHERAL_MOUSE | EFI_P_PC_DISABLE),
432     UsbMouseAbsolutePointerDevice->DevicePath
433     );
434 
435   //
436   // Delete the Asynchronous Interrupt Transfer from this device
437   //
438   UsbIo->UsbAsyncInterruptTransfer (
439            UsbIo,
440            UsbMouseAbsolutePointerDevice->IntEndpointDescriptor.EndpointAddress,
441            FALSE,
442            UsbMouseAbsolutePointerDevice->IntEndpointDescriptor.Interval,
443            0,
444            NULL,
445            NULL
446            );
447 
448   Status = gBS->UninstallProtocolInterface (
449                   Controller,
450                   &gEfiAbsolutePointerProtocolGuid,
451                   &UsbMouseAbsolutePointerDevice->AbsolutePointerProtocol
452                   );
453   if (EFI_ERROR (Status)) {
454     return Status;
455   }
456 
457   gBS->CloseProtocol (
458          Controller,
459          &gEfiUsbIoProtocolGuid,
460          This->DriverBindingHandle,
461          Controller
462          );
463 
464   //
465   // Free all resources.
466   //
467   gBS->CloseEvent (UsbMouseAbsolutePointerDevice->AbsolutePointerProtocol.WaitForInput);
468 
469   if (UsbMouseAbsolutePointerDevice->DelayedRecoveryEvent != NULL) {
470     gBS->CloseEvent (UsbMouseAbsolutePointerDevice->DelayedRecoveryEvent);
471     UsbMouseAbsolutePointerDevice->DelayedRecoveryEvent = NULL;
472   }
473 
474   if (UsbMouseAbsolutePointerDevice->ControllerNameTable != NULL) {
475     FreeUnicodeStringTable (UsbMouseAbsolutePointerDevice->ControllerNameTable);
476   }
477 
478   FreePool (UsbMouseAbsolutePointerDevice);
479 
480   return EFI_SUCCESS;
481 
482 }
483 
484 
485 /**
486   Uses USB I/O to check whether the device is a USB mouse device.
487 
488   @param  UsbIo    Pointer to a USB I/O protocol instance.
489 
490   @retval TRUE     Device is a USB mouse device.
491   @retval FALSE    Device is a not USB mouse device.
492 
493 **/
494 BOOLEAN
IsUsbMouse(IN EFI_USB_IO_PROTOCOL * UsbIo)495 IsUsbMouse (
496   IN  EFI_USB_IO_PROTOCOL     *UsbIo
497   )
498 {
499   EFI_STATUS                    Status;
500   EFI_USB_INTERFACE_DESCRIPTOR  InterfaceDescriptor;
501 
502   //
503   // Get the default interface descriptor
504   //
505   Status = UsbIo->UsbGetInterfaceDescriptor (
506                     UsbIo,
507                     &InterfaceDescriptor
508                     );
509 
510   if (EFI_ERROR (Status)) {
511     return FALSE;
512   }
513 
514   if ((InterfaceDescriptor.InterfaceClass == CLASS_HID) &&
515       (InterfaceDescriptor.InterfaceSubClass == SUBCLASS_BOOT) &&
516       (InterfaceDescriptor.InterfaceProtocol == PROTOCOL_MOUSE)
517       ) {
518     return TRUE;
519   }
520 
521   return FALSE;
522 }
523 
524 
525 /**
526   Initialize the USB mouse device.
527 
528   This function retrieves and parses HID report descriptor, and
529   initializes state of USB_MOUSE_ABSOLUTE_POINTER_DEV. Then it sets indefinite idle
530   rate for the device. Finally it creates event for delayed recovery,
531   which deals with device error.
532 
533   @param  UsbMouseAbsolutePointerDev   Device instance to be initialized.
534 
535   @retval EFI_SUCCESS                  USB mouse device successfully initialized.
536   @retval EFI_UNSUPPORTED              HID descriptor type is not report descriptor.
537   @retval Other                        USB mouse device was not initialized successfully.
538 
539 **/
540 EFI_STATUS
InitializeUsbMouseDevice(IN USB_MOUSE_ABSOLUTE_POINTER_DEV * UsbMouseAbsolutePointerDev)541 InitializeUsbMouseDevice (
542   IN  USB_MOUSE_ABSOLUTE_POINTER_DEV           *UsbMouseAbsolutePointerDev
543   )
544 {
545   EFI_USB_IO_PROTOCOL       *UsbIo;
546   UINT8                     Protocol;
547   EFI_STATUS                Status;
548   EFI_USB_HID_DESCRIPTOR    *MouseHidDesc;
549   UINT8                     *ReportDesc;
550   EFI_USB_CONFIG_DESCRIPTOR ConfigDesc;
551   VOID                      *Buf;
552   UINT32                    TransferResult;
553   UINT16                    Total;
554   USB_DESC_HEAD             *Head;
555   BOOLEAN                   Start;
556 
557   UsbIo = UsbMouseAbsolutePointerDev->UsbIo;
558 
559   //
560   // Get the current configuration descriptor. Note that it doesn't include other descriptors.
561   //
562   Status = UsbIo->UsbGetConfigDescriptor (
563                     UsbIo,
564                     &ConfigDesc
565                     );
566   if (EFI_ERROR (Status)) {
567     return Status;
568   }
569 
570   //
571   // By issuing Get_Descriptor(Configuration) request with total length, we get the Configuration descriptor,
572   // all Interface descriptors, all Endpoint descriptors, and the HID descriptor for each interface.
573   //
574   Buf = AllocateZeroPool (ConfigDesc.TotalLength);
575   if (Buf == NULL) {
576     return EFI_OUT_OF_RESOURCES;
577   }
578 
579   Status = UsbGetDescriptor (
580              UsbIo,
581              (UINT16)((USB_DESC_TYPE_CONFIG << 8) | (ConfigDesc.ConfigurationValue - 1)),
582              0,
583              ConfigDesc.TotalLength,
584              Buf,
585              &TransferResult
586              );
587   if (EFI_ERROR (Status)) {
588     FreePool (Buf);
589     return Status;
590   }
591 
592   Total = 0;
593   Start = FALSE;
594   Head  = (USB_DESC_HEAD *)Buf;
595   MouseHidDesc = NULL;
596 
597   //
598   // Get HID descriptor from the receipt of Get_Descriptor(Configuration) request.
599   // This algorithm is based on the fact that the HID descriptor shall be interleaved
600   // between the interface and endpoint descriptors for HID interfaces.
601   //
602   while (Total < ConfigDesc.TotalLength) {
603     if (Head->Type == USB_DESC_TYPE_INTERFACE) {
604       if ((((USB_INTERFACE_DESCRIPTOR *)Head)->InterfaceNumber == UsbMouseAbsolutePointerDev->InterfaceDescriptor.InterfaceNumber) &&
605         (((USB_INTERFACE_DESCRIPTOR *)Head)->AlternateSetting == UsbMouseAbsolutePointerDev->InterfaceDescriptor.AlternateSetting)) {
606         Start = TRUE;
607       }
608     }
609     if (Start && (Head->Type == USB_DESC_TYPE_ENDPOINT)) {
610       break;
611     }
612     if (Start && (Head->Type == USB_DESC_TYPE_HID)) {
613       MouseHidDesc = (EFI_USB_HID_DESCRIPTOR *)Head;
614       break;
615     }
616     Total = Total + (UINT16)Head->Len;
617     Head  = (USB_DESC_HEAD*)((UINT8 *)Buf + Total);
618   }
619 
620   if (MouseHidDesc == NULL) {
621     FreePool (Buf);
622     return EFI_UNSUPPORTED;
623   }
624 
625   //
626   // Get report descriptor
627   //
628   if (MouseHidDesc->HidClassDesc[0].DescriptorType != USB_DESC_TYPE_REPORT) {
629     FreePool (Buf);
630     return EFI_UNSUPPORTED;
631   }
632 
633   ReportDesc = AllocateZeroPool (MouseHidDesc->HidClassDesc[0].DescriptorLength);
634   ASSERT (ReportDesc != NULL);
635 
636   Status = UsbGetReportDescriptor (
637              UsbIo,
638              UsbMouseAbsolutePointerDev->InterfaceDescriptor.InterfaceNumber,
639              MouseHidDesc->HidClassDesc[0].DescriptorLength,
640              ReportDesc
641              );
642 
643   if (EFI_ERROR (Status)) {
644     FreePool (Buf);
645     FreePool (ReportDesc);
646     return Status;
647   }
648 
649   //
650   // Parse report descriptor
651   //
652   Status = ParseMouseReportDescriptor (
653              UsbMouseAbsolutePointerDev,
654              ReportDesc,
655              MouseHidDesc->HidClassDesc[0].DescriptorLength
656              );
657 
658   if (EFI_ERROR (Status)) {
659     FreePool (Buf);
660     FreePool (ReportDesc);
661     return Status;
662   }
663 
664   UsbMouseAbsolutePointerDev->Mode.AbsoluteMaxX = 1024;
665   UsbMouseAbsolutePointerDev->Mode.AbsoluteMaxY = 1024;
666   UsbMouseAbsolutePointerDev->Mode.AbsoluteMaxZ = 0;
667   UsbMouseAbsolutePointerDev->Mode.AbsoluteMinX = 0;
668   UsbMouseAbsolutePointerDev->Mode.AbsoluteMinY = 0;
669   UsbMouseAbsolutePointerDev->Mode.AbsoluteMinZ = 0;
670   UsbMouseAbsolutePointerDev->Mode.Attributes   = 0x3;
671 
672   //
673   // Let the cursor's starting position is in the center of the screen.
674   //
675   UsbMouseAbsolutePointerDev->State.CurrentX =
676     DivU64x32 (UsbMouseAbsolutePointerDev->Mode.AbsoluteMaxX + UsbMouseAbsolutePointerDev->Mode.AbsoluteMinX, 2);
677   UsbMouseAbsolutePointerDev->State.CurrentY =
678     DivU64x32 (UsbMouseAbsolutePointerDev->Mode.AbsoluteMaxY + UsbMouseAbsolutePointerDev->Mode.AbsoluteMinY, 2);
679 
680   //
681   // Set boot protocol for the USB mouse.
682   // This driver only supports boot protocol.
683   //
684   UsbGetProtocolRequest (
685     UsbIo,
686     UsbMouseAbsolutePointerDev->InterfaceDescriptor.InterfaceNumber,
687     &Protocol
688     );
689   if (Protocol != BOOT_PROTOCOL) {
690     Status = UsbSetProtocolRequest (
691                UsbIo,
692                UsbMouseAbsolutePointerDev->InterfaceDescriptor.InterfaceNumber,
693                BOOT_PROTOCOL
694                );
695 
696     if (EFI_ERROR (Status)) {
697       FreePool (Buf);
698       FreePool (ReportDesc);
699       return Status;
700     }
701   }
702 
703   FreePool (Buf);
704   FreePool (ReportDesc);
705 
706   //
707   // Create event for delayed recovery, which deals with device error.
708   //
709   if (UsbMouseAbsolutePointerDev->DelayedRecoveryEvent != NULL) {
710     gBS->CloseEvent (UsbMouseAbsolutePointerDev->DelayedRecoveryEvent);
711     UsbMouseAbsolutePointerDev->DelayedRecoveryEvent = 0;
712   }
713 
714   gBS->CreateEvent (
715          EVT_TIMER | EVT_NOTIFY_SIGNAL,
716          TPL_NOTIFY,
717          USBMouseRecoveryHandler,
718          UsbMouseAbsolutePointerDev,
719          &UsbMouseAbsolutePointerDev->DelayedRecoveryEvent
720          );
721 
722   return EFI_SUCCESS;
723 }
724 
725 
726 /**
727   Handler function for USB mouse's asynchronous interrupt transfer.
728 
729   This function is the handler function for USB mouse's asynchronous interrupt transfer
730   to manage the mouse. It parses data returned from asynchronous interrupt transfer, and
731   get button and movement state.
732 
733   @param  Data             A pointer to a buffer that is filled with key data which is
734                            retrieved via asynchronous interrupt transfer.
735   @param  DataLength       Indicates the size of the data buffer.
736   @param  Context          Pointing to USB_KB_DEV instance.
737   @param  Result           Indicates the result of the asynchronous interrupt transfer.
738 
739   @retval EFI_SUCCESS      Asynchronous interrupt transfer is handled successfully.
740   @retval EFI_DEVICE_ERROR Hardware error occurs.
741 
742 **/
743 EFI_STATUS
744 EFIAPI
OnMouseInterruptComplete(IN VOID * Data,IN UINTN DataLength,IN VOID * Context,IN UINT32 Result)745 OnMouseInterruptComplete (
746   IN  VOID        *Data,
747   IN  UINTN       DataLength,
748   IN  VOID        *Context,
749   IN  UINT32      Result
750   )
751 {
752   USB_MOUSE_ABSOLUTE_POINTER_DEV   *UsbMouseAbsolutePointerDevice;
753   EFI_USB_IO_PROTOCOL              *UsbIo;
754   UINT8                            EndpointAddr;
755   UINT32                           UsbResult;
756 
757   UsbMouseAbsolutePointerDevice  = (USB_MOUSE_ABSOLUTE_POINTER_DEV *) Context;
758   UsbIo                          = UsbMouseAbsolutePointerDevice->UsbIo;
759 
760   if (Result != EFI_USB_NOERROR) {
761     //
762     // Some errors happen during the process
763     //
764     REPORT_STATUS_CODE_WITH_DEVICE_PATH (
765       EFI_ERROR_CODE | EFI_ERROR_MINOR,
766       (EFI_PERIPHERAL_MOUSE | EFI_P_EC_INPUT_ERROR),
767       UsbMouseAbsolutePointerDevice->DevicePath
768       );
769 
770     if ((Result & EFI_USB_ERR_STALL) == EFI_USB_ERR_STALL) {
771       EndpointAddr = UsbMouseAbsolutePointerDevice->IntEndpointDescriptor.EndpointAddress;
772 
773       UsbClearEndpointHalt (
774         UsbIo,
775         EndpointAddr,
776         &UsbResult
777         );
778     }
779 
780     //
781     // Delete & Submit this interrupt again
782     // Handler of DelayedRecoveryEvent triggered by timer will re-submit the interrupt.
783     //
784     UsbIo->UsbAsyncInterruptTransfer (
785              UsbIo,
786              UsbMouseAbsolutePointerDevice->IntEndpointDescriptor.EndpointAddress,
787              FALSE,
788              0,
789              0,
790              NULL,
791              NULL
792              );
793     //
794     // EFI_USB_INTERRUPT_DELAY is defined in USB standard for error handling.
795     //
796     gBS->SetTimer (
797            UsbMouseAbsolutePointerDevice->DelayedRecoveryEvent,
798            TimerRelative,
799            EFI_USB_INTERRUPT_DELAY
800            );
801     return EFI_DEVICE_ERROR;
802   }
803 
804   //
805   // If no error and no data, just return EFI_SUCCESS.
806   //
807   if (DataLength == 0 || Data == NULL) {
808     return EFI_SUCCESS;
809   }
810 
811   //
812   // Check mouse Data
813   // USB HID Specification specifies following data format:
814   // Byte    Bits    Description
815   // 0       0       Button 1
816   //         1       Button 2
817   //         2       Button 3
818   //         4 to 7  Device-specific
819   // 1       0 to 7  X displacement
820   // 2       0 to 7  Y displacement
821   // 3 to n  0 to 7  Device specific (optional)
822   //
823   if (DataLength < 3) {
824     return EFI_DEVICE_ERROR;
825   }
826 
827   UsbMouseAbsolutePointerDevice->StateChanged = TRUE;
828 
829   UsbMouseAbsolutePointerDevice->State.ActiveButtons = *(UINT8 *) Data & (BIT0 | BIT1 | BIT2);
830 
831   UsbMouseAbsolutePointerDevice->State.CurrentX =
832     MIN (
833       MAX ((INT64) UsbMouseAbsolutePointerDevice->State.CurrentX + *((INT8 *) Data + 1),
834            (INT64) UsbMouseAbsolutePointerDevice->Mode.AbsoluteMinX),
835       (INT64) UsbMouseAbsolutePointerDevice->Mode.AbsoluteMaxX
836       );
837   UsbMouseAbsolutePointerDevice->State.CurrentY =
838     MIN (
839       MAX ((INT64) UsbMouseAbsolutePointerDevice->State.CurrentY + *((INT8 *) Data + 2),
840            (INT64) UsbMouseAbsolutePointerDevice->Mode.AbsoluteMinY),
841       (INT64) UsbMouseAbsolutePointerDevice->Mode.AbsoluteMaxY
842       );
843   if (DataLength > 3) {
844     UsbMouseAbsolutePointerDevice->State.CurrentZ =
845       MIN (
846         MAX ((INT64) UsbMouseAbsolutePointerDevice->State.CurrentZ + *((INT8 *) Data + 1),
847              (INT64) UsbMouseAbsolutePointerDevice->Mode.AbsoluteMinZ),
848         (INT64) UsbMouseAbsolutePointerDevice->Mode.AbsoluteMaxZ
849         );
850   }
851 
852   return EFI_SUCCESS;
853 }
854 
855 /**
856   Retrieves the current state of a pointer device.
857 
858   @param  This                  A pointer to the EFI_ABSOLUTE_POINTER_PROTOCOL instance.
859   @param  MouseState            A pointer to the state information on the pointer device.
860 
861   @retval EFI_SUCCESS           The state of the pointer device was returned in State.
862   @retval EFI_NOT_READY         The state of the pointer device has not changed since the last call to
863                                 GetState().
864   @retval EFI_DEVICE_ERROR      A device error occurred while attempting to retrieve the pointer device's
865                                 current state.
866   @retval EFI_INVALID_PARAMETER State is NULL.
867 
868 **/
869 EFI_STATUS
870 EFIAPI
GetMouseAbsolutePointerState(IN EFI_ABSOLUTE_POINTER_PROTOCOL * This,OUT EFI_ABSOLUTE_POINTER_STATE * State)871 GetMouseAbsolutePointerState (
872   IN   EFI_ABSOLUTE_POINTER_PROTOCOL  *This,
873   OUT  EFI_ABSOLUTE_POINTER_STATE     *State
874   )
875 {
876   USB_MOUSE_ABSOLUTE_POINTER_DEV *MouseAbsolutePointerDev;
877 
878   if (State == NULL) {
879     return EFI_INVALID_PARAMETER;
880   }
881 
882   MouseAbsolutePointerDev = USB_MOUSE_ABSOLUTE_POINTER_DEV_FROM_MOUSE_PROTOCOL (This);
883 
884   if (!MouseAbsolutePointerDev->StateChanged) {
885     return EFI_NOT_READY;
886   }
887 
888   //
889   // Retrieve mouse state from USB_MOUSE_ABSOLUTE_POINTER_DEV,
890   // which was filled by OnMouseInterruptComplete()
891   //
892   CopyMem (
893     State,
894     &MouseAbsolutePointerDev->State,
895     sizeof (EFI_ABSOLUTE_POINTER_STATE)
896     );
897 
898   MouseAbsolutePointerDev->StateChanged = FALSE;
899 
900   return EFI_SUCCESS;
901 }
902 
903 
904 /**
905   Resets the pointer device hardware.
906 
907   @param  This                  A pointer to the EFI_ABSOLUTE_POINTER_PROTOCOL instance.
908   @param  ExtendedVerification  Indicates that the driver may perform a more exhaustive
909                                 verification operation of the device during reset.
910 
911   @retval EFI_SUCCESS           The device was reset.
912   @retval EFI_DEVICE_ERROR      The device is not functioning correctly and could not be reset.
913 
914 **/
915 EFI_STATUS
916 EFIAPI
UsbMouseAbsolutePointerReset(IN EFI_ABSOLUTE_POINTER_PROTOCOL * This,IN BOOLEAN ExtendedVerification)917 UsbMouseAbsolutePointerReset (
918   IN EFI_ABSOLUTE_POINTER_PROTOCOL  *This,
919   IN BOOLEAN                        ExtendedVerification
920   )
921 {
922   USB_MOUSE_ABSOLUTE_POINTER_DEV       *UsbMouseAbsolutePointerDevice;
923 
924   UsbMouseAbsolutePointerDevice  = USB_MOUSE_ABSOLUTE_POINTER_DEV_FROM_MOUSE_PROTOCOL (This);
925 
926   REPORT_STATUS_CODE_WITH_DEVICE_PATH (
927     EFI_PROGRESS_CODE,
928     (EFI_PERIPHERAL_MOUSE | EFI_P_PC_RESET),
929     UsbMouseAbsolutePointerDevice->DevicePath
930     );
931 
932   //
933   // Clear mouse state.
934   //
935   ZeroMem (
936     &UsbMouseAbsolutePointerDevice->State,
937     sizeof (EFI_ABSOLUTE_POINTER_STATE)
938     );
939 
940   //
941   // Let the cursor's starting position is in the center of the screen.
942   //
943   UsbMouseAbsolutePointerDevice->State.CurrentX =
944     DivU64x32 (UsbMouseAbsolutePointerDevice->Mode.AbsoluteMaxX + UsbMouseAbsolutePointerDevice->Mode.AbsoluteMinX, 2);
945   UsbMouseAbsolutePointerDevice->State.CurrentY =
946     DivU64x32 (UsbMouseAbsolutePointerDevice->Mode.AbsoluteMaxY + UsbMouseAbsolutePointerDevice->Mode.AbsoluteMinY, 2);
947 
948   UsbMouseAbsolutePointerDevice->StateChanged = FALSE;
949 
950   return EFI_SUCCESS;
951 }
952 
953 /**
954   Event notification function for EFI_ABSOLUTE_POINTER_PROTOCOL.WaitForInput event.
955 
956   @param  Event        Event to be signaled when there's input from mouse.
957   @param  Context      Points to USB_MOUSE_ABSOLUTE_POINTER_DEV instance.
958 
959 **/
960 VOID
961 EFIAPI
UsbMouseAbsolutePointerWaitForInput(IN EFI_EVENT Event,IN VOID * Context)962 UsbMouseAbsolutePointerWaitForInput (
963   IN  EFI_EVENT               Event,
964   IN  VOID                    *Context
965   )
966 {
967   USB_MOUSE_ABSOLUTE_POINTER_DEV *UsbMouseAbsolutePointerDev;
968 
969   UsbMouseAbsolutePointerDev = (USB_MOUSE_ABSOLUTE_POINTER_DEV *) Context;
970 
971   //
972   // If there's input from mouse, signal the event.
973   //
974   if (UsbMouseAbsolutePointerDev->StateChanged) {
975     gBS->SignalEvent (Event);
976   }
977 }
978 
979 /**
980   Handler for Delayed Recovery event.
981 
982   This function is the handler for Delayed Recovery event triggered
983   by timer.
984   After a device error occurs, the event would be triggered
985   with interval of EFI_USB_INTERRUPT_DELAY. EFI_USB_INTERRUPT_DELAY
986   is defined in USB standard for error handling.
987 
988   @param  Event                 The Delayed Recovery event.
989   @param  Context               Points to the USB_MOUSE_ABSOLUTE_POINTER_DEV instance.
990 
991 **/
992 VOID
993 EFIAPI
USBMouseRecoveryHandler(IN EFI_EVENT Event,IN VOID * Context)994 USBMouseRecoveryHandler (
995   IN    EFI_EVENT    Event,
996   IN    VOID         *Context
997   )
998 {
999   USB_MOUSE_ABSOLUTE_POINTER_DEV       *UsbMouseAbsolutePointerDev;
1000   EFI_USB_IO_PROTOCOL                  *UsbIo;
1001 
1002   UsbMouseAbsolutePointerDev = (USB_MOUSE_ABSOLUTE_POINTER_DEV *) Context;
1003 
1004   UsbIo       = UsbMouseAbsolutePointerDev->UsbIo;
1005 
1006   //
1007   // Re-submit Asynchronous Interrupt Transfer for recovery.
1008   //
1009   UsbIo->UsbAsyncInterruptTransfer (
1010            UsbIo,
1011            UsbMouseAbsolutePointerDev->IntEndpointDescriptor.EndpointAddress,
1012            TRUE,
1013            UsbMouseAbsolutePointerDev->IntEndpointDescriptor.Interval,
1014            UsbMouseAbsolutePointerDev->IntEndpointDescriptor.MaxPacketSize,
1015            OnMouseInterruptComplete,
1016            UsbMouseAbsolutePointerDev
1017            );
1018 }
1019