You've already forked slimbootloader
mirror of
https://github.com/Dasharo/slimbootloader.git
synced 2026-03-06 15:26:20 -08:00
Convert the line endings stored for all text files in the repository to LF. The majority previously used DOS-style CRLF line endings. Add a .gitattributes file to enforce this and treat certain extensions as never being text files. Update PatchCheck.py to insist on LF line endings rather than CRLF. However, its other checks fail on this commit due to lots of pre-existing complaints that it only notices because the line endings have changed. Silicon/QemuSocPkg/FspBin/Patches/0001-Build-QEMU-FSP-2.0-binaries.patch needs to be treated as binary since it contains a mixture of line endings. This change has implications depending on the client platform you are using the repository from: * Windows The usual configuration for Git on Windows means that text files will be checked out to the work tree with DOS-style CRLF line endings. If that's not the case then you can configure Git to do so for the entire machine with: git config --global core.autocrlf true or for just the repository with: git config core.autocrlf true Line endings will be normalised to LF when they are committed to the repository. If you commit a text file with only LF line endings then it will be converted to CRLF line endings in your work tree. * Linux, MacOS and other Unices The usual configuration for Git on such platforms is to check files out of the repository with LF line endings. This is probably the right thing for you. In the unlikely even that you are using Git on Unix but editing or compiling on Windows for some reason then you may need to tweak your configuration to force the use of CRLF line endings as described above. * General For more information see https://docs.github.com/en/get-started/getting-started-with-git/configuring-git-to-handle-line-endings . Fixes: https://github.com/slimbootloader/slimbootloader/issues/1400 Signed-off-by: Mike Crowe <mac@mcrowe.com>
1610 lines
41 KiB
C
1610 lines
41 KiB
C
/** @file
|
|
Copyright (c) 2006 - 2017, Intel Corporation. All rights reserved.<BR>
|
|
|
|
SPDX-License-Identifier: BSD-2-Clause-Patent
|
|
|
|
**/
|
|
|
|
#include <Base.h>
|
|
#include <Library/BaseLib.h>
|
|
#include <Library/IoLib.h>
|
|
#include "XdciUtility.h"
|
|
#include "UsbDeviceMode.h"
|
|
#include "UsbDeviceDxe.h"
|
|
|
|
//
|
|
// Global USBD driver object. This is the main private driver object
|
|
// that contains all data needed for this driver to operate.
|
|
//
|
|
USB_DEVICE_DRIVER_OBJ mDrvObj;
|
|
|
|
//
|
|
// Global data IO transaction request object
|
|
//
|
|
USB_DEVICE_IO_REQ
|
|
mCtrlIoReq = {
|
|
//
|
|
// IO information containing the Buffer and data size
|
|
//
|
|
{
|
|
NULL,
|
|
0,
|
|
},
|
|
//
|
|
// Note: This object is used for Control Ep transfers only
|
|
// therefore the endpoint info must always be NULL
|
|
//
|
|
{
|
|
NULL,
|
|
NULL,
|
|
}
|
|
};
|
|
|
|
//
|
|
// global flag to signal device event processing loop to run/stop
|
|
//
|
|
BOOLEAN mXdciRun = FALSE;
|
|
|
|
STATIC
|
|
VOID
|
|
XhciSwitchSwid (
|
|
BOOLEAN enable
|
|
)
|
|
{
|
|
UINTN XhciPciMmBase;
|
|
EFI_PHYSICAL_ADDRESS XhciMemBaseAddress;
|
|
UINT32 DualRoleCfg0;
|
|
UINT32 DualRoleCfg1;
|
|
|
|
XhciPciMmBase = MmPciAddress (0, 0, mUsbDeviceInfo.XhciDeviceAddress.Device, mUsbDeviceInfo.XhciDeviceAddress.Func, 0);
|
|
XhciMemBaseAddress = MmioRead32 ((UINTN) (XhciPciMmBase + R_XHCI_MEM_BASE)) & B_XHCI_MEM_BASE_BA;
|
|
DEBUG ((DEBUG_INFO, "XhciPciMmBase=%x, XhciMemBaseAddress=%x\n", XhciPciMmBase, XhciMemBaseAddress));
|
|
|
|
DualRoleCfg0 = MmioRead32 ((UINTN) (XhciMemBaseAddress + R_XHCI_MEM_DUAL_ROLE_CFG0));
|
|
if (enable) {
|
|
DualRoleCfg0 = DualRoleCfg0 | (1 << 24) | (1 << 21) | (1 << 20);
|
|
DEBUG ((DEBUG_INFO, "DualRoleCfg0 : Set SW ID : 0x%x \n", DualRoleCfg0));
|
|
} else {
|
|
DualRoleCfg0 = DualRoleCfg0 & ~ (1 << 24) & ~ (1 << 21) & ~ (1 << 20);
|
|
DEBUG ((DEBUG_INFO, "DualRoleCfg0 : Clear SW ID : 0x%x \n", DualRoleCfg0));
|
|
}
|
|
MmioWrite32 ((UINTN) (XhciMemBaseAddress + R_XHCI_MEM_DUAL_ROLE_CFG0), DualRoleCfg0);
|
|
|
|
DualRoleCfg1 = MmioRead32 ((UINTN) (XhciMemBaseAddress + R_XHCI_MEM_DUAL_ROLE_CFG1));
|
|
DEBUG ((DEBUG_INFO, "DualRoleCfg1 : 0x%x \n", DualRoleCfg1));
|
|
}
|
|
|
|
VOID
|
|
EFIAPI
|
|
UsbdMonitorEvents (
|
|
IN EFI_EVENT Event,
|
|
IN VOID *Context
|
|
)
|
|
{
|
|
USB_XDCI_DEV_CONTEXT *XdciDevContext;
|
|
UINT32 EventCount;
|
|
UINT32 PreEventCount;
|
|
UINT32 LoopCount;
|
|
|
|
XdciDevContext = (USB_XDCI_DEV_CONTEXT *) Context;
|
|
EventCount = UsbRegRead ((UINT32)XdciDevContext->XdciMmioBarAddr, DWC_XDCI_EVNTCOUNT_REG (0));
|
|
if (EventCount == 0) {
|
|
return;
|
|
}
|
|
|
|
LoopCount = 0;
|
|
PreEventCount = EventCount;
|
|
while (EventCount != 0) {
|
|
if (UsbDeviceIsrRoutineTimerBased (mDrvObj.XdciDrvObj) != EFI_SUCCESS) {
|
|
DEBUG ((DEBUG_INFO, "UsbDeviceRun() - Failed to execute event ISR\n"));
|
|
}
|
|
EventCount = UsbRegRead ((UINT32)XdciDevContext->XdciMmioBarAddr, DWC_XDCI_EVNTCOUNT_REG (0));
|
|
if (PreEventCount == EventCount) {
|
|
LoopCount++;
|
|
if (LoopCount >= 5) {
|
|
DEBUG ((DEBUG_INFO, "USB is working on a long event...\n"));
|
|
break;
|
|
}
|
|
} else {
|
|
LoopCount = 0;
|
|
}
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
/**
|
|
Initializes the XDCI core.
|
|
|
|
@param MmioBar Address of MMIO BAR
|
|
@param XdciHndl Double pointer to for XDCI layer to set as an
|
|
opaque handle to the driver to be used in subsequent
|
|
interactions with the XDCI layer.
|
|
|
|
@return EFI_SUCCESS if successfully initialized XDCI, EFI_DEVICE_ERROR otherwise
|
|
|
|
**/
|
|
EFI_STATUS
|
|
UsbdInit (
|
|
IN UINT32 MmioBar,
|
|
IN VOID **XdciHndl
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
USB_DEV_CONFIG_PARAMS ConfigParams;
|
|
|
|
Status = EFI_DEVICE_ERROR;
|
|
|
|
XhciSwitchSwid (TRUE);
|
|
|
|
DEBUG ((DEBUG_INFO, "UsbdInit start\n"));
|
|
ConfigParams.ControllerId = USB_ID_DWC_XDCI;
|
|
ConfigParams.BaseAddress = MmioBar;
|
|
ConfigParams.Role = USB_ROLE_DEVICE;
|
|
ConfigParams.Speed = USB_SPEED_SUPER;
|
|
|
|
Status = UsbDeviceInit (&ConfigParams, XdciHndl);
|
|
|
|
DEBUG ((DEBUG_INFO, "UsbdInit status is %x\n", Status));
|
|
DEBUG ((DEBUG_INFO, "ConfigParams.BaseAddress 0x%x\n", ConfigParams.BaseAddress));
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
/**
|
|
Copies relevant endpoint data from standard USB endpoint descriptors
|
|
to the usbEpInfo structure used by the XDCI.
|
|
|
|
@param EpDest destination structure
|
|
@param EpSrc source structure
|
|
|
|
@return VOID
|
|
|
|
**/
|
|
VOID
|
|
UsbdSetEpInfo (
|
|
IN USB_EP_INFO *EpDest,
|
|
IN USB_DEVICE_ENDPOINT_INFO *EpSrc
|
|
)
|
|
{
|
|
EFI_USB_ENDPOINT_DESCRIPTOR *EpDesc;
|
|
EFI_USB_ENDPOINT_COMPANION_DESCRIPTOR *EpCompDesc;
|
|
|
|
EpDesc = NULL;
|
|
EpCompDesc = NULL;
|
|
|
|
//
|
|
// start by clearing all data in the destination
|
|
//
|
|
SetMem (EpDest, sizeof (USB_EP_INFO), 0);
|
|
EpDesc = EpSrc->EndpointDesc;
|
|
EpCompDesc = EpSrc->EndpointCompDesc;
|
|
|
|
if (EpDesc != NULL) {
|
|
EpDest->EpNum = EpDesc->EndpointAddress & 0x0F; //Bits 0-3 are ep num
|
|
EpDest->EpDir = ((EpDesc->EndpointAddress & USB_ENDPOINT_DIR_IN) > 0) ? UsbEpDirIn : UsbEpDirOut;
|
|
EpDest->EpType = EpDesc->Attributes & USB_ENDPOINT_TYPE_MASK;
|
|
EpDest->MaxPktSize = EpDesc->MaxPacketSize;
|
|
EpDest->Interval = EpDesc->Interval;
|
|
}
|
|
if (EpCompDesc != NULL) {
|
|
EpDest->MaxStreams = EpCompDesc->Attributes & USB_EP_BULK_BM_ATTR_MASK;
|
|
EpDest->BurstSize = EpCompDesc->MaxBurst;
|
|
EpDest->Mult = EpCompDesc->BytesPerInterval;
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
/**
|
|
Initializes the given endpoint.
|
|
|
|
@param XdciHndl Pointer (handle) to the XDCI driver object
|
|
@param DevEpInfo Pointer to endpoint info structure
|
|
for the endpoint to initialize
|
|
|
|
@return EFI_SUCCESS if operation succeeded, EFI_DEVICE_ERROR otherwise
|
|
|
|
**/
|
|
EFI_STATUS
|
|
UsbdInitEp (
|
|
IN VOID *XdciHndl,
|
|
IN USB_DEVICE_ENDPOINT_INFO *DevEpInfo
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
USB_EP_INFO EpInfo;
|
|
|
|
Status = EFI_DEVICE_ERROR;
|
|
|
|
UsbdSetEpInfo (&EpInfo, DevEpInfo);
|
|
Status = UsbDeviceInitEp (XdciHndl, &EpInfo);
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
/**
|
|
Callback handler used when transfer operations complete. Calls
|
|
upper layer routine to handle the operation.
|
|
|
|
@param XdciHndl Pointer (handle) to the XDCI driver object
|
|
@param XferReq Pointer to the transfer request structure
|
|
|
|
@return VOID
|
|
|
|
**/
|
|
VOID
|
|
EFIAPI
|
|
UsbdXferDoneHndlr (
|
|
IN VOID *XdciHndl,
|
|
IN USB_XFER_REQUEST *XferReq
|
|
)
|
|
{
|
|
EFI_USB_DEVICE_XFER_INFO XferInfo;
|
|
|
|
DEBUG ((DEBUG_INFO, "UsbdXferDoneHndlr\n"));
|
|
|
|
XferInfo.EndpointNum = (UINT8)XferReq->EpInfo.EpNum;
|
|
XferInfo.EndpointDir = XferReq->EpInfo.EpDir;
|
|
XferInfo.EndpointType = XferReq->EpInfo.EpType;
|
|
XferInfo.Buffer = XferReq->XferBuffer;
|
|
XferInfo.Length = XferReq->ActualXferLen;
|
|
|
|
//
|
|
// If this is a non-control transfer complete, notify the class driver
|
|
//
|
|
if (XferInfo.EndpointNum > 0) {
|
|
if (mDrvObj.UsbdDevObj->DataCallback != NULL) {
|
|
mDrvObj.UsbdDevObj->DataCallback (&XferInfo);
|
|
}
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
/**
|
|
Queue a request to transmit data.
|
|
|
|
@param XdciHndl Pointer (handle) to the XDCI driver object
|
|
@param IoReq Pointer to IO structure containing details of the
|
|
transfer request
|
|
|
|
@return EFI_SUCCESS if operation succeeded, EFI_DEVICE_ERROR otherwise
|
|
|
|
**/
|
|
EFI_STATUS
|
|
UsbdEpTxData (
|
|
IN VOID *XdciHndl,
|
|
IN USB_DEVICE_IO_REQ *IoReq
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
USB_XFER_REQUEST TxReq;
|
|
|
|
Status = EFI_DEVICE_ERROR;
|
|
|
|
//
|
|
//set endpoint data
|
|
//
|
|
UsbdSetEpInfo (& (TxReq.EpInfo), & (IoReq->EndpointInfo)); // set endpoint data
|
|
|
|
//
|
|
//if this is a control endpoint, set the number and direction
|
|
//
|
|
if (IoReq->EndpointInfo.EndpointDesc == NULL) {
|
|
TxReq.EpInfo.EpNum = 0;
|
|
TxReq.EpInfo.EpDir = UsbEpDirIn;
|
|
}
|
|
|
|
//
|
|
// setup the trasfer request
|
|
//
|
|
TxReq.XferBuffer = IoReq->IoInfo.Buffer;
|
|
TxReq.XferLen = IoReq->IoInfo.Length;
|
|
TxReq.XferDone = UsbdXferDoneHndlr;
|
|
|
|
DEBUG ((DEBUG_INFO, "TX REQUEST: EpNum: 0x%x, epDir: 0x%x, epType: 0x%x, MaxPktSize: 0x%x\n", \
|
|
TxReq.EpInfo.EpNum, TxReq.EpInfo.EpDir, TxReq.EpInfo.EpType, TxReq.EpInfo.MaxPktSize));
|
|
|
|
Status = UsbXdciDeviceEpTxData (XdciHndl, &TxReq);
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
/**
|
|
Queue a request to receive data.
|
|
|
|
@param XdciHndl Pointer (handle) to the XDCI driver object
|
|
@param IoReq Pointer to IO structure containing details of the
|
|
receive request
|
|
|
|
@return EFI_SUCCESS if operation succeeded, EFI_DEVICE_ERROR otherwise
|
|
|
|
**/
|
|
EFI_STATUS
|
|
UsbdEpRxData (
|
|
IN VOID *XdciHndl,
|
|
IN USB_DEVICE_IO_REQ *IoReq
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
USB_XFER_REQUEST RxReq;
|
|
UINT32 ReqPacket;
|
|
|
|
Status = EFI_DEVICE_ERROR;
|
|
|
|
DEBUG ((DEBUG_INFO, "RX REQUEST in: IoReq->IoInfo.Length: 0x%x\n", IoReq->IoInfo.Length));
|
|
DEBUG ((DEBUG_INFO, "RX REQUEST in: MaxPacketSize: 0x%x\n", IoReq->EndpointInfo.EndpointDesc->MaxPacketSize));
|
|
|
|
if (IoReq->EndpointInfo.EndpointDesc->MaxPacketSize == 0) {
|
|
return EFI_DEVICE_ERROR;
|
|
}
|
|
|
|
//
|
|
// set endpoint data
|
|
//
|
|
UsbdSetEpInfo (& (RxReq.EpInfo), & (IoReq->EndpointInfo));
|
|
|
|
//
|
|
// setup the trasfer request
|
|
//
|
|
RxReq.XferBuffer = IoReq->IoInfo.Buffer;
|
|
|
|
//
|
|
// Transfer length should be multiple of USB packet size.
|
|
//
|
|
ReqPacket = IoReq->IoInfo.Length / IoReq->EndpointInfo.EndpointDesc->MaxPacketSize;
|
|
ReqPacket = ((IoReq->IoInfo.Length % IoReq->EndpointInfo.EndpointDesc->MaxPacketSize) == 0) ? ReqPacket : ReqPacket + 1;
|
|
RxReq.XferLen = ReqPacket * IoReq->EndpointInfo.EndpointDesc->MaxPacketSize;
|
|
|
|
RxReq.XferDone = UsbdXferDoneHndlr;
|
|
|
|
DEBUG ((DEBUG_INFO, "RX REQUEST: EpNum: 0x%x, epDir: 0x%x, epType: 0x%x\n", \
|
|
RxReq.EpInfo.EpNum, RxReq.EpInfo.EpDir, RxReq.EpInfo.EpType));
|
|
DEBUG ((DEBUG_INFO, "RX REQUEST send: XferLen: 0x%x\n", RxReq.XferLen));
|
|
|
|
Status = UsbXdciDeviceEpRxData (XdciHndl, &RxReq);
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
/**
|
|
Callback used to handle Reset events from the XDCI.
|
|
|
|
@param Param Pointer to a generic callback parameter structure
|
|
|
|
@return XDCI usb status
|
|
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
UsbdResetEvtHndlr (
|
|
IN USB_DEVICE_CALLBACK_PARAM *Param
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
|
|
Status = EFI_DEVICE_ERROR;
|
|
|
|
DEBUG ((DEBUG_INFO, "UsbdResetEvtHndlr\n"));
|
|
|
|
//
|
|
// reset device address to 0
|
|
//
|
|
Status = UsbDeviceSetAddress (mDrvObj.XdciDrvObj, 0x0);
|
|
if (EFI_ERROR (Status)) {
|
|
DEBUG ((DEBUG_INFO, "UsbdResetHdlr() - Failed to set address in XDCI\n"));
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
/**
|
|
Callback used to handle Connection done events from the XDCI.
|
|
|
|
@param Param Pointer to a generic callback parameter structure
|
|
|
|
@return XDCI usb status
|
|
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
UsbdConnDoneEvtHndlr (
|
|
IN USB_DEVICE_CALLBACK_PARAM *Param
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
|
|
Status = EFI_DEVICE_ERROR;
|
|
|
|
DEBUG ((DEBUG_INFO, "UsbdConnDoneEvtHndlr\n"));
|
|
|
|
//
|
|
//reset device address to 0
|
|
//
|
|
Status = UsbDeviceSetAddress (mDrvObj.XdciDrvObj, 0x0);
|
|
if (EFI_ERROR (Status)) {
|
|
DEBUG ((DEBUG_INFO, "UsbdConnDoneHdlr() - Failed to set address in XDCI\n"));
|
|
}
|
|
|
|
//
|
|
// set the device state to attached/connected
|
|
//
|
|
mDrvObj.State = UsbDevStateAttached;
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
/**
|
|
Callback used to handle Control Endpoint Setup events from the XDCI.
|
|
|
|
@param Param Pointer to a generic callback parameter structure
|
|
|
|
@return XDCI usb status
|
|
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
UsbdSetupEvtHndlr (
|
|
IN USB_DEVICE_CALLBACK_PARAM *Param
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
EFI_USB_DEVICE_REQUEST Req;
|
|
|
|
Status = EFI_SUCCESS;
|
|
|
|
DEBUG ((DEBUG_INFO, "UsbdSetupEvtHndlr\n"));
|
|
|
|
//
|
|
// Fill out request object from the incomming Buffer
|
|
//
|
|
CopyMem (&Req, Param->Buffer, sizeof (EFI_USB_DEVICE_REQUEST));
|
|
|
|
Status = UsbdSetupHdlr (&Req);
|
|
if (EFI_ERROR (Status)) {
|
|
DEBUG ((DEBUG_INFO, "UsbdSetupEvtHndlr: EFI_DEVICE_ERROR\n"));
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
/**
|
|
Callback used to handle XferNotReady events from the XDCI.
|
|
|
|
@param[in] Param Pointer to a generic callback parameter structure
|
|
|
|
@return XDCI usb status
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
UsbdNrdyEvtHndlr (
|
|
IN USB_DEVICE_CALLBACK_PARAM *Param
|
|
)
|
|
{
|
|
DEBUG ((DEBUG_INFO, "UsbdNrdyEvtHndlr\n"));
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
|
|
/**
|
|
Registers callbacks for event handlers with the XDCI layer.
|
|
The functions will be called as the registered events are triggered.
|
|
|
|
@param XdciHndl to XDCI core driver
|
|
@return EFI_SUCCESS if successful, EFI_DEVICE_ERROR otherwise
|
|
|
|
**/
|
|
EFI_STATUS
|
|
UsbdRegisterCallbacks (
|
|
IN VOID *XdciHndl
|
|
)
|
|
{
|
|
if (UsbDeviceRegisterCallback (XdciHndl, USB_DEVICE_RESET_EVENT, UsbdResetEvtHndlr) != EFI_SUCCESS) {
|
|
goto UdciRegCallbackError;
|
|
}
|
|
|
|
if (UsbDeviceRegisterCallback (XdciHndl, USB_DEVICE_CONNECTION_DONE, UsbdConnDoneEvtHndlr) != EFI_SUCCESS) {
|
|
goto UdciRegCallbackError;
|
|
}
|
|
|
|
if (UsbDeviceRegisterCallback (XdciHndl, USB_DEVICE_SETUP_PKT_RECEIVED, UsbdSetupEvtHndlr) != EFI_SUCCESS) {
|
|
goto UdciRegCallbackError;
|
|
}
|
|
|
|
if (UsbDeviceRegisterCallback (XdciHndl, USB_DEVICE_XFER_NRDY, UsbdNrdyEvtHndlr) != EFI_SUCCESS) {
|
|
goto UdciRegCallbackError;
|
|
}
|
|
|
|
return EFI_SUCCESS;
|
|
|
|
UdciRegCallbackError:
|
|
return EFI_DEVICE_ERROR;
|
|
}
|
|
|
|
|
|
/**
|
|
Returns the configuration descriptor for this device. The data
|
|
Buffer returned will also contain all downstream interface and
|
|
endpoint Buffers.
|
|
|
|
@param Buffer Pointer to destination Buffer to copy descriptor data to
|
|
@param DescIndex the index of the descriptor to return
|
|
@param ReqLen the length in bytes of the request Buffer
|
|
@param DataLen Pointer whos value is to be filled with the byte count of
|
|
data copied to the output Buffer
|
|
|
|
@return EFI_SUCCESS if descritor successfully copied, EFI_DEVICE_ERROR otherwise
|
|
|
|
**/
|
|
EFI_STATUS
|
|
UsbdGetConfigDesc (
|
|
IN VOID *Buffer,
|
|
IN UINT8 DescIndex,
|
|
IN UINT32 ReqLen,
|
|
IN UINT32 *DataLen
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
UINT8 NumConfigs;
|
|
UINT32 ConfigLen;
|
|
USB_DEVICE_CONFIG_OBJ *ConfigObj;
|
|
VOID *Descriptor;
|
|
UINT32 Length;
|
|
|
|
Status = EFI_DEVICE_ERROR;
|
|
NumConfigs = 0;
|
|
ConfigLen = 0;
|
|
ConfigObj = NULL;
|
|
Descriptor = 0;
|
|
Length = 0;
|
|
|
|
DEBUG ((DEBUG_INFO, "UsbdGetConfigDesc()\n"));
|
|
|
|
//
|
|
// For a CONFIGURATION request we send back all descriptors branching out
|
|
// from this descriptor including the INTERFACE and ENDPOINT descriptors
|
|
//
|
|
//
|
|
// Verify the requested configuration exists - check valid index
|
|
//
|
|
NumConfigs = mDrvObj.UsbdDevObj->DeviceDesc->NumConfigurations;
|
|
|
|
if (DescIndex < NumConfigs) {
|
|
//
|
|
// get the configuration object using the index Offset
|
|
//
|
|
ConfigObj = (mDrvObj.UsbdDevObj->ConfigObjs + DescIndex);
|
|
//
|
|
// get the complete configuration Buffer block including Interface and Endpoint data
|
|
//
|
|
Descriptor = ConfigObj->ConfigAll;
|
|
//
|
|
// The config descriptor TotalLength has the full value for all desc Buffers
|
|
//
|
|
ConfigLen = ConfigObj->ConfigDesc->TotalLength;
|
|
//
|
|
// copy the data to the output Buffer
|
|
//
|
|
Length = MIN (ReqLen, ConfigLen);
|
|
CopyMem (Buffer, Descriptor, Length);
|
|
*DataLen = Length;
|
|
Status = EFI_SUCCESS;
|
|
} else {
|
|
DEBUG ((DEBUG_INFO, "UsbdGetConfigDesc() - Invalid Config index: %i\n", DescIndex));
|
|
}
|
|
|
|
if (Status == EFI_SUCCESS) {
|
|
if (ConfigObj != NULL) {
|
|
PrintConfigDescriptor (ConfigObj->ConfigDesc);
|
|
}
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
/**
|
|
Sets the active configuration to the selected configuration index if it exists.
|
|
|
|
@param CfgValue the configuration value to set
|
|
|
|
@return EFI_SUCCESS if the configuration was set, EFI_DEVICE_ERROR otherwise
|
|
|
|
**/
|
|
EFI_STATUS
|
|
UsbdSetConfig (
|
|
UINT8 CfgValue
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
UINT8 NumConfigs;
|
|
USB_DEVICE_CONFIG_OBJ *PtrConfigObj;
|
|
USB_DEVICE_INTERFACE_OBJ *PtrIfObj;
|
|
USB_DEVICE_ENDPOINT_OBJ *PtrEpObj;
|
|
UINT8 CfgItr;
|
|
UINT8 IfItr;
|
|
UINT8 EpItr;
|
|
USB_DEVICE_ENDPOINT_INFO EpInfo;
|
|
USB_EP_INFO UsbEpInfo;
|
|
|
|
Status = EFI_DEVICE_ERROR;
|
|
NumConfigs = 0;
|
|
CfgItr = 0;
|
|
IfItr = 0;
|
|
EpItr = 0;
|
|
PtrConfigObj = NULL;
|
|
PtrIfObj = NULL;
|
|
PtrEpObj = NULL;
|
|
|
|
DEBUG ((DEBUG_INFO, "UsbdSetConfig()\n"));
|
|
//
|
|
// Verify the requested configuration exists - check valid index
|
|
//
|
|
NumConfigs = mDrvObj.UsbdDevObj->DeviceDesc->NumConfigurations;
|
|
|
|
if (CfgValue != 0) {
|
|
//
|
|
// Search for a matching configuration
|
|
//
|
|
for (CfgItr = 0; CfgItr < NumConfigs; CfgItr++) {
|
|
PtrConfigObj = (mDrvObj.UsbdDevObj->ConfigObjs + CfgItr);
|
|
if (PtrConfigObj->ConfigDesc->ConfigurationValue == CfgValue) {
|
|
|
|
//
|
|
// Set the active configuration object
|
|
//
|
|
mDrvObj.ActiveConfigObj = PtrConfigObj;
|
|
//
|
|
// Find all interface objects for this configuration
|
|
//
|
|
for (IfItr = 0; IfItr < PtrConfigObj->ConfigDesc->NumInterfaces; IfItr++) {
|
|
PtrIfObj = (PtrConfigObj->InterfaceObjs + IfItr);
|
|
//
|
|
// Configure the Endpoints in the XDCI
|
|
//
|
|
for (EpItr = 0; EpItr < PtrIfObj->InterfaceDesc->NumEndpoints; EpItr++) {
|
|
PtrEpObj = (PtrIfObj->EndpointObjs + EpItr);
|
|
|
|
EpInfo.EndpointDesc = PtrEpObj->EndpointDesc;
|
|
EpInfo.EndpointCompDesc = PtrEpObj->EndpointCompDesc;
|
|
|
|
if (UsbdInitEp (mDrvObj.XdciDrvObj, &EpInfo) == EFI_SUCCESS) {
|
|
UsbdSetEpInfo (&UsbEpInfo, &EpInfo);
|
|
if (UsbDeviceEpEnable (mDrvObj.XdciDrvObj, &UsbEpInfo) == EFI_SUCCESS) {
|
|
Status = EFI_SUCCESS;
|
|
} else {
|
|
DEBUG ((DEBUG_INFO, "UsbdSetConfig() - Failed to enable endpoint\n"));
|
|
}
|
|
} else {
|
|
DEBUG ((DEBUG_INFO, "UsbdSetConfig() - Failed to initialize endpoint\n"));
|
|
}
|
|
}
|
|
}
|
|
//
|
|
// Let the class driver know it is configured
|
|
//
|
|
if (Status == EFI_SUCCESS) {
|
|
if (mDrvObj.UsbdDevObj->ConfigCallback != NULL) {
|
|
mDrvObj.UsbdDevObj->ConfigCallback (CfgValue);
|
|
}
|
|
}
|
|
|
|
mDrvObj.State = UsbDevStateConfigured; // we are now configured
|
|
|
|
break; // break from config search loop
|
|
}
|
|
}
|
|
}
|
|
|
|
if (EFI_ERROR (Status)) {
|
|
DEBUG ((DEBUG_INFO, "UsbdSetConfig() - Invalid requested configuration value: %i\n", CfgValue));
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
/**
|
|
Returns the currently active configuration value.
|
|
|
|
@param Buffer Pointer to destination Buffer to copy configuration value to
|
|
@param ReqLen the length in bytes of the request Buffer
|
|
@param DataLen Pointer whos value is to be filled with the byte count of
|
|
data copied to the output Buffer
|
|
|
|
@return EFI_SUCCESS if config value is successfully copied, EFI_DEVICE_ERROR otherwise
|
|
|
|
**/
|
|
EFI_STATUS
|
|
UsbdGetConfig (
|
|
VOID *Buffer,
|
|
UINT32 ReqLen,
|
|
UINT32 *DataLen
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
|
|
Status = EFI_DEVICE_ERROR;
|
|
|
|
DEBUG ((DEBUG_INFO, "UsbdGetConfig()\n"));
|
|
|
|
if (ReqLen >= 1) { // length of data expected must be 1
|
|
if (mDrvObj.ActiveConfigObj != NULL) { // assure we have a config active
|
|
*DataLen = 1; // one byte for ConfigurationValue
|
|
* (UINT8 *)Buffer = mDrvObj.ActiveConfigObj->ConfigDesc->ConfigurationValue;
|
|
|
|
Status = EFI_SUCCESS;
|
|
} else {
|
|
DEBUG ((DEBUG_INFO, "UsbdGetConfig() - No active configuration available\n"));
|
|
}
|
|
} else {
|
|
DEBUG ((DEBUG_INFO, "UsbdGetConfig() - Invalid data length\n"));
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
/**
|
|
Returns the requested string descriptor if it exists.
|
|
|
|
@param Buffer Pointer to destination Buffer to copy descriptor data to
|
|
@param DescIndex the index of the descriptor to return
|
|
@param LangId the target language ID
|
|
@param ReqLen the length in bytes of the request Buffer
|
|
@param DataLen Pointer whos value is to be filled with the byte count of
|
|
data copied to the output Buffer
|
|
|
|
@return EFI_SUCCESS if descritor successfully copied, EFI_DEVICE_ERROR otherwise
|
|
|
|
**/
|
|
EFI_STATUS
|
|
UsbdGetStringDesc (
|
|
VOID *Buffer,
|
|
UINT8 DescIndex,
|
|
UINT16 LangId,
|
|
UINT32 ReqLen,
|
|
UINT32 *DataLen
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
UINT32 Length;
|
|
USB_STRING_DESCRIPTOR *StringDesc;
|
|
UINT8 Index;
|
|
UINT8 StrLangEntries;
|
|
BOOLEAN StrLangFound;
|
|
|
|
Status = EFI_DEVICE_ERROR;
|
|
Length = 0;
|
|
Index = 0;
|
|
StrLangEntries = 0;
|
|
StrLangFound = FALSE;
|
|
|
|
DEBUG ((DEBUG_INFO, "UsbdGetStringDesc: Index: 0x%x, LangId: 0x%x, ReqLen: 0x%x\n", DescIndex, LangId, ReqLen));
|
|
|
|
//
|
|
// index zero of the string table contains the supported language codes
|
|
//
|
|
if (DescIndex == 0) {
|
|
StringDesc = (mDrvObj.UsbdDevObj->StringTable);
|
|
Length = MIN (ReqLen, StringDesc->Length);
|
|
CopyMem (Buffer, StringDesc, Length);
|
|
*DataLen = Length;
|
|
Status = EFI_SUCCESS;
|
|
} else {
|
|
|
|
//
|
|
// Verify the requested language ID is supported. String descriptor Zero
|
|
// (First entry in the string table) is expected to contain the language list.
|
|
// The requested language ID is specified in the Index member of the request.
|
|
//
|
|
StringDesc = mDrvObj.UsbdDevObj->StringTable; // get language string descriptor
|
|
StrLangEntries = ((StringDesc->Length - 2) >> 1);
|
|
DEBUG ((DEBUG_INFO, "StrLangEntries=%x\n", StrLangEntries));
|
|
|
|
DEBUG ((DEBUG_INFO, "Looking LangID: \n"));
|
|
|
|
for (Index = 0; Index < StrLangEntries; Index++) {
|
|
DEBUG ((DEBUG_INFO, "LangID [%x]= %x\n", Index, StringDesc->LangID [Index]));
|
|
|
|
if (StringDesc->LangID [Index] == LangId) {
|
|
DEBUG ((DEBUG_INFO, "Found it\n"));
|
|
StrLangFound = TRUE;
|
|
}
|
|
}
|
|
|
|
//
|
|
// If we found a matching language, attempt to get the string index requested
|
|
//
|
|
if (StrLangFound) {
|
|
DEBUG ((DEBUG_INFO, "UsbdGetStringDesc: StrLangFound=Found, DescIndex=%x, StrTblEntries=%x\n", DescIndex,
|
|
mDrvObj.UsbdDevObj->StrTblEntries));
|
|
|
|
if (DescIndex < mDrvObj.UsbdDevObj->StrTblEntries) {
|
|
//
|
|
// get the string descriptor for the requested index
|
|
//
|
|
StringDesc = (mDrvObj.UsbdDevObj->StringTable + DescIndex);
|
|
|
|
Length = MIN (ReqLen, StringDesc->Length);
|
|
DEBUG ((DEBUG_INFO, "ReqLen=%x, StringLength=%x, Length=%x\n", ReqLen, StringDesc->Length, Length));
|
|
|
|
CopyMem (Buffer, StringDesc, Length);
|
|
*DataLen = Length;
|
|
Status = EFI_SUCCESS;
|
|
} else {
|
|
DEBUG ((DEBUG_INFO, "UsbdGetStringDesc: Invalid String index in USB_REQ_GET_DESCRIPTOR request\n"));
|
|
}
|
|
} else {
|
|
DEBUG ((DEBUG_INFO, "UsbdGetStringDesc: Unsupported String Language ID for USB_REQ_GET_DESCRIPTOR request\n"));
|
|
}
|
|
}
|
|
|
|
if (Status == EFI_SUCCESS) {
|
|
PrintStringDescriptor (StringDesc);
|
|
}
|
|
return Status;
|
|
}
|
|
|
|
|
|
#ifdef SUPPORT_SUPER_SPEED
|
|
/**
|
|
Returns the configuration descriptor for this device. The data
|
|
Buffer returned will also contain all downstream interface and
|
|
endpoint Buffers.
|
|
|
|
@param Buffer Pointer to destination Buffer to copy descriptor data to
|
|
@param ReqLen the length in bytes of the request Buffer
|
|
@param DataLen Pointer whos value is to be filled with the byte count of
|
|
data copied to the output Buffer
|
|
|
|
@return EFI_SUCCESS if descritor successfully copied, EFI_DEVICE_ERROR otherwise
|
|
|
|
**/
|
|
EFI_STATUS
|
|
UsbdGetBOSDesc (
|
|
IN VOID *Buffer,
|
|
IN UINT32 ReqLen,
|
|
IN UINT32 *DataLen
|
|
)
|
|
{
|
|
EFI_USB_BOS_DESCRIPTOR *BosDesc;
|
|
UINT32 Length;
|
|
|
|
BosDesc = NULL;
|
|
Length = 0;
|
|
|
|
DEBUG ((DEBUG_INFO, "UsbdGetBOSDesc()\n"));
|
|
|
|
BosDesc = mDrvObj.UsbdDevObj->BosDesc;
|
|
Length = MIN (ReqLen, mDrvObj.UsbdDevObj->BosDesc->TotalLength);
|
|
|
|
CopyMem (Buffer, BosDesc, Length);
|
|
*DataLen = Length;
|
|
|
|
PrintBOSDescriptor (BosDesc);
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
#endif
|
|
|
|
/**
|
|
Returns the current status for Device/Interface/Endpoint.
|
|
|
|
@param Buffer Pointer to destination Buffer to copy descriptor data to
|
|
@param ReqType The type of status to get
|
|
@param ReqLen the length in bytes of the request Buffer
|
|
@param DataLen Pointer whos value is to be filled with the byte count of
|
|
data copied to the output Buffer
|
|
|
|
@return EFI_SUCCESS if status successfully copied, EFI_DEVICE_ERROR otherwise
|
|
|
|
**/
|
|
EFI_STATUS
|
|
UsbdGetStatus (
|
|
VOID *Buffer,
|
|
UINT8 ReqType,
|
|
UINT32 ReqLen,
|
|
UINT32 *DataLen
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
|
|
Status = EFI_DEVICE_ERROR;
|
|
|
|
DEBUG ((DEBUG_INFO, "UsbdGetStatus()\n"));
|
|
|
|
if (ReqLen >= 2) { // length of data must be at least 2 bytes
|
|
switch (ReqType & USB_TARGET_MASK) {
|
|
case USB_TARGET_DEVICE:
|
|
*DataLen = 2; // two byte for status
|
|
* (UINT16 *)Buffer = USB_STATUS_SELFPOWERED;
|
|
Status = EFI_SUCCESS;
|
|
break;
|
|
|
|
case USB_TARGET_INTERFACE:
|
|
//
|
|
// No implementation needed at this time
|
|
//
|
|
break;
|
|
|
|
case USB_TARGET_ENDPOINT:
|
|
//
|
|
// No implementation needed at this time
|
|
// Should specify if endpoint is halted. Implement as necessary.
|
|
//
|
|
break;
|
|
|
|
case USB_TARGET_OTHER:
|
|
//
|
|
// No implementation needed at this time
|
|
//
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
} else {
|
|
DEBUG ((DEBUG_INFO, "UsbdGetStatus() - Invalid data length\n"));
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
/**
|
|
Sets the address of the device.
|
|
|
|
@param Address the address value to set
|
|
|
|
@return EFI_SUCCESS if address was set, EFI_DEVICE_ERROR otherwise
|
|
|
|
**/
|
|
EFI_STATUS
|
|
UsbdSetAddress (
|
|
UINT8 Address
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
|
|
Status = EFI_DEVICE_ERROR;
|
|
|
|
DEBUG ((DEBUG_INFO, "UsbdSetAddress: setting address: 0x%x\n", Address));
|
|
|
|
if (Address <= 0x7F) { // address must not be > 127
|
|
mDrvObj.Address = Address;
|
|
|
|
//
|
|
// Configure Address in the XDCI
|
|
//
|
|
Status = UsbDeviceSetAddress (mDrvObj.XdciDrvObj, mDrvObj.Address);
|
|
if (!EFI_ERROR (Status)) {
|
|
mDrvObj.State = UsbDevStateAddress;
|
|
} else {
|
|
DEBUG ((DEBUG_INFO, "UsbdSetAddress: Failed to set address in XDCI\n"));
|
|
}
|
|
} else {
|
|
DEBUG ((DEBUG_INFO, "UsbdSetAddress: Invalid address: 0x%x\n", Address));
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
/**
|
|
Handles Setup device requests. Standard requests are immediately
|
|
handled here, and any Class/Vendor specific requests are forwarded
|
|
to the class driver.
|
|
|
|
@param CtrlRequest Pointer to a device request
|
|
|
|
@return EFI_SUCCESS if request successfully handled, FALSE otherwise
|
|
|
|
**/
|
|
EFI_STATUS
|
|
UsbdSetupHdlr (
|
|
IN EFI_USB_DEVICE_REQUEST *CtrlRequest
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
UINT8 DescIndex;
|
|
USB_DEVICE_DESCRIPTOR *DevDesc;
|
|
|
|
Status = EFI_DEVICE_ERROR;
|
|
DescIndex = 0;
|
|
DevDesc = NULL;
|
|
|
|
//
|
|
// Initialize the IO object
|
|
//
|
|
mCtrlIoReq.IoInfo.Length = 0;
|
|
|
|
DEBUG ((DEBUG_INFO, "UsbdSetupHdlr start\n"));
|
|
PrintDeviceRequest (CtrlRequest);
|
|
|
|
//
|
|
// Handle Standard Device Requests
|
|
//
|
|
if ((CtrlRequest->RequestType & USB_REQ_TYPE_MASK) == USB_REQ_TYPE_STANDARD) {
|
|
switch (CtrlRequest->Request) {
|
|
case USB_REQ_GET_DESCRIPTOR:
|
|
DEBUG ((DEBUG_INFO, "UsbdSetupHdlr: Host requests get descriptor\n"));
|
|
if (CtrlRequest->RequestType == USB_RT_TX_DIR_D_TO_H) {
|
|
DescIndex = (CtrlRequest->Value & 0xff); // low byte is the index requested
|
|
switch (CtrlRequest->Value >> 8) { // high byte contains request type
|
|
case USB_DESC_TYPE_DEVICE:
|
|
DEBUG ((DEBUG_INFO, "Descriptor tyep: Device\n"));
|
|
DevDesc = mDrvObj.UsbdDevObj->DeviceDesc;
|
|
//
|
|
// copy the data to the output Buffer
|
|
//
|
|
mCtrlIoReq.IoInfo.Length = MIN (CtrlRequest->Length, DevDesc->Length);
|
|
CopyMem (mCtrlIoReq.IoInfo.Buffer, DevDesc, mCtrlIoReq.IoInfo.Length);
|
|
PrintDeviceDescriptor (DevDesc);
|
|
break;
|
|
|
|
case USB_DESC_TYPE_CONFIG:
|
|
DEBUG ((DEBUG_INFO, "Descriptor tyep: Configuration\n"));
|
|
Status = UsbdGetConfigDesc (
|
|
mCtrlIoReq.IoInfo.Buffer,
|
|
DescIndex,
|
|
CtrlRequest->Length,
|
|
& (mCtrlIoReq.IoInfo.Length)
|
|
);
|
|
break;
|
|
|
|
case USB_DESC_TYPE_STRING:
|
|
DEBUG ((DEBUG_INFO, "Descriptor tyep: String\n"));
|
|
Status = UsbdGetStringDesc (
|
|
mCtrlIoReq.IoInfo.Buffer,
|
|
DescIndex,
|
|
CtrlRequest->Index,
|
|
CtrlRequest->Length,
|
|
& (mCtrlIoReq.IoInfo.Length)
|
|
);
|
|
break;
|
|
|
|
#ifdef SUPPORT_SUPER_SPEED
|
|
case USB_DESC_TYPE_BOS:
|
|
DEBUG ((DEBUG_INFO, "Descriptor tyep: BOS\n"));
|
|
Status = UsbdGetBOSDesc (
|
|
mCtrlIoReq.IoInfo.Buffer,
|
|
CtrlRequest->Length,
|
|
& (mCtrlIoReq.IoInfo.Length)
|
|
);
|
|
break;
|
|
|
|
case USB_DESC_TYPE_SS_ENDPOINT_COMPANION:
|
|
DEBUG ((DEBUG_INFO, "Descriptor tyep: Endpoint Companion\n"));
|
|
break;
|
|
#endif
|
|
|
|
default:
|
|
DEBUG ((DEBUG_INFO, "Descriptor tyep: Unsupported, USB_REQ_GET_DESCRIPTOR request: 0x%x\n", (CtrlRequest->Value >> 8)));
|
|
break;
|
|
}
|
|
} else {
|
|
DEBUG ((DEBUG_INFO, "UsbdSetupHdlr() - Invalid direction for USB_REQ_GET_DESCRIPTOR request\n"));
|
|
}
|
|
break;
|
|
|
|
case USB_REQ_GET_CONFIG:
|
|
DEBUG ((DEBUG_INFO, "USB_REQ_GET_CONFIG\n"));
|
|
if (CtrlRequest->RequestType == USB_RT_TX_DIR_D_TO_H) {
|
|
Status = UsbdGetConfig (mCtrlIoReq.IoInfo.Buffer, CtrlRequest->Length, & (mCtrlIoReq.IoInfo.Length));
|
|
} else {
|
|
DEBUG ((DEBUG_INFO, "UsbdSetupHdlr: Invalid direction for USB_REQ_GET_CONFIG request\n"));
|
|
}
|
|
break;
|
|
|
|
case USB_REQ_SET_CONFIG:
|
|
DEBUG ((DEBUG_INFO, "USB_REQ_SET_CONFIG\n"));
|
|
if (CtrlRequest->RequestType == USB_RT_TX_DIR_H_TO_D) {
|
|
Status = UsbdSetConfig ((UINT8)CtrlRequest->Value);
|
|
} else {
|
|
DEBUG ((DEBUG_INFO, "UsbdSetupHdlr: Invalid direction for USB_REQ_SET_CONFIG request\n"));
|
|
}
|
|
break;
|
|
|
|
case USB_REQ_SET_ADDRESS:
|
|
DEBUG ((DEBUG_INFO, "USB_REQ_SET_ADDRESS\n"));
|
|
if (CtrlRequest->RequestType == USB_RT_TX_DIR_H_TO_D) {
|
|
Status = UsbdSetAddress ((UINT8)CtrlRequest->Value);
|
|
} else {
|
|
DEBUG ((DEBUG_INFO, "UsbdSetupHdlr: Invalid direction for USB_REQ_SET_ADDRESS request\n"));
|
|
}
|
|
break;
|
|
|
|
case USB_REQ_GET_STATUS:
|
|
DEBUG ((DEBUG_INFO, "USB_REQ_GET_STATUS\n"));
|
|
if (CtrlRequest->RequestType & USB_RT_TX_DIR_D_TO_H) {
|
|
Status = UsbdGetStatus (mCtrlIoReq.IoInfo.Buffer, CtrlRequest->RequestType, CtrlRequest->Length,
|
|
& (mCtrlIoReq.IoInfo.Length));
|
|
} else {
|
|
DEBUG ((DEBUG_INFO, "UsbdSetupHdlr: Invalid direction for USB_REQ_GET_STATUS request\n"));
|
|
}
|
|
break;
|
|
#ifdef SUPPORT_SUPER_SPEED
|
|
case USB_REQ_CLEAR_FEATURE:
|
|
case USB_REQ_SET_FEATURE:
|
|
case USB_REQ_SET_DESCRIPTOR:
|
|
case USB_REQ_GET_INTERFACE:
|
|
case USB_REQ_SET_INTERFACE:
|
|
case USB_REQ_SYNCH_FRAME:
|
|
#endif
|
|
default:
|
|
DEBUG ((DEBUG_INFO, "UsbdSetupHdlr: Unsupported Standard Request: 0x%x\n", CtrlRequest->Request));
|
|
break;
|
|
}
|
|
} else { // This is not a Standard request, it specifies Class/Vendor handling
|
|
//
|
|
// Forward request to class driver
|
|
//
|
|
DEBUG ((DEBUG_INFO, "UsbdSetupHdlr: Class/Vendor Request\n"));
|
|
if (mDrvObj.UsbdDevObj->SetupCallback != NULL) {
|
|
mDrvObj.UsbdDevObj->SetupCallback (CtrlRequest, & (mCtrlIoReq.IoInfo));
|
|
}
|
|
}
|
|
|
|
DEBUG ((DEBUG_INFO, "dataLen=%x\n", mCtrlIoReq.IoInfo.Length));
|
|
//
|
|
// Transfer data according to request if necessary
|
|
//
|
|
if (mCtrlIoReq.IoInfo.Length > 0) {
|
|
Status = UsbdEpTxData (mDrvObj.XdciDrvObj, &mCtrlIoReq);
|
|
if (EFI_ERROR (Status)) {
|
|
DEBUG ((DEBUG_INFO, "UsbdSetupHdlr: Failed to TX data\n"));
|
|
}
|
|
} else {
|
|
//
|
|
// If we are not responding with data, send control status
|
|
//
|
|
Status = UsbDeviceEp0TxStatus (mDrvObj.XdciDrvObj);
|
|
if (EFI_ERROR (Status)) {
|
|
DEBUG ((DEBUG_INFO, "UsbdSetupHdlr: Failed to Tx Ep0 Status\n"));
|
|
}
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
/**
|
|
Handles Connection done events. Sets the device address to zero.
|
|
|
|
@return EFI_SUCCESS if able to set the address, EFI_DEVICE_ERROR otherwise
|
|
|
|
**/
|
|
EFI_STATUS
|
|
UsbdConnDoneHdlr (
|
|
VOID
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
|
|
Status = EFI_DEVICE_ERROR;
|
|
|
|
DEBUG ((DEBUG_INFO, "UsbdConnDoneHdlr()\n"));
|
|
|
|
//
|
|
// reset device address to 0
|
|
//
|
|
Status = UsbDeviceSetAddress (mDrvObj.XdciDrvObj, 0x0);
|
|
if (EFI_ERROR (Status)) {
|
|
DEBUG ((DEBUG_INFO, "UsbdConnDoneHdlr() - Failed to set address in XDCI\n"));
|
|
}
|
|
|
|
//
|
|
// set the device state to attached/connected
|
|
//
|
|
mDrvObj.State = UsbDevStateAttached;
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
/**
|
|
Handles transmit/receive completion events. Directly handles
|
|
control endpoint events and forwards class/vendor specific events
|
|
to the class drivers.
|
|
|
|
@param XferInfo Pointer to Xfer structure
|
|
|
|
@return
|
|
|
|
**/
|
|
VOID
|
|
UsbdXferDoneHdlr (
|
|
IN EFI_USB_DEVICE_XFER_INFO *XferInfo
|
|
)
|
|
{
|
|
//
|
|
// If this is a non-control transfer complete, notify the class driver
|
|
//
|
|
if (XferInfo->EndpointNum > 0) {
|
|
if (mDrvObj.UsbdDevObj->DataCallback != NULL) {
|
|
mDrvObj.UsbdDevObj->DataCallback (XferInfo);
|
|
}
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
/**
|
|
Binds a USB class driver with this USB device driver core.
|
|
After calling this routine, the driver is ready to begin
|
|
USB processing.
|
|
|
|
@param[in] This A pointer to the EFI_USB_DEVICE_MODE_PROTOCOL instance.
|
|
@param[in] UsbdDevObj Pointer to a usbd device object which contains
|
|
all relevant information for the class driver device
|
|
|
|
@return TRUE if binding was successful, FALSE otherwise
|
|
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
UsbDeviceBind (
|
|
IN EFI_USB_DEVICE_MODE_PROTOCOL *This,
|
|
IN USB_DEVICE_OBJ *UsbdDevObj
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
|
|
Status = EFI_SUCCESS;
|
|
|
|
//
|
|
// allocate Tx Buffer
|
|
//
|
|
mCtrlIoReq.IoInfo.Buffer = AllocateZeroPool (USB_EPO_MAX_PKT_SIZE_ALL);
|
|
if (mCtrlIoReq.IoInfo.Buffer != NULL) {
|
|
mDrvObj.UsbdDevObj = UsbdDevObj;
|
|
mDrvObj.ActiveConfigObj = NULL;
|
|
mDrvObj.Address = 0;
|
|
mDrvObj.State = UsbDevStateInit;
|
|
} else {
|
|
DEBUG ((DEBUG_INFO, "UsbDeviceBind() - Failed to allocate IO Buffer\n"));
|
|
Status = EFI_DEVICE_ERROR;
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
/**
|
|
Unbinds the USB class driver from this USB device driver core.
|
|
|
|
@param[in] This A pointer to the EFI_USB_DEVICE_MODE_PROTOCOL instance.
|
|
|
|
@return TRUE if successful, FALSE otherwise
|
|
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
UsbDeviceUnbind (
|
|
IN EFI_USB_DEVICE_MODE_PROTOCOL *This
|
|
)
|
|
{
|
|
mDrvObj.UsbdDevObj = NULL;
|
|
mDrvObj.ActiveConfigObj = NULL;
|
|
mDrvObj.Address = 0;
|
|
mDrvObj.State = UsbDevStateOff;
|
|
mDrvObj.XdciInitialized = FALSE;
|
|
|
|
//
|
|
// release allocated Buffer data
|
|
//
|
|
if (mCtrlIoReq.IoInfo.Buffer) {
|
|
FreePool (mCtrlIoReq.IoInfo.Buffer);
|
|
}
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
|
|
/**
|
|
Performs continual USB device event processing until a cancel
|
|
event occurs.
|
|
|
|
@param[in] This A pointer to the EFI_USB_DEVICE_MODE_PROTOCOL instance.
|
|
@param[in] TimeoutMs Connection timeout in ms. If 0, waits forever.
|
|
|
|
@return TRUE if run executed normally, FALSE if error ocurred
|
|
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
UsbDeviceRun (
|
|
IN EFI_USB_DEVICE_MODE_PROTOCOL *This,
|
|
IN UINT32 TimeoutMs
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
USB_XDCI_DEV_CONTEXT *XdciDevContext;
|
|
|
|
Status = EFI_DEVICE_ERROR;
|
|
|
|
XdciDevContext = USBUSBD_CONTEXT_FROM_PROTOCOL (This);
|
|
|
|
//
|
|
// can only run if XDCI is initialized
|
|
//
|
|
if ((mDrvObj.XdciInitialized == TRUE)) {
|
|
|
|
if ((mDrvObj.State == UsbDevStateConfigured) && (XdciDevContext->XdciPollTimer == NULL)) {
|
|
Status = BS_CREAT_EVENT (
|
|
EVT_TIMER | EVT_NOTIFY_SIGNAL,
|
|
TPL_NOTIFY,
|
|
UsbdMonitorEvents,
|
|
XdciDevContext,
|
|
&XdciDevContext->XdciPollTimer
|
|
);
|
|
if (!EFI_ERROR (Status)) {
|
|
Status = BS_SET_TIMER (XdciDevContext->XdciPollTimer, TimerPeriodic, EFI_TIMER_PERIOD_MILLISECONDS (20));
|
|
// DEBUG ((DEBUG_ERROR, "UsbDeviceRun Create Event\n"));
|
|
}
|
|
}
|
|
|
|
mXdciRun = TRUE; // set the run flag to active
|
|
Status = EFI_SUCCESS;
|
|
|
|
//
|
|
// start the Event processing loop
|
|
//
|
|
while (TRUE) {
|
|
if (XdciDevContext->XdciPollTimer == NULL) {
|
|
if (UsbDeviceIsrRoutine (mDrvObj.XdciDrvObj) != EFI_SUCCESS) {
|
|
DEBUG ((DEBUG_INFO, "UsbDeviceRun() - Failed to execute event ISR\n"));
|
|
}
|
|
}
|
|
|
|
//
|
|
// Check if a run cancel request exists, if so exit processing loop
|
|
//
|
|
if (!mXdciRun) {
|
|
if (XdciDevContext->XdciPollTimer != NULL) {
|
|
DEBUG ((DEBUG_ERROR, "UsbDeviceRun close Event\n"));
|
|
BS_SET_TIMER (XdciDevContext->XdciPollTimer, TimerCancel, 0);
|
|
BS_CLOSE_EVENT (XdciDevContext->XdciPollTimer);
|
|
XdciDevContext->XdciPollTimer = NULL;
|
|
}
|
|
Status = EFI_SUCCESS;
|
|
DEBUG ((DEBUG_INFO, "UsbDeviceRun() - processing was cancelled\n"));
|
|
break;
|
|
}
|
|
|
|
//
|
|
// check for timeout
|
|
//
|
|
if (TimeoutMs == 0) {
|
|
return EFI_TIMEOUT;
|
|
}
|
|
|
|
BS_STALL (50);
|
|
|
|
TimeoutMs--;
|
|
}
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
/**
|
|
Sets a flag to stop the running device processing loop.
|
|
|
|
@param[in] This A pointer to the EFI_USB_DEVICE_MODE_PROTOCOL instance.
|
|
@return TRUE always
|
|
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
UsbDeviceStop (
|
|
IN EFI_USB_DEVICE_MODE_PROTOCOL *This
|
|
)
|
|
{
|
|
mXdciRun = FALSE; // set run flag to FALSE to stop processing
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
|
|
/**
|
|
Initialize the device controller interface and setup the callback.
|
|
|
|
@param[in] This A pointer to the EFI_USB_DEVICE_MODE_PROTOCOL instance.
|
|
|
|
@return TRUE always
|
|
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
UsbDeviceInitXdci (
|
|
IN EFI_USB_DEVICE_MODE_PROTOCOL *This
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
USB_XDCI_DEV_CONTEXT *XdciDevContext;
|
|
|
|
Status = EFI_DEVICE_ERROR;
|
|
|
|
XdciDevContext = USBUSBD_CONTEXT_FROM_PROTOCOL (This);
|
|
|
|
PlatformSpecificInit ();
|
|
|
|
if (mDrvObj.XdciInitialized == FALSE) {
|
|
if (XdciDevContext->XdciMmioBarAddr != 0) {
|
|
|
|
//
|
|
// Initialize device controller driver
|
|
//
|
|
DEBUG ((DEBUG_INFO, "UsbDeviceInitXdci() - Initializing Controller...\n"));
|
|
|
|
//
|
|
// Initialize the device controller interface
|
|
//
|
|
if (UsbdInit ((UINT32)XdciDevContext->XdciMmioBarAddr, &mDrvObj.XdciDrvObj) == EFI_SUCCESS) {
|
|
|
|
//
|
|
// Setup callbacks
|
|
//
|
|
if (UsbdRegisterCallbacks (mDrvObj.XdciDrvObj) == EFI_SUCCESS) {
|
|
|
|
mDrvObj.XdciInitialized = TRUE;
|
|
Status = EFI_SUCCESS;
|
|
|
|
DEBUG ((DEBUG_INFO, "UsbDeviceInitXdci() - Controller initialization complete\n"));
|
|
} else {
|
|
DEBUG ((DEBUG_INFO, "UsbDeviceInitXdci() - Failed to register UDCI callbacks\n"));
|
|
}
|
|
} else {
|
|
DEBUG ((DEBUG_INFO, "UsbDeviceInitXdci() - Failed to initialize UDCI\n"));
|
|
}
|
|
} else {
|
|
DEBUG ((DEBUG_INFO, "UsbDeviceInitXdci() - XDCI MMIO BAR not set\n"));
|
|
}
|
|
} else {
|
|
DEBUG ((DEBUG_INFO, "UsbDeviceInitXdci() - XDCI already initialized\n"));
|
|
Status = EFI_ALREADY_STARTED;
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
/**
|
|
Wrapper function to enable device controller to connect
|
|
to USB host.
|
|
|
|
@param[in] This A pointer to the EFI_USB_DEVICE_MODE_PROTOCOL instance.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
UsbDeviceConnect (
|
|
IN EFI_USB_DEVICE_MODE_PROTOCOL *This
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
|
|
Status = EFI_DEVICE_ERROR;
|
|
|
|
DEBUG ((DEBUG_INFO, "UsbDeviceConnect \n"));
|
|
if (UsbXdciDeviceConnect (mDrvObj.XdciDrvObj) == EFI_SUCCESS) {
|
|
Status = EFI_SUCCESS;
|
|
}
|
|
return Status;
|
|
}
|
|
|
|
|
|
/**
|
|
Wrapper function to disconnect device controller
|
|
from USB host.
|
|
|
|
@param[in] This A pointer to the EFI_USB_DEVICE_MODE_PROTOCOL instance.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
UsbDeviceDisConnect (
|
|
IN EFI_USB_DEVICE_MODE_PROTOCOL *This
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
|
|
Status = EFI_DEVICE_ERROR;
|
|
|
|
DEBUG ((DEBUG_INFO, "UsbDeviceDisConnect \n"));
|
|
if (UsbDeviceDisconnect (mDrvObj.XdciDrvObj) == EFI_SUCCESS) {
|
|
mDrvObj.State = UsbDevStateInit;
|
|
Status = EFI_SUCCESS;
|
|
}
|
|
|
|
XhciSwitchSwid (FALSE);
|
|
return Status;
|
|
}
|
|
|
|
|
|
/**
|
|
Queue a request to transmit data.
|
|
|
|
@param This A pointer to the EFI_USB_DEVICE_MODE_PROTOCOL instance.
|
|
@param IoRequest Pointer to IO structure containing details of the
|
|
transfer request
|
|
|
|
@return EFI_SUCCESS if operation succeeded, EFI_DEVICE_ERROR otherwise
|
|
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
UsbDeviceEpTxData (
|
|
IN EFI_USB_DEVICE_MODE_PROTOCOL *This,
|
|
IN USB_DEVICE_IO_REQ *IoRequest
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
|
|
Status = UsbdEpTxData (mDrvObj.XdciDrvObj, IoRequest);
|
|
return Status;
|
|
}
|
|
|
|
|
|
/**
|
|
Queue a request to receive data.
|
|
|
|
@param This A pointer to the EFI_USB_DEVICE_MODE_PROTOCOL instance.
|
|
@param IoRequest Pointer to IO structure containing details of the
|
|
transfer request
|
|
|
|
@return EFI_SUCCESS if operation succeeded, EFI_DEVICE_ERROR otherwise
|
|
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
UsbDeviceEpRxData (
|
|
IN EFI_USB_DEVICE_MODE_PROTOCOL *This,
|
|
IN USB_DEVICE_IO_REQ *IoRequest
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
|
|
Status = UsbdEpRxData (mDrvObj.XdciDrvObj, IoRequest);
|
|
return Status;
|
|
}
|
|
|
|
|
|
//
|
|
// The Runtime UsbDeviceMode Protocol instance produced by this driver
|
|
//
|
|
EFI_USB_DEVICE_MODE_PROTOCOL mUsbDeviceModeProtocol = {
|
|
UsbDeviceInitXdci,
|
|
UsbDeviceConnect,
|
|
UsbDeviceDisConnect,
|
|
UsbDeviceEpTxData,
|
|
UsbDeviceEpRxData,
|
|
UsbDeviceBind,
|
|
UsbDeviceUnbind,
|
|
UsbDeviceRun,
|
|
UsbDeviceStop
|
|
};
|
|
|
|
VOID
|
|
CheckUsbEvent (
|
|
VOID
|
|
)
|
|
{
|
|
if (mUsbXdciDevContext && mUsbXdciDevContext->XdciPollTimer) {
|
|
UsbdMonitorEvents (NULL, mUsbXdciDevContext);
|
|
}
|
|
};
|