/** @file Copyright (c) 2015-2016, Linaro Limited. All rights reserved. Copyright (c) 2015-2016, Hisilicon 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 #include #include #include #include #include #include #include #include #include #include #include #include #include #include "DwUsbDxe.h" EFI_GUID gDwUsbProtocolGuid = DW_USB_PROTOCOL_GUID; STATIC dwc_otg_dev_dma_desc_t *g_dma_desc,*g_dma_desc_ep0,*g_dma_desc_in; STATIC USB_DEVICE_REQUEST *p_ctrlreq; STATIC VOID *rx_buf; STATIC UINTN rx_desc_bytes = 0; STATIC UINTN mNumDataBytes; STATIC DW_USB_PROTOCOL *DwUsb; #define USB_TYPE_LENGTH 16 #define USB_BLOCK_HIGH_SPEED_SIZE 512 #define DATA_SIZE 32768 #define CMD_SIZE 512 #define MATCH_CMD_LITERAL(Cmd, Buf) !AsciiStrnCmp (Cmd, Buf, sizeof (Cmd) - 1) STATIC USB_DEVICE_DESCRIPTOR *mDeviceDescriptor; // The config descriptor, interface descriptor, and endpoint descriptors in a // buffer (in that order) STATIC VOID *mDescriptors; // Convenience pointers to those descriptors inside the buffer: STATIC USB_INTERFACE_DESCRIPTOR *mInterfaceDescriptor; STATIC USB_CONFIG_DESCRIPTOR *mConfigDescriptor; STATIC USB_ENDPOINT_DESCRIPTOR *mEndpointDescriptors; STATIC USB_DEVICE_RX_CALLBACK mDataReceivedCallback; STATIC USB_DEVICE_TX_CALLBACK mDataSentCallback; STATIC EFI_USB_STRING_DESCRIPTOR *mLangStringDescriptor; STATIC EFI_USB_STRING_DESCRIPTOR *mManufacturerStringDescriptor; STATIC EFI_USB_STRING_DESCRIPTOR *mProductStringDescriptor; STATIC EFI_USB_STRING_DESCRIPTOR *mSerialStringDescriptor; STATIC CHAR16 mLangString[] = { 0x409 }; STATIC CHAR16 mManufacturerString[] = { '9', '6', 'B', 'o', 'a', 'r', 'd', 's' }; STATIC CHAR16 mProductString[] = { 'H', 'i', 'K', 'e', 'y' }; STATIC CHAR16 mSerialString[] = { '0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F' }; // The time between interrupt polls, in units of 100 nanoseconds // 10 Microseconds #define DW_INTERRUPT_POLL_PERIOD 10000 STATIC int usb_drv_port_speed(void) /*To detect which mode was run, high speed or full speed*/ { /* * 2'b00: High speed (PHY clock is running at 30 or 60 MHz) */ UINT32 val = READ_REG32(DSTS) & 2; return (!val); } STATIC VOID reset_endpoints(void) { /* EP0 IN ACTIVE NEXT=1 */ WRITE_REG32(DIEPCTL0, 0x8800); /* EP0 OUT ACTIVE */ WRITE_REG32(DOEPCTL0, 0x8000); /* Clear any pending OTG Interrupts */ WRITE_REG32(GOTGINT, 0xFFFFFFFF); /* Clear any pending interrupts */ WRITE_REG32(GINTSTS, 0xFFFFFFFF); WRITE_REG32(DIEPINT0, 0xFFFFFFFF); WRITE_REG32(DOEPINT0, 0xFFFFFFFF); WRITE_REG32(DIEPINT1, 0xFFFFFFFF); WRITE_REG32(DOEPINT1, 0xFFFFFFFF); /* IN EP interrupt mask */ WRITE_REG32(DIEPMSK, 0x0D); /* OUT EP interrupt mask */ WRITE_REG32(DOEPMSK, 0x0D); /* Enable interrupts on Ep0 */ WRITE_REG32(DAINTMSK, 0x00010001); /* EP0 OUT Transfer Size:64 Bytes, 1 Packet, 3 Setup Packet, Read to receive setup packet*/ WRITE_REG32(DOEPTSIZ0, 0x60080040); //notes that:the compulsive conversion is expectable. g_dma_desc_ep0->status.b.bs = 0x3; g_dma_desc_ep0->status.b.mtrf = 0; g_dma_desc_ep0->status.b.sr = 0; g_dma_desc_ep0->status.b.l = 1; g_dma_desc_ep0->status.b.ioc = 1; g_dma_desc_ep0->status.b.sp = 0; g_dma_desc_ep0->status.b.bytes = 64; g_dma_desc_ep0->buf = (UINT32)(UINTN)(p_ctrlreq); g_dma_desc_ep0->status.b.sts = 0; g_dma_desc_ep0->status.b.bs = 0x0; WRITE_REG32(DOEPDMA0, (unsigned long)(g_dma_desc_ep0)); /* EP0 OUT ENABLE CLEARNAK */ WRITE_REG32(DOEPCTL0, (READ_REG32(DOEPCTL0) | 0x84000000)); } STATIC VOID ep_tx(IN UINT8 ep, CONST VOID *ptr, UINTN len) { UINT32 blocksize; UINT32 packets; /* EPx OUT ACTIVE */ WRITE_REG32(DIEPCTL(ep), (READ_REG32(DIEPCTL(ep))) | 0x8000); if(!ep) { blocksize = 64; } else { blocksize = usb_drv_port_speed() ? USB_BLOCK_HIGH_SPEED_SIZE : 64; } packets = (len + blocksize - 1) / blocksize; if (!len) { //send a null packet /* one empty packet */ g_dma_desc_in->status.b.bs = 0x3; g_dma_desc_in->status.b.l = 1; g_dma_desc_in->status.b.ioc = 1; g_dma_desc_in->status.b.sp = 1; g_dma_desc_in->status.b.bytes = 0; g_dma_desc_in->buf = 0; g_dma_desc_in->status.b.sts = 0; g_dma_desc_in->status.b.bs = 0x0; WRITE_REG32(DIEPDMA(ep), (UINT32)(UINTN)(g_dma_desc_in)); // DMA Address (DMAAddr) is zero } else { //prepare to send a packet /*WRITE_REG32((len | (packets << 19)), DIEPTSIZ(ep));*/ // packets+transfer size WRITE_REG32(DIEPTSIZ(ep), len | (packets << 19)); //flush cache WriteBackDataCacheRange ((void*)ptr, len); g_dma_desc_in->status.b.bs = 0x3; g_dma_desc_in->status.b.l = 1; g_dma_desc_in->status.b.ioc = 1; g_dma_desc_in->status.b.sp = 1; g_dma_desc_in->status.b.bytes = len; g_dma_desc_in->buf = (UINT32)((UINTN)ptr); g_dma_desc_in->status.b.sts = 0; g_dma_desc_in->status.b.bs = 0x0; WRITE_REG32(DIEPDMA(ep), (UINT32)(UINTN)(g_dma_desc_in)); // ptr is DMA address } asm("dsb sy"); asm("isb sy"); /* epena & cnak*/ WRITE_REG32(DIEPCTL(ep), READ_REG32(DIEPCTL(ep)) | 0x84000800); return; } STATIC VOID ep_rx(unsigned ep, UINTN len) { /* EPx UNSTALL */ WRITE_REG32(DOEPCTL(ep), ((READ_REG32(DOEPCTL(ep))) & (~0x00200000))); /* EPx OUT ACTIVE */ WRITE_REG32(DOEPCTL(ep), (READ_REG32(DOEPCTL(ep)) | 0x8000)); if (len >= DATA_SIZE) rx_desc_bytes = DATA_SIZE; else rx_desc_bytes = len; rx_buf = AllocatePool (DATA_SIZE); ASSERT (rx_buf != NULL); InvalidateDataCacheRange (rx_buf, len); g_dma_desc->status.b.bs = 0x3; g_dma_desc->status.b.mtrf = 0; g_dma_desc->status.b.sr = 0; g_dma_desc->status.b.l = 1; g_dma_desc->status.b.ioc = 1; g_dma_desc->status.b.sp = 0; g_dma_desc->status.b.bytes = (UINT32)rx_desc_bytes; g_dma_desc->buf = (UINT32)((UINTN)rx_buf); g_dma_desc->status.b.sts = 0; g_dma_desc->status.b.bs = 0x0; asm("dsb sy"); asm("isb sy"); WRITE_REG32(DOEPDMA(ep), (UINT32)((UINTN)g_dma_desc)); /* EPx OUT ENABLE CLEARNAK */ WRITE_REG32(DOEPCTL(ep), (READ_REG32(DOEPCTL(ep)) | 0x84000000)); } STATIC EFI_STATUS HandleGetDescriptor ( IN USB_DEVICE_REQUEST *Request ) { UINT8 DescriptorType; UINTN ResponseSize; VOID *ResponseData; ResponseSize = 0; ResponseData = NULL; // Pretty confused if bmRequestType is anything but this: ASSERT (Request->RequestType == USB_DEV_GET_DESCRIPTOR_REQ_TYPE); // Choose the response DescriptorType = Request->Value >> 8; switch (DescriptorType) { case USB_DESC_TYPE_DEVICE: DEBUG ((EFI_D_INFO, "USB: Got a request for device descriptor\n")); ResponseSize = sizeof (USB_DEVICE_DESCRIPTOR); ResponseData = mDeviceDescriptor; break; case USB_DESC_TYPE_CONFIG: DEBUG ((EFI_D_INFO, "USB: Got a request for config descriptor\n")); ResponseSize = mConfigDescriptor->TotalLength; ResponseData = mDescriptors; break; case USB_DESC_TYPE_STRING: DEBUG ((EFI_D_INFO, "USB: Got a request for String descriptor %d\n", Request->Value & 0xFF)); switch (Request->Value & 0xff) { case 0: ResponseSize = mLangStringDescriptor->Length; ResponseData = mLangStringDescriptor; break; case 1: ResponseSize = mManufacturerStringDescriptor->Length; ResponseData = mManufacturerStringDescriptor; break; case 2: ResponseSize = mProductStringDescriptor->Length; ResponseData = mProductStringDescriptor; break; case 3: DwUsb->Get (mSerialStringDescriptor->String, &mSerialStringDescriptor->Length); ResponseSize = mSerialStringDescriptor->Length; ResponseData = mSerialStringDescriptor; break; } break; default: DEBUG ((EFI_D_INFO, "USB: Didn't understand request for descriptor 0x%04x\n", Request->Value)); break; } // Send the response if (ResponseData) { ASSERT (ResponseSize != 0); if (Request->Length < ResponseSize) { // Truncate response ResponseSize = Request->Length; } else if (Request->Length > ResponseSize) { DEBUG ((EFI_D_INFO, "USB: Info: ResponseSize < wLength\n")); } ep_tx(0, ResponseData, ResponseSize); } return EFI_SUCCESS; } STATIC EFI_STATUS HandleSetAddress ( IN USB_DEVICE_REQUEST *Request ) { // Pretty confused if bmRequestType is anything but this: ASSERT (Request->RequestType == USB_DEV_SET_ADDRESS_REQ_TYPE); DEBUG ((EFI_D_INFO, "USB: Setting address to %d\n", Request->Value)); reset_endpoints(); WRITE_REG32(DCFG, (READ_REG32(DCFG) & ~0x7F0) | (Request->Value << 4)); ep_tx(0, 0, 0); return EFI_SUCCESS; } int usb_drv_request_endpoint(unsigned int type, int dir) { unsigned int ep = 1; /*FIXME*/ int ret; unsigned long newbits; ret = (int)ep | dir; newbits = (type << 18) | 0x10000000; /* * (type << 18):Endpoint Type (EPType) * 0x10000000:Endpoint Enable (EPEna) * 0x000C000:Endpoint Type (EPType);Hardcoded to 00 for control. * (ep<<22):TxFIFO Number (TxFNum) * 0x20000:NAK Status (NAKSts);The core is transmitting NAK handshakes on this endpoint. */ if (dir) { // IN: to host WRITE_REG32(DIEPCTL(ep), ((READ_REG32(DIEPCTL(ep)))& ~0x000C0000) | newbits | (ep<<22)|0x20000); } else { // OUT: to device WRITE_REG32(DOEPCTL(ep), ((READ_REG32(DOEPCTL(ep))) & ~0x000C0000) | newbits); } return ret; } STATIC EFI_STATUS HandleSetConfiguration ( IN USB_DEVICE_REQUEST *Request ) { ASSERT (Request->RequestType == USB_DEV_SET_CONFIGURATION_REQ_TYPE); // Cancel all transfers reset_endpoints(); usb_drv_request_endpoint(2, 0); usb_drv_request_endpoint(2, 0x80); WRITE_REG32(DIEPCTL1, (READ_REG32(DIEPCTL1)) | 0x10088800); /* Enable interrupts on all endpoints */ WRITE_REG32(DAINTMSK, 0xFFFFFFFF); ep_rx(1, CMD_SIZE); ep_tx(0, 0, 0); return EFI_SUCCESS; } STATIC EFI_STATUS HandleDeviceRequest ( IN USB_DEVICE_REQUEST *Request ) { EFI_STATUS Status; switch (Request->Request) { case USB_DEV_GET_DESCRIPTOR: Status = HandleGetDescriptor (Request); break; case USB_DEV_SET_ADDRESS: Status = HandleSetAddress (Request); break; case USB_DEV_SET_CONFIGURATION: Status = HandleSetConfiguration (Request); break; default: DEBUG ((EFI_D_ERROR, "Didn't understand RequestType 0x%x Request 0x%x\n", Request->RequestType, Request->Request)); Status = EFI_INVALID_PARAMETER; break; } return Status; } // Instead of actually registering interrupt handlers, we poll the controller's // interrupt source register in this function. STATIC VOID CheckInterrupts ( IN EFI_EVENT Event, IN VOID *Context ) { UINT32 ints = READ_REG32(GINTSTS); // interrupt register UINT32 epints; /* * bus reset * The core sets this bit to indicate that a reset is detected on the USB. */ if (ints & 0x1000) { WRITE_REG32(DCFG, 0x800004); reset_endpoints(); } /* * enumeration done, we now know the speed * The core sets this bit to indicate that speed enumeration is complete. The * application must read the Device Status (DSTS) register to obtain the * enumerated speed. */ if (ints & 0x2000) { /* Set up the maximum packet sizes accordingly */ unsigned long maxpacket = usb_drv_port_speed() ? USB_BLOCK_HIGH_SPEED_SIZE : 64; //Set Maximum In Packet Size (MPS) WRITE_REG32(DIEPCTL1, ((READ_REG32(DIEPCTL1)) & ~0x000003FF) | maxpacket); //Set Maximum Out Packet Size (MPS) WRITE_REG32(DOEPCTL1, ((READ_REG32(DOEPCTL1)) & ~0x000003FF) | maxpacket); } /* * IN EP event * The core sets this bit to indicate that an interrupt is pending on one of the IN * endpoints of the core (in Device mode). The application must read the * Device All Endpoints Interrupt (DAINT) register to determine the exact * number of the IN endpoint on which the interrupt occurred, and then read * the corresponding Device IN Endpoint-n Interrupt (DIEPINTn) register to * determine the exact cause of the interrupt. The application must clear the * appropriate status bit in the corresponding DIEPINTn register to clear this bit. */ if (ints & 0x40000) { epints = READ_REG32(DIEPINT0); WRITE_REG32(DIEPINT0, epints); if (epints & 0x1) /* Transfer Completed Interrupt (XferCompl) */ DEBUG ((EFI_D_INFO, "INT: IN TX completed.DIEPTSIZ(0) = 0x%x.\n", READ_REG32(DIEPTSIZ0))); epints = READ_REG32(DIEPINT1); WRITE_REG32(DIEPINT1, epints); if (epints & 0x1) DEBUG ((EFI_D_INFO, "ep1: IN TX completed\n")); } /* * OUT EP event * The core sets this bit to indicate that an interrupt is pending on one of the * OUT endpoints of the core (in Device mode). The application must read the * Device All Endpoints Interrupt (DAINT) register to determine the exact * number of the OUT endpoint on which the interrupt occurred, and then read * the corresponding Device OUT Endpoint-n Interrupt (DOEPINTn) register * to determine the exact cause of the interrupt. The application must clear the * appropriate status bit in the corresponding DOEPINTn register to clear this bit. */ if (ints & 0x80000) { /* indicates the status of an endpoint * with respect to USB- and AHB-related events. */ epints = READ_REG32(DOEPINT0); if(epints) { WRITE_REG32(DOEPINT0, epints); if (epints & 0x1) DEBUG ((EFI_D_INFO,"INT: EP0 RX completed. DOEPTSIZ(0) = 0x%x.\n", READ_REG32(DOEPTSIZ0))); /* * IN Token Received When TxFIFO is Empty (INTknTXFEmp) * Indicates that an IN token was received when the associated TxFIFO (periodic/nonperiodic) * was empty. This interrupt is asserted on the endpoint for which the IN token * was received. */ if (epints & 0x8) { /* SETUP phase done */ // PRINT_DEBUG("Setup phase \n"); WRITE_REG32(DIEPCTL0, READ_REG32(DIEPCTL0) | 0x08000000); WRITE_REG32(DOEPCTL0, READ_REG32(DOEPCTL0) | 0x08000000); /*clear IN EP intr*/ WRITE_REG32(DIEPINT0, 0xffffffff); HandleDeviceRequest((USB_DEVICE_REQUEST *)p_ctrlreq); } /* Make sure EP0 OUT is set up to accept the next request */ /* memset(p_ctrlreq, 0, NUM_ENDPOINTS*8); */ WRITE_REG32(DOEPTSIZ0, 0x60080040); /* * IN Token Received When TxFIFO is Empty (INTknTXFEmp) * Indicates that an IN token was received when the associated TxFIFO (periodic/nonperiodic) * was empty. This interrupt is asserted on the endpoint for which the IN token * was received. */ g_dma_desc_ep0->status.b.bs = 0x3; g_dma_desc_ep0->status.b.mtrf = 0; g_dma_desc_ep0->status.b.sr = 0; g_dma_desc_ep0->status.b.l = 1; g_dma_desc_ep0->status.b.ioc = 1; g_dma_desc_ep0->status.b.sp = 0; g_dma_desc_ep0->status.b.bytes = 64; g_dma_desc_ep0->buf = (UINT32)(UINTN)(p_ctrlreq); g_dma_desc_ep0->status.b.sts = 0; g_dma_desc_ep0->status.b.bs = 0x0; WRITE_REG32(DOEPDMA0, (unsigned long)(g_dma_desc_ep0)); // endpoint enable; clear NAK WRITE_REG32(DOEPCTL0, 0x84000000); } epints = (READ_REG32(DOEPINT1)); if(epints) { WRITE_REG32(DOEPINT1, epints); /* Transfer Completed Interrupt (XferCompl);Transfer completed */ if (epints & 0x1) { asm("dsb sy"); asm("isb sy"); UINTN bytes = rx_desc_bytes - g_dma_desc->status.b.bytes; UINTN len = 0; if (MATCH_CMD_LITERAL ("download", rx_buf)) { mNumDataBytes = AsciiStrHexToUint64 (rx_buf + sizeof ("download")); } else { if (mNumDataBytes != 0) mNumDataBytes -= bytes; } mDataReceivedCallback (bytes, rx_buf); if (mNumDataBytes == 0) len = CMD_SIZE; else if (mNumDataBytes > DATA_SIZE) len = DATA_SIZE; else len = mNumDataBytes; ep_rx(1, len); } } } //WRITE_REG32 clear ints WRITE_REG32(GINTSTS, ints); } EFI_STATUS DwUsbSend ( IN UINT8 EndpointIndex, IN UINTN Size, IN CONST VOID *Buffer ) { ep_tx(EndpointIndex, Buffer, Size); return 0; } STATIC VOID usb_init() { VOID *buf; UINT32 data; buf = UncachedAllocatePages (16); g_dma_desc = buf; g_dma_desc_ep0 = g_dma_desc + sizeof(struct dwc_otg_dev_dma_desc); g_dma_desc_in = g_dma_desc_ep0 + sizeof(struct dwc_otg_dev_dma_desc); p_ctrlreq = (USB_DEVICE_REQUEST *)g_dma_desc_in + sizeof(struct dwc_otg_dev_dma_desc); SetMem(g_dma_desc, sizeof(struct dwc_otg_dev_dma_desc), 0); SetMem(g_dma_desc_ep0, sizeof(struct dwc_otg_dev_dma_desc), 0); SetMem(g_dma_desc_in, sizeof(struct dwc_otg_dev_dma_desc), 0); /*Reset usb controller.*/ /* Wait for OTG AHB master idle */ do { data = READ_REG32 (GRSTCTL) & GRSTCTL_AHBIDLE; } while (data == 0); /* OTG: Assert Software Reset */ WRITE_REG32 (GRSTCTL, GRSTCTL_CSFTRST); /* Wait for OTG to ack reset */ while (READ_REG32 (GRSTCTL) & GRSTCTL_CSFTRST); /* Wait for OTG AHB master idle */ while ((READ_REG32 (GRSTCTL) & GRSTCTL_AHBIDLE) == 0); WRITE_REG32 (GDFIFOCFG, DATA_FIFO_CONFIG); WRITE_REG32 (GRXFSIZ, RX_SIZE); WRITE_REG32 (GNPTXFSIZ, ENDPOINT_TX_SIZE); WRITE_REG32 (DIEPTXF1, DATA_IN_ENDPOINT_TX_FIFO1); WRITE_REG32 (DIEPTXF2, DATA_IN_ENDPOINT_TX_FIFO2); WRITE_REG32 (DIEPTXF3, DATA_IN_ENDPOINT_TX_FIFO3); WRITE_REG32 (DIEPTXF4, DATA_IN_ENDPOINT_TX_FIFO4); WRITE_REG32 (DIEPTXF5, DATA_IN_ENDPOINT_TX_FIFO5); WRITE_REG32 (DIEPTXF6, DATA_IN_ENDPOINT_TX_FIFO6); WRITE_REG32 (DIEPTXF7, DATA_IN_ENDPOINT_TX_FIFO7); WRITE_REG32 (DIEPTXF8, DATA_IN_ENDPOINT_TX_FIFO8); WRITE_REG32 (DIEPTXF9, DATA_IN_ENDPOINT_TX_FIFO9); WRITE_REG32 (DIEPTXF10, DATA_IN_ENDPOINT_TX_FIFO10); WRITE_REG32 (DIEPTXF11, DATA_IN_ENDPOINT_TX_FIFO11); WRITE_REG32 (DIEPTXF12, DATA_IN_ENDPOINT_TX_FIFO12); WRITE_REG32 (DIEPTXF13, DATA_IN_ENDPOINT_TX_FIFO13); WRITE_REG32 (DIEPTXF14, DATA_IN_ENDPOINT_TX_FIFO14); WRITE_REG32 (DIEPTXF15, DATA_IN_ENDPOINT_TX_FIFO15); /* * set Periodic TxFIFO Empty Level, * Non-Periodic TxFIFO Empty Level, * Enable DMA, Unmask Global Intr */ WRITE_REG32 (GAHBCFG, GAHBCFG_CTRL_MASK); /*select 8bit UTMI+, ULPI Inerface*/ WRITE_REG32 (GUSBCFG, 0x2400); /* Detect usb work mode,host or device? */ do { data = READ_REG32 (GINTSTS); } while (data & GINTSTS_CURMODE_HOST); MicroSecondDelay(3); /*Init global and device mode csr register.*/ /*set Non-Zero-Length status out handshake */ data = (0x20 << DCFG_EPMISCNT_SHIFT) | DCFG_NZ_STS_OUT_HSHK; WRITE_REG32 (DCFG, data); /* Interrupt unmask: IN event, OUT event, bus reset */ data = GINTSTS_OEPINT | GINTSTS_IEPINT | GINTSTS_ENUMDONE | GINTSTS_USBRST; WRITE_REG32 (GINTMSK, data); do { data = READ_REG32 (GINTSTS) & GINTSTS_ENUMDONE; } while (data); /* Clear any pending OTG Interrupts */ WRITE_REG32 (GOTGINT, ~0); /* Clear any pending interrupts */ WRITE_REG32 (GINTSTS, ~0); WRITE_REG32 (GINTMSK, ~0); data = READ_REG32 (GOTGINT); data &= ~0x3000; WRITE_REG32 (GOTGINT, data); /*endpoint settings cfg*/ reset_endpoints(); MicroSecondDelay (1); /*init finish. and ready to transfer data*/ /* Soft Disconnect */ WRITE_REG32(DCTL, 0x802); MicroSecondDelay(10000); /* Soft Reconnect */ WRITE_REG32(DCTL, 0x800); } EFI_STATUS EFIAPI DwUsbStart ( IN USB_DEVICE_DESCRIPTOR *DeviceDescriptor, IN VOID **Descriptors, IN USB_DEVICE_RX_CALLBACK RxCallback, IN USB_DEVICE_TX_CALLBACK TxCallback ) { UINT8 *Ptr; EFI_STATUS Status; EFI_EVENT TimerEvent; UINTN StringDescriptorSize; ASSERT (DeviceDescriptor != NULL); ASSERT (Descriptors[0] != NULL); ASSERT (RxCallback != NULL); ASSERT (TxCallback != NULL); StringDescriptorSize = sizeof (EFI_USB_STRING_DESCRIPTOR) + sizeof (mLangString) + 1; mLangStringDescriptor = AllocateZeroPool (StringDescriptorSize); ASSERT (mLangStringDescriptor != NULL); mLangStringDescriptor->Length = sizeof (mLangString); mLangStringDescriptor->DescriptorType = USB_DESC_TYPE_STRING; CopyMem (mLangStringDescriptor->String, mLangString, mLangStringDescriptor->Length); StringDescriptorSize = sizeof (EFI_USB_STRING_DESCRIPTOR) + sizeof (mManufacturerString) + 1; mManufacturerStringDescriptor = AllocateZeroPool (StringDescriptorSize); ASSERT (mManufacturerStringDescriptor != NULL); mManufacturerStringDescriptor->Length = sizeof (mManufacturerString); mManufacturerStringDescriptor->DescriptorType = USB_DESC_TYPE_STRING; CopyMem (mManufacturerStringDescriptor->String, mManufacturerString, mManufacturerStringDescriptor->Length); StringDescriptorSize = sizeof (EFI_USB_STRING_DESCRIPTOR) + sizeof (mProductString) + 1; mProductStringDescriptor = AllocateZeroPool (StringDescriptorSize); ASSERT (mProductStringDescriptor != NULL); mProductStringDescriptor->Length = sizeof (mProductString); mProductStringDescriptor->DescriptorType = USB_DESC_TYPE_STRING; CopyMem (mProductStringDescriptor->String, mProductString, mProductStringDescriptor->Length); StringDescriptorSize = sizeof (EFI_USB_STRING_DESCRIPTOR) + sizeof (mSerialString) + 1; mSerialStringDescriptor = AllocateZeroPool (StringDescriptorSize); ASSERT (mSerialStringDescriptor != NULL); mSerialStringDescriptor->Length = sizeof (mSerialString); mSerialStringDescriptor->DescriptorType = USB_DESC_TYPE_STRING; CopyMem (mSerialStringDescriptor->String, mSerialString, mSerialStringDescriptor->Length); usb_init(); mDeviceDescriptor = DeviceDescriptor; mDescriptors = Descriptors[0]; // Right now we just support one configuration ASSERT (mDeviceDescriptor->NumConfigurations == 1); mDeviceDescriptor->StrManufacturer = 1; mDeviceDescriptor->StrProduct = 2; mDeviceDescriptor->StrSerialNumber = 3; // ... and one interface mConfigDescriptor = (USB_CONFIG_DESCRIPTOR *)mDescriptors; ASSERT (mConfigDescriptor->NumInterfaces == 1); Ptr = ((UINT8 *) mDescriptors) + sizeof (USB_CONFIG_DESCRIPTOR); mInterfaceDescriptor = (USB_INTERFACE_DESCRIPTOR *) Ptr; Ptr += sizeof (USB_INTERFACE_DESCRIPTOR); mEndpointDescriptors = (USB_ENDPOINT_DESCRIPTOR *) Ptr; mDataReceivedCallback = RxCallback; mDataSentCallback = TxCallback; // Register a timer event so CheckInterupts gets called periodically Status = gBS->CreateEvent ( EVT_TIMER | EVT_NOTIFY_SIGNAL, TPL_CALLBACK, CheckInterrupts, 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); return Status; } USB_DEVICE_PROTOCOL mUsbDevice = { DwUsbStart, DwUsbSend }; EFI_STATUS EFIAPI DwUsbEntryPoint ( IN EFI_HANDLE ImageHandle, IN EFI_SYSTEM_TABLE *SystemTable ) { EFI_STATUS Status; UINT8 UsbMode; Status = gBS->LocateProtocol (&gDwUsbProtocolGuid, NULL, (VOID **) &DwUsb); if (EFI_ERROR (Status)) { return Status; } //Mode: 1 for device, 0 for Host UsbMode = USB_DEVICE_MODE; Status = DwUsb->PhyInit(UsbMode); if (EFI_ERROR (Status)) { return Status; } return gBS->InstallProtocolInterface ( &ImageHandle, &gUsbDeviceProtocolGuid, EFI_NATIVE_INTERFACE, &mUsbDevice ); }