/** * elfin_in_epn - handle IN interrupt */ static void elfin_in_epn(struct elfin_udc *dev, u32 ep_idx) { u32 csr; struct elfin_ep *ep = &dev->ep[ep_idx]; struct elfin_request *req; csr = usb_read(ep->csr1, ep_index(ep)); DPRINTK("%s: %d, csr %x\n", __FUNCTION__, ep_idx, csr); if (csr & S3C2410_UDC_ICSR1_SENTSTL) { printk("S3C2410_UDC_ICSR1_SENTSTL\n"); usb_set(S3C2410_UDC_ICSR1_SENTSTL /*| S3C2410_UDC_ICSR1_SENDSTL */ , ep->csr1, ep_index(ep)); return; } if (!ep->desc) { DPRINTK("%s: NO EP DESC\n", __FUNCTION__); return; } if (list_empty(&ep->queue)) req = 0; else req = list_entry(ep->queue.next, struct elfin_request, queue); DPRINTK("req: %p\n", req); if (!req) return; write_fifo(ep, req); }
int setdma_tx(struct s3c_ep *ep, struct s3c_request *req) { u32 *buf, ctrl = 0; u32 length, pktcnt; u32 ep_num = ep_index(ep); u32 *p = the_controller->dma_buf[ep_index(ep)+1]; buf = req->req.buf + req->req.actual; length = req->req.length - req->req.actual; if (ep_num == EP0_CON) length = min(length, (u32)ep_maxpacket(ep)); ep->len = length; ep->dma_buf = buf; memcpy(p, ep->dma_buf, length); flush_dcache_range((unsigned long) p , (unsigned long) p + DMA_BUFFER_SIZE); if (length == 0) pktcnt = 1; else pktcnt = (length - 1)/(ep->ep.maxpacket) + 1; /* Flush the endpoint's Tx FIFO */ writel(TX_FIFO_NUMBER(ep->fifo_num), ®->grstctl); writel(TX_FIFO_NUMBER(ep->fifo_num) | TX_FIFO_FLUSH, ®->grstctl); while (readl(®->grstctl) & TX_FIFO_FLUSH) ; writel(the_controller->dma_addr[ep_index(ep)+1], ®->in_endp[ep_num].diepdma); writel(DIEPT_SIZ_PKT_CNT(pktcnt) | DIEPT_SIZ_XFER_SIZE(length), ®->in_endp[ep_num].dieptsiz); ctrl = readl(®->in_endp[ep_num].diepctl); /* Write the FIFO number to be used for this endpoint */ ctrl &= DIEPCTL_TX_FIFO_NUM_MASK; ctrl |= DIEPCTL_TX_FIFO_NUM(ep->fifo_num); /* Clear reserved (Next EP) bits */ ctrl = (ctrl&~(EP_MASK<<DEPCTL_NEXT_EP_BIT)); writel(DEPCTL_EPENA|DEPCTL_CNAK|ctrl, ®->in_endp[ep_num].diepctl); debug_cond(DEBUG_IN_EP, "%s:EP%d TX DMA start : DIEPDMA0 = 0x%x," "DIEPTSIZ0 = 0x%x, DIEPCTL0 = 0x%x\n" "\tbuf = 0x%p, pktcnt = %d, xfersize = %d\n", __func__, ep_num, readl(®->in_endp[ep_num].diepdma), readl(®->in_endp[ep_num].dieptsiz), readl(®->in_endp[ep_num].diepctl), buf, pktcnt, length); return length; }
/** Read to request from FIFO (max read == bytes in fifo) * Return: 0 = still running, 1 = completed, negative = errno */ static int read_fifo(struct elfin_ep *ep, struct elfin_request *req) { u32 csr; u8 *buf; unsigned bufferspace, count, is_short; void* fifo = ep->fifo; /* make sure there's a packet in the FIFO. */ csr = usb_read(ep->csr1, ep_index(ep)); if (!(csr & S3C2410_UDC_OCSR1_PKTRDY)) { DPRINTK("%s: Packet NOT ready!\n", __FUNCTION__); return -EINVAL; } buf = req->req.buf + req->req.actual; prefetchw(buf); bufferspace = req->req.length - req->req.actual; /* read all bytes from this packet */ count = (( (usb_read(S3C2410_UDC_OUT_FIFO_CNT2_REG, ep_index(ep)) & 0xff ) << 8) | (usb_read(S3C2410_UDC_OUT_FIFO_CNT1_REG, ep_index(ep)) & 0xff)); req->req.actual += min(count, bufferspace); is_short = (count < ep->ep.maxpacket); DPRINTK("read %s %02x, %d bytes%s req %p %d/%d\n", ep->ep.name, csr, count, is_short ? "/S" : "", req, req->req.actual, req->req.length); while (likely(count-- != 0)) { u8 byte = (u8) __raw_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--; } } usb_clear(S3C2410_UDC_OCSR1_PKTRDY, ep->csr1, ep_index(ep)); /* 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; }
static int udc_read_fifo(struct udc_ep *ep, struct udc_req *req) { struct udc *udc = ep->dev; void __iomem *fifo = ep->fifo; u16 *buf, word; int buflen, count, length, bytes; u32 offset; u16 esr; int is_last = 0; offset = ep_index(ep) ? UDC_ESR : UDC_EP0SR; esr = readw(udc->regs + offset); if (!(esr & UDC_ESR_RX_SUCCESS)) return -EINVAL; buf = req->buf + req->actual; buflen = req->length - req->actual; count = readw(udc->regs + UDC_BRCR); length = count * 2; if (esr & (ep_index(ep) ? UDC_ESR_LWO : UDC_EP0SR_EP0_LWO)) length -= 1; bytes = min(length, buflen); req->actual += bytes; is_last = (length < ep->maxpacket); while (count--) { word = readw(fifo); if (buflen) { *buf++ = word; buflen -= 2; } else { req->status = -EOVERFLOW; } } if (!ep_index(ep)) { writew(UDC_ESR_RX_SUCCESS, udc->regs + UDC_EP0SR); /* undocumented bits in ep0sr that signal last data */ is_last |= (esr & (1 << 15)) || (esr & (1 << 12)); } is_last |= (req->actual == req->length); if (is_last) udc_complete_req(ep, req, 0); return is_last; }
/** Write request to FIFO (max write == maxp size) * Return: 0 = still running, 1 = completed, negative = errno * NOTE: INDEX register must be set for EP */ static int write_fifo(struct lh7a40x_ep *ep, struct lh7a40x_request *req) { u32 max; u32 csr; max = le16_to_cpu(ep->desc->wMaxPacketSize); csr = usb_read(ep->csr1); DEBUG("CSR: %x %d\n", csr, csr & USB_IN_CSR1_FIFO_NOT_EMPTY); if (!(csr & USB_IN_CSR1_FIFO_NOT_EMPTY)) { unsigned count; int is_last, is_short; count = write_packet(ep, req, max); usb_set(USB_IN_CSR1_IN_PKT_RDY, ep->csr1); /* last packet is usually short (or a zlp) */ if (unlikely(count != max)) is_last = is_short = 1; else { if (likely(req->req.length != req->req.actual) || req->req.zero) is_last = 0; else is_last = 1; /* interrupt/iso maxpacket may not fill the fifo */ is_short = unlikely(max < ep_maxpacket(ep)); } DEBUG("%s: wrote %s %d bytes%s%s %d left %p\n", __FUNCTION__, ep->ep.name, count, is_last ? "/L" : "", is_short ? "/S" : "", req->req.length - req->req.actual, req); /* requests complete when all IN data is in the FIFO */ if (is_last) { done(ep, req, 0); if (list_empty(&ep->queue)) { pio_irq_disable(ep_index(ep)); } return 1; } } else { DEBUG("Hmm.. %d ep FIFO is not empty!\n", ep_index(ep)); } return 0; }
/* Inline code */ static __inline__ int write_packet(struct s3c_ep *ep, struct s3c_request *req, int max) { u16 *buf; int length, count; u32 fifo = ep->fifo; buf = req->req.buf + req->req.actual; prefetch(buf); length = req->req.length - req->req.actual; length = min(length, max); req->req.actual += length; DEBUG("%s: Write %d (max %d), fifo=0x%x\n", __FUNCTION__, length, max, fifo); usb_write(length, (u32) S3C_UDC_BYTE_WRITE_CNT_REG, ep_index(ep)); for (count=0;count<length;count+=2) { __raw_writel(*buf++, fifo); } return length; }
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; }
/** Read to request from FIFO (max read == bytes in fifo) * Return: 0 = still running, 1 = completed, negative = errno * NOTE: INDEX register must be set for EP */ static int read_fifo(struct lh7a40x_ep *ep, struct lh7a40x_request *req) { u32 csr; u8 *buf; unsigned bufferspace, count, is_short; volatile u32 *fifo = (volatile u32 *)ep->fifo; /* make sure there's a packet in the FIFO. */ csr = usb_read(ep->csr1); if (!(csr & USB_OUT_CSR1_OUT_PKT_RDY)) { DEBUG("%s: Packet NOT ready!\n", __func__); return -EINVAL; } buf = req->req.buf + req->req.actual; prefetchw(buf); bufferspace = req->req.length - req->req.actual; /* read all bytes from this packet */ count = usb_read(USB_OUT_FIFO_WC1); req->req.actual += min(count, bufferspace); is_short = (count < ep->ep.maxpacket); DEBUG("read %s %02x, %d bytes%s req %p %d/%d\n", ep->ep.name, csr, count, is_short ? "/S" : "", req, req->req.actual, req->req.length); while (likely(count-- != 0)) { u8 byte = (u8) (*fifo & 0xff); 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(KERN_WARNING "%s overflow %d\n", ep->ep.name, count); req->req.status = -EOVERFLOW; } else { *buf++ = byte; bufferspace--; } } usb_clear(USB_OUT_CSR1_OUT_PKT_RDY, ep->csr1); /* completion */ if (is_short || req->req.actual == req->req.length) { done(ep, req, 0); usb_set(USB_OUT_CSR1_FIFO_FLUSH, ep->csr1); if (list_empty(&ep->queue)) pio_irq_disable(ep_index(ep)); return 1; } /* finished that packet. the next one may be waiting... */ return 0; }
static void usb_send(int n) { int max_pkt_size, len; int i; unsigned char *p; #ifdef LCD_DEBUG if (endpoints[n].halt[DIR_TX]) log_char('H'); if (!endpoints[n].out_in_progress) log_char('$'); #endif if (endpoints[n].halt[DIR_TX] || !endpoints[n].enabled[DIR_TX] || !endpoints[n].out_in_progress) return; if (endpoints[n].out_ptr < 0) { endpoints[n].out_in_progress = 0; if (endpoints[n].out_done) (*(endpoints[n].out_done))(n, endpoints[n].out_buf, endpoints[n].out_len); return; } if (usb_out_buffer_full(n)) { log_char('F'); return; } usb_select_endpoint(ep_index(n, DIR_TX)); max_pkt_size = endpoints[n].max_pkt_size[DIR_TX]; len = endpoints[n].out_len - endpoints[n].out_ptr; if (len > max_pkt_size) len = max_pkt_size; log_char('0' + (len % 10)); ISP1582_BUFLEN = len; p = endpoints[n].out_buf + endpoints[n].out_ptr; i = 0; while (len - i >= 2) { ISP1582_DATA = p[i] | (p[i + 1] << 8); i += 2; } if (i < len) ISP1582_DATA = p[i]; endpoints[n].out_ptr += len; /* if (endpoints[n].out_ptr == endpoints[n].out_len && len < max_pkt_size) */ if (endpoints[n].out_ptr == endpoints[n].out_len) endpoints[n].out_ptr = -1; }
static int setdma_tx(struct s3c_ep *ep, struct s3c_request *req) { u32 *buf, ctrl = 0; u32 length, pktcnt; u32 ep_num = ep_index(ep); struct device *dev = &the_controller->dev->dev; buf = req->req.buf + req->req.actual; prefetch(buf); length = req->req.length - req->req.actual; if (ep_num == EP0_CON) length = min(length, (u32)ep_maxpacket(ep)); req->req.actual += length; req->req.dma = dma_map_single(dev, buf, length, DMA_TO_DEVICE); req->mapped = 1; if (length == 0) pktcnt = 1; else pktcnt = (length - 1)/(ep->ep.maxpacket) + 1; #ifdef DED_TX_FIFO /* Flush the endpoint's Tx FIFO */ writel(ep_num<<6, S3C_UDC_OTG_GRSTCTL); writel((ep_num<<6)|0x20, S3C_UDC_OTG_GRSTCTL); while (readl(S3C_UDC_OTG_GRSTCTL) & 0x20) ; /* Write the FIFO number to be used for this endpoint */ ctrl = readl(S3C_UDC_OTG_DIEPCTL(ep_num)); ctrl &= ~DEPCTL_TXFNUM_MASK;; ctrl |= (ep_num << DEPCTL_TXFNUM_BIT); writel(ctrl , S3C_UDC_OTG_DIEPCTL(ep_num)); #endif writel(virt_to_phys(buf), S3C_UDC_OTG_DIEPDMA(ep_num)); writel((pktcnt<<19)|(length<<0), S3C_UDC_OTG_DIEPTSIZ(ep_num)); ctrl = readl(S3C_UDC_OTG_DIEPCTL(ep_num)); writel(DEPCTL_EPENA|DEPCTL_CNAK|ctrl, S3C_UDC_OTG_DIEPCTL(ep_num)); #ifndef DED_TX_FIFO ctrl = readl(S3C_UDC_OTG_DIEPCTL(EP0_CON)); ctrl = (ctrl&~(EP_MASK<<DEPCTL_NEXT_EP_BIT))|(ep_num<<DEPCTL_NEXT_EP_BIT); writel(ctrl, S3C_UDC_OTG_DIEPCTL(EP0_CON)); #endif DEBUG_IN_EP("%s:EP%d TX DMA start : DIEPDMA0 = 0x%x, DIEPTSIZ0 = 0x%x, DIEPCTL0 = 0x%x\n" "\tbuf = 0x%p, pktcnt = %d, xfersize = %d\n", __func__, ep_num, readl(S3C_UDC_OTG_DIEPDMA(ep_num)), readl(S3C_UDC_OTG_DIEPTSIZ(ep_num)), readl(S3C_UDC_OTG_DIEPCTL(ep_num)), buf, pktcnt, length); return length; }
static int usb_out_buffer_full(int ep) { usb_select_endpoint(ep_index(ep, DIR_TX)); if (ISP1582_EPTYPE & 4) return (ISP1582_BUFSTAT & 3) == 3; else return (ISP1582_BUFSTAT & 3) != 0; }
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_cond(DEBUG_OUT_EP != 0, "%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_cond(DEBUG_OUT_EP != 0, "%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_cond(DEBUG_OUT_EP != 0, " => 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_cond(DEBUG_OUT_EP != 0, "%s: Next Rx request start...\n", __func__); setdma_rx(ep, req); } } } else
/** Write request to FIFO (max write == maxp size) * Return: 0 = still running, 1 = completed, negative = errno */ static int write_fifo(struct elfin_ep *ep, struct elfin_request *req) { u32 max; unsigned count; int is_last, is_short; max = le16_to_cpu(ep->desc->wMaxPacketSize); count = write_packet(ep, req, max); /* last packet is usually short (or a zlp) */ if (unlikely(count != max)) is_last = is_short = 1; else { if (likely(req->req.length != req->req.actual) || req->req.zero) is_last = 0; else is_last = 1; /* interrupt/iso maxpacket may not fill the fifo */ is_short = unlikely(max < ep_maxpacket(ep)); } /* requests complete when all IN data is in the FIFO */ if (is_last) { if(!ep_index(ep)){ // EP0 must not come here BUG(); //usb_set(S3C2410_UDC_EP0_CSR_IPKRDY | S3C2410_UDC_EP0_CSR_DE, // S3C2410_UDC_EP0_CSR_REG, 0); }else{ usb_set(S3C2410_UDC_ICSR1_PKTRDY, ep->csr1, ep_index(ep)); } done(ep, req, 0); return 1; } else{ usb_set(S3C2410_UDC_ICSR1_PKTRDY, ep->csr1, ep_index(ep)); } DEBUG_EP0("%s: wrote %s %d bytes%s%s %d left %p\n", __FUNCTION__, ep->ep.name, count, is_last ? "/L" : "", is_short ? "/S" : "", req->req.length - req->req.actual, req); 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_cond(DEBUG_OUT_EP != 0, "%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; }
static void usb_setup_set_configuration(int value) { switch (value) { case 0: usb_disable_endpoint(ep_index(1, DIR_RX)); usb_disable_endpoint(ep_index(1, DIR_TX)); usb_state = STATE_ADDRESS; usb_status_ack(DIR_TX); break; case 1: usb_setup_interface(); usb_state = STATE_CONFIGURED; usb_status_ack(DIR_TX); break; default: usb_request_error(); } }
/** Write request to FIFO (max write == maxp size) * Return: 0 = still running, 1 = completed, negative = errno */ static int write_fifo(struct s3c_ep *ep, struct s3c_request *req) { u32 max; unsigned count; int is_last = 0, is_short = 0; #if TX_DMA_MODE if(tx_dmaStart) return 0; if ((req->req.actual == 0) && (req->req.length > ep->ep.maxpacket) && (!tx_dmaStart)) { DEBUG("TX_DMA_Start:: %s: read %s, bytes req %p %d/%d\n", __FUNCTION__, ep->ep.name, req, req->req.actual, req->req.length); usb_set(S3C_DMA_ENABLE, (u32) S3C_UDC_FCON_REG, ep_index(ep)); usb_write(ep->ep.maxpacket, (u32) S3C_UDC_MAXP_REG, ep_index(ep)); usb_write(ep->ep.maxpacket, (u32) S3C_UDC_BYTE_WRITE_CNT_REG, ep_index(ep)); usb_set((u16)req->req.length, (u32) S3C_UDC_DMA_TOTAL_CNT1_REG, ep_index(ep)); usb_set((u16)((req->req.length)>>16), (u32) S3C_UDC_DMA_TOTAL_CNT2_REG, ep_index(ep)); usb_set(virt_to_phys(req->req.buf), (u32) S3C_UDC_DMA_MEM_BASE_ADDR_REG, ep_index(ep)); usb_set(ep->ep.maxpacket, (u32) S3C_UDC_DMA_CNT_REG, ep_index(ep)); usb_set(ep->ep.maxpacket, (u32) S3C_UDC_DMA_FIFO_CNT_REG, ep_index(ep)); usb_set(S3C_MAX_BURST_INCR16, (u32) S3C_UDC_DMA_IF_CON_REG, ep_index(ep)); usb_set(S3C_DMA_FLY_ENABLE|S3C_DMA_TX_START|S3C_USB_DMA_MODE, (u32) S3C_UDC_DMA_CON_REG, ep_index(ep)); tx_dmaStart = 1; udelay(600); }
static void usb_setup(int reset) { int i; for (i = 0; i < N_ENDPOINTS; i++) endpoints[i].enabled[0] = endpoints[i].enabled[1] = 0; ISP1582_UNLOCK = ISP1582_UNLOCK_CODE; if (!reset) ISP1582_MODE = 0x88; /* CLKAON | GLINTENA */ ISP1582_INTCONF = 0x57; ISP1582_INTEN = 0xd39; ISP1582_ADDRESS = reset ? 0x80: 0; usb_setup_endpoint(ep_index(0, DIR_RX), 64, 0); usb_setup_endpoint(ep_index(0, DIR_TX), 64, 0); ISP1582_MODE |= 1; /* SOFTCT on */ usb_state = STATE_DEFAULT; usb_remote_wakeup = 0; }
static void elfin_out_epn(struct elfin_udc *dev, u32 ep_idx) { struct elfin_ep *ep = &dev->ep[ep_idx]; struct elfin_request *req; DPRINTK("%s: %d\n", __FUNCTION__, ep_idx); if (ep->desc) { u32 csr; csr = usb_read(ep->csr1, ep_index(ep)); while ((csr = usb_read(ep->csr1, ep_index(ep))) & (S3C2410_UDC_OCSR1_PKTRDY | S3C2410_UDC_OCSR1_SENTSTL)) { DPRINTK("%s: %x\n", __FUNCTION__, csr); if (csr & S3C2410_UDC_OCSR1_SENTSTL) { DPRINTK("%s: stall sent, flush fifo\n", __FUNCTION__); /* usb_set(USB_OUT_CSR1_FIFO_FLUSH, ep->csr1, ep_index(ep)); */ } else if (csr & S3C2410_UDC_OCSR1_PKTRDY) { if (list_empty(&ep->queue)) req = 0; else req = list_entry(ep->queue.next, struct elfin_request, queue); if (!req) { //printk("%s: NULL REQ %d\n", // __FUNCTION__, ep_idx); break; } else { read_fifo(ep, req); } } } } else {
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; 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((pktcnt<<19)|(length<<0), ®->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; }
static int setdma_tx(struct s3c_ep *ep, struct s3c_request *req) { u32 *buf, ctrl = 0; u32 length, pktcnt; u32 ep_num = ep_index(ep); buf = req->req.buf + req->req.actual; prefetch(buf); length = req->req.length - req->req.actual; if (ep_num == EP0_CON) { length = min(length, (u32)ep_maxpacket(ep)); } req->req.actual += length; dma_cache_maint(buf, length, DMA_TO_DEVICE); if (length == 0) pktcnt = 1; else pktcnt = (length - 1)/(ep->ep.maxpacket) + 1; #ifdef DED_TX_FIFO /* Write the FIFO number to be used for this endpoint */ ctrl = readl(S3C_UDC_OTG_DIEPCTL(ep_num)); ctrl &= ~DEPCTL_TXFNUM_MASK;; ctrl |= (ep_num << DEPCTL_TXFNUM_BIT); writel(ctrl , S3C_UDC_OTG_DIEPCTL(ep_num)); #endif writel(virt_to_phys(buf), S3C_UDC_OTG_DIEPDMA(ep_num)); writel((pktcnt<<19)|(length<<0), S3C_UDC_OTG_DIEPTSIZ(ep_num)); ctrl = readl(S3C_UDC_OTG_DIEPCTL(ep_num)); writel(DEPCTL_EPENA|DEPCTL_CNAK|ctrl, S3C_UDC_OTG_DIEPCTL(ep_num)); ctrl = readl(S3C_UDC_OTG_DIEPCTL(EP0_CON)); ctrl = (ctrl&~(EP_MASK<<DEPCTL_NEXT_EP_BIT))|(ep_num<<DEPCTL_NEXT_EP_BIT); writel(ctrl, S3C_UDC_OTG_DIEPCTL(EP0_CON)); DEBUG_IN_EP("%s:EP%d TX DMA start : DIEPDMA0 = 0x%x, DIEPTSIZ0 = 0x%x, DIEPCTL0 = 0x%x\n" "\tbuf = 0x%p, pktcnt = %d, xfersize = %d\n", __func__, ep_num, readl(S3C_UDC_OTG_DIEPDMA(ep_num)), readl(S3C_UDC_OTG_DIEPTSIZ(ep_num)), readl(S3C_UDC_OTG_DIEPCTL(ep_num)), buf, pktcnt, length); return length; }
static void udc_complete_req(struct udc_ep *ep, struct udc_req *req, int status) { struct udc *udc = ep->dev; list_del_init(&req->queue); req->status = status; if (!ep_index(ep)) { udc->ep0_state = WAIT_FOR_SETUP; ep->address &= ~USB_DIR_IN; } if (req->complete) req->complete(ep, req); }
/** Write request to FIFO (max write == maxp size) * Return: 0 = still running, 1 = completed, negative = errno */ static int write_fifo(struct s3c_ep *ep, struct s3c_request *req) { u32 max, gintmsk; unsigned count; int is_last = 0, is_short = 0; gintmsk = readl(S3C_UDC_OTG_GINTMSK); max = le16_to_cpu(ep->desc->wMaxPacketSize); count = write_packet(ep, req, max); /* last packet is usually short (or a zlp) */ if (unlikely(count != max)) is_last = is_short = 1; else { if (likely(req->req.length != req->req.actual) || req->req.zero) is_last = 0; else is_last = 1; /* interrupt/iso maxpacket may not fill the fifo */ is_short = unlikely(max < ep_maxpacket(ep)); } DEBUG_IN_EP("%s: wrote %s %d bytes%s%s req %p %d/%d\n", __FUNCTION__, ep->ep.name, count, is_last ? "/L" : "", is_short ? "/S" : "", req, req->req.actual, req->req.length); /* requests complete when all IN data is in the FIFO */ if (is_last) { if(!ep_index(ep)){ printk("%s: --> Error EP0 must not come here!\n", __FUNCTION__); BUG(); } writel(gintmsk&(~INT_NP_TX_FIFO_EMPTY), S3C_UDC_OTG_GINTMSK); done(ep, req, 0); return 1; } /* Unmask USB OTG 2.0 interrupt source : INT_NP_TX_FIFO_EMPTY */ writel(gintmsk | INT_NP_TX_FIFO_EMPTY, S3C_UDC_OTG_GINTMSK); return 0; }
/* * nuke - dequeue ALL requests */ void nuke(struct lh7a40x_ep *ep, int status) { struct lh7a40x_request *req; DEBUG("%s, %p\n", __FUNCTION__, ep); /* Flush FIFO */ flush(ep); /* called with irqs blocked */ while (!list_empty(&ep->queue)) { req = list_entry(ep->queue.next, struct lh7a40x_request, queue); done(ep, req, status); } /* Disable IRQ if EP is enabled (has descriptor) */ if (ep->desc) pio_irq_disable(ep_index(ep)); }
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 dwc2_ep *ep, struct dwc2_request *req) { u32 *buf, ctrl; u32 length, pktcnt; u32 ep_num = ep_index(ep); buf = req->req.buf + req->req.actual; length = min_t(u32, req->req.length - req->req.actual, ep_num ? DMA_BUFFER_SIZE : ep->ep.maxpacket); ep->len = length; ep->dma_buf = buf; if (ep_num == EP0_CON || length == 0) pktcnt = 1; else pktcnt = (length - 1)/(ep->ep.maxpacket) + 1; ctrl = readl(®->out_endp[ep_num].doepctl); invalidate_dcache_range((unsigned long) ep->dma_buf, (unsigned long) ep->dma_buf + ROUND(ep->len, CONFIG_SYS_CACHELINE_SIZE)); writel((unsigned long) ep->dma_buf, ®->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_cond(DEBUG_OUT_EP != 0, "%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; }
static void usb_receive(int n) { int len; if (endpoints[n].halt[DIR_RX] || !endpoints[n].enabled[DIR_RX] || endpoints[n].in_min_len < 0 || !endpoints[n].in_ack) return; endpoints[n].in_ack = 0; usb_select_endpoint(ep_index(n, DIR_RX)); len = usb_get_packet(endpoints[n].in_buf + endpoints[n].in_ptr, endpoints[n].in_max_len - endpoints[n].in_ptr); endpoints[n].in_ptr += len; if (endpoints[n].in_ptr >= endpoints[n].in_min_len) { endpoints[n].in_min_len = -1; if (endpoints[n].in_done) (*(endpoints[n].in_done))(n, endpoints[n].in_buf, endpoints[n].in_ptr); } }
static void usb_data_stage_enable(int dir) { usb_select_endpoint(ep_index(0, dir)); ISP1582_CTRLFUN |= 4; }
static void usb_request_error(void) { usb_stall_endpoint(ep_index(0, DIR_TX)); usb_stall_endpoint(ep_index(0, DIR_RX)); }
/* Inline code */ static __inline__ int write_packet(struct s3c_ep *ep, struct s3c_request *req, int max) { u32 *buf; int length, count; u32 fifo = ep->fifo, in_ctrl; buf = req->req.buf + req->req.actual; prefetch(buf); length = req->req.length - req->req.actual; length = min(length, max); req->req.actual += length; DEBUG("%s: Write %d (max %d), fifo=0x%x\n", __FUNCTION__, length, max, fifo); if(ep_index(ep) == EP0_CON) { writel((1<<19)|(length<<0), (u32) S3C_UDC_OTG_DIEPTSIZ0); in_ctrl = readl(S3C_UDC_OTG_DIEPCTL0); writel(DEPCTL_EPENA|DEPCTL_CNAK|(EP2_IN<<11)| in_ctrl, (u32) S3C_UDC_OTG_DIEPCTL0); DEBUG_EP0("%s:(DIEPTSIZ0):0x%x, (DIEPCTL0):0x%x, (GNPTXSTS):0x%x\n", __FUNCTION__, readl(S3C_UDC_OTG_DIEPTSIZ0),readl(S3C_UDC_OTG_DIEPCTL0), readl(S3C_UDC_OTG_GNPTXSTS)); udelay(30); } else if ((ep_index(ep) == EP2_IN)) { writel((1<<19)|(length<<0), S3C_UDC_OTG_DIEPTSIZ2); in_ctrl = readl(S3C_UDC_OTG_DIEPCTL2); writel(DEPCTL_EPENA|DEPCTL_CNAK|(EP2_IN<<11)| in_ctrl, (u32) S3C_UDC_OTG_DIEPCTL2); DEBUG_IN_EP("%s:(DIEPTSIZ2):0x%x, (DIEPCTL2):0x%x, (GNPTXSTS):0x%x\n", __FUNCTION__, readl(S3C_UDC_OTG_DIEPTSIZ2),readl(S3C_UDC_OTG_DIEPCTL2), readl(S3C_UDC_OTG_GNPTXSTS)); udelay(30); } else if ((ep_index(ep) == EP3_IN)) { if (set_interface_first == 1) { DEBUG_IN_EP("%s: first packet write skipped after set_interface\n", __FUNCTION__); set_interface_first = 0; return length; } writel((1<<19)|(length<<0), S3C_UDC_OTG_DIEPTSIZ3); in_ctrl = readl(S3C_UDC_OTG_DIEPCTL3); writel(DEPCTL_EPENA|DEPCTL_CNAK|(EP2_IN<<11)| in_ctrl, (u32) S3C_UDC_OTG_DIEPCTL3); DEBUG_IN_EP("%s:(DIEPTSIZ3):0x%x, (DIEPCTL3):0x%x, (GNPTXSTS):0x%x\n", __FUNCTION__, readl(S3C_UDC_OTG_DIEPTSIZ3),readl(S3C_UDC_OTG_DIEPCTL3), readl(S3C_UDC_OTG_GNPTXSTS)); udelay(30); } else { printk("%s: --> Error Unused Endpoint!!\n", __FUNCTION__); BUG(); } for (count = 0; count < length; count += 4) writel(*buf++, fifo); return length; }
static void usb_setup_interface(void) { usb_setup_endpoint(ep_index(1, DIR_RX), 64, TYPE_BULK); usb_setup_endpoint(ep_index(1, DIR_TX), 64, TYPE_BULK); }