Home | History | Annotate | Download | only in UsbMouseDxe
      1 /** @file
      2   USB Mouse Driver that manages USB mouse and produces Simple 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 "UsbMouse.h"
     16 
     17 EFI_DRIVER_BINDING_PROTOCOL gUsbMouseDriverBinding = {
     18   USBMouseDriverBindingSupported,
     19   USBMouseDriverBindingStart,
     20   USBMouseDriverBindingStop,
     21   0xa,
     22   NULL,
     23   NULL
     24 };
     25 
     26 /**
     27   Entrypoint of USB Mouse 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 USBMouseDriverBindingEntryPoint (
     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              &gUsbMouseDriverBinding,
     51              ImageHandle,
     52              &gUsbMouseComponentName,
     53              &gUsbMouseComponentName2
     54              );
     55   ASSERT_EFI_ERROR (Status);
     56 
     57   return EFI_SUCCESS;
     58 }
     59 
     60 
     61 /**
     62   Check whether USB mouse driver supports this device.
     63 
     64   @param  This                   The USB mouse 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 USBMouseDriverBindingSupported (
     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 Simple Pointer Protocol, and submits Asynchronous Interrupt
    120   Transfer to manage the USB mouse device.
    121 
    122   @param  This                  The USB mouse 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 USBMouseDriverBindingStart (
    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_DEV               *UsbMouseDevice;
    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   UsbMouseDevice = AllocateZeroPool (sizeof (USB_MOUSE_DEV));
    171   ASSERT (UsbMouseDevice != NULL);
    172 
    173   UsbMouseDevice->UsbIo     = UsbIo;
    174   UsbMouseDevice->Signature = USB_MOUSE_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 **) &UsbMouseDevice->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     UsbMouseDevice->DevicePath
    199     );
    200 
    201   //
    202   // Get interface & endpoint descriptor
    203   //
    204   UsbIo->UsbGetInterfaceDescriptor (
    205            UsbIo,
    206            &UsbMouseDevice->InterfaceDescriptor
    207            );
    208 
    209   EndpointNumber = UsbMouseDevice->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(&UsbMouseDevice->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     UsbMouseDevice->DevicePath
    254     );
    255 
    256   Status = InitializeUsbMouseDevice (UsbMouseDevice);
    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       UsbMouseDevice->DevicePath
    265       );
    266 
    267     goto ErrorExit;
    268   }
    269 
    270   //
    271   // Initialize and install EFI Simple Pointer Protocol.
    272   //
    273   UsbMouseDevice->SimplePointerProtocol.GetState  = GetMouseState;
    274   UsbMouseDevice->SimplePointerProtocol.Reset     = UsbMouseReset;
    275   UsbMouseDevice->SimplePointerProtocol.Mode      = &UsbMouseDevice->Mode;
    276 
    277   Status = gBS->CreateEvent (
    278                   EVT_NOTIFY_WAIT,
    279                   TPL_NOTIFY,
    280                   UsbMouseWaitForInput,
    281                   UsbMouseDevice,
    282                   &((UsbMouseDevice->SimplePointerProtocol).WaitForInput)
    283                   );
    284   if (EFI_ERROR (Status)) {
    285     goto ErrorExit;
    286   }
    287 
    288   Status = gBS->InstallProtocolInterface (
    289                   &Controller,
    290                   &gEfiSimplePointerProtocolGuid,
    291                   EFI_NATIVE_INTERFACE,
    292                   &UsbMouseDevice->SimplePointerProtocol
    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     UsbMouseDevice->DevicePath
    308     );
    309 
    310   //
    311   // Submit Asynchronous Interrupt Transfer to manage this device.
    312   //
    313   EndpointAddr    = UsbMouseDevice->IntEndpointDescriptor.EndpointAddress;
    314   PollingInterval = UsbMouseDevice->IntEndpointDescriptor.Interval;
    315   PacketSize      = (UINT8) (UsbMouseDevice->IntEndpointDescriptor.MaxPacketSize);
    316 
    317   Status = UsbIo->UsbAsyncInterruptTransfer (
    318                     UsbIo,
    319                     EndpointAddr,
    320                     TRUE,
    321                     PollingInterval,
    322                     PacketSize,
    323                     OnMouseInterruptComplete,
    324                     UsbMouseDevice
    325                     );
    326 
    327   if (EFI_ERROR (Status)) {
    328     //
    329     // If submit error, uninstall that interface
    330     //
    331     gBS->UninstallProtocolInterface (
    332            Controller,
    333            &gEfiSimplePointerProtocolGuid,
    334            &UsbMouseDevice->SimplePointerProtocol
    335            );
    336     goto ErrorExit;
    337   }
    338 
    339   UsbMouseDevice->ControllerNameTable = NULL;
    340   AddUnicodeString2 (
    341     "eng",
    342     gUsbMouseComponentName.SupportedLanguages,
    343     &UsbMouseDevice->ControllerNameTable,
    344     L"Generic Usb Mouse",
    345     TRUE
    346     );
    347   AddUnicodeString2 (
    348     "en",
    349     gUsbMouseComponentName2.SupportedLanguages,
    350     &UsbMouseDevice->ControllerNameTable,
    351     L"Generic Usb Mouse",
    352     FALSE
    353     );
    354 
    355   gBS->RestoreTPL (OldTpl);
    356 
    357   return EFI_SUCCESS;
    358 
    359 //
    360 // Error handler
    361 //
    362 ErrorExit:
    363   if (EFI_ERROR (Status)) {
    364     gBS->CloseProtocol (
    365           Controller,
    366           &gEfiUsbIoProtocolGuid,
    367           This->DriverBindingHandle,
    368           Controller
    369           );
    370 
    371     if (UsbMouseDevice != NULL) {
    372       if ((UsbMouseDevice->SimplePointerProtocol).WaitForInput != NULL) {
    373         gBS->CloseEvent ((UsbMouseDevice->SimplePointerProtocol).WaitForInput);
    374       }
    375 
    376       FreePool (UsbMouseDevice);
    377       UsbMouseDevice = NULL;
    378     }
    379   }
    380 
    381 ErrorExit1:
    382   gBS->RestoreTPL (OldTpl);
    383   return Status;
    384 }
    385 
    386 
    387 /**
    388   Stop the USB mouse device handled by this driver.
    389 
    390   @param  This                   The USB mouse 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        Simple 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 USBMouseDriverBindingStop (
    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_DEV               *UsbMouseDevice;
    411   EFI_SIMPLE_POINTER_PROTOCOL *SimplePointerProtocol;
    412   EFI_USB_IO_PROTOCOL         *UsbIo;
    413 
    414   Status = gBS->OpenProtocol (
    415                   Controller,
    416                   &gEfiSimplePointerProtocolGuid,
    417                   (VOID **) &SimplePointerProtocol,
    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   UsbMouseDevice = USB_MOUSE_DEV_FROM_MOUSE_PROTOCOL (SimplePointerProtocol);
    428 
    429   UsbIo = UsbMouseDevice->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     UsbMouseDevice->DevicePath
    438     );
    439 
    440   //
    441   // Delete the Asynchronous Interrupt Transfer from this device
    442   //
    443   UsbIo->UsbAsyncInterruptTransfer (
    444            UsbIo,
    445            UsbMouseDevice->IntEndpointDescriptor.EndpointAddress,
    446            FALSE,
    447            UsbMouseDevice->IntEndpointDescriptor.Interval,
    448            0,
    449            NULL,
    450            NULL
    451            );
    452 
    453   Status = gBS->UninstallProtocolInterface (
    454                   Controller,
    455                   &gEfiSimplePointerProtocolGuid,
    456                   &UsbMouseDevice->SimplePointerProtocol
    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 (UsbMouseDevice->SimplePointerProtocol.WaitForInput);
    473 
    474   if (UsbMouseDevice->DelayedRecoveryEvent != NULL) {
    475     gBS->CloseEvent (UsbMouseDevice->DelayedRecoveryEvent);
    476     UsbMouseDevice->DelayedRecoveryEvent = NULL;
    477   }
    478 
    479   if (UsbMouseDevice->ControllerNameTable != NULL) {
    480     FreeUnicodeStringTable (UsbMouseDevice->ControllerNameTable);
    481   }
    482 
    483   FreePool (UsbMouseDevice);
    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_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  UsbMouseDev           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 OUT USB_MOUSE_DEV           *UsbMouseDev
    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 = UsbMouseDev->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 == UsbMouseDev->InterfaceDescriptor.InterfaceNumber) &&
    610         (((USB_INTERFACE_DESCRIPTOR *)Head)->AlternateSetting == UsbMouseDev->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              UsbMouseDev->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              UsbMouseDev,
    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   //
    670   // Check the presence of left and right buttons,
    671   // and initialize fields of EFI_SIMPLE_POINTER_MODE.
    672   //
    673   if (UsbMouseDev->NumberOfButtons >= 1) {
    674     UsbMouseDev->Mode.LeftButton = TRUE;
    675   }
    676   if (UsbMouseDev->NumberOfButtons > 1) {
    677     UsbMouseDev->Mode.RightButton = TRUE;
    678   }
    679   UsbMouseDev->Mode.ResolutionX = 8;
    680   UsbMouseDev->Mode.ResolutionY = 8;
    681   UsbMouseDev->Mode.ResolutionZ = 0;
    682 
    683   //
    684   // Set boot protocol for the USB mouse.
    685   // This driver only supports boot protocol.
    686   //
    687   UsbGetProtocolRequest (
    688     UsbIo,
    689     UsbMouseDev->InterfaceDescriptor.InterfaceNumber,
    690     &Protocol
    691     );
    692   if (Protocol != BOOT_PROTOCOL) {
    693     Status = UsbSetProtocolRequest (
    694                UsbIo,
    695                UsbMouseDev->InterfaceDescriptor.InterfaceNumber,
    696                BOOT_PROTOCOL
    697                );
    698 
    699     if (EFI_ERROR (Status)) {
    700       FreePool (Buf);
    701       FreePool (ReportDesc);
    702       return Status;
    703     }
    704   }
    705 
    706   FreePool (Buf);
    707   FreePool (ReportDesc);
    708 
    709   //
    710   // Create event for delayed recovery, which deals with device error.
    711   //
    712   if (UsbMouseDev->DelayedRecoveryEvent != NULL) {
    713     gBS->CloseEvent (UsbMouseDev->DelayedRecoveryEvent);
    714     UsbMouseDev->DelayedRecoveryEvent = 0;
    715   }
    716 
    717   gBS->CreateEvent (
    718          EVT_TIMER | EVT_NOTIFY_SIGNAL,
    719          TPL_NOTIFY,
    720          USBMouseRecoveryHandler,
    721          UsbMouseDev,
    722          &UsbMouseDev->DelayedRecoveryEvent
    723          );
    724 
    725   return EFI_SUCCESS;
    726 }
    727 
    728 
    729 /**
    730   Handler function for USB mouse's asynchronous interrupt transfer.
    731 
    732   This function is the handler function for USB mouse's asynchronous interrupt transfer
    733   to manage the mouse. It parses data returned from asynchronous interrupt transfer, and
    734   get button and movement state.
    735 
    736   @param  Data             A pointer to a buffer that is filled with key data which is
    737                            retrieved via asynchronous interrupt transfer.
    738   @param  DataLength       Indicates the size of the data buffer.
    739   @param  Context          Pointing to USB_KB_DEV instance.
    740   @param  Result           Indicates the result of the asynchronous interrupt transfer.
    741 
    742   @retval EFI_SUCCESS      Asynchronous interrupt transfer is handled successfully.
    743   @retval EFI_DEVICE_ERROR Hardware error occurs.
    744 
    745 **/
    746 EFI_STATUS
    747 EFIAPI
    748 OnMouseInterruptComplete (
    749   IN  VOID        *Data,
    750   IN  UINTN       DataLength,
    751   IN  VOID        *Context,
    752   IN  UINT32      Result
    753   )
    754 {
    755   USB_MOUSE_DEV       *UsbMouseDevice;
    756   EFI_USB_IO_PROTOCOL *UsbIo;
    757   UINT8               EndpointAddr;
    758   UINT32              UsbResult;
    759 
    760   UsbMouseDevice  = (USB_MOUSE_DEV *) Context;
    761   UsbIo           = UsbMouseDevice->UsbIo;
    762 
    763   if (Result != EFI_USB_NOERROR) {
    764     //
    765     // Some errors happen during the process
    766     //
    767     REPORT_STATUS_CODE_WITH_DEVICE_PATH (
    768       EFI_ERROR_CODE | EFI_ERROR_MINOR,
    769       (EFI_PERIPHERAL_MOUSE | EFI_P_EC_INPUT_ERROR),
    770       UsbMouseDevice->DevicePath
    771       );
    772 
    773     if ((Result & EFI_USB_ERR_STALL) == EFI_USB_ERR_STALL) {
    774       EndpointAddr = UsbMouseDevice->IntEndpointDescriptor.EndpointAddress;
    775 
    776       UsbClearEndpointHalt (
    777         UsbIo,
    778         EndpointAddr,
    779         &UsbResult
    780         );
    781     }
    782 
    783     //
    784     // Delete & Submit this interrupt again
    785     // Handler of DelayedRecoveryEvent triggered by timer will re-submit the interrupt.
    786     //
    787     UsbIo->UsbAsyncInterruptTransfer (
    788              UsbIo,
    789              UsbMouseDevice->IntEndpointDescriptor.EndpointAddress,
    790              FALSE,
    791              0,
    792              0,
    793              NULL,
    794              NULL
    795              );
    796     //
    797     // EFI_USB_INTERRUPT_DELAY is defined in USB standard for error handling.
    798     //
    799     gBS->SetTimer (
    800            UsbMouseDevice->DelayedRecoveryEvent,
    801            TimerRelative,
    802            EFI_USB_INTERRUPT_DELAY
    803            );
    804     return EFI_DEVICE_ERROR;
    805   }
    806 
    807   //
    808   // If no error and no data, just return EFI_SUCCESS.
    809   //
    810   if (DataLength == 0 || Data == NULL) {
    811     return EFI_SUCCESS;
    812   }
    813 
    814   UsbMouseDevice->StateChanged = TRUE;
    815 
    816   //
    817   // Check mouse Data
    818   // USB HID Specification specifies following data format:
    819   // Byte    Bits    Description
    820   // 0       0       Button 1
    821   //         1       Button 2
    822   //         2       Button 3
    823   //         4 to 7  Device-specific
    824   // 1       0 to 7  X displacement
    825   // 2       0 to 7  Y displacement
    826   // 3 to n  0 to 7  Device specific (optional)
    827   //
    828   UsbMouseDevice->State.LeftButton  = (BOOLEAN) ((*(UINT8 *) Data & BIT0) != 0);
    829   UsbMouseDevice->State.RightButton = (BOOLEAN) ((*(UINT8 *) Data & BIT1) != 0);
    830   UsbMouseDevice->State.RelativeMovementX += *((INT8 *) Data + 1);
    831   UsbMouseDevice->State.RelativeMovementY += *((INT8 *) Data + 2);
    832 
    833   if (DataLength > 3) {
    834     UsbMouseDevice->State.RelativeMovementZ += *((INT8 *) Data + 3);
    835   }
    836 
    837   return EFI_SUCCESS;
    838 }
    839 
    840 /**
    841   Retrieves the current state of a pointer device.
    842 
    843   @param  This                  A pointer to the EFI_SIMPLE_POINTER_PROTOCOL instance.
    844   @param  MouseState            A pointer to the state information on the pointer device.
    845 
    846   @retval EFI_SUCCESS           The state of the pointer device was returned in State.
    847   @retval EFI_NOT_READY         The state of the pointer device has not changed since the last call to
    848                                 GetState().
    849   @retval EFI_DEVICE_ERROR      A device error occurred while attempting to retrieve the pointer device's
    850                                 current state.
    851   @retval EFI_INVALID_PARAMETER MouseState is NULL.
    852 
    853 **/
    854 EFI_STATUS
    855 EFIAPI
    856 GetMouseState (
    857   IN   EFI_SIMPLE_POINTER_PROTOCOL  *This,
    858   OUT  EFI_SIMPLE_POINTER_STATE     *MouseState
    859   )
    860 {
    861   USB_MOUSE_DEV *MouseDev;
    862 
    863   if (MouseState == NULL) {
    864     return EFI_INVALID_PARAMETER;
    865   }
    866 
    867   MouseDev = USB_MOUSE_DEV_FROM_MOUSE_PROTOCOL (This);
    868 
    869   if (!MouseDev->StateChanged) {
    870     return EFI_NOT_READY;
    871   }
    872 
    873   //
    874   // Retrieve mouse state from USB_MOUSE_DEV, which was filled by OnMouseInterruptComplete()
    875   //
    876   CopyMem (
    877     MouseState,
    878     &MouseDev->State,
    879     sizeof (EFI_SIMPLE_POINTER_STATE)
    880     );
    881 
    882   //
    883   // Clear previous move state
    884   //
    885   MouseDev->State.RelativeMovementX = 0;
    886   MouseDev->State.RelativeMovementY = 0;
    887   MouseDev->State.RelativeMovementZ = 0;
    888 
    889   MouseDev->StateChanged            = FALSE;
    890 
    891   return EFI_SUCCESS;
    892 }
    893 
    894 
    895 /**
    896   Resets the pointer device hardware.
    897 
    898   @param  This                  A pointer to the EFI_SIMPLE_POINTER_PROTOCOL instance.
    899   @param  ExtendedVerification  Indicates that the driver may perform a more exhaustive
    900                                 verification operation of the device during reset.
    901 
    902   @retval EFI_SUCCESS           The device was reset.
    903   @retval EFI_DEVICE_ERROR      The device is not functioning correctly and could not be reset.
    904 
    905 **/
    906 EFI_STATUS
    907 EFIAPI
    908 UsbMouseReset (
    909   IN EFI_SIMPLE_POINTER_PROTOCOL    *This,
    910   IN BOOLEAN                        ExtendedVerification
    911   )
    912 {
    913   USB_MOUSE_DEV       *UsbMouseDevice;
    914 
    915   UsbMouseDevice  = USB_MOUSE_DEV_FROM_MOUSE_PROTOCOL (This);
    916 
    917   REPORT_STATUS_CODE_WITH_DEVICE_PATH (
    918     EFI_PROGRESS_CODE,
    919     (EFI_PERIPHERAL_MOUSE | EFI_P_PC_RESET),
    920     UsbMouseDevice->DevicePath
    921     );
    922 
    923   //
    924   // Clear mouse state.
    925   //
    926   ZeroMem (
    927     &UsbMouseDevice->State,
    928     sizeof (EFI_SIMPLE_POINTER_STATE)
    929     );
    930   UsbMouseDevice->StateChanged = FALSE;
    931 
    932   return EFI_SUCCESS;
    933 }
    934 
    935 /**
    936   Event notification function for EFI_SIMPLE_POINTER_PROTOCOL.WaitForInput event.
    937 
    938   @param  Event        Event to be signaled when there's input from mouse.
    939   @param  Context      Points to USB_MOUSE_DEV instance.
    940 
    941 **/
    942 VOID
    943 EFIAPI
    944 UsbMouseWaitForInput (
    945   IN  EFI_EVENT               Event,
    946   IN  VOID                    *Context
    947   )
    948 {
    949   USB_MOUSE_DEV *UsbMouseDev;
    950 
    951   UsbMouseDev = (USB_MOUSE_DEV *) Context;
    952 
    953   //
    954   // If there's input from mouse, signal the event.
    955   //
    956   if (UsbMouseDev->StateChanged) {
    957     gBS->SignalEvent (Event);
    958   }
    959 }
    960 
    961 /**
    962   Handler for Delayed Recovery event.
    963 
    964   This function is the handler for Delayed Recovery event triggered
    965   by timer.
    966   After a device error occurs, the event would be triggered
    967   with interval of EFI_USB_INTERRUPT_DELAY. EFI_USB_INTERRUPT_DELAY
    968   is defined in USB standard for error handling.
    969 
    970   @param  Event              The Delayed Recovery event.
    971   @param  Context            Points to the USB_MOUSE_DEV instance.
    972 
    973 **/
    974 VOID
    975 EFIAPI
    976 USBMouseRecoveryHandler (
    977   IN    EFI_EVENT    Event,
    978   IN    VOID         *Context
    979   )
    980 {
    981   USB_MOUSE_DEV       *UsbMouseDev;
    982   EFI_USB_IO_PROTOCOL *UsbIo;
    983 
    984   UsbMouseDev = (USB_MOUSE_DEV *) Context;
    985 
    986   UsbIo       = UsbMouseDev->UsbIo;
    987 
    988   //
    989   // Re-submit Asynchronous Interrupt Transfer for recovery.
    990   //
    991   UsbIo->UsbAsyncInterruptTransfer (
    992            UsbIo,
    993            UsbMouseDev->IntEndpointDescriptor.EndpointAddress,
    994            TRUE,
    995            UsbMouseDev->IntEndpointDescriptor.Interval,
    996            UsbMouseDev->IntEndpointDescriptor.MaxPacketSize,
    997            OnMouseInterruptComplete,
    998            UsbMouseDev
    999            );
   1000 }
   1001