/** Get the usb endpoint descriptor. @param PeiServices General-purpose services that are available to every PEIM. @param This Indicates the PEI_USB_IO_PPI instance. @param EndpointIndex The valid index of the specified endpoint. @param EndpointDescriptor Request endpoint descriptor. @retval EFI_SUCCESS Usb endpoint descriptor is obtained successfully. @retval EFI_NOT_FOUND Usb endpoint descriptor is NOT found. **/ EFI_STATUS EFIAPI PeiUsbGetEndpointDescriptor ( IN EFI_PEI_SERVICES **PeiServices, IN PEI_USB_IO_PPI *This, IN UINT8 EndpointIndex, OUT EFI_USB_ENDPOINT_DESCRIPTOR **EndpointDescriptor ) { PEI_USB_DEVICE *PeiUsbDev; PeiUsbDev = PEI_USB_DEVICE_FROM_THIS (This); ASSERT (EndpointDescriptor != NULL); // // The valid range of EndpointIndex is 0..15 // If EndpointIndex is lesser than 15 but larger than the number of interfaces, // a EFI_NOT_FOUND should be returned // ASSERT (EndpointIndex <= 15); if (EndpointIndex >= PeiUsbDev->InterfaceDesc->NumEndpoints) { return EFI_NOT_FOUND; } *EndpointDescriptor = PeiUsbDev->EndpointDesc[EndpointIndex]; return EFI_SUCCESS; }
/** Get the usb interface descriptor. @param PeiServices General-purpose services that are available to every PEIM. @param This Indicates the PEI_USB_IO_PPI instance. @param InterfaceDescriptor Request interface descriptor. @retval EFI_SUCCESS Usb interface descriptor is obtained successfully. **/ EFI_STATUS EFIAPI PeiUsbGetInterfaceDescriptor ( IN EFI_PEI_SERVICES **PeiServices, IN PEI_USB_IO_PPI *This, OUT EFI_USB_INTERFACE_DESCRIPTOR **InterfaceDescriptor ) { PEI_USB_DEVICE *PeiUsbDev; PeiUsbDev = PEI_USB_DEVICE_FROM_THIS (This); *InterfaceDescriptor = PeiUsbDev->InterfaceDesc; return EFI_SUCCESS; }
/** Submits control transfer to a target USB device. @param PeiServices The pointer of EFI_PEI_SERVICES. @param This The pointer of PEI_USB_IO_PPI. @param Request USB device request to send. @param Direction Specifies the data direction for the data stage. @param Timeout Indicates the maximum timeout, in millisecond. @param Data Data buffer to be transmitted or received from USB device. @param DataLength The size (in bytes) of the data buffer. @retval EFI_SUCCESS Transfer was completed successfully. @retval EFI_OUT_OF_RESOURCES The transfer failed due to lack of resources. @retval EFI_INVALID_PARAMETER Some parameters are invalid. @retval EFI_TIMEOUT Transfer failed due to timeout. @retval EFI_DEVICE_ERROR Transfer failed due to host controller or device error. **/ EFI_STATUS EFIAPI PeiUsbControlTransfer ( IN EFI_PEI_SERVICES **PeiServices, IN PEI_USB_IO_PPI *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 ) { EFI_STATUS Status; PEI_USB_DEVICE *PeiUsbDev; UINT32 TransferResult; PeiUsbDev = PEI_USB_DEVICE_FROM_THIS (This); if (PeiUsbDev->Usb2HcPpi != NULL) { Status = PeiUsbDev->Usb2HcPpi->ControlTransfer ( PeiServices, PeiUsbDev->Usb2HcPpi, PeiUsbDev->DeviceAddress, PeiUsbDev->DeviceSpeed, PeiUsbDev->MaxPacketSize0, Request, Direction, Data, &DataLength, Timeout, &(PeiUsbDev->Translator), &TransferResult ); } else { Status = PeiUsbDev->UsbHcPpi->ControlTransfer ( PeiServices, PeiUsbDev->UsbHcPpi, PeiUsbDev->DeviceAddress, PeiUsbDev->DeviceSpeed, PeiUsbDev->MaxPacketSize0, Request, Direction, Data, &DataLength, Timeout, &TransferResult ); } return Status; }
/** Reset the port and re-configure the usb device. @param PeiServices General-purpose services that are available to every PEIM. @param This Indicates the PEI_USB_IO_PPI instance. @retval EFI_SUCCESS Usb device is reset and configured successfully. @retval Others Other failure occurs. **/ EFI_STATUS EFIAPI PeiUsbPortReset ( IN EFI_PEI_SERVICES **PeiServices, IN PEI_USB_IO_PPI *This ) { PEI_USB_DEVICE *PeiUsbDev; EFI_STATUS Status; UINT8 Address; PeiUsbDev = PEI_USB_DEVICE_FROM_THIS (This); ResetRootPort ( PeiServices, PeiUsbDev->UsbHcPpi, PeiUsbDev->Usb2HcPpi, PeiUsbDev->DeviceAddress, 0 ); // // Set address // Address = PeiUsbDev->DeviceAddress; PeiUsbDev->DeviceAddress = 0; Status = PeiUsbSetDeviceAddress ( PeiServices, This, Address ); if (EFI_ERROR (Status)) { return Status; } PeiUsbDev->DeviceAddress = Address; // // Set default configuration // Status = PeiUsbSetConfiguration ( PeiServices, This ); return Status; }
/** Clear Endpoint Halt. @param PeiServices General-purpose services that are available to every PEIM. @param UsbIoPpi Indicates the PEI_USB_IO_PPI instance. @param EndpointAddress The endpoint address. @retval EFI_SUCCESS Endpoint halt is cleared successfully. @retval EFI_DEVICE_ERROR Cannot clear the endpoint halt status due to a hardware error. @retval Others Other failure occurs. **/ EFI_STATUS PeiUsbClearEndpointHalt ( IN EFI_PEI_SERVICES **PeiServices, IN PEI_USB_IO_PPI *UsbIoPpi, IN UINT8 EndpointAddress ) { EFI_STATUS Status; PEI_USB_DEVICE *PeiUsbDev; EFI_USB_ENDPOINT_DESCRIPTOR *EndpointDescriptor; UINT8 EndpointIndex; EndpointIndex = 0; PeiUsbDev = PEI_USB_DEVICE_FROM_THIS (UsbIoPpi); while (EndpointIndex < MAX_ENDPOINT) { Status = UsbIoPpi->UsbGetEndpointDescriptor (PeiServices, UsbIoPpi, EndpointIndex, &EndpointDescriptor); if (EFI_ERROR (Status)) { return EFI_INVALID_PARAMETER; } if (EndpointDescriptor->EndpointAddress == EndpointAddress) { break; } EndpointIndex++; } if (EndpointIndex == MAX_ENDPOINT) { return EFI_INVALID_PARAMETER; } Status = PeiUsbClearDeviceFeature ( PeiServices, UsbIoPpi, EfiUsbEndpoint, EfiUsbEndpointHalt, EndpointAddress ); // // set data toggle to zero. // if ((PeiUsbDev->DataToggle & (1 << EndpointIndex)) != 0) { PeiUsbDev->DataToggle = (UINT8) (PeiUsbDev->DataToggle ^ (1 << EndpointIndex)); } return Status; }
/** Submits bulk transfer to a bulk endpoint of a USB device. @param PeiServices The pointer of EFI_PEI_SERVICES. @param This The pointer of PEI_USB_IO_PPI. @param DeviceEndpoint Endpoint number and its direction in bit 7. @param Data A pointer to the buffer of data to transmit from or receive into. @param DataLength The lenght of the data buffer. @param Timeout Indicates the maximum time, in millisecond, which the transfer is allowed to complete. @retval EFI_SUCCESS The transfer was completed successfully. @retval EFI_OUT_OF_RESOURCES The transfer failed due to lack of resource. @retval EFI_INVALID_PARAMETER Parameters are invalid. @retval EFI_TIMEOUT The transfer failed due to timeout. @retval EFI_DEVICE_ERROR The transfer failed due to host controller error. **/ EFI_STATUS EFIAPI PeiUsbBulkTransfer ( IN EFI_PEI_SERVICES **PeiServices, IN PEI_USB_IO_PPI *This, IN UINT8 DeviceEndpoint, IN OUT VOID *Data, IN OUT UINTN *DataLength, IN UINTN Timeout ) { EFI_STATUS Status; PEI_USB_DEVICE *PeiUsbDev; UINT32 TransferResult; UINTN MaxPacketLength; UINT8 DataToggle; UINT8 OldToggle; EFI_USB_ENDPOINT_DESCRIPTOR *EndpointDescriptor; UINT8 EndpointIndex; VOID *Data2[EFI_USB_MAX_BULK_BUFFER_NUM]; PeiUsbDev = PEI_USB_DEVICE_FROM_THIS (This); EndpointDescriptor = NULL; EndpointIndex = 0; Data2[0] = Data; Data2[1] = NULL; while (EndpointIndex < MAX_ENDPOINT) { Status = PeiUsbGetEndpointDescriptor (PeiServices, This, EndpointIndex, &EndpointDescriptor); if (EFI_ERROR (Status)) { return EFI_INVALID_PARAMETER; } if (EndpointDescriptor->EndpointAddress == DeviceEndpoint) { break; } EndpointIndex++; } if (EndpointIndex == MAX_ENDPOINT) { return EFI_INVALID_PARAMETER; } MaxPacketLength = PeiUsbDev->EndpointDesc[EndpointIndex]->MaxPacketSize; if ((PeiUsbDev->DataToggle & (1 << EndpointIndex)) != 0) { DataToggle = 1; } else { DataToggle = 0; } OldToggle = DataToggle; if (PeiUsbDev->Usb2HcPpi != NULL) { Status = PeiUsbDev->Usb2HcPpi->BulkTransfer ( PeiServices, PeiUsbDev->Usb2HcPpi, PeiUsbDev->DeviceAddress, DeviceEndpoint, PeiUsbDev->DeviceSpeed, MaxPacketLength, Data2, DataLength, &DataToggle, Timeout, &(PeiUsbDev->Translator), &TransferResult ); } else { Status = PeiUsbDev->UsbHcPpi->BulkTransfer ( PeiServices, PeiUsbDev->UsbHcPpi, PeiUsbDev->DeviceAddress, DeviceEndpoint, (UINT8) MaxPacketLength, Data, DataLength, &DataToggle, Timeout, &TransferResult ); } if (OldToggle != DataToggle) { PeiUsbDev->DataToggle = (UINT8) (PeiUsbDev->DataToggle ^ (1 << EndpointIndex)); } return Status; }
/** Submits control transfer to a target USB device. @param PeiServices The pointer of EFI_PEI_SERVICES. @param This The pointer of PEI_USB_IO_PPI. @param Request USB device request to send. @param Direction Specifies the data direction for the data stage. @param Timeout Indicates the maximum timeout, in millisecond. If Timeout is 0, then the caller must wait for the function to be completed until EFI_SUCCESS or EFI_DEVICE_ERROR is returned. @param Data Data buffer to be transmitted or received from USB device. @param DataLength The size (in bytes) of the data buffer. @retval EFI_SUCCESS Transfer was completed successfully. @retval EFI_OUT_OF_RESOURCES The transfer failed due to lack of resources. @retval EFI_INVALID_PARAMETER Some parameters are invalid. @retval EFI_TIMEOUT Transfer failed due to timeout. @retval EFI_DEVICE_ERROR Transfer failed due to host controller or device error. **/ EFI_STATUS EFIAPI PeiUsbControlTransfer ( IN EFI_PEI_SERVICES **PeiServices, IN PEI_USB_IO_PPI *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 ) { EFI_STATUS Status; PEI_USB_DEVICE *PeiUsbDev; UINT32 TransferResult; EFI_USB_ENDPOINT_DESCRIPTOR *EndpointDescriptor; UINT8 EndpointIndex; PeiUsbDev = PEI_USB_DEVICE_FROM_THIS (This); EndpointDescriptor = NULL; EndpointIndex = 0; if ((Request->Request == USB_REQ_CLEAR_FEATURE) && (Request->RequestType == USB_DEV_CLEAR_FEATURE_REQ_TYPE_E) && (Request->Value == USB_FEATURE_ENDPOINT_HALT)) { // // Request->Index is the Endpoint Address, use it to get the Endpoint Index. // while (EndpointIndex < MAX_ENDPOINT) { Status = PeiUsbGetEndpointDescriptor (PeiServices, This, EndpointIndex, &EndpointDescriptor); if (EFI_ERROR (Status)) { return EFI_INVALID_PARAMETER; } if (EndpointDescriptor->EndpointAddress == Request->Index) { break; } EndpointIndex++; } if (EndpointIndex == MAX_ENDPOINT) { return EFI_INVALID_PARAMETER; } } if (PeiUsbDev->Usb2HcPpi != NULL) { Status = PeiUsbDev->Usb2HcPpi->ControlTransfer ( PeiServices, PeiUsbDev->Usb2HcPpi, PeiUsbDev->DeviceAddress, PeiUsbDev->DeviceSpeed, PeiUsbDev->MaxPacketSize0, Request, Direction, Data, &DataLength, Timeout, &(PeiUsbDev->Translator), &TransferResult ); } else { Status = PeiUsbDev->UsbHcPpi->ControlTransfer ( PeiServices, PeiUsbDev->UsbHcPpi, PeiUsbDev->DeviceAddress, PeiUsbDev->DeviceSpeed, (UINT8) PeiUsbDev->MaxPacketSize0, Request, Direction, Data, &DataLength, Timeout, &TransferResult ); } // // Reset the endpoint toggle when endpoint stall is cleared // if ((Request->Request == USB_REQ_CLEAR_FEATURE) && (Request->RequestType == USB_DEV_CLEAR_FEATURE_REQ_TYPE_E) && (Request->Value == USB_FEATURE_ENDPOINT_HALT)) { if ((PeiUsbDev->DataToggle & (1 << EndpointIndex)) != 0) { PeiUsbDev->DataToggle = (UINT16) (PeiUsbDev->DataToggle ^ (1 << EndpointIndex)); } } DEBUG ((EFI_D_INFO, "PeiUsbControlTransfer: %r\n", Status)); return Status; }