/** Execute a synchronous interrupt transfer. @param This The USB IO instance. @param Endpoint The device endpoint. @param Data The data to transfer. @param DataLength The length of the data to transfer. @param Timeout Time to wait before timeout. @param UsbStatus The result of USB transfer. @retval EFI_SUCCESS The synchronous interrupt transfer is OK. @retval EFI_INVALID_PARAMETER Some parameters are invalid. @retval Others Failed to execute transfer, reason returned in UsbStatus. **/ EFI_STATUS EFIAPI UsbIoSyncInterruptTransfer ( IN EFI_USB_IO_PROTOCOL *This, IN UINT8 Endpoint, IN OUT VOID *Data, IN OUT UINTN *DataLength, IN UINTN Timeout, OUT UINT32 *UsbStatus ) { USB_DEVICE *Dev; USB_INTERFACE *UsbIf; USB_ENDPOINT_DESC *EpDesc; EFI_TPL OldTpl; UINT8 Toggle; EFI_STATUS Status; if ((USB_ENDPOINT_ADDR (Endpoint) == 0) || (USB_ENDPOINT_ADDR(Endpoint) > 15) || (UsbStatus == NULL)) { return EFI_INVALID_PARAMETER; } OldTpl = gBS->RaiseTPL (USB_BUS_TPL); UsbIf = USB_INTERFACE_FROM_USBIO (This); Dev = UsbIf->Device; EpDesc = UsbGetEndpointDesc (UsbIf, Endpoint); if ((EpDesc == NULL) || (USB_ENDPOINT_TYPE (&EpDesc->Desc) != USB_ENDPOINT_INTERRUPT)) { Status = EFI_INVALID_PARAMETER; goto ON_EXIT; } Toggle = EpDesc->Toggle; Status = UsbHcSyncInterruptTransfer ( Dev->Bus, Dev->Address, Endpoint, Dev->Speed, EpDesc->Desc.MaxPacketSize, Data, DataLength, &Toggle, Timeout, &Dev->Translator, UsbStatus ); EpDesc->Toggle = Toggle; ON_EXIT: gBS->RestoreTPL (OldTpl); return Status; }
/** Execute a bulk transfer to the device endpoint. @param This The USB IO instance. @param Endpoint The device endpoint. @param Data The data to transfer. @param DataLength The length of the data to transfer. @param Timeout Time to wait before timeout. @param UsbStatus The result of USB transfer. @retval EFI_SUCCESS The bulk transfer is OK. @retval EFI_INVALID_PARAMETER Some parameters are invalid. @retval Others Failed to execute transfer, reason returned in UsbStatus. **/ EFI_STATUS EFIAPI UsbIoBulkTransfer ( IN EFI_USB_IO_PROTOCOL *This, IN UINT8 Endpoint, IN OUT VOID *Data, IN OUT UINTN *DataLength, IN UINTN Timeout, OUT UINT32 *UsbStatus ) { USB_DEVICE *Dev; USB_INTERFACE *UsbIf; USB_ENDPOINT_DESC *EpDesc; UINT8 BufNum; UINT8 Toggle; EFI_TPL OldTpl; EFI_STATUS Status; if ((USB_ENDPOINT_ADDR (Endpoint) == 0) || (USB_ENDPOINT_ADDR(Endpoint) > 15) || (UsbStatus == NULL)) { return EFI_INVALID_PARAMETER; } OldTpl = gBS->RaiseTPL (USB_BUS_TPL); UsbIf = USB_INTERFACE_FROM_USBIO (This); Dev = UsbIf->Device; EpDesc = UsbGetEndpointDesc (UsbIf, Endpoint); if ((EpDesc == NULL) || (USB_ENDPOINT_TYPE (&EpDesc->Desc) != USB_ENDPOINT_BULK)) { Status = EFI_INVALID_PARAMETER; goto ON_EXIT; } BufNum = 1; Toggle = EpDesc->Toggle; Status = UsbHcBulkTransfer ( Dev->Bus, Dev->Address, Endpoint, Dev->Speed, EpDesc->Desc.MaxPacketSize, BufNum, &Data, DataLength, &Toggle, Timeout, &Dev->Translator, UsbStatus ); EpDesc->Toggle = Toggle; 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_BULK ); } } ON_EXIT: 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; }