static void complete_rx(struct s3c_udc *dev, u8 ep_num) { struct s3c_ep *ep = &dev->ep[ep_num]; struct s3c_request *req = NULL; u32 ep_tsr = 0, xfer_size = 0, is_short = 0; u32 *p = the_controller->dma_buf[ep_index(ep)+1]; if (list_empty(&ep->queue)) { DEBUG_OUT_EP("%s: RX DMA done : NULL REQ on OUT EP-%d\n", __func__, ep_num); return; } req = list_entry(ep->queue.next, struct s3c_request, queue); ep_tsr = readl(®->out_endp[ep_num].doeptsiz); if (ep_num == EP0_CON) xfer_size = (ep_tsr & DOEPT_SIZ_XFER_SIZE_MAX_EP0); else xfer_size = (ep_tsr & DOEPT_SIZ_XFER_SIZE_MAX_EP); xfer_size = ep->len - xfer_size; invalidate_dcache_range((unsigned long) p, (unsigned long) p + DMA_BUFFER_SIZE); memcpy(ep->dma_buf, p, ep->len); req->req.actual += min(xfer_size, req->req.length - req->req.actual); is_short = (xfer_size < ep->ep.maxpacket); DEBUG_OUT_EP("%s: RX DMA done : ep = %d, rx bytes = %d/%d, " "is_short = %d, DOEPTSIZ = 0x%x, remained bytes = %d\n", __func__, ep_num, req->req.actual, req->req.length, is_short, ep_tsr, xfer_size); if (is_short || req->req.actual == req->req.length) { if (ep_num == EP0_CON && dev->ep0state == DATA_STATE_RECV) { DEBUG_OUT_EP(" => Send ZLP\n"); s3c_udc_ep0_zlp(dev); /* packet will be completed in complete_tx() */ dev->ep0state = WAIT_FOR_IN_COMPLETE; } else { done(ep, req, 0); if (!list_empty(&ep->queue)) { req = list_entry(ep->queue.next, struct s3c_request, queue); DEBUG_OUT_EP("%s: Next Rx request start...\n", __func__); setdma_rx(ep, req); } } } else
static void complete_rx(struct s3c_udc *dev, u8 ep_num) { struct s3c_ep *ep = &dev->ep[ep_num]; struct s3c_request *req = NULL; u32 ep_tsr = 0, xfer_size = 0, xfer_length, is_short = 0; if (list_empty(&ep->queue)) { DEBUG_OUT_EP("%s: RX DMA done : NULL REQ on OUT EP-%d\n", __func__, ep_num); return; } req = list_entry(ep->queue.next, struct s3c_request, queue); ep_tsr = readl(S3C_UDC_OTG_DOEPTSIZ(ep_num)); if (ep_num == EP0_CON) xfer_size = (ep_tsr & 0x7f); else xfer_size = (ep_tsr & 0x7fff); dma_cache_maint(req->req.buf, req->req.length, DMA_FROM_DEVICE); xfer_length = req->req.length - xfer_size; req->req.actual += min(xfer_length, req->req.length - req->req.actual); is_short = (xfer_length < ep->ep.maxpacket); DEBUG_OUT_EP("%s: RX DMA done : ep = %d, rx bytes = %d/%d, " "is_short = %d, DOEPTSIZ = 0x%x, remained bytes = %d\n", __func__, ep_num, req->req.actual, req->req.length, is_short, ep_tsr, xfer_size); if (is_short || req->req.actual == xfer_length) { if(ep_num == EP0_CON && dev->ep0state == DATA_STATE_RECV) { DEBUG_OUT_EP(" => Send ZLP\n"); dev->ep0state = WAIT_FOR_SETUP; s3c_udc_ep0_zlp(); } else { done(ep, req, 0); if(!list_empty(&ep->queue)) { req = list_entry(ep->queue.next, struct s3c_request, queue); DEBUG_OUT_EP("%s: Next Rx request start...\n", __func__); if (ep_num == EP0_CON && dev->ep0state == WAIT_FOR_SETUP) setdma_rx(ep, req, 1); else setdma_rx(ep, req, 0); } } }
static void s3c_out_epn(struct s3c_udc *dev, u32 ep_idx) { struct s3c_ep *ep = &dev->ep[ep_idx]; struct s3c_request *req; if (unlikely(!(ep->desc))) { /* Throw packet away.. */ printk("%s: No descriptor?!?\n", __FUNCTION__); return; } if (list_empty(&ep->queue)) req = 0; else req = list_entry(ep->queue.next, struct s3c_request, queue); if (unlikely(!req)) { DEBUG_OUT_EP("%s: NULL REQ on OUT EP-%d\n", __FUNCTION__, ep_idx); return; } else { read_fifo(ep, req); } }
static int setdma_rx(struct s3c_ep *ep, struct s3c_request *req) { u32 *buf, ctrl; u32 length, pktcnt; u32 ep_num = ep_index(ep); buf = req->req.buf + req->req.actual; prefetchw(buf); length = req->req.length - req->req.actual; dma_cache_maint(buf, length, DMA_FROM_DEVICE); if(length == 0) pktcnt = 1; else pktcnt = (length - 1)/(ep->ep.maxpacket) + 1; ctrl = readl(S3C_UDC_OTG_DOEPCTL(ep_num)); writel(virt_to_phys(buf), S3C_UDC_OTG_DOEPDMA(ep_num)); writel((pktcnt<<19)|(length<<0), S3C_UDC_OTG_DOEPTSIZ(ep_num)); writel(DEPCTL_EPENA|DEPCTL_CNAK|ctrl, S3C_UDC_OTG_DOEPCTL(ep_num)); DEBUG_OUT_EP("%s: EP%d RX DMA start : DOEPDMA = 0x%x, DOEPTSIZ = 0x%x, DOEPCTL = 0x%x\n" "\tbuf = 0x%p, pktcnt = %d, xfersize = %d\n", __func__, ep_num, readl(S3C_UDC_OTG_DOEPDMA(ep_num)), readl(S3C_UDC_OTG_DOEPTSIZ(ep_num)), readl(S3C_UDC_OTG_DOEPCTL(ep_num)), buf, pktcnt, length); return 0; }
static int setdma_rx(struct s3c_ep *ep, struct s3c_request *req) { u32 *buf, ctrl; u32 length, pktcnt; u32 ep_num = ep_index(ep); struct s3c_udc *udc = ep->dev; struct device *dev = &udc->dev->dev; aligned_map_buf(req, ep_is_in(ep)); buf = req->req.buf + req->req.actual; prefetchw(buf); length = req->req.length - req->req.actual; req->req.dma = dma_map_single(dev, buf, length, DMA_FROM_DEVICE); req->mapped = 1; if (length == 0) pktcnt = 1; else pktcnt = (length - 1)/(ep->ep.maxpacket) + 1; ctrl = __raw_readl(udc->regs + S3C_UDC_OTG_DOEPCTL(ep_num)); __raw_writel(virt_to_phys(buf), udc->regs + S3C_UDC_OTG_DOEPDMA(ep_num)); __raw_writel((pktcnt<<19) | (length<<0), udc->regs + S3C_UDC_OTG_DOEPTSIZ(ep_num)); __raw_writel(DEPCTL_EPENA | DEPCTL_CNAK | ctrl, udc->regs + S3C_UDC_OTG_DOEPCTL(ep_num)); DEBUG_OUT_EP("%s: EP%d RX DMA start : DOEPDMA = 0x%x," "DOEPTSIZ = 0x%x, DOEPCTL = 0x%x\n" "\tbuf = 0x%p, pktcnt = %d, xfersize = %d\n", __func__, ep_num, __raw_readl(udc->regs + S3C_UDC_OTG_DOEPDMA(ep_num)), __raw_readl(udc->regs + S3C_UDC_OTG_DOEPTSIZ(ep_num)), __raw_readl(udc->regs + S3C_UDC_OTG_DOEPCTL(ep_num)), buf, pktcnt, length); return 0; }
static int setdma_rx(struct s3c_ep *ep, struct s3c_request *req) { u32 *buf, ctrl; u32 length, pktcnt; u32 ep_num = ep_index(ep); buf = req->req.buf + req->req.actual; length = min(req->req.length - req->req.actual, (int)ep->ep.maxpacket); ep->len = length; ep->dma_buf = buf; invalidate_dcache_range((unsigned long) ep->dev->dma_buf[ep_num], (unsigned long) ep->dev->dma_buf[ep_num] + DMA_BUFFER_SIZE); if (length == 0) pktcnt = 1; else pktcnt = (length - 1)/(ep->ep.maxpacket) + 1; pktcnt = 1; ctrl = readl(®->out_endp[ep_num].doepctl); writel(the_controller->dma_addr[ep_index(ep)+1], ®->out_endp[ep_num].doepdma); writel(DOEPT_SIZ_PKT_CNT(pktcnt) | DOEPT_SIZ_XFER_SIZE(length), ®->out_endp[ep_num].doeptsiz); writel(DEPCTL_EPENA|DEPCTL_CNAK|ctrl, ®->out_endp[ep_num].doepctl); DEBUG_OUT_EP("%s: EP%d RX DMA start : DOEPDMA = 0x%x," "DOEPTSIZ = 0x%x, DOEPCTL = 0x%x\n" "\tbuf = 0x%p, pktcnt = %d, xfersize = %d\n", __func__, ep_num, readl(®->out_endp[ep_num].doepdma), readl(®->out_endp[ep_num].doeptsiz), readl(®->out_endp[ep_num].doepctl), buf, pktcnt, length); return 0; }
/** Read to request from FIFO (max read == bytes in fifo) * Return: 0 = still running, 1 = completed, negative = errno */ static int read_fifo(struct s3c_ep *ep, struct s3c_request *req) { u32 csr, gintmsk; u32 *buf; u32 bufferspace, count, count_bytes, is_short = 0; u32 fifo = ep->fifo; csr = readl(S3C_UDC_OTG_GRXSTSP); count_bytes = (csr & 0x7ff0)>>4; gintmsk = readl(S3C_UDC_OTG_GINTMSK); if(!count_bytes) { DEBUG_OUT_EP("%s: count_bytes %d bytes\n", __FUNCTION__, count_bytes); /* Unmask USB OTG 2.0 interrupt source : INT_RX_FIFO_NOT_EMPTY */ writel(gintmsk | INT_RX_FIFO_NOT_EMPTY, S3C_UDC_OTG_GINTMSK); return 0; } buf = req->req.buf + req->req.actual; prefetchw(buf); bufferspace = req->req.length - req->req.actual; count = count_bytes / 4; if (count_bytes%4) count = count + 1; req->req.actual += min(count_bytes, bufferspace); is_short = (count_bytes < ep->ep.maxpacket); DEBUG_OUT_EP("%s: read %s, %d bytes%s req %p %d/%d GRXSTSP:0x%x\n", __FUNCTION__, ep->ep.name, count_bytes, is_short ? "/S" : "", req, req->req.actual, req->req.length, csr); while (likely(count-- != 0)) { u32 byte = (u32) readl(fifo); if (unlikely(bufferspace == 0)) { /* this happens when the driver's buffer * is smaller than what the host sent. * discard the extra data. */ if (req->req.status != -EOVERFLOW) printk("%s overflow %d\n", ep->ep.name, count); req->req.status = -EOVERFLOW; } else { *buf++ = byte; bufferspace-=4; } } /* Unmask USB OTG 2.0 interrupt source : INT_RX_FIFO_NOT_EMPTY */ writel(gintmsk | INT_RX_FIFO_NOT_EMPTY, S3C_UDC_OTG_GINTMSK); /* completion */ if (is_short || req->req.actual == req->req.length) { done(ep, req, 0); return 1; } /* finished that packet. the next one may be waiting... */ return 0; }