/** Handler for Delayed Recovery event. This function is the handler for Delayed Recovery event triggered by timer. After a device error occurs, the event would be triggered with interval of EFI_USB_INTERRUPT_DELAY. EFI_USB_INTERRUPT_DELAY is defined in USB standard for error handling. @param Event The Delayed Recovery event. @param Context Points to the USB_MOUSE_DEV instance. **/ VOID EFIAPI USBMouseRecoveryHandler ( IN EFI_EVENT Event, IN VOID *Context ) { USB_MOUSE_DEV *UsbMouseDev; EFI_USB_IO_PROTOCOL *UsbIo; UsbMouseDev = (USB_MOUSE_DEV *) Context; UsbIo = UsbMouseDev->UsbIo; // // Re-submit Asynchronous Interrupt Transfer for recovery. // UsbIo->UsbAsyncInterruptTransfer ( UsbIo, UsbMouseDev->IntEndpointDescriptor.EndpointAddress, TRUE, UsbMouseDev->IntEndpointDescriptor.Interval, UsbMouseDev->IntEndpointDescriptor.MaxPacketSize, OnMouseInterruptComplete, UsbMouseDev ); }
/** Release the hub's control of the interface. @param HubIf The hub interface. @retval EFI_SUCCESS The interface is release of hub control. **/ EFI_STATUS UsbHubRelease ( IN USB_INTERFACE *HubIf ) { EFI_USB_IO_PROTOCOL *UsbIo; EFI_STATUS Status; UsbIo = &HubIf->UsbIo; Status = UsbIo->UsbAsyncInterruptTransfer ( UsbIo, HubIf->HubEp->Desc.EndpointAddress, FALSE, USB_HUB_POLL_INTERVAL, 0, NULL, 0 ); if (EFI_ERROR (Status)) { return Status; } gBS->CloseEvent (HubIf->HubNotify); HubIf->IsHub = FALSE; HubIf->HubApi = NULL; HubIf->HubEp = NULL; HubIf->HubNotify = NULL; DEBUG (( EFI_D_INFO, "UsbHubRelease: hub device %d released\n", HubIf->Device->Address)); return EFI_SUCCESS; }
/** Verify the controller type @param [in] pThis Protocol instance pointer. @param [in] Controller Handle of device to test. @param [in] pRemainingDevicePath Not used. @retval EFI_SUCCESS This driver supports this device. @retval other This driver does not support this device. **/ EFI_STATUS EFIAPI DriverSupported ( IN EFI_DRIVER_BINDING_PROTOCOL * pThis, IN EFI_HANDLE Controller, IN EFI_DEVICE_PATH_PROTOCOL * pRemainingDevicePath ) { EFI_USB_DEVICE_DESCRIPTOR Device; EFI_USB_IO_PROTOCOL * pUsbIo; EFI_STATUS Status; // // Connect to the USB stack // Status = gBS->OpenProtocol ( Controller, &gEfiUsbIoProtocolGuid, (VOID **) &pUsbIo, pThis->DriverBindingHandle, Controller, EFI_OPEN_PROTOCOL_BY_DRIVER ); if (!EFI_ERROR ( Status )) { // // Get the interface descriptor to check the USB class and find a transport // protocol handler. // Status = pUsbIo->UsbGetDeviceDescriptor ( pUsbIo, &Device ); if (!EFI_ERROR ( Status )) { // // Validate the adapter // if (( VENDOR_ID != Device.IdVendor ) || ( PRODUCT_ID != Device.IdProduct )) { Status = EFI_UNSUPPORTED; } } // // Done with the USB stack // gBS->CloseProtocol ( Controller, &gEfiUsbIoProtocolGuid, pThis->DriverBindingHandle, Controller ); } // // Return the device supported status // return Status; }
/** Tests to see if this driver supports a given controller. @param This[in] A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance. @param ControllerHandle[in] The handle of the controller to test. @param RemainingDevicePath[in] The remaining device path. (Ignored - this is not a bus driver.) @retval EFI_SUCCESS The driver supports this controller. @retval EFI_ALREADY_STARTED The device specified by ControllerHandle is already being managed by the driver specified by This. @retval EFI_UNSUPPORTED The device specified by ControllerHandle is not supported by the driver specified by This. **/ EFI_STATUS EFIAPI UsbHwrngDriverBindingSupported ( IN EFI_DRIVER_BINDING_PROTOCOL *This, IN EFI_HANDLE ControllerHandle, IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath ) { EFI_USB_DEVICE_DESCRIPTOR Device; EFI_USB_IO_PROTOCOL *UsbIo; EFI_STATUS Status; // // Connect to the USB stack // Status = gBS->OpenProtocol (ControllerHandle, &gEfiUsbIoProtocolGuid, (VOID **) &UsbIo, This->DriverBindingHandle, ControllerHandle, EFI_OPEN_PROTOCOL_BY_DRIVER); if (EFI_ERROR (Status)) { return Status; } // // Get the interface descriptor to check the USB class and find a transport // protocol handler. // Status = UsbIo->UsbGetDeviceDescriptor (UsbIo, &Device); if (!EFI_ERROR (Status)) { // // Validate the adapter // if ((Device.IdVendor != CHAOSKEY_VENDOR_ID) || (Device.IdProduct != CHAOSKEY_PRODUCT_ID)) { Status = EFI_UNSUPPORTED; } else { DEBUG ((DEBUG_INIT | DEBUG_INFO, "Detected ChaosKey RNG device (USB VendorID:0x%04x ProductID:0x%04x)\n", Device.IdVendor, Device.IdProduct)); Status = EFI_SUCCESS; } } // // Clean up. // gBS->CloseProtocol (ControllerHandle, &gEfiUsbIoProtocolGuid, This->DriverBindingHandle, ControllerHandle); return Status; }
VOID EFIAPI SEnvUsbIo ( IN EFI_HANDLE h, IN VOID *Interface ) /*++ Routine Description: Arguments: h - An EFI handle Interface - The interface Returns: --*/ { EFI_USB_IO_PROTOCOL *UsbIo; EFI_USB_INTERFACE_DESCRIPTOR InterfaceDesc; UsbIo = Interface; UsbIo->UsbGetInterfaceDescriptor (UsbIo, &InterfaceDesc); // // Dump UsbIo Info // Print (L"\n"); PrintToken ( STRING_TOKEN (STR_SHELLENV_DPROT_INTERFACE_NUMBER), HiiEnvHandle, InterfaceDesc.InterfaceNumber ); PrintToken ( STRING_TOKEN (STR_SHELLENV_DPROT_INTERFACE_CLASS), HiiEnvHandle, InterfaceDesc.InterfaceClass ); PrintToken ( STRING_TOKEN (STR_SHELLENV_DPROT_INTERFACE_SUBCLASS), HiiEnvHandle, InterfaceDesc.InterfaceSubClass ); PrintToken ( STRING_TOKEN (STR_SHELLENV_DPROT_INTERFACE_PROTOCOL), HiiEnvHandle, InterfaceDesc.InterfaceProtocol ); }
/** Try to get the controller's USB description. @param Handle Controller handle. @return The description string. **/ CHAR16 * BmGetUsbDescription ( IN EFI_HANDLE Handle ) { EFI_STATUS Status; EFI_USB_IO_PROTOCOL *UsbIo; CHAR16 NullChar; CHAR16 *Manufacturer; CHAR16 *Product; CHAR16 *SerialNumber; CHAR16 *Description; EFI_USB_DEVICE_DESCRIPTOR DevDesc; UINTN DescMaxSize; Status = gBS->HandleProtocol ( Handle, &gEfiUsbIoProtocolGuid, (VOID **) &UsbIo ); if (EFI_ERROR (Status)) { return NULL; } NullChar = L'\0'; Status = UsbIo->UsbGetDeviceDescriptor (UsbIo, &DevDesc); if (EFI_ERROR (Status)) { return NULL; } Status = UsbIo->UsbGetStringDescriptor ( UsbIo, mBmUsbLangId, DevDesc.StrManufacturer, &Manufacturer ); if (EFI_ERROR (Status)) { Manufacturer = &NullChar; } Status = UsbIo->UsbGetStringDescriptor ( UsbIo, mBmUsbLangId, DevDesc.StrProduct, &Product ); if (EFI_ERROR (Status)) { Product = &NullChar; } Status = UsbIo->UsbGetStringDescriptor ( UsbIo, mBmUsbLangId, DevDesc.StrSerialNumber, &SerialNumber ); if (EFI_ERROR (Status)) { SerialNumber = &NullChar; } if ((Manufacturer == &NullChar) && (Product == &NullChar) && (SerialNumber == &NullChar) ) { return NULL; } DescMaxSize = StrSize (Manufacturer) + StrSize (Product) + StrSize (SerialNumber); Description = AllocateZeroPool (DescMaxSize); ASSERT (Description != NULL); StrCatS (Description, DescMaxSize/sizeof(CHAR16), Manufacturer); StrCatS (Description, DescMaxSize/sizeof(CHAR16), L" "); StrCatS (Description, DescMaxSize/sizeof(CHAR16), Product); StrCatS (Description, DescMaxSize/sizeof(CHAR16), L" "); StrCatS (Description, DescMaxSize/sizeof(CHAR16), SerialNumber); if (Manufacturer != &NullChar) { FreePool (Manufacturer); } if (Product != &NullChar) { FreePool (Product); } if (SerialNumber != &NullChar) { FreePool (SerialNumber); } BmEliminateExtraSpaces (Description); return Description; }
/** Starts the keyboard device with this driver. This function produces Simple Text Input Protocol and Simple Text Input Ex Protocol, initializes the keyboard device, and submit Asynchronous Interrupt Transfer to manage this keyboard device. @param This The USB keyboard driver binding instance. @param Controller Handle of device to bind driver to. @param RemainingDevicePath Optional parameter use to pick a specific child device to start. @retval EFI_SUCCESS The controller is controlled by the usb keyboard driver. @retval EFI_UNSUPPORTED No interrupt endpoint can be found. @retval Other This controller cannot be started. **/ EFI_STATUS EFIAPI USBKeyboardDriverBindingStart ( IN EFI_DRIVER_BINDING_PROTOCOL *This, IN EFI_HANDLE Controller, IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath ) { EFI_STATUS Status; EFI_USB_IO_PROTOCOL *UsbIo; USB_KB_DEV *UsbKeyboardDevice; UINT8 EndpointNumber; EFI_USB_ENDPOINT_DESCRIPTOR EndpointDescriptor; UINT8 Index; UINT8 EndpointAddr; UINT8 PollingInterval; UINT8 PacketSize; BOOLEAN Found; EFI_TPL OldTpl; OldTpl = gBS->RaiseTPL (TPL_CALLBACK); // // Open USB I/O Protocol // Status = gBS->OpenProtocol ( Controller, &gEfiUsbIoProtocolGuid, (VOID **) &UsbIo, This->DriverBindingHandle, Controller, EFI_OPEN_PROTOCOL_BY_DRIVER ); if (EFI_ERROR (Status)) { goto ErrorExit1; } UsbKeyboardDevice = AllocateZeroPool (sizeof (USB_KB_DEV)); ASSERT (UsbKeyboardDevice != NULL); // // Get the Device Path Protocol on Controller's handle // Status = gBS->OpenProtocol ( Controller, &gEfiDevicePathProtocolGuid, (VOID **) &UsbKeyboardDevice->DevicePath, This->DriverBindingHandle, Controller, EFI_OPEN_PROTOCOL_GET_PROTOCOL ); if (EFI_ERROR (Status)) { goto ErrorExit; } // // Report that the USB keyboard is being enabled // REPORT_STATUS_CODE_WITH_DEVICE_PATH ( EFI_PROGRESS_CODE, (EFI_PERIPHERAL_KEYBOARD | EFI_P_PC_ENABLE), UsbKeyboardDevice->DevicePath ); // // This is pretty close to keyboard detection, so log progress // REPORT_STATUS_CODE_WITH_DEVICE_PATH ( EFI_PROGRESS_CODE, (EFI_PERIPHERAL_KEYBOARD | EFI_P_PC_PRESENCE_DETECT), UsbKeyboardDevice->DevicePath ); UsbKeyboardDevice->UsbIo = UsbIo; // // Get interface & endpoint descriptor // UsbIo->UsbGetInterfaceDescriptor ( UsbIo, &UsbKeyboardDevice->InterfaceDescriptor ); EndpointNumber = UsbKeyboardDevice->InterfaceDescriptor.NumEndpoints; // // Traverse endpoints to find interrupt endpoint // Found = FALSE; for (Index = 0; Index < EndpointNumber; Index++) { UsbIo->UsbGetEndpointDescriptor ( UsbIo, Index, &EndpointDescriptor ); if ((EndpointDescriptor.Attributes & (BIT0 | BIT1)) == USB_ENDPOINT_INTERRUPT) { // // We only care interrupt endpoint here // CopyMem(&UsbKeyboardDevice->IntEndpointDescriptor, &EndpointDescriptor, sizeof(EndpointDescriptor)); Found = TRUE; break; } } if (!Found) { // // No interrupt endpoint found, then return unsupported. // Status = EFI_UNSUPPORTED; goto ErrorExit; } UsbKeyboardDevice->Signature = USB_KB_DEV_SIGNATURE; UsbKeyboardDevice->SimpleInput.Reset = USBKeyboardReset; UsbKeyboardDevice->SimpleInput.ReadKeyStroke = USBKeyboardReadKeyStroke; UsbKeyboardDevice->SimpleInputEx.Reset = USBKeyboardResetEx; UsbKeyboardDevice->SimpleInputEx.ReadKeyStrokeEx = USBKeyboardReadKeyStrokeEx; UsbKeyboardDevice->SimpleInputEx.SetState = USBKeyboardSetState; UsbKeyboardDevice->SimpleInputEx.RegisterKeyNotify = USBKeyboardRegisterKeyNotify; UsbKeyboardDevice->SimpleInputEx.UnregisterKeyNotify = USBKeyboardUnregisterKeyNotify; InitializeListHead (&UsbKeyboardDevice->NotifyList); Status = gBS->CreateEvent ( EVT_TIMER | EVT_NOTIFY_SIGNAL, TPL_NOTIFY, USBKeyboardTimerHandler, UsbKeyboardDevice, &UsbKeyboardDevice->TimerEvent ); if (!EFI_ERROR (Status)) { Status = gBS->SetTimer (UsbKeyboardDevice->TimerEvent, TimerPeriodic, KEYBOARD_TIMER_INTERVAL); } if (EFI_ERROR (Status)) { goto ErrorExit; } Status = gBS->CreateEvent ( EVT_NOTIFY_WAIT, TPL_NOTIFY, USBKeyboardWaitForKey, UsbKeyboardDevice, &(UsbKeyboardDevice->SimpleInputEx.WaitForKeyEx) ); if (EFI_ERROR (Status)) { goto ErrorExit; } Status = gBS->CreateEvent ( EVT_NOTIFY_WAIT, TPL_NOTIFY, USBKeyboardWaitForKey, UsbKeyboardDevice, &(UsbKeyboardDevice->SimpleInput.WaitForKey) ); if (EFI_ERROR (Status)) { goto ErrorExit; } // // Install Simple Text Input Protocol and Simple Text Input Ex Protocol // for the USB keyboard device. // USB keyboard is a hot plug device, and expected to work immediately // when plugging into system, other conventional console devices could // distinguish it by its device path. // Status = gBS->InstallMultipleProtocolInterfaces ( &Controller, &gEfiSimpleTextInProtocolGuid, &UsbKeyboardDevice->SimpleInput, &gEfiSimpleTextInputExProtocolGuid, &UsbKeyboardDevice->SimpleInputEx, NULL ); if (EFI_ERROR (Status)) { goto ErrorExit; } UsbKeyboardDevice->ControllerHandle = Controller; Status = InitKeyboardLayout (UsbKeyboardDevice); if (EFI_ERROR (Status)) { gBS->UninstallMultipleProtocolInterfaces ( Controller, &gEfiSimpleTextInProtocolGuid, &UsbKeyboardDevice->SimpleInput, &gEfiSimpleTextInputExProtocolGuid, &UsbKeyboardDevice->SimpleInputEx, NULL ); goto ErrorExit; } // // Reset USB Keyboard Device exhaustively. // Status = UsbKeyboardDevice->SimpleInputEx.Reset ( &UsbKeyboardDevice->SimpleInputEx, TRUE ); if (EFI_ERROR (Status)) { gBS->UninstallMultipleProtocolInterfaces ( Controller, &gEfiSimpleTextInProtocolGuid, &UsbKeyboardDevice->SimpleInput, &gEfiSimpleTextInputExProtocolGuid, &UsbKeyboardDevice->SimpleInputEx, NULL ); goto ErrorExit; } // // Submit Asynchronous Interrupt Transfer to manage this device. // EndpointAddr = UsbKeyboardDevice->IntEndpointDescriptor.EndpointAddress; PollingInterval = UsbKeyboardDevice->IntEndpointDescriptor.Interval; PacketSize = (UINT8) (UsbKeyboardDevice->IntEndpointDescriptor.MaxPacketSize); Status = UsbIo->UsbAsyncInterruptTransfer ( UsbIo, EndpointAddr, TRUE, PollingInterval, PacketSize, KeyboardHandler, UsbKeyboardDevice ); if (EFI_ERROR (Status)) { gBS->UninstallMultipleProtocolInterfaces ( Controller, &gEfiSimpleTextInProtocolGuid, &UsbKeyboardDevice->SimpleInput, &gEfiSimpleTextInputExProtocolGuid, &UsbKeyboardDevice->SimpleInputEx, NULL ); goto ErrorExit; } UsbKeyboardDevice->ControllerNameTable = NULL; AddUnicodeString2 ( "eng", gUsbKeyboardComponentName.SupportedLanguages, &UsbKeyboardDevice->ControllerNameTable, L"Generic Usb Keyboard", TRUE ); AddUnicodeString2 ( "en", gUsbKeyboardComponentName2.SupportedLanguages, &UsbKeyboardDevice->ControllerNameTable, L"Generic Usb Keyboard", FALSE ); gBS->RestoreTPL (OldTpl); return EFI_SUCCESS; // // Error handler // ErrorExit: if (UsbKeyboardDevice != NULL) { if (UsbKeyboardDevice->TimerEvent != NULL) { gBS->CloseEvent (UsbKeyboardDevice->TimerEvent); } if (UsbKeyboardDevice->SimpleInput.WaitForKey != NULL) { gBS->CloseEvent (UsbKeyboardDevice->SimpleInput.WaitForKey); } if (UsbKeyboardDevice->SimpleInputEx.WaitForKeyEx != NULL) { gBS->CloseEvent (UsbKeyboardDevice->SimpleInputEx.WaitForKeyEx); } if (UsbKeyboardDevice->KeyboardLayoutEvent != NULL) { ReleaseKeyboardLayoutResources (UsbKeyboardDevice); gBS->CloseEvent (UsbKeyboardDevice->KeyboardLayoutEvent); } FreePool (UsbKeyboardDevice); UsbKeyboardDevice = NULL; } gBS->CloseProtocol ( Controller, &gEfiUsbIoProtocolGuid, This->DriverBindingHandle, Controller ); ErrorExit1: gBS->RestoreTPL (OldTpl); return Status; }
/** Initialize the device for a non-root hub. @param HubIf The USB hub interface. @retval EFI_SUCCESS The hub is initialized. @retval EFI_DEVICE_ERROR Failed to initialize the hub. **/ EFI_STATUS UsbHubInit ( IN USB_INTERFACE *HubIf ) { EFI_USB_HUB_DESCRIPTOR HubDesc; USB_ENDPOINT_DESC *EpDesc; USB_INTERFACE_SETTING *Setting; EFI_USB_IO_PROTOCOL *UsbIo; USB_DEVICE *HubDev; EFI_STATUS Status; UINT8 Index; UINT8 NumEndpoints; // // Locate the interrupt endpoint for port change map // HubIf->IsHub = FALSE; Setting = HubIf->IfSetting; HubDev = HubIf->Device; EpDesc = NULL; NumEndpoints = Setting->Desc.NumEndpoints; for (Index = 0; Index < NumEndpoints; Index++) { ASSERT ((Setting->Endpoints != NULL) && (Setting->Endpoints[Index] != NULL)); EpDesc = Setting->Endpoints[Index]; if (USB_BIT_IS_SET (EpDesc->Desc.EndpointAddress, USB_ENDPOINT_DIR_IN) && (USB_ENDPOINT_TYPE (&EpDesc->Desc) == USB_ENDPOINT_INTERRUPT)) { break; } } if (Index == NumEndpoints) { DEBUG (( EFI_D_ERROR, "UsbHubInit: no interrupt endpoint found for hub %d\n", HubDev->Address)); return EFI_DEVICE_ERROR; } Status = UsbHubReadDesc (HubDev, &HubDesc); if (EFI_ERROR (Status)) { DEBUG (( EFI_D_ERROR, "UsbHubInit: failed to read HUB descriptor %r\n", Status)); return Status; } HubIf->NumOfPort = HubDesc.NumPorts; DEBUG (( EFI_D_INFO, "UsbHubInit: hub %d has %d ports\n", HubDev->Address,HubIf->NumOfPort)); // // Create an event to enumerate the hub's port. On // Status = gBS->CreateEvent ( EVT_NOTIFY_SIGNAL, TPL_CALLBACK, UsbHubEnumeration, HubIf, &HubIf->HubNotify ); if (EFI_ERROR (Status)) { DEBUG (( EFI_D_ERROR, "UsbHubInit: failed to create signal for hub %d - %r\n", HubDev->Address, Status)); return Status; } // // Create AsyncInterrupt to query hub port change endpoint // periodically. If the hub ports are changed, hub will return // changed port map from the interrupt endpoint. The port map // must be able to hold (HubIf->NumOfPort + 1) bits (one bit for // host change status). // UsbIo = &HubIf->UsbIo; Status = UsbIo->UsbAsyncInterruptTransfer ( UsbIo, EpDesc->Desc.EndpointAddress, TRUE, USB_HUB_POLL_INTERVAL, HubIf->NumOfPort / 8 + 1, UsbOnHubInterrupt, HubIf ); if (EFI_ERROR (Status)) { DEBUG (( EFI_D_ERROR, "UsbHubInit: failed to queue interrupt transfer for hub %d - %r\n", HubDev->Address, Status)); gBS->CloseEvent (HubIf->HubNotify); HubIf->HubNotify = NULL; return Status; } // // OK, set IsHub to TRUE. Now usb bus can handle this device // as a working HUB. If failed eariler, bus driver will not // recognize it as a hub. Other parts of the bus should be able // to work. // HubIf->IsHub = TRUE; HubIf->HubApi = &mUsbHubApi; HubIf->HubEp = EpDesc; // // Feed power to all the hub ports. It should be ok // for both gang/individual powered hubs. // for (Index = 0; Index < HubDesc.NumPorts; Index++) { UsbHubCtrlSetPortFeature (HubIf->Device, Index, (EFI_USB_PORT_FEATURE) USB_HUB_PORT_POWER); } gBS->Stall (HubDesc.PwrOn2PwrGood * USB_SET_PORT_POWER_STALL); UsbHubAckHubStatus (HubIf->Device); DEBUG (( EFI_D_INFO, "UsbHubInit: hub %d initialized\n", HubDev->Address)); return Status; }
/** The callback function to the USB hub status change interrupt endpoint. It is called periodically by the underlying host controller. @param Data The data read. @param DataLength The length of the data read. @param Context The context. @param Result The result of the last interrupt transfer. @retval EFI_SUCCESS The process is OK. @retval EFI_OUT_OF_RESOURCES Failed to allocate resource. **/ EFI_STATUS EFIAPI UsbOnHubInterrupt ( IN VOID *Data, IN UINTN DataLength, IN VOID *Context, IN UINT32 Result ) { USB_INTERFACE *HubIf; EFI_USB_IO_PROTOCOL *UsbIo; EFI_USB_ENDPOINT_DESCRIPTOR *EpDesc; EFI_STATUS Status; HubIf = (USB_INTERFACE *) Context; UsbIo = &(HubIf->UsbIo); EpDesc = &(HubIf->HubEp->Desc); if (Result != EFI_USB_NOERROR) { // // If endpoint is stalled, clear the stall. Use UsbIo to access // the control transfer so internal status are maintained. // if (USB_BIT_IS_SET (Result, EFI_USB_ERR_STALL)) { UsbIoClearFeature ( UsbIo, USB_TARGET_ENDPOINT, USB_FEATURE_ENDPOINT_HALT, EpDesc->EndpointAddress ); } // // Delete and submit a new async interrupt // Status = UsbIo->UsbAsyncInterruptTransfer ( UsbIo, EpDesc->EndpointAddress, FALSE, 0, 0, NULL, NULL ); if (EFI_ERROR (Status)) { DEBUG (( EFI_D_ERROR, "UsbOnHubInterrupt: failed to remove async transfer - %r\n", Status)); return Status; } Status = UsbIo->UsbAsyncInterruptTransfer ( UsbIo, EpDesc->EndpointAddress, TRUE, USB_HUB_POLL_INTERVAL, HubIf->NumOfPort / 8 + 1, UsbOnHubInterrupt, HubIf ); if (EFI_ERROR (Status)) { DEBUG (( EFI_D_ERROR, "UsbOnHubInterrupt: failed to submit new async transfer - %r\n", Status)); } return Status; } if ((DataLength == 0) || (Data == NULL)) { return EFI_SUCCESS; } // // OK, actually something is changed, save the change map // then signal the HUB to do enumeration. This is a good // practise since UsbOnHubInterrupt is called in the context // of host contrller's AsyncInterrupt monitor. // HubIf->ChangeMap = AllocateZeroPool (DataLength); if (HubIf->ChangeMap == NULL) { return EFI_OUT_OF_RESOURCES; } CopyMem (HubIf->ChangeMap, Data, DataLength); gBS->SignalEvent (HubIf->HubNotify); return EFI_SUCCESS; }
/** Check whether the controller is a supported USB mass storage. @param This The USB mass storage driver binding protocol. @param Controller The controller handle to check. @param RemainingDevicePath The remaining device path. @retval EFI_SUCCESS The driver supports this controller. @retval other This device isn't supported. **/ EFI_STATUS EFIAPI USBMassDriverBindingSupported ( IN EFI_DRIVER_BINDING_PROTOCOL *This, IN EFI_HANDLE Controller, IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath ) { EFI_USB_IO_PROTOCOL *UsbIo; EFI_USB_INTERFACE_DESCRIPTOR Interface; USB_MASS_TRANSPORT *Transport; EFI_STATUS Status; UINTN Index; Status = gBS->OpenProtocol ( Controller, &gEfiUsbIoProtocolGuid, (VOID **) &UsbIo, This->DriverBindingHandle, Controller, EFI_OPEN_PROTOCOL_BY_DRIVER ); if (EFI_ERROR (Status)) { return Status; } // // Get the interface descriptor to check the USB class and find a transport // protocol handler. // Status = UsbIo->UsbGetInterfaceDescriptor (UsbIo, &Interface); if (EFI_ERROR (Status)) { goto ON_EXIT; } Status = EFI_UNSUPPORTED; if (Interface.InterfaceClass != USB_MASS_STORE_CLASS) { goto ON_EXIT; } // // Traverse the USB_MASS_TRANSPORT arrary and try to find the // matching transport method. // If not found, return EFI_UNSUPPORTED. // If found, execute USB_MASS_TRANSPORT.Init() to initialize the transport context. // for (Index = 0; Index < USB_MASS_TRANSPORT_COUNT; Index++) { Transport = mUsbMassTransport[Index]; if (Interface.InterfaceProtocol == Transport->Protocol) { Status = Transport->Init (UsbIo, NULL); break; } } ON_EXIT: gBS->CloseProtocol ( Controller, &gEfiUsbIoProtocolGuid, This->DriverBindingHandle, Controller ); return Status; }
/** Initilize the USB Mass Storage transport. This function tries to find the matching USB Mass Storage transport protocol for USB device. If found, initializes the matching transport. @param This The USB mass driver's driver binding. @param Controller The device to test. @param Transport The pointer to pointer to USB_MASS_TRANSPORT. @param Context The parameter for USB_MASS_DEVICE.Context. @param MaxLun Get the MaxLun if is BOT dev. @retval EFI_SUCCESS The initialization is successful. @retval EFI_UNSUPPORTED No matching transport protocol is found. @retval Others Failed to initialize dev. **/ EFI_STATUS UsbMassInitTransport ( IN EFI_DRIVER_BINDING_PROTOCOL *This, IN EFI_HANDLE Controller, OUT USB_MASS_TRANSPORT **Transport, OUT VOID **Context, OUT UINT8 *MaxLun ) { EFI_USB_IO_PROTOCOL *UsbIo; EFI_USB_INTERFACE_DESCRIPTOR Interface; UINT8 Index; EFI_STATUS Status; Status = gBS->OpenProtocol ( Controller, &gEfiUsbIoProtocolGuid, (VOID **) &UsbIo, This->DriverBindingHandle, Controller, EFI_OPEN_PROTOCOL_BY_DRIVER ); if (EFI_ERROR (Status)) { return Status; } Status = UsbIo->UsbGetInterfaceDescriptor (UsbIo, &Interface); if (EFI_ERROR (Status)) { goto ON_EXIT; } Status = EFI_UNSUPPORTED; // // Traverse the USB_MASS_TRANSPORT arrary and try to find the // matching transport protocol. // If not found, return EFI_UNSUPPORTED. // If found, execute USB_MASS_TRANSPORT.Init() to initialize the transport context. // for (Index = 0; Index < USB_MASS_TRANSPORT_COUNT; Index++) { *Transport = mUsbMassTransport[Index]; if (Interface.InterfaceProtocol == (*Transport)->Protocol) { Status = (*Transport)->Init (UsbIo, Context); break; } } if (EFI_ERROR (Status)) { goto ON_EXIT; } // // For BOT device, try to get its max LUN. // If max LUN is 0, then it is a non-lun device. // Otherwise, it is a multi-lun device. // if ((*Transport)->Protocol == USB_MASS_STORE_BOT) { (*Transport)->GetMaxLun (*Context, MaxLun); } ON_EXIT: gBS->CloseProtocol ( Controller, &gEfiUsbIoProtocolGuid, This->DriverBindingHandle, Controller ); return Status; }
/** Handler function for USB mouse's asynchronous interrupt transfer. This function is the handler function for USB mouse's asynchronous interrupt transfer to manage the mouse. It parses data returned from asynchronous interrupt transfer, and get button and movement state. @param Data A pointer to a buffer that is filled with key data which is retrieved via asynchronous interrupt transfer. @param DataLength Indicates the size of the data buffer. @param Context Pointing to USB_KB_DEV instance. @param Result Indicates the result of the asynchronous interrupt transfer. @retval EFI_SUCCESS Asynchronous interrupt transfer is handled successfully. @retval EFI_DEVICE_ERROR Hardware error occurs. **/ EFI_STATUS EFIAPI OnMouseInterruptComplete ( IN VOID *Data, IN UINTN DataLength, IN VOID *Context, IN UINT32 Result ) { USB_MOUSE_DEV *UsbMouseDevice; EFI_USB_IO_PROTOCOL *UsbIo; UINT8 EndpointAddr; UINT32 UsbResult; UsbMouseDevice = (USB_MOUSE_DEV *) Context; UsbIo = UsbMouseDevice->UsbIo; if (Result != EFI_USB_NOERROR) { // // Some errors happen during the process // REPORT_STATUS_CODE_WITH_DEVICE_PATH ( EFI_ERROR_CODE | EFI_ERROR_MINOR, (EFI_PERIPHERAL_MOUSE | EFI_P_EC_INPUT_ERROR), UsbMouseDevice->DevicePath ); if ((Result & EFI_USB_ERR_STALL) == EFI_USB_ERR_STALL) { EndpointAddr = UsbMouseDevice->IntEndpointDescriptor.EndpointAddress; UsbClearEndpointHalt ( UsbIo, EndpointAddr, &UsbResult ); } // // Delete & Submit this interrupt again // Handler of DelayedRecoveryEvent triggered by timer will re-submit the interrupt. // UsbIo->UsbAsyncInterruptTransfer ( UsbIo, UsbMouseDevice->IntEndpointDescriptor.EndpointAddress, FALSE, 0, 0, NULL, NULL ); // // EFI_USB_INTERRUPT_DELAY is defined in USB standard for error handling. // gBS->SetTimer ( UsbMouseDevice->DelayedRecoveryEvent, TimerRelative, EFI_USB_INTERRUPT_DELAY ); return EFI_DEVICE_ERROR; } // // If no error and no data, just return EFI_SUCCESS. // if (DataLength == 0 || Data == NULL) { return EFI_SUCCESS; } UsbMouseDevice->StateChanged = TRUE; // // Check mouse Data // USB HID Specification specifies following data format: // Byte Bits Description // 0 0 Button 1 // 1 Button 2 // 2 Button 3 // 4 to 7 Device-specific // 1 0 to 7 X displacement // 2 0 to 7 Y displacement // 3 to n 0 to 7 Device specific (optional) // UsbMouseDevice->State.LeftButton = (BOOLEAN) ((*(UINT8 *) Data & BIT0) != 0); UsbMouseDevice->State.RightButton = (BOOLEAN) ((*(UINT8 *) Data & BIT1) != 0); UsbMouseDevice->State.RelativeMovementX += *((INT8 *) Data + 1); UsbMouseDevice->State.RelativeMovementY += *((INT8 *) Data + 2); if (DataLength > 3) { UsbMouseDevice->State.RelativeMovementZ += *((INT8 *) Data + 3); } return EFI_SUCCESS; }
/** Initialize the USB mouse device. This function retrieves and parses HID report descriptor, and initializes state of USB_MOUSE_DEV. Then it sets indefinite idle rate for the device. Finally it creates event for delayed recovery, which deals with device error. @param UsbMouseDev Device instance to be initialized. @retval EFI_SUCCESS USB mouse device successfully initialized.. @retval EFI_UNSUPPORTED HID descriptor type is not report descriptor. @retval Other USB mouse device was not initialized successfully. **/ EFI_STATUS InitializeUsbMouseDevice ( IN OUT USB_MOUSE_DEV *UsbMouseDev ) { EFI_USB_IO_PROTOCOL *UsbIo; UINT8 Protocol; EFI_STATUS Status; EFI_USB_HID_DESCRIPTOR *MouseHidDesc; UINT8 *ReportDesc; EFI_USB_CONFIG_DESCRIPTOR ConfigDesc; VOID *Buf; UINT32 TransferResult; UINT16 Total; USB_DESC_HEAD *Head; BOOLEAN Start; UsbIo = UsbMouseDev->UsbIo; // // Get the current configuration descriptor. Note that it doesn't include other descriptors. // Status = UsbIo->UsbGetConfigDescriptor ( UsbIo, &ConfigDesc ); if (EFI_ERROR (Status)) { return Status; } // // By issuing Get_Descriptor(Configuration) request with total length, we get the Configuration descriptor, // all Interface descriptors, all Endpoint descriptors, and the HID descriptor for each interface. // Buf = AllocateZeroPool (ConfigDesc.TotalLength); if (Buf == NULL) { return EFI_OUT_OF_RESOURCES; } Status = UsbGetDescriptor ( UsbIo, (UINT16)((USB_DESC_TYPE_CONFIG << 8) | (ConfigDesc.ConfigurationValue - 1)), 0, ConfigDesc.TotalLength, Buf, &TransferResult ); if (EFI_ERROR (Status)) { FreePool (Buf); return Status; } Total = 0; Start = FALSE; Head = (USB_DESC_HEAD *)Buf; MouseHidDesc = NULL; // // Get HID descriptor from the receipt of Get_Descriptor(Configuration) request. // This algorithm is based on the fact that the HID descriptor shall be interleaved // between the interface and endpoint descriptors for HID interfaces. // while (Total < ConfigDesc.TotalLength) { if (Head->Type == USB_DESC_TYPE_INTERFACE) { if ((((USB_INTERFACE_DESCRIPTOR *)Head)->InterfaceNumber == UsbMouseDev->InterfaceDescriptor.InterfaceNumber) && (((USB_INTERFACE_DESCRIPTOR *)Head)->AlternateSetting == UsbMouseDev->InterfaceDescriptor.AlternateSetting)) { Start = TRUE; } } if (Start && (Head->Type == USB_DESC_TYPE_ENDPOINT)) { break; } if (Start && (Head->Type == USB_DESC_TYPE_HID)) { MouseHidDesc = (EFI_USB_HID_DESCRIPTOR *)Head; break; } Total = Total + (UINT16)Head->Len; Head = (USB_DESC_HEAD*)((UINT8 *)Buf + Total); } if (MouseHidDesc == NULL) { FreePool (Buf); return EFI_UNSUPPORTED; } // // Get report descriptor // if (MouseHidDesc->HidClassDesc[0].DescriptorType != USB_DESC_TYPE_REPORT) { FreePool (Buf); return EFI_UNSUPPORTED; } ReportDesc = AllocateZeroPool (MouseHidDesc->HidClassDesc[0].DescriptorLength); ASSERT (ReportDesc != NULL); Status = UsbGetReportDescriptor ( UsbIo, UsbMouseDev->InterfaceDescriptor.InterfaceNumber, MouseHidDesc->HidClassDesc[0].DescriptorLength, ReportDesc ); if (EFI_ERROR (Status)) { FreePool (Buf); FreePool (ReportDesc); return Status; } // // Parse report descriptor // Status = ParseMouseReportDescriptor ( UsbMouseDev, ReportDesc, MouseHidDesc->HidClassDesc[0].DescriptorLength ); if (EFI_ERROR (Status)) { FreePool (Buf); FreePool (ReportDesc); return Status; } // // Check the presence of left and right buttons, // and initialize fields of EFI_SIMPLE_POINTER_MODE. // if (UsbMouseDev->NumberOfButtons >= 1) { UsbMouseDev->Mode.LeftButton = TRUE; } if (UsbMouseDev->NumberOfButtons > 1) { UsbMouseDev->Mode.RightButton = TRUE; } UsbMouseDev->Mode.ResolutionX = 8; UsbMouseDev->Mode.ResolutionY = 8; UsbMouseDev->Mode.ResolutionZ = 0; // // Set boot protocol for the USB mouse. // This driver only supports boot protocol. // UsbGetProtocolRequest ( UsbIo, UsbMouseDev->InterfaceDescriptor.InterfaceNumber, &Protocol ); if (Protocol != BOOT_PROTOCOL) { Status = UsbSetProtocolRequest ( UsbIo, UsbMouseDev->InterfaceDescriptor.InterfaceNumber, BOOT_PROTOCOL ); if (EFI_ERROR (Status)) { FreePool (Buf); FreePool (ReportDesc); return Status; } } FreePool (Buf); FreePool (ReportDesc); // // Create event for delayed recovery, which deals with device error. // if (UsbMouseDev->DelayedRecoveryEvent != NULL) { gBS->CloseEvent (UsbMouseDev->DelayedRecoveryEvent); UsbMouseDev->DelayedRecoveryEvent = 0; } gBS->CreateEvent ( EVT_TIMER | EVT_NOTIFY_SIGNAL, TPL_NOTIFY, USBMouseRecoveryHandler, UsbMouseDev, &UsbMouseDev->DelayedRecoveryEvent ); return EFI_SUCCESS; }
/** Stop the USB mouse device handled by this driver. @param This The USB mouse driver binding protocol. @param Controller The controller to release. @param NumberOfChildren The number of handles in ChildHandleBuffer. @param ChildHandleBuffer The array of child handle. @retval EFI_SUCCESS The device was stopped. @retval EFI_UNSUPPORTED Simple Pointer Protocol is not installed on Controller. @retval Others Fail to uninstall protocols attached on the device. **/ EFI_STATUS EFIAPI USBMouseDriverBindingStop ( IN EFI_DRIVER_BINDING_PROTOCOL *This, IN EFI_HANDLE Controller, IN UINTN NumberOfChildren, IN EFI_HANDLE *ChildHandleBuffer ) { EFI_STATUS Status; USB_MOUSE_DEV *UsbMouseDevice; EFI_SIMPLE_POINTER_PROTOCOL *SimplePointerProtocol; EFI_USB_IO_PROTOCOL *UsbIo; Status = gBS->OpenProtocol ( Controller, &gEfiSimplePointerProtocolGuid, (VOID **) &SimplePointerProtocol, This->DriverBindingHandle, Controller, EFI_OPEN_PROTOCOL_GET_PROTOCOL ); if (EFI_ERROR (Status)) { return EFI_UNSUPPORTED; } UsbMouseDevice = USB_MOUSE_DEV_FROM_MOUSE_PROTOCOL (SimplePointerProtocol); UsbIo = UsbMouseDevice->UsbIo; // // The key data input from this device will be disabled. // REPORT_STATUS_CODE_WITH_DEVICE_PATH ( EFI_PROGRESS_CODE, (EFI_PERIPHERAL_MOUSE | EFI_P_PC_DISABLE), UsbMouseDevice->DevicePath ); // // Delete the Asynchronous Interrupt Transfer from this device // UsbIo->UsbAsyncInterruptTransfer ( UsbIo, UsbMouseDevice->IntEndpointDescriptor.EndpointAddress, FALSE, UsbMouseDevice->IntEndpointDescriptor.Interval, 0, NULL, NULL ); Status = gBS->UninstallProtocolInterface ( Controller, &gEfiSimplePointerProtocolGuid, &UsbMouseDevice->SimplePointerProtocol ); if (EFI_ERROR (Status)) { return Status; } gBS->CloseProtocol ( Controller, &gEfiUsbIoProtocolGuid, This->DriverBindingHandle, Controller ); // // Free all resources. // gBS->CloseEvent (UsbMouseDevice->SimplePointerProtocol.WaitForInput); if (UsbMouseDevice->DelayedRecoveryEvent != NULL) { gBS->CloseEvent (UsbMouseDevice->DelayedRecoveryEvent); UsbMouseDevice->DelayedRecoveryEvent = NULL; } if (UsbMouseDevice->ControllerNameTable != NULL) { FreeUnicodeStringTable (UsbMouseDevice->ControllerNameTable); } FreePool (UsbMouseDevice); return EFI_SUCCESS; }
/** Starts the mouse device with this driver. This function consumes USB I/O Portocol, intializes USB mouse device, installs Simple Pointer Protocol, and submits Asynchronous Interrupt Transfer to manage the USB mouse device. @param This The USB mouse driver binding instance. @param Controller Handle of device to bind driver to. @param RemainingDevicePath Optional parameter use to pick a specific child device to start. @retval EFI_SUCCESS This driver supports this device. @retval EFI_UNSUPPORTED This driver does not support this device. @retval EFI_DEVICE_ERROR This driver cannot be started due to device Error. @retval EFI_OUT_OF_RESOURCES Can't allocate memory resources. @retval EFI_ALREADY_STARTED This driver has been started. **/ EFI_STATUS EFIAPI USBMouseDriverBindingStart ( IN EFI_DRIVER_BINDING_PROTOCOL *This, IN EFI_HANDLE Controller, IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath ) { EFI_STATUS Status; EFI_USB_IO_PROTOCOL *UsbIo; USB_MOUSE_DEV *UsbMouseDevice; UINT8 EndpointNumber; EFI_USB_ENDPOINT_DESCRIPTOR EndpointDescriptor; UINT8 Index; UINT8 EndpointAddr; UINT8 PollingInterval; UINT8 PacketSize; BOOLEAN Found; EFI_TPL OldTpl; OldTpl = gBS->RaiseTPL (TPL_CALLBACK); // // Open USB I/O Protocol // Status = gBS->OpenProtocol ( Controller, &gEfiUsbIoProtocolGuid, (VOID **) &UsbIo, This->DriverBindingHandle, Controller, EFI_OPEN_PROTOCOL_BY_DRIVER ); if (EFI_ERROR (Status)) { goto ErrorExit1; } UsbMouseDevice = AllocateZeroPool (sizeof (USB_MOUSE_DEV)); ASSERT (UsbMouseDevice != NULL); UsbMouseDevice->UsbIo = UsbIo; UsbMouseDevice->Signature = USB_MOUSE_DEV_SIGNATURE; // // Get the Device Path Protocol on Controller's handle // Status = gBS->OpenProtocol ( Controller, &gEfiDevicePathProtocolGuid, (VOID **) &UsbMouseDevice->DevicePath, This->DriverBindingHandle, Controller, EFI_OPEN_PROTOCOL_GET_PROTOCOL ); if (EFI_ERROR (Status)) { goto ErrorExit; } // // Report Status Code here since USB mouse will be detected next. // REPORT_STATUS_CODE_WITH_DEVICE_PATH ( EFI_PROGRESS_CODE, (EFI_PERIPHERAL_MOUSE | EFI_P_PC_PRESENCE_DETECT), UsbMouseDevice->DevicePath ); // // Get interface & endpoint descriptor // UsbIo->UsbGetInterfaceDescriptor ( UsbIo, &UsbMouseDevice->InterfaceDescriptor ); EndpointNumber = UsbMouseDevice->InterfaceDescriptor.NumEndpoints; // // Traverse endpoints to find interrupt endpoint // Found = FALSE; for (Index = 0; Index < EndpointNumber; Index++) { UsbIo->UsbGetEndpointDescriptor ( UsbIo, Index, &EndpointDescriptor ); if ((EndpointDescriptor.Attributes & (BIT0 | BIT1)) == USB_ENDPOINT_INTERRUPT) { // // We only care interrupt endpoint here // CopyMem(&UsbMouseDevice->IntEndpointDescriptor, &EndpointDescriptor, sizeof(EndpointDescriptor)); Found = TRUE; break; } } if (!Found) { // // Report Status Code to indicate that there is no USB mouse // REPORT_STATUS_CODE ( EFI_ERROR_CODE | EFI_ERROR_MINOR, (EFI_PERIPHERAL_MOUSE | EFI_P_EC_NOT_DETECTED) ); // // No interrupt endpoint found, then return unsupported. // Status = EFI_UNSUPPORTED; goto ErrorExit; } // // Report Status Code here since USB mouse has be detected. // REPORT_STATUS_CODE_WITH_DEVICE_PATH ( EFI_PROGRESS_CODE, (EFI_PERIPHERAL_MOUSE | EFI_P_PC_DETECTED), UsbMouseDevice->DevicePath ); Status = InitializeUsbMouseDevice (UsbMouseDevice); if (EFI_ERROR (Status)) { // // Fail to initialize USB mouse device. // REPORT_STATUS_CODE_WITH_DEVICE_PATH ( EFI_ERROR_CODE | EFI_ERROR_MINOR, (EFI_PERIPHERAL_MOUSE | EFI_P_EC_INTERFACE_ERROR), UsbMouseDevice->DevicePath ); goto ErrorExit; } // // Initialize and install EFI Simple Pointer Protocol. // UsbMouseDevice->SimplePointerProtocol.GetState = GetMouseState; UsbMouseDevice->SimplePointerProtocol.Reset = UsbMouseReset; UsbMouseDevice->SimplePointerProtocol.Mode = &UsbMouseDevice->Mode; Status = gBS->CreateEvent ( EVT_NOTIFY_WAIT, TPL_NOTIFY, UsbMouseWaitForInput, UsbMouseDevice, &((UsbMouseDevice->SimplePointerProtocol).WaitForInput) ); if (EFI_ERROR (Status)) { goto ErrorExit; } Status = gBS->InstallProtocolInterface ( &Controller, &gEfiSimplePointerProtocolGuid, EFI_NATIVE_INTERFACE, &UsbMouseDevice->SimplePointerProtocol ); if (EFI_ERROR (Status)) { goto ErrorExit; } // // The next step would be submitting Asynchronous Interrupt Transfer on this mouse device. // After that we will be able to get key data from it. Thus this is deemed as // the enable action of the mouse, so report status code accordingly. // REPORT_STATUS_CODE_WITH_DEVICE_PATH ( EFI_PROGRESS_CODE, (EFI_PERIPHERAL_MOUSE | EFI_P_PC_ENABLE), UsbMouseDevice->DevicePath ); // // Submit Asynchronous Interrupt Transfer to manage this device. // EndpointAddr = UsbMouseDevice->IntEndpointDescriptor.EndpointAddress; PollingInterval = UsbMouseDevice->IntEndpointDescriptor.Interval; PacketSize = (UINT8) (UsbMouseDevice->IntEndpointDescriptor.MaxPacketSize); Status = UsbIo->UsbAsyncInterruptTransfer ( UsbIo, EndpointAddr, TRUE, PollingInterval, PacketSize, OnMouseInterruptComplete, UsbMouseDevice ); if (EFI_ERROR (Status)) { // // If submit error, uninstall that interface // gBS->UninstallProtocolInterface ( Controller, &gEfiSimplePointerProtocolGuid, &UsbMouseDevice->SimplePointerProtocol ); goto ErrorExit; } UsbMouseDevice->ControllerNameTable = NULL; AddUnicodeString2 ( "eng", gUsbMouseComponentName.SupportedLanguages, &UsbMouseDevice->ControllerNameTable, L"Generic Usb Mouse", TRUE ); AddUnicodeString2 ( "en", gUsbMouseComponentName2.SupportedLanguages, &UsbMouseDevice->ControllerNameTable, L"Generic Usb Mouse", FALSE ); gBS->RestoreTPL (OldTpl); return EFI_SUCCESS; // // Error handler // ErrorExit: if (EFI_ERROR (Status)) { gBS->CloseProtocol ( Controller, &gEfiUsbIoProtocolGuid, This->DriverBindingHandle, Controller ); if (UsbMouseDevice != NULL) { if ((UsbMouseDevice->SimplePointerProtocol).WaitForInput != NULL) { gBS->CloseEvent ((UsbMouseDevice->SimplePointerProtocol).WaitForInput); } FreePool (UsbMouseDevice); UsbMouseDevice = NULL; } } ErrorExit1: gBS->RestoreTPL (OldTpl); return Status; }