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