/** Remove the device and all its children from the bus. @param Device The device to remove. @retval EFI_SUCCESS The device is removed. **/ EFI_STATUS UsbRemoveDevice ( IN USB_DEVICE *Device ) { USB_BUS *Bus; USB_DEVICE *Child; EFI_STATUS Status; EFI_STATUS ReturnStatus; UINTN Index; Bus = Device->Bus; // // Remove all the devices on its downstream ports. Search from devices[1]. // Devices[0] is the root hub. // ReturnStatus = EFI_SUCCESS; for (Index = 1; Index < Bus->MaxDevices; Index++) { Child = Bus->Devices[Index]; if ((Child == NULL) || (Child->ParentAddr != Device->Address)) { continue; } DBG("Remove child %d\n", Index); Status = UsbRemoveDevice (Child); if (!EFI_ERROR (Status)) { Bus->Devices[Index] = NULL; } else { Bus->Devices[Index]->DisconnectFail = TRUE; ReturnStatus = Status; // DEBUG ((EFI_D_INFO, "UsbRemoveDevice: failed to remove child %p at parent %p\n", Child, Device)); DBG("UsbRemoveDevice: failed to remove child %p at parent %p\n", Child, Device); } } if (EFI_ERROR (ReturnStatus)) { return ReturnStatus; } Status = UsbRemoveConfig (Device); if (!EFI_ERROR (Status)) { // DEBUG (( EFI_D_INFO, "UsbRemoveDevice: device %d removed\n", Device->Address)); DBG("UsbRemoveDevice: device %d removed\n", Device->Address); // ASSERT (Device->Address < Bus->MaxDevices); if (Device->Address >= Bus->MaxDevices) { DBG("Device->Address=%d > %d\n", Device->Address, Bus->MaxDevices); return EFI_DEVICE_ERROR; } Bus->Devices[Device->Address] = NULL; UsbFreeDevice (Device); } else { Bus->Devices[Device->Address]->DisconnectFail = TRUE; } return Status; }
EFI_STATUS UsbRemoveDevice ( IN USB_DEVICE *Device ) /*++ Routine Description: Remove the device and all its children from the bus. Arguments: Device - The device to remove Returns: EFI_SUCCESS - The device is removed --*/ { USB_BUS *Bus; USB_DEVICE *Child; EFI_STATUS Status; UINT8 Index; Bus = Device->Bus; // // Remove all the devices on its downstream ports. Search from devices[1]. // Devices[0] is the root hub. // for (Index = 1; Index < USB_MAX_DEVICES; Index++) { Child = Bus->Devices[Index]; if ((Child == NULL) || (Child->ParentAddr != Device->Address)) { continue; } Status = UsbRemoveDevice (Child); if (EFI_ERROR (Status)) { USB_ERROR (("UsbRemoveDevice: failed to remove child, ignore error\n")); Bus->Devices[Index] = NULL; } } UsbRemoveConfig (Device); USB_DEBUG (("UsbRemoveDevice: device %d removed\n", Device->Address)); Bus->Devices[Device->Address] = NULL; UsbFreeDevice (Device); return EFI_SUCCESS; }
/** Remove the device and all its children from the bus. @param Device The device to remove. @retval EFI_SUCCESS The device is removed. **/ EFI_STATUS UsbRemoveDevice ( IN USB_DEVICE *Device ) { USB_BUS *Bus; USB_DEVICE *Child; EFI_STATUS Status; UINTN Index; Bus = Device->Bus; // // Remove all the devices on its downstream ports. Search from devices[1]. // Devices[0] is the root hub. // for (Index = 1; Index < Bus->MaxDevices; Index++) { Child = Bus->Devices[Index]; if ((Child == NULL) || (Child->ParentAddr != Device->Address)) { continue; } Status = UsbRemoveDevice (Child); if (EFI_ERROR (Status)) { DEBUG ((EFI_D_ERROR, "UsbRemoveDevice: failed to remove child, ignore error\n")); Bus->Devices[Index] = NULL; } } UsbRemoveConfig (Device); DEBUG (( EFI_D_INFO, "UsbRemoveDevice: device %d removed\n", Device->Address)); ASSERT (Device->Address < Bus->MaxDevices); Bus->Devices[Device->Address] = NULL; UsbFreeDevice (Device); return EFI_SUCCESS; }
/** USB_IO function to execute a control transfer. This function will execute the USB transfer. If transfer successes, it will sync the internal state of USB bus with device state. @param This The USB_IO instance @param Request The control transfer request @param Direction Direction for data stage @param Timeout The time to wait before timeout @param Data The buffer holding the data @param DataLength Then length of the data @param UsbStatus USB result @retval EFI_INVALID_PARAMETER The parameters are invalid @retval EFI_SUCCESS The control transfer succeeded. @retval Others Failed to execute the transfer **/ EFI_STATUS EFIAPI UsbIoControlTransfer ( IN EFI_USB_IO_PROTOCOL *This, IN EFI_USB_DEVICE_REQUEST *Request, IN EFI_USB_DATA_DIRECTION Direction, IN UINT32 Timeout, IN OUT VOID *Data, OPTIONAL IN UINTN DataLength, OPTIONAL OUT UINT32 *UsbStatus ) { USB_DEVICE *Dev; USB_INTERFACE *UsbIf; USB_ENDPOINT_DESC *EpDesc; EFI_TPL OldTpl; EFI_STATUS Status; if (UsbStatus == NULL) { return EFI_INVALID_PARAMETER; } OldTpl = gBS->RaiseTPL (USB_BUS_TPL); UsbIf = USB_INTERFACE_FROM_USBIO (This); Dev = UsbIf->Device; Status = UsbHcControlTransfer ( Dev->Bus, Dev->Address, Dev->Speed, Dev->MaxPacket0, Request, Direction, Data, &DataLength, (UINTN) Timeout, &Dev->Translator, UsbStatus ); if (EFI_ERROR (Status) || (*UsbStatus != EFI_USB_NOERROR)) { // // Clear TT buffer when CTRL/BULK split transaction failes // Clear the TRANSLATOR TT buffer, not parent's buffer // ASSERT (Dev->Translator.TranslatorHubAddress < Dev->Bus->MaxDevices); if (Dev->Translator.TranslatorHubAddress != 0) { UsbHubCtrlClearTTBuffer ( Dev->Bus->Devices[Dev->Translator.TranslatorHubAddress], Dev->Translator.TranslatorPortNumber, Dev->Address, 0, USB_ENDPOINT_CONTROL ); } goto ON_EXIT; } // // Some control transfer will change the device's internal // status, such as Set_Configuration and Set_Interface. // We must synchronize the bus driver's status with that in // device. We ignore the Set_Descriptor request because it's // hardly used by any device, especially in pre-boot environment // // // Reset the endpoint toggle when endpoint stall is cleared // if ((Request->Request == USB_REQ_CLEAR_FEATURE) && (Request->RequestType == USB_REQUEST_TYPE (EfiUsbNoData, USB_REQ_TYPE_STANDARD, USB_TARGET_ENDPOINT)) && (Request->Value == USB_FEATURE_ENDPOINT_HALT)) { EpDesc = UsbGetEndpointDesc (UsbIf, (UINT8) Request->Index); if (EpDesc != NULL) { EpDesc->Toggle = 0; } } // // Select a new configuration. This is a dangerous action. Upper driver // should stop use its current UsbIo after calling this driver. The old // UsbIo will be uninstalled and new UsbIo be installed. We can't use // ReinstallProtocol since interfaces in different configuration may be // completely irrelevant. // if ((Request->Request == USB_REQ_SET_CONFIG) && (Request->RequestType == USB_REQUEST_TYPE (EfiUsbNoData, USB_REQ_TYPE_STANDARD, USB_TARGET_DEVICE))) { // // Don't re-create the USB interfaces if configuration isn't changed. // if ((Dev->ActiveConfig != NULL) && (Request->Value == Dev->ActiveConfig->Desc.ConfigurationValue)) { goto ON_EXIT; } DEBUG ((EFI_D_INFO, "UsbIoControlTransfer: configure changed!!! Do NOT use old UsbIo!!!\n")); if (Dev->ActiveConfig != NULL) { UsbRemoveConfig (Dev); } if (Request->Value != 0) { Status = UsbSelectConfig (Dev, (UINT8) Request->Value); } // // Exit now, Old USB_IO is invalid now // goto ON_EXIT; } // // A new alternative setting is selected for the interface. // No need to reinstall UsbIo in this case because only // underlying communication endpoints are changed. Functionality // should remains the same. // if ((Request->Request == USB_REQ_SET_INTERFACE) && (Request->RequestType == USB_REQUEST_TYPE (EfiUsbNoData, USB_REQ_TYPE_STANDARD, USB_TARGET_INTERFACE)) && (Request->Index == UsbIf->IfSetting->Desc.InterfaceNumber)) { Status = UsbSelectSetting (UsbIf->IfDesc, (UINT8) Request->Value); if (!EFI_ERROR (Status)) { ASSERT (UsbIf->IfDesc->ActiveIndex < USB_MAX_INTERFACE_SETTING); UsbIf->IfSetting = UsbIf->IfDesc->Settings[UsbIf->IfDesc->ActiveIndex]; } } ON_EXIT: gBS->RestoreTPL (OldTpl); return Status; }