/** @file Copyright (c) 2017, Linaro Limited. All rights reserved. This program and the accompanying materials are licensed and made available under the terms and conditions of the BSD License which accompanies this distribution. The full text of the license may be found at http://opensource.org/licenses/bsd-license.php THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. **/ #include <IndustryStandard/Usb.h> #include <Library/ArmLib.h> #include <Library/BaseLib.h> #include <Library/BaseMemoryLib.h> #include <Library/CacheMaintenanceLib.h> #include <Library/DebugLib.h> #include <Library/IoLib.h> #include <Library/MemoryAllocationLib.h> #include <Library/TimerLib.h> #include <Library/UefiBootServicesTableLib.h> #include <Library/UefiDriverEntryPoint.h> #include <Library/UefiRuntimeServicesTableLib.h> #include <Library/UncachedMemoryAllocationLib.h> #include <Protocol/DwUsb.h> #include <Protocol/UsbDevice.h> #include "DwUsb3Dxe.h" #define FIFO_DIR_TX 0 #define FIFO_DIR_RX 1 #define TX_FIFO_ADDR 0 #define RX_FIFO_ADDR 0 #define RAM_WIDTH 8 #define RAM_TX0_DEPTH 2048 #define RAM_TX1_DEPTH 4096 #define RAM_RX_DEPTH 8192 #define USB_TYPE_LENGTH 16 #define USB_BLOCK_HIGH_SPEED_SIZE 512 #define DATA_SIZE 131072 #define CMD_SIZE 512 #define MATCH_CMD_LITERAL(Cmd, Buf) !AsciiStrnCmp (Cmd, Buf, sizeof (Cmd) - 1) // The time between interrupt polls, in units of 100 nanoseconds // 10 Microseconds #define DW_INTERRUPT_POLL_PERIOD 100 #define DWUSB3_EVENT_BUF_SIZE 256 // Maxpacket size for EP0, defined by USB3 spec #define USB3_MAX_EP0_SIZE 512 // Maxpacket size for any EP, defined by USB3 spec #define USB3_MAX_PACKET_SIZE 1024 #define USB2_HS_MAX_PACKET_SIZE 512 #define USB2_FS_MAX_PACKET_SIZE 64 #define USB3_STATE_UNCONNECTED 0 #define USB3_STATE_DEFAULT 1 #define USB3_STATE_ADDRESSED 2 #define USB3_STATE_CONFIGURED 3 #define GET_EVENTBUF_COUNT() (GEVNTCOUNT_EVNTCOUNT (MmioRead32 (GEVNTCOUNT (0)))) #define UPDATE_EVENTBUF_COUNT(x) (MmioWrite32 (GEVNTCOUNT (0), GEVNTCOUNT_EVNTCOUNT (x))) #define CLEAR_EVENTBUF() do { \ MmioOr32 (GEVNTSIZ (0), GEVNTSIZ_EVNTINTMASK); \ MmioOr32 (GEVNTCOUNT (0), 0); \ } while (0) #define SET_DEVADDR(x) (MmioAndThenOr32 (DCFG, ~DCFG_DEVADDR_MASK, DCFG_DEVADDR (x))) EFI_GUID gDwUsbProtocolGuid = DW_USB_PROTOCOL_GUID; STATIC DW_USB_PROTOCOL *DwUsb; STATIC usb3_pcd_t gPcd; STATIC UINT32 *gEventBuf, *gEventPtr; STATIC struct usb_device_descriptor gDwUsb3DevDesc; STATIC VOID *gRxBuf; STATIC usb_setup_pkt_t *gEndPoint0SetupPacket; #define USB3_STATUS_BUF_SIZE 512 STATIC UINT8 *gEndPoint0StatusBuf; STATIC USB_DEVICE_RX_CALLBACK mDataReceivedCallback; STATIC UINTN mDataBufferSize; /* UINT8 ep0_status_buf[USB3_STATUS_BUF_SIZE]; */ struct usb_interface_descriptor intf = { sizeof (struct usb_interface_descriptor), UDESC_INTERFACE, 0, 0, 2, USB_CLASS_VENDOR_SPEC, 0x42, 0x03, 0 }; const struct usb_ss_ep_comp_descriptor ep_comp = { sizeof (struct usb_ss_ep_comp_descriptor), UDESC_SS_USB_COMPANION, 0, 0, 0 }; const struct usb_endpoint_descriptor hs_bulk_in = { sizeof (struct usb_endpoint_descriptor), UDESC_ENDPOINT, UE_DIR_IN | USB3_BULK_IN_EP, USB_ENDPOINT_XFER_BULK, 0x200, 0 }; const struct usb_endpoint_descriptor hs_bulk_out = { sizeof(struct usb_endpoint_descriptor), /* bLength */ UDESC_ENDPOINT, /* bDescriptorType */ UE_DIR_OUT | USB3_BULK_OUT_EP, /* bEndpointAddress */ USB_ENDPOINT_XFER_BULK, /* bmAttributes */ 0x200, /* wMaxPacketSize: 512 of high-speed */ 1, /* bInterval */ }; const struct usb_endpoint_descriptor ss_bulk_in = { sizeof(struct usb_endpoint_descriptor), /* bLength */ UDESC_ENDPOINT, /* bDescriptorType */ UE_DIR_IN | USB3_BULK_IN_EP, /* bEndpointAddress */ USB_ENDPOINT_XFER_BULK, /* bmAttributes */ 0x400, /* wMaxPacketSize: 1024 of super-speed */ 0, /* bInterval */ }; const struct usb_endpoint_descriptor ss_bulk_out = { sizeof(struct usb_endpoint_descriptor), /* bLength */ UDESC_ENDPOINT, /* bDescriptorType */ UE_DIR_OUT | USB3_BULK_OUT_EP, /* bEndpointAddress */ USB_ENDPOINT_XFER_BULK, /* bmAttributes */ 0x400, /* wMaxPacketSize: 1024 of super-speed */ 0, /* bInterval */ }; /** The BOS Descriptor */ const struct usb_dev_cap_20_ext_desc cap1 = { sizeof(struct usb_dev_cap_20_ext_desc), /* bLength */ UDESC_DEVICE_CAPABILITY, /* bDescriptorType */ USB_DEVICE_CAPABILITY_20_EXTENSION, /* bDevCapabilityType */ 0x2, /* bmAttributes */ }; const struct usb_dev_cap_ss_usb cap2 = { sizeof(struct usb_dev_cap_ss_usb), /* bLength */ UDESC_DEVICE_CAPABILITY, /* bDescriptorType */ USB_DEVICE_CAPABILITY_SS_USB, /* bDevCapabilityType */ 0x0, /* bmAttributes */ (USB_DC_SS_USB_SPEED_SUPPORT_SS | USB_DC_SS_USB_SPEED_SUPPORT_HIGH), /* wSpeedsSupported */ 0x2, /* bFunctionalitySupport */ /* @todo set these to correct value */ 0xa, /* bU1DevExitLat */ 0x100, /* wU2DevExitLat */ }; const struct usb_dev_cap_container_id cap3 = { sizeof(struct usb_dev_cap_container_id),/* bLength */ UDESC_DEVICE_CAPABILITY, /* bDescriptorType */ USB_DEVICE_CAPABILITY_CONTAINER_ID, /* bDevCapabilityType */ 0, /* bReserved */ /* @todo Create UUID */ {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, /* containerID */ }; const struct wusb_bos_desc bos = { sizeof(struct wusb_bos_desc), /* bLength */ UDESC_BOS, /* bDescriptorType */ (sizeof(struct wusb_bos_desc) /* wTotalLength */ + sizeof(cap1) + sizeof(cap2) + sizeof(cap3)), 3, /* bNumDeviceCaps */ }; STATIC struct usb_enum_port_param usb_port_activity_config = { .idVendor = USB_ENUM_ADB_PORT_VID, .idProduct = USB_ENUM_ADB_PORT_PID, .bInterfaceSubClass = USB_ENUM_INTERFACE_ADB_SUBCLASS, .bInterfaceProtocol = USB_ENUM_INTERFACE_ADB_PROTOCOL }; STATIC UINT32 DwUsb3GetEventBufEvent ( IN UINTN Size ) { UINT32 Event; Event = *gEventPtr++; if ((UINT32)(UINTN)gEventPtr >= (UINT32)(UINTN)gEventBuf + Size) { gEventPtr = gEventBuf; } return Event; } STATIC VOID DwUsb3SetFifoSize ( IN UINT32 Addr, IN UINT32 Depth, IN UINT32 Dir, IN UINT32 FifoNum ) { UINT32 Reg; if (Dir == FIFO_DIR_TX) { Reg = GTXFIFOSIZ (FifoNum); } else if (Dir == FIFO_DIR_RX) { Reg = GRXFIFOSIZ (FifoNum); } else { ASSERT (0); } MmioWrite32 (Reg, FIFOSIZ_DEP (Depth) | FIFOSIZ_ADDR (Addr)); } STATIC UINT32 Handshake ( IN UINT32 Reg, IN UINT32 Mask, IN UINT32 Done ) { UINT32 Timeout = 100000; do { if ((MmioRead32 (Reg) & Mask) == Done) { return 1; } MicroSecondDelay (1); } while (Timeout-- > 0); return 0; } STATIC VOID DwUsb3FillDesc ( IN usb3_dma_desc_t *desc, IN UINT64 dma_addr, IN UINT32 dma_len, IN UINT32 stream, IN UINT32 type, IN UINT32 ctrlbits, IN UINT32 own ) { desc->bptl = (UINT32)(dma_addr & 0xFFFFFFFF); desc->bpth = (UINT32)(dma_addr >> 32); desc->status = DSCSTS_XFERCNT (dma_len); if (type) { desc->control = DSCCTL_TRBCTL (type); } desc->control |= DSCCTL_STRMID_SOFN (stream) | ctrlbits; ArmDataSynchronizationBarrier (); /* must execute this operation at last */ if (own) { desc->control |= DSCCTL_HWO; } ArmDataSynchronizationBarrier (); } STATIC VOID DwUsb3DepStartNewCfg ( IN UINT32 EpIdx, IN UINT32 RsrcIdx ) { /* start the command */ MmioWrite32 ( DEPCMD (EpIdx), DEPCMD_XFER_RSRC_IDX (RsrcIdx) | DEPCMD_CMDTYPE (CMDTYPE_START_NEW_CFG) | DEPCMD_CMDACT ); Handshake (DEPCMD (EpIdx), DEPCMD_CMDACT, 0); } STATIC VOID DwUsb3DepCfg ( IN UINT32 EpIdx, IN UINT32 DepCfg0, IN UINT32 DepCfg1, IN UINT32 DepCfg2 ) { MmioWrite32 (DEPCMDPAR2 (EpIdx), DepCfg2); MmioWrite32 (DEPCMDPAR1 (EpIdx), DepCfg1); MmioWrite32 (DEPCMDPAR0 (EpIdx), DepCfg0); MmioWrite32 (DEPCMD (EpIdx), DEPCMD_CMDTYPE (CMDTYPE_SET_EP_CFG) | DEPCMD_CMDACT); Handshake (DEPCMD (EpIdx), DEPCMD_CMDACT, 0); } STATIC VOID DwUsb3DepXferCfg ( IN UINT32 EpIdx, IN UINT32 DepStrmCfg ) { MmioWrite32 (DEPCMDPAR0 (EpIdx), DepStrmCfg); MmioWrite32 (DEPCMD (EpIdx), DEPCMD_CMDTYPE (CMDTYPE_SET_XFER_CFG) | DEPCMD_CMDACT); Handshake (DEPCMD (EpIdx), DEPCMD_CMDACT, 0); } STATIC UINT8 DwUsb3DepStartXfer ( IN UINT32 EpIdx, IN UINT64 DmaAddr, IN UINT32 StreamOrUf ) { UINT32 Data; MmioWrite32 (DEPCMDPAR1 (EpIdx), (UINT32)DmaAddr); MmioWrite32 (DEPCMDPAR0 (EpIdx), (UINT32)(DmaAddr >> 32)); MmioWrite32 ( DEPCMD (EpIdx), DEPCMD_STR_NUM_OR_UF (StreamOrUf) | DEPCMD_CMDTYPE (CMDTYPE_START_XFER) | DEPCMD_CMDACT ); Handshake (DEPCMD (EpIdx), DEPCMD_CMDACT, 0); Data = MmioRead32 (DEPCMD (EpIdx)); return GET_DEPCMD_XFER_RSRC_IDX(Data); } STATIC VOID DwUsb3DepStopXfer ( IN UINT32 EpIdx, IN UINT32 Tri ) { MmioWrite32 (DEPCMDPAR2 (EpIdx), 0); MmioWrite32 (DEPCMDPAR1 (EpIdx), 0); MmioWrite32 (DEPCMDPAR0 (EpIdx), 0); MmioWrite32 ( DEPCMD (EpIdx), DEPCMD_XFER_RSRC_IDX (Tri) | DEPCMD_CMDTYPE (CMDTYPE_END_XFER) | DEPCMD_CMDACT ); Handshake (DEPCMD (EpIdx), DEPCMD_CMDACT, 0); } VOID DwUsb3DepUpdateXfer ( IN UINT32 EpIdx, IN UINT32 Tri ) { MmioWrite32 ( DEPCMD (EpIdx), DEPCMD_XFER_RSRC_IDX (Tri) | DEPCMD_CMDTYPE (CMDTYPE_UPDATE_XFER) | DEPCMD_CMDACT ); Handshake (DEPCMD (EpIdx), DEPCMD_CMDACT, 0); } STATIC VOID DwUsb3DepClearStall ( IN UINTN EpIdx ) { MmioWrite32 (DEPCMD (EpIdx), DEPCMD_CMDTYPE (CMDTYPE_CLR_STALL) | DEPCMD_CMDACT); Handshake (DEPCMD (EpIdx), DEPCMD_CMDACT, 0); } STATIC VOID DwUsb3DepSetStall ( IN UINTN EpIdx ) { MmioWrite32 (DEPCMD (EpIdx), DEPCMD_CMDTYPE (CMDTYPE_SET_STALL) | DEPCMD_CMDACT); Handshake (DEPCMD (EpIdx), DEPCMD_CMDACT, 0); } STATIC VOID DwUsb3EnableEp ( IN UINT32 EpIdx, IN usb3_pcd_ep_t *ep ) { UINT32 Dalepena; Dalepena = MmioRead32 (DALEPENA); /* If the EP is already enabled, skip to set it again. */ if (Dalepena & (1 << EpIdx)) { return; } Dalepena |= 1 << EpIdx; MmioWrite32 (DALEPENA, Dalepena); } STATIC VOID DwUsb3Ep0Activate ( IN OUT usb3_pcd_t *pcd ) { /* issue DEPCFG command to EP0 OUT */ DwUsb3DepStartNewCfg (EP_OUT_IDX (0), 0); DwUsb3DepCfg ( EP_OUT_IDX (0), EPCFG0_EPTYPE (EPTYPE_CONTROL) | EPCFG0_MPS (512), EPCFG1_XFER_CMPL | EPCFG1_XFER_NRDY, 0 ); /* issue DEPSTRMCFG command to EP0 OUT */ DwUsb3DepXferCfg (EP_OUT_IDX (0), 1); // one stream /* issue DEPCFG command to EP0 IN */ DwUsb3DepCfg ( EP_IN_IDX (0), EPCFG0_EPTYPE (EPTYPE_CONTROL) | EPCFG0_MPS (512) | EPCFG0_TXFNUM (pcd->ep0.tx_fifo_num), EPCFG1_XFER_NRDY | EPCFG1_XFER_CMPL | EPCFG1_EP_DIR_IN, 0 ); /* issue DEPSTRMCFG command to EP0 IN */ DwUsb3DepXferCfg (EP_IN_IDX (0), 1); // one stream pcd->ep0.active = 1; } STATIC VOID DwUsb3EpActivate ( IN OUT usb3_pcd_t *pcd, IN OUT usb3_pcd_ep_t *ep ) { UINT32 EpIdx, DepCfg0, DepCfg1; if (ep->is_in) { EpIdx = EP_IN_IDX (ep->num); } else { EpIdx = EP_OUT_IDX (ep->num); } /* Start a new configurate when enable the first EP. */ if (!pcd->eps_enabled) { pcd->eps_enabled = 1; /* Issue DEPCFG command to physical EP1 (logical EP0 IN) first. * It resets the core's Tx FIFO mapping table. */ DepCfg0 = EPCFG0_EPTYPE (EPTYPE_CONTROL); DepCfg0 |= EPCFG0_CFG_ACTION (CFG_ACTION_MODIFY); DepCfg1 = EPCFG1_XFER_CMPL | EPCFG1_XFER_NRDY | EPCFG1_EP_DIR_IN; switch (pcd->speed) { case USB_SPEED_SUPER: DepCfg0 |= EPCFG0_MPS (512); break; case USB_SPEED_HIGH: case USB_SPEED_FULL: DepCfg0 |= EPCFG0_MPS (64); break; case USB_SPEED_LOW: DepCfg0 |= EPCFG0_MPS (8); break; default: ASSERT (0); break; } DwUsb3DepCfg (EP_IN_IDX (0), DepCfg0, DepCfg1, 0); DwUsb3DepStartNewCfg (EP_OUT_IDX (0), 2); } /* issue DEPCFG command to EP */ DepCfg0 = EPCFG0_EPTYPE (ep->type); DepCfg0 |= EPCFG0_MPS (ep->maxpacket); if (ep->is_in) { DepCfg0 |= EPCFG0_TXFNUM (ep->tx_fifo_num); } DepCfg0 |= EPCFG0_BRSTSIZ (ep->maxburst); DepCfg1 = EPCFG1_EP_NUM (ep->num); if (ep->is_in) { DepCfg1 |= EPCFG1_EP_DIR_IN; } else { DepCfg1 |= EPCFG1_XFER_CMPL; } DwUsb3DepCfg (EpIdx, DepCfg0, DepCfg1, 0); /* issue DEPSTRMCFG command to EP */ DwUsb3DepXferCfg (EpIdx, 1); DwUsb3EnableEp (EpIdx, ep); ep->active = 1; } STATIC VOID DwUsb3Ep0OutStart ( IN usb3_pcd_t *pcd ) { usb3_dma_desc_t *desc; /* Get the SETUP packet DMA Descriptor (TRB) */ desc = pcd->ep0_setup_desc; /* DMA Descriptor setup */ DwUsb3FillDesc ( desc, (UINT64)gEndPoint0SetupPacket, pcd->ep0.maxpacket, 0, TRBCTL_SETUP, DSCCTL_IOC | DSCCTL_ISP | DSCCTL_LST, 1 ); /* issue DEPSTRTXFER command to EP0 OUT */ pcd->ep0.tri_out = DwUsb3DepStartXfer (EP_OUT_IDX (0), (UINT64)desc, 0); } STATIC VOID DwUsb3Init ( VOID ) { UINT32 Data, Addr; usb3_pcd_t *pcd = &gPcd; /* soft reset the usb core */ do { MmioAndThenOr32 (DCTL, ~DCTL_RUN_STOP, DCTL_CSFTRST); do { MicroSecondDelay (1000); Data = MmioRead32 (DCTL); } while (Data & DCTL_CSFTRST); // wait for at least 3 PHY clocks MicroSecondDelay (1000); } while (0); pcd->link_state = 0; /* TI PHY: Set Turnaround Time = 9 (8-bit UTMI+ / ULPI) */ MmioAndThenOr32 (GUSB2PHYCFG (0), ~GUSB2PHYCFG_USBTRDTIM_MASK, GUSB2PHYCFG_USBTRDTIM (9)); /* set TX FIFO size */ Addr = TX_FIFO_ADDR; DwUsb3SetFifoSize (Addr, RAM_TX0_DEPTH / RAM_WIDTH, FIFO_DIR_TX, 0); Addr += RAM_TX0_DEPTH / RAM_WIDTH; DwUsb3SetFifoSize (Addr, RAM_TX1_DEPTH / RAM_WIDTH, FIFO_DIR_TX, 1); /* set RX FIFO size */ DwUsb3SetFifoSize (RX_FIFO_ADDR, RAM_RX_DEPTH / RAM_WIDTH, FIFO_DIR_RX, 0); /* set LFPS filter delay1trans */ MmioAndThenOr32 ( GUSB3PIPECTL (0), ~PIPECTL_DELAYP1TRANS, PIPECTL_LFPS_FILTER | PIPECTL_TX_DEMPH (1) ); /* set GCTL */ Data = GCTL_U2EXIT_LFPS | GCTL_PRTCAPDIR_DEVICE | GCTL_U2RSTECN | GCTL_PWRDNSCALE(2); MmioWrite32 (GCTL, Data); /* init event buf */ MmioWrite32 (GEVNTADRL(0), (UINT32)(UINTN)gEventBuf); MmioWrite32 (GEVNTADRH(0), (UINTN)gEventBuf >> 32); MmioWrite32 (GEVNTSIZ(0), DWUSB3_EVENT_BUF_SIZE << 2); MmioWrite32 (GEVNTCOUNT(0), 0); /* set max speed to super speed */ MmioAndThenOr32 ( DCFG, ~DCFG_DEVSPD_MASK, DCFG_DEVSPD (DEVSPD_SS_PHY_125MHZ_OR_250MHZ) ); /* set nump */ MmioAndThenOr32 (DCFG, ~DCFG_NUMP_MASK, DCFG_NUMP (16)); /* init address */ SET_DEVADDR (0); /* disable phy suspend */ MmioAnd32 (GUSB3PIPECTL (0), ~PIPECTL_SUSPEND_EN); MmioAnd32 (GUSB2PHYCFG (0), ~GUSB2PHYCFG_SUSPHY); /* clear any pending interrupts */ #if 0 CLEAR_EVENTBUF (); #else Data = MmioRead32 (GEVNTCOUNT (0)); MmioWrite32 (GEVNTCOUNT (0), Data); #endif /* enable device interrupts */ MmioWrite32 (DEVTEN, DEVTEN_CONNECTDONEEN | DEVTEN_USBRSTEN); /* activate EP0 */ DwUsb3Ep0Activate (pcd); /* start EP0 to receive SETUP packets */ DwUsb3Ep0OutStart (pcd); /* enable EP0 OUT/IN in DALEPENA */ MmioWrite32 (DALEPENA, (1 << EP_OUT_IDX (0)) | (1 << EP_IN_IDX (0))); /* set RUN/STOP bit */ MmioOr32 (DCTL, DCTL_RUN_STOP); } #define ALIGN(x, a) (((x) + ((a) - 1)) & ~((a) - 1)) STATIC VOID DriverInit ( VOID ) { usb3_pcd_t *pcd = &gPcd; usb3_pcd_ep_t *ep; pcd->speed = USB_SPEED_UNKNOWN; // init EP0 ep = &pcd->ep0; ep->pcd = pcd; ep->stopped = 1; ep->is_in = 0; ep->active = 0; ep->phys = 0; ep->num = 0; ep->tx_fifo_num = 0; ep->type = EPTYPE_CONTROL; ep->maxburst = 0; ep->maxpacket = USB3_MAX_EP0_SIZE; ep->send_zlp = 0; ep->req.length = 0; ep->req.actual = 0; pcd->ep0_req.length = 0; pcd->ep0_req.actual = 0; // init EP1 OUT ep = &pcd->out_ep; ep->pcd = pcd; ep->stopped = 1; ep->is_in = 0; ep->active = 0; ep->phys = USB3_BULK_OUT_EP << 1; ep->num = 1; ep->tx_fifo_num = 0; // bulk ep is activated ep->type = EPTYPE_BULK; ep->maxburst = 0; ep->maxpacket = USB3_MAX_PACKET_SIZE; ep->send_zlp = 0; ep->req.length = 0; ep->req.actual = 0; // init EP1 IN ep = &pcd->in_ep; ep->stopped = 1; ep->is_in = 1; ep->active = 0; ep->phys = (USB3_BULK_IN_EP << 1) | 1; ep->num = 1; ep->tx_fifo_num = USB3_BULK_IN_EP; // bulk ep is activated ep->type = EPTYPE_BULK; ep->maxburst = 0; ep->maxpacket = USB3_MAX_PACKET_SIZE; ep->send_zlp = 0; ep->req.length = 0; ep->req.actual = 0; pcd->ep0state = EP0_IDLE; pcd->ep0.maxpacket = USB3_MAX_EP0_SIZE; pcd->ep0.type = EPTYPE_CONTROL; #if 0 pcd->ep0_setup_desc = (usb3_dma_desc_t *)ALIGN ((UINTN)pcd->ep0_setup, 16); pcd->ep0_in_desc = (usb3_dma_desc_t *)ALIGN ((UINTN)pcd->ep0_in, 16); pcd->ep0_out_desc = (usb3_dma_desc_t *)ALIGN ((UINTN)pcd->ep0_out, 16); pcd->in_ep.ep_desc = (usb3_dma_desc_t *)ALIGN ((UINTN)pcd->in_ep.epx_desc, 16); pcd->out_ep.ep_desc = (usb3_dma_desc_t *)ALIGN ((UINTN)pcd->out_ep.epx_desc, 16); #else pcd->ep0_setup_desc = (usb3_dma_desc_t *)UncachedAllocateAlignedZeroPool (64, 64); pcd->ep0_in_desc = (usb3_dma_desc_t *)UncachedAllocateAlignedZeroPool (64, 64); pcd->ep0_out_desc = (usb3_dma_desc_t *)UncachedAllocateAlignedZeroPool (64, 64); pcd->in_ep.ep_desc = (usb3_dma_desc_t *)UncachedAllocateAlignedZeroPool (64, 64); pcd->out_ep.ep_desc = (usb3_dma_desc_t *)UncachedAllocateAlignedZeroPool (64, 64); #endif } STATIC VOID DwUsb3HandleUsbResetInterrupt ( IN usb3_pcd_t *pcd ) { usb3_pcd_ep_t *ep; // clear stall on each EP ep = &pcd->in_ep; if (ep->xfer_started) { if (ep->is_in) { DwUsb3DepStopXfer (EP_IN_IDX (ep->num), ep->tri_in); } else { DwUsb3DepStopXfer (EP_OUT_IDX (ep->num), ep->tri_out); } } if (ep->stopped) { if (ep->is_in) { DwUsb3DepClearStall (EP_IN_IDX (ep->num)); } else { DwUsb3DepClearStall (EP_OUT_IDX (ep->num)); } } ep = &pcd->out_ep; if (ep->xfer_started) { if (ep->is_in) { DwUsb3DepStopXfer (EP_IN_IDX (ep->num), ep->tri_in); } else { DwUsb3DepStopXfer (EP_OUT_IDX (ep->num), ep->tri_out); } } if (ep->stopped) { if (ep->is_in) { DwUsb3DepClearStall (EP_IN_IDX (ep->num)); } else { DwUsb3DepClearStall (EP_OUT_IDX (ep->num)); } } // set device address to 0 SET_DEVADDR (0); pcd->ltm_enable = 0; DEBUG ((DEBUG_INFO, "usb reset\n")); } STATIC UINT32 DwUsb3GetDeviceSpeed ( IN usb3_pcd_t *pcd ) { UINT32 Data, Speed; Data = MmioRead32 (DSTS); switch (DSTS_GET_DEVSPD (Data)) { case DEVSPD_HS_PHY_30MHZ_OR_60MHZ: Speed = USB_SPEED_HIGH; break; case DEVSPD_FS_PHY_30MHZ_OR_60MHZ: case DEVSPD_FS_PHY_48MHZ: Speed = USB_SPEED_FULL; break; case DEVSPD_LS_PHY_6MHZ: Speed = USB_SPEED_LOW; break; case DEVSPD_SS_PHY_125MHZ_OR_250MHZ: Speed = USB_SPEED_SUPER; break; default: DEBUG ((DEBUG_ERROR, "DwUsb3GetDeviceSpeed: invalid DSTS:0x%x\n", Data)); Speed = USB_SPEED_UNKNOWN; break; } return Speed; } STATIC VOID DwUsb3PcdSetSpeed ( IN usb3_pcd_t *pcd, IN UINTN speed ) { // set the MPS of EP0 based on the connection speed switch (speed) { case USB_SPEED_SUPER: pcd->ep0.maxpacket = 512; pcd->in_ep.maxpacket = USB3_MAX_PACKET_SIZE; pcd->out_ep.maxpacket = USB3_MAX_PACKET_SIZE; break; case USB_SPEED_HIGH: pcd->ep0.maxpacket = 64; pcd->in_ep.maxpacket = USB2_HS_MAX_PACKET_SIZE; pcd->out_ep.maxpacket = USB2_HS_MAX_PACKET_SIZE; break; case USB_SPEED_FULL: pcd->ep0.maxpacket = 64; pcd->in_ep.maxpacket = USB2_FS_MAX_PACKET_SIZE; pcd->out_ep.maxpacket = USB2_FS_MAX_PACKET_SIZE; break; default: DEBUG ((DEBUG_ERROR, "invalid speed: %d\n", speed)); break; } } STATIC VOID DwUsb3HandleConnectDoneInterrupt ( IN usb3_pcd_t *pcd ) { usb3_pcd_ep_t *ep0 = &pcd->ep0; UINT32 DiepCfg0, DoepCfg0, DiepCfg1, DoepCfg1; UINT32 Speed; ep0->stopped = 0; Speed = (UINT32)DwUsb3GetDeviceSpeed (pcd); pcd->speed = (UINT8)Speed; DwUsb3PcdSetSpeed (pcd, Speed); // set the MPS of EP0 based on the connection speed DiepCfg0 = EPCFG0_EPTYPE (EPTYPE_CONTROL) | EPCFG0_CFG_ACTION (CFG_ACTION_MODIFY); DiepCfg1 = EPCFG1_XFER_CMPL | EPCFG1_XFER_NRDY | EPCFG1_EP_DIR_IN; DoepCfg0 = EPCFG0_EPTYPE (EPTYPE_CONTROL) | EPCFG0_CFG_ACTION (CFG_ACTION_MODIFY); DoepCfg1 = EPCFG1_XFER_CMPL | EPCFG1_XFER_NRDY; switch (Speed) { case USB_SPEED_SUPER: DiepCfg0 |= EPCFG0_MPS (512); DoepCfg0 |= EPCFG0_MPS (512); break; case USB_SPEED_HIGH: case USB_SPEED_FULL: DiepCfg0 |= EPCFG0_MPS (64); DoepCfg0 |= EPCFG0_MPS (64); break; case USB_SPEED_LOW: DiepCfg0 |= EPCFG0_MPS (8); DoepCfg0 |= EPCFG0_MPS (8); break; default: DEBUG ((DEBUG_ERROR, "DwUsb3HandleConnectDoneInterrupt: invalid speed %d\n", Speed)); break; } DiepCfg0 |= EPCFG0_TXFNUM (ep0->tx_fifo_num); // issue DEPCFG command to EP0 OUT DwUsb3DepCfg (EP_OUT_IDX (0), DoepCfg0, DoepCfg1, 0); // issue DEPCFG command to EP0 IN DwUsb3DepCfg (EP_IN_IDX (0), DiepCfg0, DiepCfg1, 0); pcd->state = USB3_STATE_DEFAULT; } STATIC VOID DwUsb3HandleDeviceInterrupt ( IN usb3_pcd_t *pcd, IN UINT32 Event ) { switch (Event & GEVNT_DEVT_MASK) { case GEVNT_DEVT_USBRESET: DwUsb3HandleUsbResetInterrupt (pcd); break; case GEVNT_DEVT_CONNDONE: DwUsb3HandleConnectDoneInterrupt (pcd); break; default: DEBUG ((DEBUG_ERROR, "DwUsb3HandleDeviceInterrupt: invalid event\n")); break; } } STATIC usb3_pcd_ep_t * DwUsb3GetOutEndPoint ( IN usb3_pcd_t *pcd, IN UINT32 EndPointNum ) { if (EndPointNum == 0) { return &pcd->ep0; } return &pcd->out_ep; } STATIC usb3_pcd_ep_t * DwUsb3GetInEndPoint ( IN usb3_pcd_t *pcd, IN UINT32 EndPointNum ) { if (EndPointNum == 0) { return &pcd->ep0; } return &pcd->in_ep; } STATIC VOID EndPoint0DoStall ( IN usb3_pcd_t *pcd ) { usb3_pcd_ep_t *ep0 = &pcd->ep0; // stall EP0 IN & OUT simultanelusly ep0->is_in = 1; DwUsb3DepSetStall (EP_IN_IDX (0)); ep0->is_in = 0; DwUsb3DepSetStall (EP_OUT_IDX (0)); // prepare for the next setup transfer ep0->stopped = 1; pcd->ep0state = EP0_IDLE; DwUsb3Ep0OutStart (pcd); } STATIC VOID EndPoint0ContinueTransfer ( IN usb3_pcd_t *pcd, IN usb3_pcd_req_t *req ) { usb3_pcd_ep_t *ep0 = &pcd->ep0; usb3_dma_desc_t *desc; UINT64 desc_dma; UINT8 tri; // send a 0-byte length packet after the end of transfer if (ep0->is_in) { desc = pcd->ep0_in_desc; desc_dma = (UINT64)pcd->ep0_in_desc; // DMA descriptor setup DwUsb3FillDesc ( desc, (UINT64)req->bufdma, 0, 0, TRBCTL_NORMAL, DSCCTL_IOC | DSCCTL_ISP | DSCCTL_LST, 1 ); tri = DwUsb3DepStartXfer (EP_IN_IDX (0), desc_dma, 0); ep0->tri_in = tri; } } STATIC VOID EndPoint0CompleteRequest ( IN usb3_pcd_t *pcd, IN usb3_pcd_req_t *req, IN usb3_dma_desc_t *desc ) { usb3_pcd_ep_t *ep = &pcd->ep0; if (req == NULL) { return; } if ((pcd->ep0state == EP0_OUT_DATA_PHASE) || (pcd->ep0state == EP0_IN_DATA_PHASE)) { if (ep->is_in) { if (GET_DSCSTS_XFERCNT (desc->status) == 0) { pcd->ep0.is_in = 0; pcd->ep0state = EP0_OUT_WAIT_NRDY; } } else { pcd->ep0.is_in = 1; pcd->ep0state = EP0_IN_WAIT_NRDY; } } } STATIC VOID DwUsb3OsGetTrb ( IN usb3_pcd_t *pcd, IN usb3_pcd_ep_t *ep, IN usb3_pcd_req_t *req ) { // If EP0, fill request with EP0 IN/OUT data TRB if (ep == &pcd->ep0) { if (ep->is_in) { req->trb = pcd->ep0_in_desc; req->trbdma = (UINT64)pcd->ep0_in_desc; } else { req->trb = pcd->ep0_out_desc; req->trbdma = (UINT64)pcd->ep0_out_desc; } } else { // fill request with TRB from the non-EP0 allocation req->trb = ep->ep_desc; req->trbdma = (UINT64)ep->ep_desc; } } STATIC VOID DwUsb3EndPoint0StartTransfer ( IN usb3_pcd_t *pcd, IN usb3_pcd_req_t *req ) { usb3_pcd_ep_t *ep0 = &pcd->ep0; usb3_dma_desc_t *desc; UINT64 desc_dma; UINT32 desc_type, len; // get the DMA descriptor (TRB) for this request DwUsb3OsGetTrb (pcd, ep0, req); desc = req->trb; desc_dma = req->trbdma; if (ep0->is_in) { // start DMA on EP0 IN // DMA Descriptor (TRB) setup len = req->length; if (pcd->ep0state == EP0_IN_STATUS_PHASE) { if (ep0->three_stage) { desc_type = TRBCTL_STATUS_3; } else { desc_type = TRBCTL_STATUS_2; } } else { desc_type = TRBCTL_CTLDATA_1ST; } DwUsb3FillDesc ( desc, (UINT64)req->bufdma, len, 0, desc_type, DSCCTL_IOC | DSCCTL_ISP | DSCCTL_LST, 1 ); // issue DEPSTRTXFER command to EP0 IN ep0->tri_in = DwUsb3DepStartXfer (EP_IN_IDX (0), desc_dma, 0); } else { // start DMA on EP0 OUT // DMA Descriptor (TRB) setup len = ALIGN (req->length, ep0->maxpacket); if (pcd->ep0state == EP0_OUT_STATUS_PHASE) { if (ep0->three_stage) { desc_type = TRBCTL_STATUS_3; } else { desc_type = TRBCTL_STATUS_2; } } else { desc_type = TRBCTL_CTLDATA_1ST; } DwUsb3FillDesc ( desc, (UINT64)req->bufdma, len, 0, desc_type, DSCCTL_IOC | DSCCTL_ISP | DSCCTL_LST, 1 ); // issue DEPSTRTXFER command to EP0 OUT ep0->tri_out = DwUsb3DepStartXfer (EP_OUT_IDX (0), desc_dma, 0); } } STATIC INTN DwUsb3EndPointXStartTransfer ( IN usb3_pcd_t *pcd, IN usb3_pcd_ep_t *ep ) { usb3_pcd_req_t *req = &ep->req; usb3_dma_desc_t *desc; UINT64 desc_dma; UINT32 len; // get the TRB for this request DwUsb3OsGetTrb (pcd, ep, req); desc = req->trb; desc_dma = req->trbdma; if (ep->is_in) { // For IN, TRB length is just xfer length len = req->length; if (ep->xfer_started && !(desc->control & DSCCTL_HWO)) { DEBUG ((DEBUG_INFO, "[%a] last tx succ, but not in 10s!\n", __func__)); ep->xfer_started = 0; } } else { // For OUT, TRB length must be multiple of maxpacket // must be power of 2, use cheap AND len = (req->length + ep->maxpacket - 1) & ~(ep->maxpacket - 1); req->length = len; } // DMA descriptor setup DwUsb3FillDesc ( desc, (UINT64)req->bufdma, len, 0, TRBCTL_NORMAL, DSCCTL_IOC | DSCCTL_ISP | DSCCTL_LST, 1 ); if (ep->is_in) { // start DMA on EPn IN if (ep->xfer_started) { // issue DEPUPDTXFER command to EP DwUsb3DepUpdateXfer (EP_IN_IDX (ep->num), ep->tri_in); } else { ep->tri_in = DwUsb3DepStartXfer (EP_IN_IDX (ep->num), desc_dma, 0); ep->xfer_started = 1; } } else { // start DMA on EPn OUT if (ep->xfer_started) { // issue DEPUPDTXFER command to EP DwUsb3DepUpdateXfer (EP_OUT_IDX (ep->num), ep->tri_out); } else { ep->tri_out = DwUsb3DepStartXfer (EP_OUT_IDX (ep->num), desc_dma, 0); ep->xfer_started = 1; } } if (ep->is_in) { UINT32 count = 0; // wait until send complete while ((desc->control & DSCCTL_HWO) && (count < 1000000)) { MicroSecondDelay (10); count++; } if (count >= 1000000) { DEBUG ((DEBUG_INFO, "[%a]: ep%d transfer timeout!\n", __func__, ep->num)); DEBUG ((DEBUG_INFO, "please disconnect then connect USB cable again to recovery!\n")); return -1; } ep->xfer_started = 0; } return 0; } #if 0 STATIC VOID DwUsb3EndPointXStopTransfer ( IN usb3_pcd_t *pcd, IN usb3_pcd_ep_t *ep ) { if (ep->is_in) { DwUsb3DepStopXfer (EP_IN_IDX (ep->num), ep->tri_in); } else { DwUsb3DepStopXfer (EP_OUT_IDX (ep->num), ep->tri_out); } } #endif STATIC VOID SetupInStatusPhase ( IN usb3_pcd_t *pcd, IN VOID *buf ) { usb3_pcd_ep_t *ep0 = &pcd->ep0; if (pcd->ep0state == EP0_STALL) return; ep0->is_in = 1; pcd->ep0state = EP0_IN_STATUS_PHASE; pcd->ep0_req.bufdma = buf; pcd->ep0_req.length = 0; pcd->ep0_req.actual = 0; DwUsb3EndPoint0StartTransfer (pcd, &pcd->ep0_req); } STATIC VOID SetupOutStatusPhase ( IN usb3_pcd_t *pcd, IN VOID *buf ) { usb3_pcd_ep_t *ep0 = &pcd->ep0; if (pcd->ep0state == EP0_STALL) return; ep0->is_in = 0; pcd->ep0state = EP0_OUT_STATUS_PHASE; pcd->ep0_req.bufdma = buf; pcd->ep0_req.length = 0; pcd->ep0_req.actual = 0; DwUsb3EndPoint0StartTransfer (pcd, &pcd->ep0_req); } STATIC VOID DwUsb3HandleEndPoint0 ( IN usb3_pcd_t *pcd, IN usb3_pcd_req_t *req, IN UINT32 event ) { usb3_pcd_ep_t *ep0 = &pcd->ep0; usb3_dma_desc_t *desc; UINT32 byte_count, len; switch (pcd->ep0state) { case EP0_IN_DATA_PHASE: if (req == NULL) { req = &pcd->ep0_req; } desc = pcd->ep0_in_desc; if (desc->control & DSCCTL_HWO) { goto out; } if (GET_DSCSTS_TRBRSP (desc->status) == TRBRSP_SETUP_PEND) { // start of a new control transfer desc->status = 0; } byte_count = req->length - GET_DSCSTS_XFERCNT (desc->status); req->actual += byte_count; req->bufdma += byte_count; if (req->actual < req->length) { // IN CONTINUE, stall EP0 EndPoint0DoStall (pcd); } else if (ep0->send_zlp) { // CONTINUE TRANSFER IN ZLP EndPoint0ContinueTransfer (pcd, req); ep0->send_zlp = 0; } else { // COMPLETE IN TRANSFER EndPoint0CompleteRequest (pcd, req, desc); } break; case EP0_OUT_DATA_PHASE: if (req == NULL) { req = &pcd->ep0_req; } desc = pcd->ep0_out_desc; if (desc->control & DSCCTL_HWO) { goto out; } if (GET_DSCSTS_TRBRSP (desc->status) == TRBRSP_SETUP_PEND) { // start of a new control transfer desc->status = 0; } len = (req->length + ep0->maxpacket - 1) & ~(ep0->maxpacket - 1); byte_count = len - GET_DSCSTS_XFERCNT (desc->status); req->actual += byte_count; req->bufdma += byte_count; if (req->actual < req->length) { // IN CONTINUE, stall EP0 EndPoint0DoStall (pcd); } else if (ep0->send_zlp) { // CONTINUE TRANSFER IN ZLP EndPoint0ContinueTransfer (pcd, req); ep0->send_zlp = 0; } else { // COMPLETE IN TRANSFER EndPoint0CompleteRequest (pcd, req, desc); } break; #if 0 case EP0_IN_WAIT_NRDY: case EP0_OUT_WAIT_NRDY: if (ep0->is_in) { SetupInStatusPhase (pcd, gEndPoint0SetupPacket); } else { SetupOutStatusPhase (pcd, gEndPoint0SetupPacket); } break; case EP0_IN_STATUS_PHASE: case EP0_OUT_STATUS_PHASE: if (ep0->is_in) { desc = pcd->ep0_in_desc; } else { desc = pcd->ep0_out_desc; } //ASSERT (0); EndPoint0CompleteRequest (pcd, req, desc); // skip test mode pcd->ep0state = EP0_IDLE; ep0->stopped = 1; ep0->is_in = 0; // OUT for next SETUP // prepare for more SETUP packets DwUsb3Ep0OutStart (pcd); break; #else case EP0_IN_WAIT_NRDY: if (ep0->is_in) { SetupInStatusPhase (pcd, gEndPoint0SetupPacket); } else { ASSERT (0); } break; case EP0_OUT_WAIT_NRDY: if (!ep0->is_in) { SetupOutStatusPhase (pcd, gEndPoint0SetupPacket); } else { ASSERT (0); } break; case EP0_IN_STATUS_PHASE: if (ep0->is_in) { desc = pcd->ep0_in_desc; } else { ASSERT (0); } EndPoint0CompleteRequest (pcd, req, desc); pcd->ep0state = EP0_IDLE; ep0->stopped = 1; ep0->is_in = 0; // OUT for next SETUP // prepare for more SETUP packets DwUsb3Ep0OutStart (pcd); break; case EP0_OUT_STATUS_PHASE: if (!ep0->is_in) { desc = pcd->ep0_out_desc; } else { ASSERT (0); } EndPoint0CompleteRequest (pcd, req, desc); pcd->ep0state = EP0_IDLE; ep0->stopped = 1; ep0->is_in = 0; // OUT for next SETUP // prepare for more SETUP packets DwUsb3Ep0OutStart (pcd); break; #endif case EP0_STALL: break; case EP0_IDLE: break; default: DEBUG ((DEBUG_ERROR, "%a: invalid state %d\n", __func__, pcd->ep0state)); break; } out: return; } STATIC usb3_pcd_ep_t * Addr2EndPoint ( IN usb3_pcd_t *pcd, IN UINT16 index ) { UINT32 ep_num; ep_num = UE_GET_ADDR (index); if (ep_num == 0) { return &pcd->ep0; } else { if (UE_GET_DIR (index) == UE_DIR_IN) { return &pcd->in_ep; } return &pcd->out_ep; } } STATIC VOID DwUsb3DoGetStatus ( IN usb3_pcd_t *pcd ) { usb_device_request_t *ctrl = &gEndPoint0SetupPacket->req; UINT8 *status = gEndPoint0StatusBuf; usb3_pcd_ep_t *ep; if (ctrl->wLength != 2) { EndPoint0DoStall (pcd); return; } switch (UT_GET_RECIPIENT (ctrl->bmRequestType)) { case UT_DEVICE: *status = 0; // bus powered if (pcd->speed == USB_SPEED_SUPER) { if (pcd->state == USB3_STATE_CONFIGURED) { if (MmioRead32 (DCTL) & DCTL_INIT_U1_EN) { *status |= 1 << 2; } if (MmioRead32 (DCTL) & DCTL_INIT_U2_EN) { *status |= 1 << 3; } *status |= (UINT8)(pcd->ltm_enable << 4); } } *(status + 1) = 0; break; case UT_INTERFACE: *status = 0; *(status + 1) = 0; break; case UT_ENDPOINT: ep = Addr2EndPoint (pcd, ctrl->wIndex); *status = ep->stopped; *(status + 1) = 0; break; default: EndPoint0DoStall (pcd); return; } pcd->ep0_req.bufdma = (UINT64 *)status; pcd->ep0_req.length = 2; pcd->ep0_req.actual = 0; DwUsb3EndPoint0StartTransfer (pcd, &pcd->ep0_req); } STATIC VOID DoClearHalt ( IN usb3_pcd_t *pcd, IN usb3_pcd_ep_t *ep ) { if (ep->is_in) { DwUsb3DepClearStall (EP_IN_IDX (ep->num)); } else { DwUsb3DepClearStall (EP_OUT_IDX (ep->num)); } if (ep->stopped) { ep->stopped = 0; } } STATIC VOID Usb3PcdEpEnable ( IN usb3_pcd_t *pcd, IN usb3_pcd_ep_t *ep ) { // activate the EP ep->stopped = 0; ep->xfer_started = 0; ep->ep_desc->control = 0; ep->ep_desc->status = 0; // set initial data pid. if (ep->type == EPTYPE_BULK) { ep->data_pid_start = 0; } DwUsb3EpActivate (pcd, ep); } STATIC VOID DwUsb3DoClearFeature ( IN usb3_pcd_t *pcd ) { usb_device_request_t *ctrl = &gEndPoint0SetupPacket->req; usb3_pcd_ep_t *ep; switch (UT_GET_RECIPIENT (ctrl->bmRequestType)) { case UT_DEVICE: switch (ctrl->wValue) { case UF_U1_ENABLE: if ((pcd->speed != USB_SPEED_SUPER) || (pcd->state != USB3_STATE_CONFIGURED)) { EndPoint0DoStall (pcd); return; } MmioAnd32 (DCTL, ~DCTL_INIT_U1_EN); break; case UF_U2_ENABLE: if ((pcd->speed != USB_SPEED_SUPER) || (pcd->state != USB3_STATE_CONFIGURED)) { EndPoint0DoStall (pcd); return; } MmioAnd32 (DCTL, ~DCTL_INIT_U2_EN); break; case UF_LTM_ENABLE: if ((pcd->speed != USB_SPEED_SUPER) || (pcd->state != USB3_STATE_CONFIGURED) || (ctrl->wIndex != 0)) { EndPoint0DoStall (pcd); return; } pcd->ltm_enable = 0; break; default: EndPoint0DoStall (pcd); return; } break; case UT_INTERFACE: // if FUNCTION_SUSPEND if (ctrl->wValue) { EndPoint0DoStall (pcd); return; } break; case UT_ENDPOINT: ep = Addr2EndPoint (pcd, ctrl->wIndex); if (ctrl->wValue != UF_ENDPOINT_HALT) { EndPoint0DoStall (pcd); return; } DoClearHalt (pcd, ep); break; default: DEBUG ((DEBUG_ERROR, "invalid bmRequestType :%d\n", UT_GET_RECIPIENT (ctrl->bmRequestType))); break; } pcd->ep0.is_in = 1; pcd->ep0state = EP0_IN_WAIT_NRDY; } STATIC VOID DwUsb3DoSetFeature ( IN usb3_pcd_t *pcd ) { usb_device_request_t *ctrl = &gEndPoint0SetupPacket->req; usb3_pcd_ep_t *ep; switch (UT_GET_RECIPIENT (ctrl->bmRequestType)) { case UT_DEVICE: switch (ctrl->wValue) { case UF_DEVICE_REMOTE_WAKEUP: break; case UF_TEST_MODE: pcd->test_mode_nr = ctrl->wIndex >> 8; pcd->test_mode = 1; break; case UF_U1_ENABLE: if ((pcd->speed != USB_SPEED_SUPER) || (pcd->state != USB3_STATE_CONFIGURED)) { EndPoint0DoStall (pcd); return; } MmioOr32 (DCTL, DCTL_INIT_U1_EN); break; case UF_U2_ENABLE: if ((pcd->speed != USB_SPEED_SUPER) || (pcd->state != USB3_STATE_CONFIGURED)) { EndPoint0DoStall (pcd); return; } MmioOr32 (DCTL, DCTL_INIT_U2_EN); break; case UF_LTM_ENABLE: if ((pcd->speed != USB_SPEED_SUPER) || (pcd->state != USB3_STATE_CONFIGURED) || (ctrl->wIndex != 0)) { EndPoint0DoStall (pcd); return; } pcd->ltm_enable = 1; break; default: EndPoint0DoStall (pcd); return; } break; case UT_INTERFACE: // if FUNCTION_SUSPEND if (ctrl->wValue) { EndPoint0DoStall (pcd); return; } break; case UT_ENDPOINT: ep = Addr2EndPoint (pcd, ctrl->wIndex); if (ctrl->wValue != UF_ENDPOINT_HALT) { EndPoint0DoStall (pcd); return; } ep->stopped = 1; if (ep->is_in) { DwUsb3DepClearStall (EP_IN_IDX (ep->num)); } else { DwUsb3DepClearStall (EP_OUT_IDX (ep->num)); } break; default: DEBUG ((DEBUG_ERROR, "invalid bmRequestType %d\n", UT_GET_RECIPIENT (ctrl->bmRequestType))); break; } pcd->ep0.is_in = 1; pcd->ep0state = EP0_IN_WAIT_NRDY; } STATIC VOID DwUsb3DoSetAddress ( IN usb3_pcd_t *pcd ) { usb_device_request_t *ctrl = &gEndPoint0SetupPacket->req; if (ctrl->bmRequestType == UT_DEVICE) { SET_DEVADDR (ctrl->wValue); pcd->ep0.is_in = 1; pcd->ep0state = EP0_IN_WAIT_NRDY; if (ctrl->wValue) { pcd->state = USB3_STATE_ADDRESSED; } else { pcd->state = USB3_STATE_DEFAULT; } } } #if 0 STATIC UINTN UsbStatus ( IN UINTN online, IN UINTN speed ) { if (online) { } VOID DwUsb3SetConfig ( IN usb3_pcd_t *pcd ) { usb_device_request_t *ctrl = &gEndPoint0SetupPacket->req; UINT16 wvalue = ctrl->wValue; usb3_pcd_ep_t *ep; DEBUG ((DEBUG_ERROR, "#%a, %d, wvalue:0x%x\n", __func__, __LINE__, wvalue)); if (ctrl->bmRequestType != (UT_WRITE | UT_STANDARD | UT_DEVICE)) { EndPoint0DoStall (pcd); return; } if (!wvalue || (wvalue == CONFIG_VALUE)) { UINT32 speed; pcd->new_config = (UINT8)wvalue; // set new configuration if (wvalue) { // activate bulk in endpoint ep = &pcd->in_ep; Usb3PcdEpEnable (pcd, ep); // activate bulk out endpoint ep = &pcd->out_ep; Usb3PcdEpEnable (pcd, ep); // prepare for next bulk transfer speed = DwUsb3GetDeviceSpeed (pcd); (VOID)speed; #if 0 if (g_usb_ops->status) { g_usb_ops->status (ctrl->wValue ? 1 : 0, speed == USB_SPEED_SUPER ? USB_SS : speed == USB_SPEED_HIGH ? USB_HS : USB_FS); } usb_status (); #endif pcd->state = USB3_STATE_CONFIGURED; } else { pcd->state = USB3_STATE_ADDRESSED; } DEBUG ((DEBUG_ERROR, "#%a, %d, state:%d\n", __func__, __LINE__, pcd->state)); pcd->ep0.is_in = 1; pcd->ep0state = EP0_IN_WAIT_NRDY; } else { EndPoint0DoStall (pcd); } } #endif STATIC VOID DwUsb3DoGetConfig ( IN usb3_pcd_t *pcd ) { usb_device_request_t *ctrl = &gEndPoint0SetupPacket->req; UINT8 *status = gEndPoint0StatusBuf; if (ctrl->bmRequestType != (UT_READ | UT_STANDARD | UT_DEVICE)) { EndPoint0DoStall (pcd); return; } // Notify host the current config value *status = pcd->new_config; pcd->ep0_req.bufdma = (UINT64 *)status; pcd->ep0_req.length = 1; pcd->ep0_req.actual = 0; DwUsb3EndPoint0StartTransfer (pcd, &pcd->ep0_req); } STATIC VOID DwUsb3DoSetConfig ( IN usb3_pcd_t *pcd ) { usb_device_request_t *ctrl = &gEndPoint0SetupPacket->req; UINT16 wvalue = ctrl->wValue; usb3_pcd_ep_t *ep; if (ctrl->bmRequestType != (UT_WRITE | UT_STANDARD | UT_DEVICE)) { EndPoint0DoStall (pcd); return; } if (!wvalue || (wvalue == CONFIG_VALUE)) { //UINT32 speed; pcd->new_config = (UINT8)wvalue; // set new configuration if (wvalue) { // activate bulk in endpoint ep = &pcd->in_ep; Usb3PcdEpEnable (pcd, ep); // activate bulk out endpoint ep = &pcd->out_ep; Usb3PcdEpEnable (pcd, ep); #if 0 // prepare for next bulk transfer speed = DwUsb3GetDeviceSpeed (pcd); (VOID)speed; g_usb_ops->status #endif pcd->state = USB3_STATE_CONFIGURED; { // prepare for EP1 OUT usb3_pcd_ep_t *ep = &pcd->out_ep; usb3_pcd_req_t *req = &ep->req; // AndroidFast App will free the rx buffer. gRxBuf = AllocatePool (DATA_SIZE); ASSERT (gRxBuf != NULL); WriteBackDataCacheRange (gRxBuf, DATA_SIZE); req->bufdma = (UINT64 *)gRxBuf; if (mDataBufferSize == 0) { req->length = CMD_SIZE; } else if (mDataBufferSize > DATA_SIZE) { req->length = DATA_SIZE; mDataBufferSize = mDataBufferSize - DATA_SIZE; } else if (mDataBufferSize > CMD_SIZE) { req->length = CMD_SIZE; mDataBufferSize = mDataBufferSize - CMD_SIZE; } else { req->length = mDataBufferSize; mDataBufferSize = 0; } DwUsb3EndPointXStartTransfer (pcd, ep); } } else { pcd->state = USB3_STATE_ADDRESSED; } pcd->ep0.is_in = 1; pcd->ep0state = EP0_IN_WAIT_NRDY; } else { EndPoint0DoStall (pcd); } } STATIC VOID DwUsb3DoGetDescriptor ( IN usb3_pcd_t *pcd ) { usb_device_request_t *ctrl = &gEndPoint0SetupPacket->req; UINT8 dt = ctrl->wValue >> 8; UINT8 index = (UINT8)ctrl->wValue; UINT16 len = ctrl->wLength; UINT8 *buf = gEndPoint0StatusBuf; UINT16 value = 0; EFI_USB_STRING_DESCRIPTOR *Descriptor = NULL; if (ctrl->bmRequestType != (UT_READ | UT_STANDARD | UT_DEVICE)) { EndPoint0DoStall (pcd); return; } switch (dt) { case UDESC_DEVICE: { struct usb_device_descriptor *dev = &gDwUsb3DevDesc; dev->bLength = sizeof (struct usb_device_descriptor); dev->bDescriptorType = UDESC_DEVICE; dev->bDeviceClass = 0; dev->bDeviceSubClass = 0; dev->bDeviceProtocol = 0; if (pcd->speed == USB_SPEED_SUPER) { dev->bcdUSB = 0x300; // 2^9 = 512 dev->bMaxPacketSize0 = 9; } else { dev->bcdUSB = 0x0200; dev->bMaxPacketSize0 = 0x40; } dev->idVendor = usb_port_activity_config.idVendor; dev->idProduct = usb_port_activity_config.idProduct; dev->bcdDevice = 0x0100; dev->iManufacturer = STRING_MANUFACTURER; dev->iProduct = STRING_PRODUCT; dev->iSerialNumber = STRING_SERIAL; dev->bNumConfigurations = 1; value = sizeof (struct usb_device_descriptor); CopyMem ((void *)buf, (void *)dev, value); } break; case UDESC_DEVICE_QUALIFIER: { struct usb_qualifier_descriptor *qual = (struct usb_qualifier_descriptor *)buf; struct usb_device_descriptor *dev = &gDwUsb3DevDesc; qual->bLength = sizeof (*qual); qual->bDescriptorType = UDESC_DEVICE_QUALIFIER; qual->bcdUSB = dev->bcdUSB; qual->bDeviceClass = dev->bDeviceClass; qual->bDeviceSubClass = dev->bDeviceSubClass; qual->bDeviceProtocol = dev->bDeviceProtocol; qual->bMaxPacketSize0 = dev->bMaxPacketSize0; qual->bNumConfigurations = 1; qual->bRESERVED = 0; value = sizeof (struct usb_qualifier_descriptor); } break; case UDESC_CONFIG: { struct usb_config_descriptor *config = (struct usb_config_descriptor *)buf; config->bLength = sizeof (*config); config->bDescriptorType = UDESC_CONFIG; config->bNumInterfaces = 1; config->bConfigurationValue = 1; config->iConfiguration = 0; config->bmAttributes = USB_CONFIG_ATT_ONE; if (pcd->speed == USB_SPEED_SUPER) { config->bMaxPower = 0x50; } else { config->bMaxPower = 0x80; } buf += sizeof (*config); intf.bInterfaceSubClass = usb_port_activity_config.bInterfaceSubClass; intf.bInterfaceProtocol = usb_port_activity_config.bInterfaceProtocol; CopyMem ((void *)buf, (void *)&intf, sizeof (intf)); buf += sizeof (intf); switch (pcd->speed) { case USB_SPEED_SUPER: CopyMem (buf, &ss_bulk_in, sizeof (ss_bulk_in)); buf += sizeof (ss_bulk_in); CopyMem (buf, &ep_comp, sizeof (ep_comp)); buf += sizeof (ep_comp); CopyMem (buf, &ss_bulk_out, sizeof (ss_bulk_out)); buf += sizeof (ss_bulk_out); CopyMem (buf, &ep_comp, sizeof (ep_comp)); config->wTotalLength = sizeof (*config) + sizeof (intf) + sizeof (ss_bulk_in) + sizeof (ep_comp) + sizeof (ss_bulk_out) + sizeof (ep_comp); break; default: // HS/FS { struct usb_endpoint_descriptor *endp = (struct usb_endpoint_descriptor *)buf; CopyMem (buf, &hs_bulk_in, sizeof (hs_bulk_in)); (endp++)->wMaxPacketSize = pcd->in_ep.maxpacket; buf += sizeof (hs_bulk_in); CopyMem (buf, &hs_bulk_out, sizeof (hs_bulk_out)); endp->wMaxPacketSize = pcd->out_ep.maxpacket; config->wTotalLength = sizeof (*config) + sizeof (intf) + sizeof (hs_bulk_in) + sizeof (hs_bulk_out); break; } } value = config->wTotalLength; } break; case UDESC_STRING: { switch (index) { case STRING_LANGUAGE: Descriptor = (EFI_USB_STRING_DESCRIPTOR *)(UINTN)gEndPoint0StatusBuf; ASSERT (Descriptor != NULL); Descriptor->Length = LANG_LENGTH * sizeof (CHAR16); Descriptor->DescriptorType = USB_DESC_TYPE_STRING; DwUsb->GetLang (Descriptor->String, &Descriptor->Length); value = Descriptor->Length; break; case STRING_MANUFACTURER: Descriptor = (EFI_USB_STRING_DESCRIPTOR *)(UINTN)gEndPoint0StatusBuf; ASSERT (Descriptor != NULL); Descriptor->Length = MANU_FACTURER_STRING_LENGTH * sizeof (CHAR16); Descriptor->DescriptorType = USB_DESC_TYPE_STRING; DwUsb->GetManuFacturer (Descriptor->String, &Descriptor->Length); value = Descriptor->Length; break; case STRING_PRODUCT: Descriptor = (EFI_USB_STRING_DESCRIPTOR *)(UINTN)gEndPoint0StatusBuf; ASSERT (Descriptor != NULL); Descriptor->Length = PRODUCT_STRING_LENGTH * sizeof (CHAR16); Descriptor->DescriptorType = USB_DESC_TYPE_STRING; DwUsb->GetProduct (Descriptor->String, &Descriptor->Length); value = Descriptor->Length; break; case STRING_SERIAL: Descriptor = (EFI_USB_STRING_DESCRIPTOR *)(UINTN)gEndPoint0StatusBuf; ASSERT (Descriptor != NULL); Descriptor->Length = SERIAL_STRING_LENGTH * sizeof (CHAR16); Descriptor->DescriptorType = USB_DESC_TYPE_STRING; DwUsb->GetSerialNo (Descriptor->String, &Descriptor->Length); value = Descriptor->Length; break; default: EndPoint0DoStall (pcd); break; } } break; case UDESC_BOS: if (pcd->speed != USB_SPEED_SUPER) { EndPoint0DoStall (pcd); return; } value = bos.wTotalLength; CopyMem (buf, &bos, sizeof (bos)); buf += sizeof (bos); CopyMem (buf, &cap1, sizeof (cap1)); buf += sizeof (cap1); CopyMem (buf, &cap2, sizeof (cap2)); buf += sizeof (cap2); CopyMem (buf, &cap3, sizeof (cap3)); break; default: EndPoint0DoStall (pcd); return; } pcd->ep0_req.bufdma = (UINT64 *)gEndPoint0StatusBuf; pcd->ep0_req.length = value < len ? value : len; pcd->ep0_req.actual = 0; DwUsb3EndPoint0StartTransfer (pcd, &pcd->ep0_req); } STATIC VOID DwUsb3DoSetup ( IN usb3_pcd_t *pcd ) { usb_device_request_t *ctrl = &gEndPoint0SetupPacket->req; usb3_pcd_ep_t *ep0 = &pcd->ep0; UINT16 wLength; wLength = ctrl->wLength; ep0->stopped = 0; ep0->three_stage = 1; if (ctrl->bmRequestType & UE_DIR_IN) { ep0->is_in = 1; pcd->ep0state = EP0_IN_DATA_PHASE; } else { ep0->is_in = 0; pcd->ep0state = EP0_OUT_DATA_PHASE; } if (wLength == 0) { ep0->is_in = 1; pcd->ep0state = EP0_IN_WAIT_NRDY; ep0->three_stage = 0; } if (UT_GET_TYPE (ctrl->bmRequestType) != UT_STANDARD) { EndPoint0DoStall (pcd); return; } switch (ctrl->bRequest) { case UR_GET_STATUS: DwUsb3DoGetStatus (pcd); break; case UR_CLEAR_FEATURE: DwUsb3DoClearFeature (pcd); break; case UR_SET_FEATURE: DwUsb3DoSetFeature (pcd); break; case UR_SET_ADDRESS: DwUsb3DoSetAddress (pcd); break; case UR_SET_CONFIG: DwUsb3DoSetConfig (pcd); MmioOr32 (DCTL, DCTL_ACCEPT_U1_EN); MmioOr32 (DCTL, DCTL_ACCEPT_U2_EN); DEBUG ((DEBUG_INFO, "enum done")); pcd->ltm_enable = 0; break; case UR_GET_CONFIG: DwUsb3DoGetConfig (pcd); break; case UR_GET_DESCRIPTOR: DwUsb3DoGetDescriptor (pcd); break; case UR_SET_SEL: // for now this is a no-op pcd->ep0_req.bufdma = (UINT64 *)gEndPoint0StatusBuf; pcd->ep0_req.length = USB3_STATUS_BUF_SIZE; pcd->ep0_req.actual = 0; ep0->send_zlp = 0; DwUsb3EndPoint0StartTransfer (pcd, &pcd->ep0_req); break; default: EndPoint0DoStall (pcd); break; } } STATIC VOID DwUsb3OsHandleEndPoint0 ( IN usb3_pcd_t *pcd, IN UINT32 event ) { if (pcd->ep0state == EP0_IDLE) { DwUsb3DoSetup (pcd); } else { DwUsb3HandleEndPoint0 (pcd, NULL, event); } } STATIC VOID DwUsb3RequestDone ( IN usb3_pcd_t *pcd, IN usb3_pcd_ep_t *ep, IN usb3_pcd_req_t *req, IN UINTN status ) { if (ep != &pcd->ep0) { req->trb = NULL; } if (req->complete) { req->complete (req->actual, status); } else { if (!ep->is_in) { ASSERT (req->actual <= req->length); InvalidateDataCacheRange (gRxBuf, req->actual); mDataReceivedCallback (req->actual, gRxBuf); } } req->actual = 0; } STATIC VOID DwUsb3EndPointcompleteRequest ( IN usb3_pcd_t *pcd, IN usb3_pcd_ep_t *ep, IN UINT32 event ) { usb3_pcd_req_t *req = &ep->req; usb3_dma_desc_t *desc = req->trb; UINT32 byte_count; ep->send_zlp = 0; if (!desc) { return; } if (desc->control & DSCCTL_HWO) { return; } if (ep->is_in) { // IN ep if (GET_DSCSTS_XFERCNT (desc->status) == 0) { req->actual += req->length; } // reset IN tri ep->tri_in = 0; // complete the IN request // flush for dma? DwUsb3RequestDone (pcd, ep, req, 0); } else { // OUT ep byte_count = req->length - GET_DSCSTS_XFERCNT (desc->status); req->actual += byte_count; //req->bufdma += byte_count; // reset OUT tri ep->tri_out = 0; // OUT transfer complete or not // complete the OUT request // FIXME flush dma? DwUsb3RequestDone (pcd, ep, req, 0); { // prepare for EP1 OUT usb3_pcd_ep_t *ep = &pcd->out_ep; usb3_pcd_req_t *req = &ep->req; ZeroMem (req, sizeof (usb3_pcd_req_t)); gRxBuf = AllocatePool (DATA_SIZE); ASSERT (gRxBuf != NULL); WriteBackDataCacheRange (gRxBuf, DATA_SIZE); req->bufdma = (UINT64 *)gRxBuf; if (mDataBufferSize == 0) { req->length = CMD_SIZE; } else if (mDataBufferSize > DATA_SIZE) { req->length = DATA_SIZE; mDataBufferSize = mDataBufferSize - DATA_SIZE; } else if (mDataBufferSize > CMD_SIZE) { req->length = CMD_SIZE; mDataBufferSize = mDataBufferSize - CMD_SIZE; } else { req->length = mDataBufferSize; mDataBufferSize = 0; } DwUsb3EndPointXStartTransfer (pcd, ep); } } } STATIC VOID DwUsb3HandleEndPointInterrupt ( IN usb3_pcd_t *pcd, IN UINTN PhySep, IN UINT32 event ) { usb3_pcd_ep_t *ep; UINT32 epnum, is_in; // Physical Out EPs are even, physical In EPs are odd is_in = (UINT32)PhySep & 1; epnum = ((UINT32)PhySep >> 1) & 0xF; // Get the EP pointer if (is_in) { ep = DwUsb3GetInEndPoint (pcd, epnum); } else { ep = DwUsb3GetOutEndPoint (pcd, epnum); } switch (event & GEVNT_DEPEVT_INTTYPE_MASK) { case GEVNT_DEPEVT_INTTYPE_XFER_CMPL: ep->xfer_started = 0; // complete the transfer if (epnum == 0) { DwUsb3OsHandleEndPoint0 (pcd, event); } else { DwUsb3EndPointcompleteRequest (pcd, ep, event); } break; case GEVNT_DEPEVT_INTTYPE_XFER_IN_PROG: break; case GEVNT_DEPEVT_INTTYPE_XFER_NRDY: if (epnum == 0) { switch (pcd->ep0state) { #if 1 case EP0_IN_WAIT_NRDY: if (is_in) { DwUsb3OsHandleEndPoint0 (pcd, event); } else { } break; case EP0_OUT_WAIT_NRDY: if (!is_in) { DwUsb3OsHandleEndPoint0 (pcd, event); } else { } break; #else case EP0_IN_WAIT_NRDY: case EP0_OUT_WAIT_NRDY: DwUsb3OsHandleEndPoint0 (pcd, event); break; #endif default: break; } } else { } break; default: DEBUG ((DEBUG_ERROR, "invalid event %d\n", event & GEVNT_DEPEVT_INTTYPE_MASK)); break; } } STATIC UINTN DwUsb3HandleEvent ( VOID ) { usb3_pcd_t *pcd = &gPcd; UINT32 Count, Index, Event, Intr; UINT32 PhySep; Count = GET_EVENTBUF_COUNT (); // reset event buffer when it's full if ((GEVNTCOUNT_EVNTCOUNT (Count) == GEVNTCOUNT_EVNTCOUNT_MASK) || (Count >= DWUSB3_EVENT_BUF_SIZE * sizeof (UINT32))) { UPDATE_EVENTBUF_COUNT (Count); Count = 0; } for (Index = 0; Index < Count; Index += sizeof (UINT32)) { Event = DwUsb3GetEventBufEvent (DWUSB3_EVENT_BUF_SIZE << 2); UPDATE_EVENTBUF_COUNT (sizeof (UINT32)); if (Event == 0) { // ignore null events continue; } if (Event & GEVNT_NON_EP) { Intr = Event & GEVNT_INTTYPE_MASK; if (Intr == GEVNT_INTTYPE (EVENT_DEV_INT)) { DwUsb3HandleDeviceInterrupt (pcd, Event); } } else { PhySep = (Event & GEVNT_DEPEVT_EPNUM_MASK) >> GEVNT_DEPEVT_EPNUM_SHIFT; DwUsb3HandleEndPointInterrupt (pcd, PhySep, Event); } } return 0; } STATIC VOID DwUsb3Poll ( IN EFI_EVENT Event, IN VOID *Context ) { if (DwUsb3HandleEvent ()) { DEBUG ((DEBUG_ERROR, "error: exit from usb_poll\n")); return; } } EFI_STATUS EFIAPI DwUsb3Start ( IN USB_DEVICE_DESCRIPTOR *DeviceDescriptor, IN VOID **Descriptors, IN USB_DEVICE_RX_CALLBACK RxCallback, IN USB_DEVICE_TX_CALLBACK TxCallback ) { EFI_STATUS Status; EFI_EVENT TimerEvent; //gEventBuf = UncachedAllocateAlignedZeroPool (DWUSB3_EVENT_BUF_SIZE << 2, 256); gEventBuf = UncachedAllocatePages (EFI_SIZE_TO_PAGES (DWUSB3_EVENT_BUF_SIZE << 2)); if (gEventBuf == NULL) { return EFI_OUT_OF_RESOURCES; } ZeroMem (gEventBuf, EFI_SIZE_TO_PAGES (DWUSB3_EVENT_BUF_SIZE << 2)); gEventPtr = gEventBuf; DriverInit (); DwUsb3Init (); Status = gBS->CreateEvent ( EVT_TIMER | EVT_NOTIFY_SIGNAL, TPL_CALLBACK, DwUsb3Poll, NULL, &TimerEvent ); ASSERT_EFI_ERROR (Status); if (EFI_ERROR (Status)) { return Status; } Status = gBS->SetTimer ( TimerEvent, TimerPeriodic, DW_INTERRUPT_POLL_PERIOD ); ASSERT_EFI_ERROR (Status); mDataReceivedCallback = RxCallback; return Status; } EFI_STATUS DwUsb3Send ( IN UINT8 EndpointIndex, IN UINTN Size, IN CONST VOID *Buffer ) { usb3_pcd_t *pcd = &gPcd; usb3_pcd_ep_t *ep = &pcd->in_ep; usb3_pcd_req_t *req = &ep->req; WriteBackDataCacheRange ((VOID *)Buffer, Size); req->bufdma = (UINT64 *)Buffer; req->length = Size; DwUsb3EndPointXStartTransfer (pcd, ep); return EFI_SUCCESS; } EFI_STATUS DwUsb3Request ( IN UINTN BufferSize ) { if (BufferSize) { mDataBufferSize = BufferSize; } return EFI_SUCCESS; } USB_DEVICE_PROTOCOL mUsbDevice = { DwUsb3Start, DwUsb3Send, DwUsb3Request }; EFI_STATUS EFIAPI DwUsb3EntryPoint ( IN EFI_HANDLE ImageHandle, IN EFI_SYSTEM_TABLE *SystemTable ) { EFI_STATUS Status; gEndPoint0SetupPacket = UncachedAllocatePages (EFI_SIZE_TO_PAGES (sizeof (usb_setup_pkt_t) * 5)); if (gEndPoint0SetupPacket == NULL) { return EFI_OUT_OF_RESOURCES; } gEndPoint0StatusBuf = UncachedAllocatePages (EFI_SIZE_TO_PAGES (USB3_STATUS_BUF_SIZE * sizeof (UINT8))); if (gEndPoint0StatusBuf == NULL) { return EFI_OUT_OF_RESOURCES; } #if 0 gRxBuf = UncachedAllocatePages (1); if (gRxBuf == NULL) { return EFI_OUT_OF_RESOURCES; } #endif Status = gBS->LocateProtocol (&gDwUsbProtocolGuid, NULL, (VOID **) &DwUsb); if (EFI_ERROR (Status)) { return Status; } Status = DwUsb->PhyInit(USB_DEVICE_MODE); if (EFI_ERROR (Status)) { return Status; } return gBS->InstallProtocolInterface ( &ImageHandle, &gUsbDeviceProtocolGuid, EFI_NATIVE_INTERFACE, &mUsbDevice ); }