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