static int ehci_submit_async(struct usb_device *dev, unsigned long pipe, void *buffer, int length, struct devrequest *req) { struct QH *qh; struct qTD *td; volatile struct qTD *vtd; unsigned long ts; uint32_t *tdp; uint32_t endpt, token, usbsts; uint32_t c, toggle; uint32_t cmd; int timeout; int ret = 0; debug("dev=%p, pipe=%lx, buffer=%p, length=%d, req=%p\n", dev, pipe, buffer, length, req); if (req != NULL) debug("req=%u (%#x), type=%u (%#x), value=%u (%#x), index=%u\n", req->request, req->request, req->requesttype, req->requesttype, le16_to_cpu(req->value), le16_to_cpu(req->value), le16_to_cpu(req->index)); qh = ehci_alloc(sizeof(struct QH), 32); if (qh == NULL) { debug("unable to allocate QH\n"); return -1; } qh->qh_link = cpu_to_hc32((uint32_t)&qh_list | QH_LINK_TYPE_QH); c = (usb_pipespeed(pipe) != USB_SPEED_HIGH && usb_pipeendpoint(pipe) == 0) ? 1 : 0; endpt = (8 << 28) | (c << 27) | (usb_maxpacket(dev, pipe) << 16) | (0 << 15) | (1 << 14) | (usb_pipespeed(pipe) << 12) | (usb_pipeendpoint(pipe) << 8) | (0 << 7) | (usb_pipedevice(pipe) << 0); qh->qh_endpt1 = cpu_to_hc32(endpt); endpt = (1 << 30) | (dev->portnr << 23) | (dev->parent->devnum << 16) | (0 << 8) | (0 << 0); qh->qh_endpt2 = cpu_to_hc32(endpt); qh->qh_overlay.qt_next = cpu_to_hc32(QT_NEXT_TERMINATE); td = NULL; tdp = &qh->qh_overlay.qt_next; toggle = usb_gettoggle(dev, usb_pipeendpoint(pipe), usb_pipeout(pipe)); if (req != NULL) { td = ehci_alloc(sizeof(struct qTD), 32); if (td == NULL) { debug("unable to allocate SETUP td\n"); goto fail; } td->qt_next = cpu_to_hc32(QT_NEXT_TERMINATE); td->qt_altnext = cpu_to_hc32(QT_NEXT_TERMINATE); token = (0 << 31) | (sizeof(*req) << 16) | (0 << 15) | (0 << 12) | (3 << 10) | (2 << 8) | (0x80 << 0); td->qt_token = cpu_to_hc32(token); if (ehci_td_buffer(td, req, sizeof(*req)) != 0) { debug("unable construct SETUP td\n"); ehci_free(td, sizeof(*td)); goto fail; } *tdp = cpu_to_hc32((uint32_t) td); tdp = &td->qt_next; toggle = 1; } if (length > 0 || req == NULL) { td = ehci_alloc(sizeof(struct qTD), 32); if (td == NULL) { debug("unable to allocate DATA td\n"); goto fail; } td->qt_next = cpu_to_hc32(QT_NEXT_TERMINATE); td->qt_altnext = cpu_to_hc32(QT_NEXT_TERMINATE); token = (toggle << 31) | (length << 16) | ((req == NULL ? 1 : 0) << 15) | (0 << 12) | (3 << 10) | ((usb_pipein(pipe) ? 1 : 0) << 8) | (0x80 << 0); td->qt_token = cpu_to_hc32(token); if (ehci_td_buffer(td, buffer, length) != 0) { debug("unable construct DATA td\n"); ehci_free(td, sizeof(*td)); goto fail; } *tdp = cpu_to_hc32((uint32_t) td); tdp = &td->qt_next; } if (req != NULL) { td = ehci_alloc(sizeof(struct qTD), 32); if (td == NULL) { debug("unable to allocate ACK td\n"); goto fail; } td->qt_next = cpu_to_hc32(QT_NEXT_TERMINATE); td->qt_altnext = cpu_to_hc32(QT_NEXT_TERMINATE); token = (toggle << 31) | (0 << 16) | (1 << 15) | (0 << 12) | (3 << 10) | ((usb_pipein(pipe) ? 0 : 1) << 8) | (0x80 << 0); td->qt_token = cpu_to_hc32(token); *tdp = cpu_to_hc32((uint32_t) td); tdp = &td->qt_next; } qh_list.qh_link = cpu_to_hc32((uint32_t) qh | QH_LINK_TYPE_QH); /* Flush dcache */ ehci_flush_dcache(&qh_list); usbsts = ehci_readl(&hcor->or_usbsts); ehci_writel(&hcor->or_usbsts, (usbsts & 0x3f)); /* Enable async. schedule. */ cmd = ehci_readl(&hcor->or_usbcmd); cmd |= CMD_ASE; ehci_writel(&hcor->or_usbcmd, cmd); ret = handshake((uint32_t *)&hcor->or_usbsts, STD_ASS, STD_ASS, 100 * 1000); if (ret < 0) { printf("EHCI fail timeout STD_ASS set\n"); goto fail; } /* Wait for TDs to be processed. */ ts = get_timer(0); vtd = td; timeout = USB_TIMEOUT_MS(pipe); do { /* Invalidate dcache */ ehci_invalidate_dcache(&qh_list); token = hc32_to_cpu(vtd->qt_token); if (!(token & 0x80)) break; WATCHDOG_RESET(); } while (get_timer(ts) < timeout); /* Check that the TD processing happened */ if (token & 0x80) { printf("EHCI timed out on TD - token=%#x\n", token); } /* Disable async schedule. */ cmd = ehci_readl(&hcor->or_usbcmd); cmd &= ~CMD_ASE; ehci_writel(&hcor->or_usbcmd, cmd); ret = handshake((uint32_t *)&hcor->or_usbsts, STD_ASS, 0, 100 * 1000); if (ret < 0) { printf("EHCI fail timeout STD_ASS reset\n"); goto fail; } qh_list.qh_link = cpu_to_hc32((uint32_t)&qh_list | QH_LINK_TYPE_QH); token = hc32_to_cpu(qh->qh_overlay.qt_token); if (!(token & 0x80)) { debug("TOKEN=%#x\n", token); switch (token & 0xfc) { case 0: toggle = token >> 31; usb_settoggle(dev, usb_pipeendpoint(pipe), usb_pipeout(pipe), toggle); dev->status = 0; break; case 0x40: dev->status = USB_ST_STALLED; break; case 0xa0: case 0x20: dev->status = USB_ST_BUF_ERR; break; case 0x50: case 0x10: dev->status = USB_ST_BABBLE_DET; break; default: dev->status = USB_ST_CRC_ERR; if ((token & 0x40) == 0x40) dev->status |= USB_ST_STALLED; break; } dev->act_len = length - ((token >> 16) & 0x7fff); } else {
int submit_control_msg(struct usb_device *dev, unsigned long pipe, void *buffer, int len,struct devrequest *setup) { int done = 0; int devnum = usb_pipedevice(pipe); int ep = usb_pipeendpoint(pipe); dev->status = 0; if (devnum == root_hub_devnum) return sl811_rh_submit_urb(dev, pipe, buffer, len, setup); PDEBUG(7, "dev = %d pipe = %ld buf = %p size = %d rt = %#x req = %#x bus = %i\n", devnum, ep, buffer, len, (int)setup->requesttype, (int)setup->request, sl811_read(SL811_SOFCNTDIV)*64); sl811_write(SL811_DEV_A, devnum); sl811_write(SL811_PIDEP_A, PIDEP(USB_PID_SETUP, ep)); /* setup phase */ usb_settoggle(dev, ep, 1, 0); if (sl811_send_packet(dev, usb_sndctrlpipe(dev, ep), (__u8*)setup, sizeof(*setup)) == sizeof(*setup)) { int dir_in = usb_pipein(pipe); int max = usb_maxpacket(dev, pipe); /* data phase */ sl811_write(SL811_PIDEP_A, PIDEP(dir_in ? USB_PID_IN : USB_PID_OUT, ep)); usb_settoggle(dev, ep, usb_pipeout(pipe), 1); while (done < len) { int res = sl811_send_packet(dev, pipe, (__u8*)buffer+done, max > len - done ? len - done : max); if (res < 0) { PDEBUG(0, "status data failed!\n"); dev->status = -res; return 0; } done += res; usb_dotoggle(dev, ep, usb_pipeout(pipe)); if (dir_in && res < max) /* short packet */ break; } /* status phase */ sl811_write(SL811_PIDEP_A, PIDEP(!dir_in ? USB_PID_IN : USB_PID_OUT, ep)); usb_settoggle(dev, ep, !usb_pipeout(pipe), 1); if (sl811_send_packet(dev, !dir_in ? usb_rcvctrlpipe(dev, ep) : usb_sndctrlpipe(dev, ep), 0, 0) < 0) { PDEBUG(0, "status phase failed!\n"); dev->status = -1; } } else { PDEBUG(0, "setup phase failed!\n"); dev->status = -1; } dev->act_len = done; return done; }
int chunk_msg(struct usb_device *dev, unsigned long pipe, int *pid, int in, void *buffer, int len, bool ignore_ack) { struct dwc2_hc_regs *hc_regs = ®s->hc_regs[DWC2_HC_CHANNEL]; int devnum = usb_pipedevice(pipe); int ep = usb_pipeendpoint(pipe); int max = usb_maxpacket(dev, pipe); int eptype = dwc2_eptype[usb_pipetype(pipe)]; int done = 0; int ret = 0; uint32_t sub; uint32_t xfer_len; uint32_t num_packets; int stop_transfer = 0; debug("%s: msg: pipe %lx pid %d in %d len %d\n", __func__, pipe, *pid, in, len); do { /* Initialize channel */ dwc_otg_hc_init(regs, DWC2_HC_CHANNEL, dev, devnum, ep, in, eptype, max); xfer_len = len - done; if (xfer_len > CONFIG_DWC2_MAX_TRANSFER_SIZE) xfer_len = CONFIG_DWC2_MAX_TRANSFER_SIZE - max + 1; if (xfer_len > DWC2_DATA_BUF_SIZE) xfer_len = DWC2_DATA_BUF_SIZE - max + 1; /* Make sure that xfer_len is a multiple of max packet size. */ if (xfer_len > 0) { num_packets = (xfer_len + max - 1) / max; if (num_packets > CONFIG_DWC2_MAX_PACKET_COUNT) { num_packets = CONFIG_DWC2_MAX_PACKET_COUNT; xfer_len = num_packets * max; } } else { num_packets = 1; } if (in) xfer_len = num_packets * max; debug("%s: chunk: pid %d xfer_len %u pkts %u\n", __func__, *pid, xfer_len, num_packets); writel((xfer_len << DWC2_HCTSIZ_XFERSIZE_OFFSET) | (num_packets << DWC2_HCTSIZ_PKTCNT_OFFSET) | (*pid << DWC2_HCTSIZ_PID_OFFSET), &hc_regs->hctsiz); if (!in) memcpy(aligned_buffer, (char *)buffer + done, len); writel(phys_to_bus((unsigned long)aligned_buffer), &hc_regs->hcdma); /* Set host channel enable after all other setup is complete. */ clrsetbits_le32(&hc_regs->hcchar, DWC2_HCCHAR_MULTICNT_MASK | DWC2_HCCHAR_CHEN | DWC2_HCCHAR_CHDIS, (1 << DWC2_HCCHAR_MULTICNT_OFFSET) | DWC2_HCCHAR_CHEN); ret = wait_for_chhltd(&sub, pid, ignore_ack); if (ret) break; if (in) { xfer_len -= sub; memcpy(buffer + done, aligned_buffer, xfer_len); if (sub) stop_transfer = 1; } done += xfer_len; } while ((done < len) && !stop_transfer); writel(0, &hc_regs->hcintmsk); writel(0xFFFFFFFF, &hc_regs->hcint); dev->status = 0; dev->act_len = done; return ret; }
static int ehci_submit_async(struct usb_device *dev, unsigned long pipe, void *buffer, int length, struct devrequest *req) { ALLOC_ALIGN_BUFFER(struct QH, qh, 1, USB_DMA_MINALIGN); struct qTD *qtd; int qtd_count = 0; int qtd_counter = 0; volatile struct qTD *vtd; unsigned long ts; uint32_t *tdp; uint32_t endpt, maxpacket, token, usbsts; uint32_t c, toggle; uint32_t cmd; int timeout; int ret = 0; struct ehci_ctrl *ctrl = dev->controller; debug("dev=%p, pipe=%lx, buffer=%p, length=%d, req=%p\n", dev, pipe, buffer, length, req); if (req != NULL) debug("req=%u (%#x), type=%u (%#x), value=%u (%#x), index=%u\n", req->request, req->request, req->requesttype, req->requesttype, le16_to_cpu(req->value), le16_to_cpu(req->value), le16_to_cpu(req->index)); #define PKT_ALIGN 512 /* * The USB transfer is split into qTD transfers. Eeach qTD transfer is * described by a transfer descriptor (the qTD). The qTDs form a linked * list with a queue head (QH). * * Each qTD transfer starts with a new USB packet, i.e. a packet cannot * have its beginning in a qTD transfer and its end in the following * one, so the qTD transfer lengths have to be chosen accordingly. * * Each qTD transfer uses up to QT_BUFFER_CNT data buffers, mapped to * single pages. The first data buffer can start at any offset within a * page (not considering the cache-line alignment issues), while the * following buffers must be page-aligned. There is no alignment * constraint on the size of a qTD transfer. */ if (req != NULL) /* 1 qTD will be needed for SETUP, and 1 for ACK. */ qtd_count += 1 + 1; if (length > 0 || req == NULL) { /* * Determine the qTD transfer size that will be used for the * data payload (not considering the first qTD transfer, which * may be longer or shorter, and the final one, which may be * shorter). * * In order to keep each packet within a qTD transfer, the qTD * transfer size is aligned to PKT_ALIGN, which is a multiple of * wMaxPacketSize (except in some cases for interrupt transfers, * see comment in submit_int_msg()). * * By default, i.e. if the input buffer is aligned to PKT_ALIGN, * QT_BUFFER_CNT full pages will be used. */ int xfr_sz = QT_BUFFER_CNT; /* * However, if the input buffer is not aligned to PKT_ALIGN, the * qTD transfer size will be one page shorter, and the first qTD * data buffer of each transfer will be page-unaligned. */ if ((uint32_t)buffer & (PKT_ALIGN - 1)) xfr_sz--; /* Convert the qTD transfer size to bytes. */ xfr_sz *= EHCI_PAGE_SIZE; /* * Approximate by excess the number of qTDs that will be * required for the data payload. The exact formula is way more * complicated and saves at most 2 qTDs, i.e. a total of 128 * bytes. */ qtd_count += 2 + length / xfr_sz; } /* * Threshold value based on the worst-case total size of the allocated qTDs for * a mass-storage transfer of 65535 blocks of 512 bytes. */ #if CONFIG_SYS_MALLOC_LEN <= 64 + 128 * 1024 #warning CONFIG_SYS_MALLOC_LEN may be too small for EHCI #endif qtd = memalign(USB_DMA_MINALIGN, qtd_count * sizeof(struct qTD)); if (qtd == NULL) { printf("unable to allocate TDs\n"); return -1; } memset(qh, 0, sizeof(struct QH)); memset(qtd, 0, qtd_count * sizeof(*qtd)); toggle = usb_gettoggle(dev, usb_pipeendpoint(pipe), usb_pipeout(pipe)); /* * Setup QH (3.6 in ehci-r10.pdf) * * qh_link ................. 03-00 H * qh_endpt1 ............... 07-04 H * qh_endpt2 ............... 0B-08 H * - qh_curtd * qh_overlay.qt_next ...... 13-10 H * - qh_overlay.qt_altnext */ qh->qh_link = cpu_to_hc32((uint32_t)&ctrl->qh_list | QH_LINK_TYPE_QH); c = (dev->speed != USB_SPEED_HIGH) && !usb_pipeendpoint(pipe); maxpacket = usb_maxpacket(dev, pipe); endpt = QH_ENDPT1_RL(8) | QH_ENDPT1_C(c) | QH_ENDPT1_MAXPKTLEN(maxpacket) | QH_ENDPT1_H(0) | QH_ENDPT1_DTC(QH_ENDPT1_DTC_DT_FROM_QTD) | QH_ENDPT1_EPS(ehci_encode_speed(dev->speed)) | QH_ENDPT1_ENDPT(usb_pipeendpoint(pipe)) | QH_ENDPT1_I(0) | QH_ENDPT1_DEVADDR(usb_pipedevice(pipe)); qh->qh_endpt1 = cpu_to_hc32(endpt); endpt = QH_ENDPT2_MULT(1) | QH_ENDPT2_UFCMASK(0) | QH_ENDPT2_UFSMASK(0); qh->qh_endpt2 = cpu_to_hc32(endpt); ehci_update_endpt2_dev_n_port(dev, qh); qh->qh_overlay.qt_next = cpu_to_hc32(QT_NEXT_TERMINATE); qh->qh_overlay.qt_altnext = cpu_to_hc32(QT_NEXT_TERMINATE); tdp = &qh->qh_overlay.qt_next; if (req != NULL) { /* * Setup request qTD (3.5 in ehci-r10.pdf) * * qt_next ................ 03-00 H * qt_altnext ............. 07-04 H * qt_token ............... 0B-08 H * * [ buffer, buffer_hi ] loaded with "req". */ qtd[qtd_counter].qt_next = cpu_to_hc32(QT_NEXT_TERMINATE); qtd[qtd_counter].qt_altnext = cpu_to_hc32(QT_NEXT_TERMINATE); token = QT_TOKEN_DT(0) | QT_TOKEN_TOTALBYTES(sizeof(*req)) | QT_TOKEN_IOC(0) | QT_TOKEN_CPAGE(0) | QT_TOKEN_CERR(3) | QT_TOKEN_PID(QT_TOKEN_PID_SETUP) | QT_TOKEN_STATUS(QT_TOKEN_STATUS_ACTIVE); qtd[qtd_counter].qt_token = cpu_to_hc32(token); if (ehci_td_buffer(&qtd[qtd_counter], req, sizeof(*req))) { printf("unable to construct SETUP TD\n"); goto fail; } /* Update previous qTD! */ *tdp = cpu_to_hc32((uint32_t)&qtd[qtd_counter]); tdp = &qtd[qtd_counter++].qt_next; toggle = 1; } if (length > 0 || req == NULL) { uint8_t *buf_ptr = buffer; int left_length = length; do { /* * Determine the size of this qTD transfer. By default, * QT_BUFFER_CNT full pages can be used. */ int xfr_bytes = QT_BUFFER_CNT * EHCI_PAGE_SIZE; /* * However, if the input buffer is not page-aligned, the * portion of the first page before the buffer start * offset within that page is unusable. */ xfr_bytes -= (uint32_t)buf_ptr & (EHCI_PAGE_SIZE - 1); /* * In order to keep each packet within a qTD transfer, * align the qTD transfer size to PKT_ALIGN. */ xfr_bytes &= ~(PKT_ALIGN - 1); /* * This transfer may be shorter than the available qTD * transfer size that has just been computed. */ xfr_bytes = min(xfr_bytes, left_length); /* * Setup request qTD (3.5 in ehci-r10.pdf) * * qt_next ................ 03-00 H * qt_altnext ............. 07-04 H * qt_token ............... 0B-08 H * * [ buffer, buffer_hi ] loaded with "buffer". */ qtd[qtd_counter].qt_next = cpu_to_hc32(QT_NEXT_TERMINATE); qtd[qtd_counter].qt_altnext = cpu_to_hc32(QT_NEXT_TERMINATE); token = QT_TOKEN_DT(toggle) | QT_TOKEN_TOTALBYTES(xfr_bytes) | QT_TOKEN_IOC(req == NULL) | QT_TOKEN_CPAGE(0) | QT_TOKEN_CERR(3) | QT_TOKEN_PID(usb_pipein(pipe) ? QT_TOKEN_PID_IN : QT_TOKEN_PID_OUT) | QT_TOKEN_STATUS(QT_TOKEN_STATUS_ACTIVE); qtd[qtd_counter].qt_token = cpu_to_hc32(token); if (ehci_td_buffer(&qtd[qtd_counter], buf_ptr, xfr_bytes)) { printf("unable to construct DATA TD\n"); goto fail; } /* Update previous qTD! */ *tdp = cpu_to_hc32((uint32_t)&qtd[qtd_counter]); tdp = &qtd[qtd_counter++].qt_next; /* * Data toggle has to be adjusted since the qTD transfer * size is not always an even multiple of * wMaxPacketSize. */ if ((xfr_bytes / maxpacket) & 1) toggle ^= 1; buf_ptr += xfr_bytes; left_length -= xfr_bytes; } while (left_length > 0); } if (req != NULL) { /* * Setup request qTD (3.5 in ehci-r10.pdf) * * qt_next ................ 03-00 H * qt_altnext ............. 07-04 H * qt_token ............... 0B-08 H */ qtd[qtd_counter].qt_next = cpu_to_hc32(QT_NEXT_TERMINATE); qtd[qtd_counter].qt_altnext = cpu_to_hc32(QT_NEXT_TERMINATE); token = QT_TOKEN_DT(1) | QT_TOKEN_TOTALBYTES(0) | QT_TOKEN_IOC(1) | QT_TOKEN_CPAGE(0) | QT_TOKEN_CERR(3) | QT_TOKEN_PID(usb_pipein(pipe) ? QT_TOKEN_PID_OUT : QT_TOKEN_PID_IN) | QT_TOKEN_STATUS(QT_TOKEN_STATUS_ACTIVE); qtd[qtd_counter].qt_token = cpu_to_hc32(token); /* Update previous qTD! */ *tdp = cpu_to_hc32((uint32_t)&qtd[qtd_counter]); tdp = &qtd[qtd_counter++].qt_next; } ctrl->qh_list.qh_link = cpu_to_hc32((uint32_t)qh | QH_LINK_TYPE_QH); /* Flush dcache */ flush_dcache_range((uint32_t)&ctrl->qh_list, ALIGN_END_ADDR(struct QH, &ctrl->qh_list, 1)); flush_dcache_range((uint32_t)qh, ALIGN_END_ADDR(struct QH, qh, 1)); flush_dcache_range((uint32_t)qtd, ALIGN_END_ADDR(struct qTD, qtd, qtd_count)); /* Set async. queue head pointer. */ ehci_writel(&ctrl->hcor->or_asynclistaddr, (uint32_t)&ctrl->qh_list); usbsts = ehci_readl(&ctrl->hcor->or_usbsts); ehci_writel(&ctrl->hcor->or_usbsts, (usbsts & 0x3f)); /* Enable async. schedule. */ cmd = ehci_readl(&ctrl->hcor->or_usbcmd); cmd |= CMD_ASE; ehci_writel(&ctrl->hcor->or_usbcmd, cmd); ret = handshake((uint32_t *)&ctrl->hcor->or_usbsts, STS_ASS, STS_ASS, 100 * 1000); if (ret < 0) { printf("EHCI fail timeout STS_ASS set\n"); goto fail; } /* Wait for TDs to be processed. */ ts = get_timer(0); vtd = &qtd[qtd_counter - 1]; timeout = USB_TIMEOUT_MS(pipe); do { /* Invalidate dcache */ invalidate_dcache_range((uint32_t)&ctrl->qh_list, ALIGN_END_ADDR(struct QH, &ctrl->qh_list, 1)); invalidate_dcache_range((uint32_t)qh, ALIGN_END_ADDR(struct QH, qh, 1)); invalidate_dcache_range((uint32_t)qtd, ALIGN_END_ADDR(struct qTD, qtd, qtd_count)); token = hc32_to_cpu(vtd->qt_token); if (!(QT_TOKEN_GET_STATUS(token) & QT_TOKEN_STATUS_ACTIVE)) break; WATCHDOG_RESET(); } while (get_timer(ts) < timeout); /* * Invalidate the memory area occupied by buffer * Don't try to fix the buffer alignment, if it isn't properly * aligned it's upper layer's fault so let invalidate_dcache_range() * vow about it. But we have to fix the length as it's actual * transfer length and can be unaligned. This is potentially * dangerous operation, it's responsibility of the calling * code to make sure enough space is reserved. */ invalidate_dcache_range((uint32_t)buffer, ALIGN((uint32_t)buffer + length, ARCH_DMA_MINALIGN)); /* Check that the TD processing happened */ if (QT_TOKEN_GET_STATUS(token) & QT_TOKEN_STATUS_ACTIVE) printf("EHCI timed out on TD - token=%#x\n", token); /* Disable async schedule. */ cmd = ehci_readl(&ctrl->hcor->or_usbcmd); cmd &= ~CMD_ASE; ehci_writel(&ctrl->hcor->or_usbcmd, cmd); ret = handshake((uint32_t *)&ctrl->hcor->or_usbsts, STS_ASS, 0, 100 * 1000); if (ret < 0) { printf("EHCI fail timeout STS_ASS reset\n"); goto fail; } token = hc32_to_cpu(qh->qh_overlay.qt_token); if (!(QT_TOKEN_GET_STATUS(token) & QT_TOKEN_STATUS_ACTIVE)) { debug("TOKEN=%#x\n", token); switch (QT_TOKEN_GET_STATUS(token) & ~(QT_TOKEN_STATUS_SPLITXSTATE | QT_TOKEN_STATUS_PERR)) { case 0: toggle = QT_TOKEN_GET_DT(token); usb_settoggle(dev, usb_pipeendpoint(pipe), usb_pipeout(pipe), toggle); dev->status = 0; break; case QT_TOKEN_STATUS_HALTED: dev->status = USB_ST_STALLED; break; case QT_TOKEN_STATUS_ACTIVE | QT_TOKEN_STATUS_DATBUFERR: case QT_TOKEN_STATUS_DATBUFERR: dev->status = USB_ST_BUF_ERR; break; case QT_TOKEN_STATUS_HALTED | QT_TOKEN_STATUS_BABBLEDET: case QT_TOKEN_STATUS_BABBLEDET: dev->status = USB_ST_BABBLE_DET; break; default: dev->status = USB_ST_CRC_ERR; if (QT_TOKEN_GET_STATUS(token) & QT_TOKEN_STATUS_HALTED) dev->status |= USB_ST_STALLED; break; } dev->act_len = length - QT_TOKEN_GET_TOTALBYTES(token); } else { dev->act_len = 0; #ifndef CONFIG_USB_EHCI_FARADAY debug("dev=%u, usbsts=%#x, p[1]=%#x, p[2]=%#x\n", dev->devnum, ehci_readl(&ctrl->hcor->or_usbsts), ehci_readl(&ctrl->hcor->or_portsc[0]), ehci_readl(&ctrl->hcor->or_portsc[1])); #endif } free(qtd); return (dev->status != USB_ST_NOT_PROC) ? 0 : -1; fail: free(qtd); return -1; }
int usb_emul_find(struct udevice *bus, ulong pipe, struct udevice **emulp) { int devnum = usb_pipedevice(pipe); return usb_emul_find_devnum(devnum, emulp); }
/* * do a bulk transfer */ int submit_bulk_msg(struct usb_device *dev, unsigned long pipe, void *buffer, int len) { int dir_out = usb_pipeout(pipe); int ep = usb_pipeendpoint(pipe); #ifndef MUSB_NO_MULTIPOINT int devnum = usb_pipedevice(pipe); #endif u8 type; u16 csr; u32 txlen = 0; u32 nextlen = 0; u8 devspeed; /* select bulk endpoint */ writeb(MUSB_BULK_EP, &musbr->index); #ifndef MUSB_NO_MULTIPOINT /* write the address of the device */ if (dir_out) writeb(devnum, &musbr->tar[MUSB_BULK_EP].txfuncaddr); else writeb(devnum, &musbr->tar[MUSB_BULK_EP].rxfuncaddr); #endif /* configure the hub address and the port number as required */ devspeed = get_dev_speed(dev); if ((musb_ishighspeed()) && (dev->parent != NULL) && (devspeed != MUSB_TYPE_SPEED_HIGH)) { /* * MUSB is in high speed and the destination device is full * speed device. So configure the hub address and port * address registers. */ config_hub_port(dev, MUSB_BULK_EP); } else { #ifndef MUSB_NO_MULTIPOINT if (dir_out) { writeb(0, &musbr->tar[MUSB_BULK_EP].txhubaddr); writeb(0, &musbr->tar[MUSB_BULK_EP].txhubport); } else { writeb(0, &musbr->tar[MUSB_BULK_EP].rxhubaddr); writeb(0, &musbr->tar[MUSB_BULK_EP].rxhubport); } #endif devspeed = musb_cfg.musb_speed; } /* Write the saved toggle bit value */ write_toggle(dev, ep, dir_out); if (dir_out) { /* bulk-out transfer */ /* Program the TxType register */ type = (devspeed << MUSB_TYPE_SPEED_SHIFT) | (MUSB_TYPE_PROTO_BULK << MUSB_TYPE_PROTO_SHIFT) | (ep & MUSB_TYPE_REMOTE_END); writeb(type, &musbr->txtype); /* Write maximum packet size to the TxMaxp register */ writew(dev->epmaxpacketout[ep], &musbr->txmaxp); while (txlen < len) { nextlen = ((len-txlen) < dev->epmaxpacketout[ep]) ? (len-txlen) : dev->epmaxpacketout[ep]; #ifdef CONFIG_USB_BLACKFIN /* Set the transfer data size */ writew(nextlen, &musbr->txcount); #endif /* Write the data to the FIFO */ write_fifo(MUSB_BULK_EP, nextlen, (void *)(((u8 *)buffer) + txlen)); /* Set the TxPktRdy bit */ csr = readw(&musbr->txcsr); writew(csr | MUSB_TXCSR_TXPKTRDY, &musbr->txcsr); /* Wait until the TxPktRdy bit is cleared */ if (wait_until_txep_ready(dev, MUSB_BULK_EP) != 1) { readw(&musbr->txcsr); usb_settoggle(dev, ep, dir_out, (csr >> MUSB_TXCSR_H_DATATOGGLE_SHIFT) & 1); dev->act_len = txlen; return 0; } txlen += nextlen; } /* Keep a copy of the data toggle bit */ csr = readw(&musbr->txcsr); usb_settoggle(dev, ep, dir_out, (csr >> MUSB_TXCSR_H_DATATOGGLE_SHIFT) & 1); } else { /* bulk-in transfer */
/* * do a control transfer */ int submit_control_msg(struct usb_device *dev, unsigned long pipe, void *buffer, int len, struct devrequest *setup) { int devnum = usb_pipedevice(pipe); u8 devspeed; #ifdef MUSB_NO_MULTIPOINT /* Control message is for the HUB? */ if (devnum == rh_devnum) { int stat = musb_submit_rh_msg(dev, pipe, buffer, len, setup); if (stat) return stat; } #endif /* select control endpoint */ writeb(MUSB_CONTROL_EP, &musbr->index); readw(&musbr->txcsr); #ifndef MUSB_NO_MULTIPOINT /* target addr and (for multipoint) hub addr/port */ writeb(devnum, &musbr->tar[MUSB_CONTROL_EP].txfuncaddr); writeb(devnum, &musbr->tar[MUSB_CONTROL_EP].rxfuncaddr); #endif /* configure the hub address and the port number as required */ devspeed = get_dev_speed(dev); if ((musb_ishighspeed()) && (dev->parent != NULL) && (devspeed != MUSB_TYPE_SPEED_HIGH)) { config_hub_port(dev, MUSB_CONTROL_EP); writeb(devspeed << 6, &musbr->txtype); } else { writeb(musb_cfg.musb_speed << 6, &musbr->txtype); #ifndef MUSB_NO_MULTIPOINT writeb(0, &musbr->tar[MUSB_CONTROL_EP].txhubaddr); writeb(0, &musbr->tar[MUSB_CONTROL_EP].txhubport); writeb(0, &musbr->tar[MUSB_CONTROL_EP].rxhubaddr); writeb(0, &musbr->tar[MUSB_CONTROL_EP].rxhubport); #endif } /* Control transfer setup phase */ if (ctrlreq_setup_phase(dev, setup) < 0) return 0; switch (setup->request) { case USB_REQ_GET_DESCRIPTOR: case USB_REQ_GET_CONFIGURATION: case USB_REQ_GET_INTERFACE: case USB_REQ_GET_STATUS: case USB_MSC_BBB_GET_MAX_LUN: /* control transfer in-data-phase */ if (ctrlreq_in_data_phase(dev, len, buffer) < 0) return 0; /* control transfer out-status-phase */ if (ctrlreq_out_status_phase(dev) < 0) return 0; break; case USB_REQ_SET_ADDRESS: case USB_REQ_SET_CONFIGURATION: case USB_REQ_SET_FEATURE: case USB_REQ_SET_INTERFACE: case USB_REQ_CLEAR_FEATURE: case USB_MSC_BBB_RESET: /* control transfer in status phase */ if (ctrlreq_in_status_phase(dev) < 0) return 0; break; case USB_REQ_SET_DESCRIPTOR: /* control transfer out data phase */ if (ctrlreq_out_data_phase(dev, len, buffer) < 0) return 0; /* control transfer in status phase */ if (ctrlreq_in_status_phase(dev) < 0) return 0; break; default: /* unhandled control transfer */ return -1; } dev->status = 0; dev->act_len = len; #ifdef MUSB_NO_MULTIPOINT /* Set device address to USB_FADDR register */ if (setup->request == USB_REQ_SET_ADDRESS) writeb(dev->devnum, &musbr->faddr); #endif return len; }
static struct usbhsh_device *usbhsh_device_attach(struct usbhsh_hpriv *hpriv, struct urb *urb) { struct usbhsh_device *udev = NULL; struct usbhsh_device *udev0 = usbhsh_device0(hpriv); struct usbhsh_device *pos; struct usb_hcd *hcd = usbhsh_hpriv_to_hcd(hpriv); struct device *dev = usbhsh_hcd_to_dev(hcd); struct usb_device *usbv = usbhsh_urb_to_usbv(urb); struct usbhs_priv *priv = usbhsh_hpriv_to_priv(hpriv); unsigned long flags; u16 upphub, hubport; int i; /* * This function should be called only while urb is pointing to device0. * It will attach unused usbhsh_device to urb (usbv), * and initialize device0. * You can use usbhsh_device_get() to get "current" udev, * and usbhsh_usbv_to_udev() is for "attached" udev. */ if (0 != usb_pipedevice(urb->pipe)) { dev_err(dev, "%s fail: urb isn't pointing device0\n", __func__); return NULL; } /******************** spin lock ********************/ usbhs_lock(priv, flags); /* * find unused device */ usbhsh_for_each_udev(pos, hpriv, i) { if (usbhsh_udev_is_used(pos)) continue; udev = pos; break; } if (udev) { /* * usbhsh_usbv_to_udev() * usbhsh_udev_to_usbv() * will be enable */ dev_set_drvdata(&usbv->dev, udev); udev->usbv = usbv; } usbhs_unlock(priv, flags); /******************** spin unlock ******************/ if (!udev) { dev_err(dev, "no free usbhsh_device\n"); return NULL; } if (usbhsh_device_has_endpoint(udev)) { dev_warn(dev, "udev have old endpoint\n"); usbhsh_endpoint_detach_all(hpriv, udev); } if (usbhsh_device_has_endpoint(udev0)) { dev_warn(dev, "udev0 have old endpoint\n"); usbhsh_endpoint_detach_all(hpriv, udev0); } /* uep will be attached */ INIT_LIST_HEAD(&udev0->ep_list_head); INIT_LIST_HEAD(&udev->ep_list_head); /* * set device0 config */ usbhs_set_device_config(priv, 0, 0, 0, usbv->speed); /* * set new device config */ upphub = 0; hubport = 0; if (!usbhsh_connected_to_rhdev(hcd, udev)) { /* if udev is not connected to rhdev, it means parent is Hub */ struct usbhsh_device *parent = usbhsh_device_parent(udev); upphub = usbhsh_device_number(hpriv, parent); hubport = usbhsh_device_hubport(udev); dev_dbg(dev, "%s connecte to Hub [%d:%d](%p)\n", __func__, upphub, hubport, parent); } usbhs_set_device_config(priv, usbhsh_device_number(hpriv, udev), upphub, hubport, usbv->speed); dev_dbg(dev, "%s [%d](%p)\n", __func__, usbhsh_device_number(hpriv, udev), udev); return udev; }