/* ******************************************************************************* * __usb_read_ep0_data * * Description: * void * * Parameters: * void * * Return value: * void * * note: * void * ******************************************************************************* */ static int __usb_read_ep0_data(void *buffer, uint data_type) { u32 fifo_count = 0; u32 fifo = 0; int ret = 0; u32 old_ep_index = 0; old_ep_index = USBC_GetActiveEp(sunxi_udc_source.usbc_hd); fifo = USBC_SelectFIFO(sunxi_udc_source.usbc_hd, SUNXI_USB_CTRL_EP_INDEX); fifo_count = USBC_ReadLenFromFifo(sunxi_udc_source.usbc_hd, USBC_EP_TYPE_EP0); if(!data_type) { if(fifo_count != 8 ) { printf("err: ep0 fifo_count %d is not 8\n", fifo_count); return -1; } } USBC_ReadPacket(sunxi_udc_source.usbc_hd, fifo, fifo_count, (void *)buffer); __usb_readcomplete(sunxi_udc_source.usbc_hd, USBC_EP_TYPE_EP0, 1); USBC_SelectActiveEp(sunxi_udc_source.usbc_hd, old_ep_index); return ret; }
/* ******************************************************************************* * sw_hcd_write_fifo * * Description: * Load an endpoint's FIFO * * Parameters: * void * * Return value: * void * * note: * void * ******************************************************************************* */ void sw_hcd_write_fifo(struct sw_hcd_hw_ep *hw_ep, u16 len, const u8 *src) { void __iomem *fifo = hw_ep->fifo; __u32 old_ep_index = 0; prefetch((u8 *)src); DMSG_DBG_HCD("sw_hcd_write_fifo: %cX ep%d fifo %p count %d buf %p\n", 'T', hw_ep->epnum, fifo, len, src); old_ep_index = USBC_GetActiveEp(hw_ep->sw_hcd->sw_hcd_io->usb_bsp_hdle); USBC_SelectActiveEp(hw_ep->sw_hcd->sw_hcd_io->usb_bsp_hdle, hw_ep->epnum); /* we can't assume unaligned reads work */ if (likely((0x01 & (unsigned long) src) == 0)) { u16 index = 0; /* best case is 32bit-aligned source address */ if ((0x02 & (unsigned long) src) == 0) { if (len >= 4) { sw_hcd_writesl(fifo, src + index, len >> 2); index += len & ~0x03; } if (len & 0x02) { USBC_Writew(*(u16 *)&src[index], fifo); index += 2; } } else {
/* ******************************************************************************* * fastboot_bulk_endpoint_reset * * Description: * void * * Parameters: * void * * Return value: * void * * note: * void * ******************************************************************************* */ static void fastboot_bulk_endpoint_reset (void) { u8 old_ep_index = 0; DMSG_INFO("fastboot_bulk_endpoint_reset\n"); old_ep_index = USBC_GetActiveEp(udc.bsp); print_sw_udc(&udc); /* tx */ USBC_SelectActiveEp(udc.bsp, BULK_IN_EP_INDEX); USBC_Dev_ConfigEp(udc.bsp, USBC_TS_TYPE_BULK, USBC_EP_TYPE_TX, 1, udc.bulk_ep_size & 0x7ff); USBC_ConfigFifo(udc.bsp, USBC_EP_TYPE_TX, 1, udc.fifo_size, 1024); //1k开始, 每个ep分配1K的空间 USBC_INT_EnableEp(udc.bsp, USBC_EP_TYPE_TX, BULK_IN_EP_INDEX); /* rx */ USBC_SelectActiveEp(udc.bsp, BULK_OUT_EP_INDEX); USBC_Dev_ConfigEp(udc.bsp, USBC_TS_TYPE_BULK, USBC_EP_TYPE_RX, 1, udc.bulk_ep_size & 0x7ff); USBC_ConfigFifo(udc.bsp, USBC_EP_TYPE_RX, 1, udc.fifo_size, 2048); //2k开始, 每个ep分配1K的空间 USBC_INT_EnableEp(udc.bsp, USBC_EP_TYPE_RX, BULK_OUT_EP_INDEX); USBC_SelectActiveEp(udc.bsp, old_ep_index); return; }
/* ******************************************************************************* * fastboot_tx_status * * Description: * void * * Parameters: * void * * Return value: * void * * note: * void * ******************************************************************************* */ static int __usb_write_fifo(uchar *buffer, unsigned int buffer_size) { u32 old_ep_idx = 0; u32 fifo = 0; u32 transfered = 0; u32 left = 0; u32 this_len; /* Save index */ old_ep_idx = USBC_GetActiveEp(sunxi_udc_source.usbc_hd); USBC_SelectActiveEp(sunxi_udc_source.usbc_hd, SUNXI_USB_BULK_IN_EP_INDEX); left = buffer_size; fifo = USBC_SelectFIFO(sunxi_udc_source.usbc_hd, SUNXI_USB_BULK_IN_EP_INDEX); while(left) { this_len = MIN(sunxi_udc_source.fifo_size, left); this_len = USBC_WritePacket(sunxi_udc_source.usbc_hd, fifo, this_len, buffer + transfered); transfered += this_len; left -= this_len; __usb_writecomplete(sunxi_udc_source.usbc_hd, USBC_EP_TYPE_TX, 1); } USBC_SelectActiveEp(sunxi_udc_source.usbc_hd, old_ep_idx); return 0; }
/* ************************************************************************************************************ * * function * * name : * * parmeters : * * return : * * note : * * ************************************************************************************************************ */ static void __usb_recv_by_dma_isr(void *p_arg) { u32 old_ep_idx; old_ep_idx = USBC_GetActiveEp(sunxi_udc_source.usbc_hd); USBC_SelectActiveEp(sunxi_udc_source.usbc_hd, SUNXI_USB_BULK_OUT_EP_INDEX); //选择RXEP //选择使用IO方式搬运数据 sunxi_usb_dbg("select io mode to transfer data\n"); USBC_Dev_ClearEpDma(sunxi_udc_source.usbc_hd, USBC_EP_TYPE_RX); if(usb_dma_trans_unaliged_bytes) { uint fifo, this_len; this_len = USBC_ReadLenFromFifo(sunxi_udc_source.usbc_hd, USBC_EP_TYPE_RX); fifo = USBC_SelectFIFO(sunxi_udc_source.usbc_hd, SUNXI_USB_BULK_OUT_EP_INDEX); USBC_ReadPacket(sunxi_udc_source.usbc_hd, fifo, this_len, usb_dma_trans_unaligned_buf); __usb_readcomplete(sunxi_udc_source.usbc_hd, USBC_EP_TYPE_RX, 1); //返回状态 usb_dma_trans_unaliged_bytes = 0; } //如果当前dma传输的不是完整包,则需要手动清除中断 if(sunxi_ubuf.request_size % sunxi_udc_source.bulk_ep_max) { USBC_Dev_ReadDataStatus(sunxi_udc_source.usbc_hd, USBC_EP_TYPE_RX, 1); //printf("clear rx pending manually\n"); } USBC_SelectActiveEp(sunxi_udc_source.usbc_hd, old_ep_idx); sunxi_udev_active->dma_rx_isr(p_arg); }
/* ************************************************************************************************************ * * function * * name : * * parmeters : * * return : * * note : * * ************************************************************************************************************ */ static int eprx_recv_op(void) { uint old_ep_index; uint this_len; uint fifo; old_ep_index = USBC_GetActiveEp(sunxi_udc_source.usbc_hd); USBC_SelectActiveEp(sunxi_udc_source.usbc_hd, SUNXI_USB_BULK_OUT_EP_INDEX); if (USBC_Dev_IsEpStall(sunxi_udc_source.usbc_hd, USBC_EP_TYPE_RX)) { USBC_Dev_EpClearStall(sunxi_udc_source.usbc_hd, USBC_EP_TYPE_RX); printf("sunxi ubs read error: usb rx ep is busy already\n"); } else { if(USBC_Dev_IsReadDataReady(sunxi_udc_source.usbc_hd, USBC_EP_TYPE_RX)) { this_len = USBC_ReadLenFromFifo(sunxi_udc_source.usbc_hd, USBC_EP_TYPE_RX); if(fastboot_data_flag == 1) { fifo = USBC_SelectFIFO(sunxi_udc_source.usbc_hd, SUNXI_USB_BULK_OUT_EP_INDEX); sunxi_ubuf.rx_req_length = USBC_ReadPacket(sunxi_udc_source.usbc_hd, fifo, this_len, sunxi_ubuf.rx_req_buffer); sunxi_ubuf.rx_req_buffer += this_len; sunxi_usb_dbg("special read ep bytes 0x%x\n", sunxi_ubuf.rx_req_length); __usb_readcomplete(sunxi_udc_source.usbc_hd, USBC_EP_TYPE_RX, 1); //返回状态 } else if(!sunxi_ubuf.rx_ready_for_data) { fifo = USBC_SelectFIFO(sunxi_udc_source.usbc_hd, SUNXI_USB_BULK_OUT_EP_INDEX); memset(sunxi_ubuf.rx_req_buffer, 0, 64); sunxi_ubuf.rx_req_length = USBC_ReadPacket(sunxi_udc_source.usbc_hd, fifo, this_len, sunxi_ubuf.rx_req_buffer); sunxi_ubuf.rx_ready_for_data = 1; sunxi_usb_dbg("read ep bytes 0x%x\n", sunxi_ubuf.rx_req_length); __usb_readcomplete(sunxi_udc_source.usbc_hd, USBC_EP_TYPE_RX, 1); //返回状态 } else { sunxi_usb_dbg("eprx do nothing and left it to dma\n"); } } else { sunxi_usb_dbg("sunxi usb rxdata not ready\n"); } } USBC_SelectActiveEp(sunxi_udc_source.usbc_hd, old_ep_index); return 0; }
static int __usb_read_fifo(void *buffer, unsigned int buffer_size) { u32 old_ep_idx = 0; u32 fifo = 0; u32 transfered = 0; u32 left = 0; u32 this_len; old_ep_idx = USBC_GetActiveEp(sunxi_udc_source.usbc_hd); USBC_SelectActiveEp(sunxi_udc_source.usbc_hd, SUNXI_USB_BULK_OUT_EP_INDEX); //选择当前EP fifo = USBC_SelectFIFO(sunxi_udc_source.usbc_hd, SUNXI_USB_BULK_OUT_EP_INDEX); //选择fifo left = buffer_size; if(left) { while(left) { if(USBC_Dev_IsReadDataReady(sunxi_udc_source.usbc_hd, USBC_EP_TYPE_RX)) { this_len = USBC_ReadLenFromFifo(sunxi_udc_source.usbc_hd, USBC_EP_TYPE_RX); this_len = USBC_ReadPacket(sunxi_udc_source.usbc_hd, fifo, this_len, buffer + transfered); transfered += this_len; left -= this_len; __usb_readcomplete(sunxi_udc_source.usbc_hd, USBC_EP_TYPE_RX, 1); //返回状态 } } USBC_INT_ClearEpPending(sunxi_udc_source.usbc_hd, USBC_EP_TYPE_RX, SUNXI_USB_BULK_OUT_EP_INDEX); } else { if(USBC_Dev_IsReadDataReady(sunxi_udc_source.usbc_hd, USBC_EP_TYPE_RX)) { this_len = USBC_ReadLenFromFifo(sunxi_udc_source.usbc_hd, USBC_EP_TYPE_RX); this_len = USBC_ReadPacket(sunxi_udc_source.usbc_hd, fifo, this_len, buffer); transfered = this_len; __usb_readcomplete(sunxi_udc_source.usbc_hd, USBC_EP_TYPE_RX, 1); //返回状态 } else { sunxi_usb_dbg("sunxi usb rxdata not ready\n"); } } USBC_SelectActiveEp(sunxi_udc_source.usbc_hd, old_ep_idx); sunxi_usb_dbg("read bytes 0x%x\n", transfered); return transfered; }
/* ******************************************************************************* * __usb_bulk_ep_reset * * Description: * void * * Parameters: * void * * Return value: * void * * note: * void * ******************************************************************************* */ static void __usb_bulk_ep_reset (void) { u8 old_ep_index = 0; old_ep_index = USBC_GetActiveEp(sunxi_udc_source.usbc_hd); /* tx */ USBC_SelectActiveEp(sunxi_udc_source.usbc_hd, SUNXI_USB_BULK_IN_EP_INDEX); USBC_Dev_ConfigEp(sunxi_udc_source.usbc_hd, USBC_TS_TYPE_BULK, USBC_EP_TYPE_TX, 1, sunxi_udc_source.bulk_ep_max & 0x7ff); USBC_ConfigFifo(sunxi_udc_source.usbc_hd, USBC_EP_TYPE_TX, 1, sunxi_udc_source.fifo_size, (uint)sunxi_udc_source.bulk_out_addr); USBC_INT_EnableEp(sunxi_udc_source.usbc_hd, USBC_EP_TYPE_TX, SUNXI_USB_BULK_IN_EP_INDEX); /* rx */ USBC_SelectActiveEp(sunxi_udc_source.usbc_hd, SUNXI_USB_BULK_OUT_EP_INDEX); USBC_Dev_ConfigEp(sunxi_udc_source.usbc_hd, USBC_TS_TYPE_BULK, USBC_EP_TYPE_RX, 1, sunxi_udc_source.bulk_ep_max & 0x7ff); USBC_ConfigFifo(sunxi_udc_source.usbc_hd, USBC_EP_TYPE_RX, 1, sunxi_udc_source.fifo_size, (uint)sunxi_udc_source.bulk_in_addr); USBC_INT_EnableEp(sunxi_udc_source.usbc_hd, USBC_EP_TYPE_RX, SUNXI_USB_BULK_OUT_EP_INDEX); USBC_SelectActiveEp(sunxi_udc_source.usbc_hd, old_ep_index); return; }
/* ************************************************************************************************************ * * function * * name : * * parmeters : * * return : * * note : * * ************************************************************************************************************ */ static void __usb_recv_by_dma_isr(void *p_arg) { u32 old_ep_idx; old_ep_idx = USBC_GetActiveEp(sunxi_udc_source.usbc_hd); USBC_SelectActiveEp(sunxi_udc_source.usbc_hd, SUNXI_USB_BULK_OUT_EP_INDEX); //选择RXEP //如果当前dma传输的不是完整包,则需要手动清除中断 //printf("sunxi_ubuf.request_size=0x%x\n",sunxi_ubuf.request_size); if(sunxi_ubuf.request_size % sunxi_udc_source.bulk_ep_max) { USBC_Dev_ReadDataStatus(sunxi_udc_source.usbc_hd, USBC_EP_TYPE_RX, 1); //printf("clear rx pending manually\n"); } //选择使用IO方式搬运数据 sunxi_usb_dbg("select io mode to transfer data\n"); USBC_Dev_ClearEpDma(sunxi_udc_source.usbc_hd, USBC_EP_TYPE_RX); USBC_SelectActiveEp(sunxi_udc_source.usbc_hd, old_ep_idx); sunxi_udev_active->dma_rx_isr(p_arg); }
/* ************************************************************************************************************ * * function * * name : * * parmeters : * * return : * * note : * * ************************************************************************************************************ */ int sunxi_udc_start_recv_by_dma(uint mem_buf, uint length) { uint old_ep_idx; uint fifo; old_ep_idx = USBC_GetActiveEp(sunxi_udc_source.usbc_hd); USBC_SelectActiveEp(sunxi_udc_source.usbc_hd, SUNXI_USB_BULK_OUT_EP_INDEX); //选择当前EP //usb控制器选择dma传输方式 USBC_Dev_ConfigEpDma(sunxi_udc_source.usbc_hd, USBC_EP_TYPE_RX); //选择buffer fifo = USBC_SelectFIFO(sunxi_udc_source.usbc_hd, SUNXI_USB_BULK_OUT_EP_INDEX); //刷掉cache flush_cache(mem_buf, length); //使能dma传输 sunxi_ubuf.request_size = length; sunxi_usb_dbg("dma start\n"); sunxi_dma_start(sunxi_udc_source.dma_recv_channal, fifo, mem_buf, length); //恢复EP USBC_SelectActiveEp(sunxi_udc_source.usbc_hd, old_ep_idx); //恢复原有EP return 0; }
/* ******************************************************************************* * read_request * * Description: * void * * Parameters: * void * * Return value: * void * * note: * void * ******************************************************************************* */ static int read_request(struct usb_device_request *req) { u32 fifo_count = 0; u32 fifo = 0; int ret = FASTBOOT_OK; u8 old_ep_index = 0; old_ep_index = USBC_GetActiveEp(udc.bsp); USBC_SelectActiveEp(udc.bsp, CTRL_EP_INDEX); fifo = USBC_SelectFIFO(udc.bsp, CTRL_EP_INDEX); fifo_count = USBC_ReadLenFromFifo(udc.bsp, USBC_EP_TYPE_EP0); if(fifo_count != 8 ){ DMSG_PANIC("err: ep0 fifo_count is not 8\n", fifo_count); return FASTBOOT_ERROR; } USBC_ReadPacket(udc.bsp, fifo, fifo_count, (void *)req); ReadDataStatusComplete(udc.bsp, USBC_EP_TYPE_EP0, 0); USBC_SelectActiveEp(udc.bsp, old_ep_index); return ret; }
/* ************************************************************************************************************ * * function * * name : * * parmeters : * * return : * * note : * * ************************************************************************************************************ */ int sunxi_udc_start_recv_by_dma(uint mem_buf, uint length) { uint old_ep_idx; usb_dma_trans_unaliged_bytes = length & (sizeof(int) - 1); length &= ~(sizeof(int) - 1); usb_dma_trans_unaligned_buf = (uchar *)mem_buf + length; old_ep_idx = USBC_GetActiveEp(sunxi_udc_source.usbc_hd); USBC_SelectActiveEp(sunxi_udc_source.usbc_hd, SUNXI_USB_BULK_OUT_EP_INDEX); //选择当前EP //usb控制器选择dma传输方式 USBC_Dev_ConfigEpDma(sunxi_udc_source.usbc_hd, USBC_EP_TYPE_RX); //刷掉cache flush_cache(mem_buf, length); //使能dma传输 sunxi_ubuf.request_size = length; sunxi_usb_dbg("dma start 0x%x, length 0x%x\n", mem_buf, length); usb_dma_start(sunxi_udc_source.dma_recv_channal, mem_buf, length); //恢复EP USBC_SelectActiveEp(sunxi_udc_source.usbc_hd, old_ep_idx); //恢复原有EP return 0; }
/* ************************************************************************************************************ * * function * * name : * * parmeters : * * return : * * note : * * ************************************************************************************************************ */ void sunxi_usb_irq(void *data) { u8 misc_irq = 0; u16 tx_irq = 0; u16 rx_irq = 0; u32 old_ep_idx = 0; /* Save index */ old_ep_idx = USBC_GetActiveEp(sunxi_udc_source.usbc_hd); /* Read status registers */ misc_irq = USBC_INT_MiscPending(sunxi_udc_source.usbc_hd); tx_irq = USBC_INT_EpPending(sunxi_udc_source.usbc_hd, USBC_EP_TYPE_TX); rx_irq = USBC_INT_EpPending(sunxi_udc_source.usbc_hd, USBC_EP_TYPE_RX); /* RESET */ if(misc_irq & USBC_INTUSB_RESET) { sunxi_usb_dbg("IRQ: reset\n"); USBC_INT_ClearMiscPending(sunxi_udc_source.usbc_hd, USBC_INTUSB_RESET); __usb_clear_all_irq(); USBC_SelectActiveEp(sunxi_udc_source.usbc_hd, 0); USBC_Dev_SetAddress_default(sunxi_udc_source.usbc_hd); sunxi_udc_source.address = 0; //default value sunxi_udc_source.speed = USB_SPEED_HIGH; //default value sunxi_dma_stop(sunxi_udc_source.dma_recv_channal); sunxi_dma_stop(sunxi_udc_source.dma_send_channal); sunxi_ubuf.rx_ready_for_data = 0; sunxi_udev_active->state_reset(); return ; } /* RESUME 暂时不处理,仅仅清理中断*/ if (misc_irq & USBC_INTUSB_RESUME) { sunxi_usb_dbg("IRQ: resume\n"); /* clear interrupt */ USBC_INT_ClearMiscPending(sunxi_udc_source.usbc_hd, USBC_INTUSB_RESUME); } /* SUSPEND */ if (misc_irq & USBC_INTUSB_SUSPEND) { sunxi_usb_dbg("IRQ: suspend\n"); /* clear interrupt */ USBC_INT_ClearMiscPending(sunxi_udc_source.usbc_hd, USBC_INTUSB_SUSPEND); } /* DISCONNECT */ if(misc_irq & USBC_INTUSB_DISCONNECT) { sunxi_usb_dbg("IRQ: disconnect\n"); USBC_INT_ClearMiscPending(sunxi_udc_source.usbc_hd, USBC_INTUSB_DISCONNECT); return ; } #if 0 /* SOF */ if(misc_irq & USBC_INTUSB_SOF) { sunxi_usb_dbg("IRQ: SOF\n"); USBC_INT_ClearMiscPending(sunxi_udc_source.usbc_hd, USBC_INTUSB_SOF); } #endif /* ep0 */ if (tx_irq & (1 << SUNXI_USB_CTRL_EP_INDEX) ) { sunxi_usb_dbg("IRQ: EP0\n"); USBC_INT_ClearEpPending(sunxi_udc_source.usbc_hd, USBC_EP_TYPE_TX, SUNXI_USB_CTRL_EP_INDEX); //中断内完成ep0处理 ep0_recv_op(); } /* tx endpoint data transfers */ if (tx_irq & (1 << SUNXI_USB_BULK_IN_EP_INDEX)) { sunxi_usb_dbg("tx irq occur\n"); /* Clear the interrupt bit by setting it to 1 */ USBC_INT_ClearEpPending(sunxi_udc_source.usbc_hd, USBC_EP_TYPE_TX, SUNXI_USB_BULK_IN_EP_INDEX); eptx_send_op(); } /* rx endpoint data transfers */ if (rx_irq & (1 << SUNXI_USB_BULK_OUT_EP_INDEX)) { sunxi_usb_dbg("rx irq occur\n"); /* Clear the interrupt bit by setting it to 1 */ USBC_INT_ClearEpPending(sunxi_udc_source.usbc_hd, USBC_EP_TYPE_RX, SUNXI_USB_BULK_OUT_EP_INDEX); eprx_recv_op(); } USBC_SelectActiveEp(sunxi_udc_source.usbc_hd, old_ep_idx); return ; }
/* ************************************************************************************************************ * * function * * name : * * parmeters : * * return : * * note : * * ************************************************************************************************************ */ static int ep0_recv_op(void) { u32 old_ep_index = 0; int ret = 0; static uint ep0_stage = 0; if(!ep0_stage) { memset(&sunxi_udc_source.standard_reg, 0, sizeof(struct usb_device_request)); } old_ep_index = USBC_GetActiveEp(sunxi_udc_source.usbc_hd); USBC_SelectActiveEp(sunxi_udc_source.usbc_hd, SUNXI_USB_CTRL_EP_INDEX); //clear stall status if(USBC_Dev_IsEpStall(sunxi_udc_source.usbc_hd, USBC_EP_TYPE_EP0)) { printf("ERR: handle_ep0: ep0 stall\n"); USBC_Dev_EpClearStall(sunxi_udc_source.usbc_hd, USBC_EP_TYPE_EP0); ret = -1; goto __ep0_recv_op_err; } //clear setup end if (USBC_Dev_Ctrl_IsSetupEnd(sunxi_udc_source.usbc_hd)) { USBC_Dev_Ctrl_ClearSetupEnd(sunxi_udc_source.usbc_hd); } //检查读ep0数据是否完成 if(USBC_Dev_IsReadDataReady(sunxi_udc_source.usbc_hd, USBC_EP_TYPE_EP0)) { uint status; if(!ep0_stage) { status = __usb_read_ep0_data(&sunxi_udc_source.standard_reg, ep0_stage); } else { status = __usb_read_ep0_data(sunxi_usb_ep0_buffer, ep0_stage); } if(status!= 0) { printf("sunxi usb err: read_request failed\n"); ret = -1; goto __ep0_recv_op_err; } } else //此情况通常由于ep0发送空包引起,可以不处理 { sunxi_usb_dbg("sunxi usb msg: ep0 rx data is not ready\n"); goto __ep0_recv_op_err; } /* Check data */ if(USB_REQ_TYPE_STANDARD == (sunxi_udc_source.standard_reg.bmRequestType & USB_REQ_TYPE_MASK)) { ret = SUNXI_USB_REQ_UNMATCHED_COMMAND; /* standard */ switch(sunxi_udc_source.standard_reg.bRequest) { case USB_REQ_GET_STATUS: // 0x00 { /* device-to-host */ if(USB_DIR_IN == (sunxi_udc_source.standard_reg.bmRequestType & USB_REQ_DIRECTION_MASK)) { ret = sunxi_udev_active->standard_req_op(USB_REQ_GET_STATUS, &sunxi_udc_source.standard_reg, sunxi_usb_ep0_buffer); } break; } case USB_REQ_CLEAR_FEATURE: // 0x01 { /* host-to-device */ if(USB_DIR_OUT == (sunxi_udc_source.standard_reg.bmRequestType & USB_REQ_DIRECTION_MASK)) { ret = sunxi_udev_active->standard_req_op(USB_REQ_CLEAR_FEATURE, &sunxi_udc_source.standard_reg, NULL); } break; } case USB_REQ_SET_FEATURE: // 0x03 { /* host-to-device */ if(USB_DIR_OUT == (sunxi_udc_source.standard_reg.bmRequestType & USB_REQ_DIRECTION_MASK)) { ret = sunxi_udev_active->standard_req_op(USB_REQ_SET_FEATURE, &sunxi_udc_source.standard_reg, NULL); } break; } case USB_REQ_SET_ADDRESS: // 0x05 { /* host-to-device */ if(USB_DIR_OUT == (sunxi_udc_source.standard_reg.bmRequestType & USB_REQ_DIRECTION_MASK)) { if(USB_RECIP_DEVICE == (sunxi_udc_source.standard_reg.bmRequestType & USB_REQ_RECIPIENT_MASK)) { /* receiver is device */ ret = sunxi_udev_active->standard_req_op(USB_REQ_SET_ADDRESS, &sunxi_udc_source.standard_reg, NULL); } } break; } case USB_REQ_GET_DESCRIPTOR: // 0x06 { /* device-to-host */ if(USB_DIR_IN == (sunxi_udc_source.standard_reg.bmRequestType & USB_REQ_DIRECTION_MASK)) { if(USB_RECIP_DEVICE == (sunxi_udc_source.standard_reg.bmRequestType & USB_REQ_RECIPIENT_MASK)) { ret = sunxi_udev_active->standard_req_op(USB_REQ_GET_DESCRIPTOR, &sunxi_udc_source.standard_reg, sunxi_usb_ep0_buffer); } } break; } case USB_REQ_SET_DESCRIPTOR: // 0x07 { /* host-to-device */ if(USB_DIR_OUT == (sunxi_udc_source.standard_reg.bmRequestType & USB_REQ_DIRECTION_MASK)) { if(USB_RECIP_DEVICE == (sunxi_udc_source.standard_reg.bmRequestType & USB_REQ_RECIPIENT_MASK)) { //there is some problem ret = sunxi_udev_active->standard_req_op(USB_REQ_SET_DESCRIPTOR, &sunxi_udc_source.standard_reg, sunxi_usb_ep0_buffer); } } break; } case USB_REQ_GET_CONFIGURATION: // 0x08 { /* device-to-host */ if(USB_DIR_IN == (sunxi_udc_source.standard_reg.bmRequestType & USB_REQ_DIRECTION_MASK)) { if(USB_RECIP_DEVICE == (sunxi_udc_source.standard_reg.bmRequestType & USB_REQ_RECIPIENT_MASK)) { ret = sunxi_udev_active->standard_req_op(USB_REQ_GET_CONFIGURATION, &sunxi_udc_source.standard_reg, sunxi_usb_ep0_buffer); } } break; } case USB_REQ_SET_CONFIGURATION: // 0x09 { /* host-to-device */ if(USB_DIR_OUT == (sunxi_udc_source.standard_reg.bmRequestType & USB_REQ_DIRECTION_MASK)) { if(USB_RECIP_DEVICE == (sunxi_udc_source.standard_reg.bmRequestType & USB_REQ_RECIPIENT_MASK)) { ret = sunxi_udev_active->standard_req_op(USB_REQ_SET_CONFIGURATION, &sunxi_udc_source.standard_reg, NULL); } } break; } case USB_REQ_GET_INTERFACE: // 0x0a { /* device-to-host */ if(USB_DIR_IN == (sunxi_udc_source.standard_reg.bmRequestType & USB_REQ_DIRECTION_MASK)) { if(USB_RECIP_DEVICE == (sunxi_udc_source.standard_reg.bmRequestType & USB_REQ_RECIPIENT_MASK)) { ret = sunxi_udev_active->standard_req_op(USB_REQ_GET_INTERFACE, &sunxi_udc_source.standard_reg, sunxi_usb_ep0_buffer); } } break; } case USB_REQ_SET_INTERFACE: // 0x0b { /* host-to-device */ if(USB_DIR_OUT == (sunxi_udc_source.standard_reg.bmRequestType & USB_REQ_DIRECTION_MASK)) { if(USB_RECIP_INTERFACE == (sunxi_udc_source.standard_reg.bmRequestType & USB_REQ_RECIPIENT_MASK)) { ret = sunxi_udev_active->standard_req_op(USB_REQ_SET_INTERFACE, &sunxi_udc_source.standard_reg, NULL); } } break; } case USB_REQ_SYNCH_FRAME: // 0x0b { /* device-to-host */ if(USB_DIR_IN == (sunxi_udc_source.standard_reg.bmRequestType & USB_REQ_DIRECTION_MASK)) { if(USB_RECIP_INTERFACE == (sunxi_udc_source.standard_reg.bmRequestType & USB_REQ_RECIPIENT_MASK)) { //there is some problem if(!ep0_stage) { ep0_stage = 1; } else { ret = sunxi_udev_active->standard_req_op(USB_REQ_SYNCH_FRAME, &sunxi_udc_source.standard_reg, NULL); ep0_stage = 0; } } } break; } default: { printf("sunxi usb err: unknown usb out request to device\n"); USBC_Dev_EpSendStall(sunxi_udc_source.usbc_hd, USBC_EP_TYPE_EP0); ret = SUNXI_USB_REQ_DEVICE_NOT_SUPPORTED; ep0_stage = 0; break; } } } else { /* Non-Standard Req */ printf("non standard req\n"); ret = sunxi_udev_active->nonstandard_req_op(USB_REQ_GET_STATUS, &sunxi_udc_source.standard_reg, sunxi_usb_ep0_buffer, ep0_stage); if(ret == SUNXI_USB_REQ_DATA_HUNGRY) { ep0_stage = 1; } else if(ret == SUNXI_USB_REQ_SUCCESSED) { ep0_stage = 0; } else if(ret < 0) { ep0_stage = 0; printf("err: unkown bmRequestType(%d)\n", sunxi_udc_source.standard_reg.bmRequestType); USBC_Dev_EpSendStall(sunxi_udc_source.usbc_hd, USBC_EP_TYPE_EP0); } } __ep0_recv_op_err: USBC_SelectActiveEp(sunxi_udc_source.usbc_hd, old_ep_index); return ret; }
/* ******************************************************************************* * sw_hcd_port_reset * * Description: * reset USB port * * Parameters: * sw_hcd : input. USB¿ØÖÆÆ÷ * do_reset : input. flag. is reset USB port or not? * * Return value: * void * * note: * void * ******************************************************************************* */ static void sw_hcd_port_reset(struct sw_hcd *sw_hcd, bool do_reset) { u8 power = 0; void __iomem *usbc_base = sw_hcd->mregs; if (!is_host_active(sw_hcd)){ DMSG_PANIC("ERR: usb host is not active\n"); return; } /* NOTE: caller guarantees it will turn off the reset when * the appropriate amount of time has passed */ power = USBC_Readb(USBC_REG_PCTL(usbc_base)); if (do_reset) { DMSG_INFO("[sw_hcd]: reset port. \n"); /* * If RESUME is set, we must make sure it stays minimum 20 ms. * Then we must clear RESUME and wait a bit to let sw_hcd start * generating SOFs. If we don't do this, OPT HS A 6.8 tests * fail with "Error! Did not receive an SOF before suspend * detected". */ if (power & (1 << USBC_BP_POWER_H_RESUME)) { while (time_before(jiffies, sw_hcd->rh_timer)){ msleep(1); } power &= ~(1 << USBC_BP_POWER_H_RESUME); USBC_Writeb(power, USBC_REG_PCTL(usbc_base)); msleep(1); } sw_hcd->ignore_disconnect = true; power &= 0xf0; power |= (1 << USBC_BP_POWER_H_RESET); USBC_Writeb(power, USBC_REG_PCTL(usbc_base)); sw_hcd->port1_status |= USB_PORT_STAT_RESET; sw_hcd->port1_status &= ~USB_PORT_STAT_ENABLE; sw_hcd->rh_timer = jiffies + msecs_to_jiffies(50); USBC_Host_SetFunctionAddress_Deafult(sw_hcd->sw_hcd_io->usb_bsp_hdle, USBC_EP_TYPE_TX, 0); //set address ep0 { __u32 i = 1; __u8 old_ep_index = 0; old_ep_index = USBC_GetActiveEp(sw_hcd->sw_hcd_io->usb_bsp_hdle); USBC_SelectActiveEp(sw_hcd->sw_hcd_io->usb_bsp_hdle, 0); USBC_Host_SetFunctionAddress_Deafult(sw_hcd->sw_hcd_io->usb_bsp_hdle, USBC_EP_TYPE_TX, 0); for( i = 1 ; i <= 5; i++){ USBC_SelectActiveEp(sw_hcd->sw_hcd_io->usb_bsp_hdle, i); USBC_Host_SetFunctionAddress_Deafult(sw_hcd->sw_hcd_io->usb_bsp_hdle, USBC_EP_TYPE_TX, i); USBC_Host_SetFunctionAddress_Deafult(sw_hcd->sw_hcd_io->usb_bsp_hdle, USBC_EP_TYPE_RX, i); } USBC_SelectActiveEp(sw_hcd->sw_hcd_io->usb_bsp_hdle, old_ep_index); } }else{ DMSG_INFO("[sw_hcd]: reset port stopped.\n"); UsbPhyEndReset(0); power &= ~(1 << USBC_BP_POWER_H_RESET); USBC_Writeb(power, USBC_REG_PCTL(usbc_base)); sw_hcd->ignore_disconnect = false; power = USBC_Readb(USBC_REG_PCTL(usbc_base)); if(power & (1 << USBC_BP_POWER_H_HIGH_SPEED_FLAG)){ DMSG_DBG_HCD("high-speed device connected\n"); sw_hcd->port1_status |= USB_PORT_STAT_HIGH_SPEED; } sw_hcd->port1_status &= ~USB_PORT_STAT_RESET; sw_hcd->port1_status |= USB_PORT_STAT_ENABLE | (USB_PORT_STAT_C_RESET << 16) | (USB_PORT_STAT_C_ENABLE << 16); usb_hcd_poll_rh_status(sw_hcd_to_hcd(sw_hcd)); sw_hcd->vbuserr_retry = VBUSERR_RETRY_COUNT; } return ; }