/** * 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); }
/** * lh7a40x_in_epn - handle IN interrupt */ static void lh7a40x_in_epn(struct lh7a40x_udc *dev, u32 ep_idx, u32 intr) { u32 csr; struct lh7a40x_ep *ep = &dev->ep[ep_idx]; struct lh7a40x_request *req; usb_set_index(ep_idx); csr = usb_read(ep->csr1); DEBUG("%s: %d, csr %x\n", __FUNCTION__, ep_idx, csr); if (csr & USB_IN_CSR1_SENT_STALL) { DEBUG("USB_IN_CSR1_SENT_STALL\n"); usb_set(USB_IN_CSR1_SENT_STALL /*|USB_IN_CSR1_SEND_STALL */ , ep->csr1); return; } if (!ep->desc) { DEBUG("%s: NO EP DESC\n", __FUNCTION__); return; } if (list_empty(&ep->queue)) req = 0; else req = list_entry(ep->queue.next, struct lh7a40x_request, queue); DEBUG("req: %p\n", req); if (!req) return; write_fifo(ep, req); }
/** 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; }
/** 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; }
/** Enable EP interrupt */ static void pio_irq_enable(int ep) { DEBUG("%s: %d\n", __FUNCTION__, ep); switch (ep) { case 1: usb_set(USB_IN_INT_EP1, USB_IN_INT_EN); break; case 2: usb_set(USB_OUT_INT_EP2, USB_OUT_INT_EN); break; case 3: usb_set(USB_IN_INT_EP3, USB_IN_INT_EN); break; default: DEBUG("Unknown endpoint: %d\n", ep); break; } }
/** Flush EP * NOTE: INDEX register must be set before this call */ static void flush(struct lh7a40x_ep *ep) { DEBUG("%s, %p\n", __FUNCTION__, ep); switch (ep->ep_type) { case ep_control: /* check, by implication c.f. 15.1.2.11 */ break; case ep_bulk_in: case ep_interrupt: /* if(csr & USB_IN_CSR1_IN_PKT_RDY) */ usb_set(USB_IN_CSR1_FIFO_FLUSH, ep->csr1); break; case ep_bulk_out: /* if(csr & USB_OUT_CSR1_OUT_PKT_RDY) */ usb_set(USB_OUT_CSR1_FIFO_FLUSH, ep->csr1); break; } }
/** 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; }
/** 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); }
/* until it's enabled, this UDC should be completely invisible * to any USB host. */ static void udc_enable(struct lh7a40x_udc *dev) { int ep; DEBUG("%s, %p\n", __FUNCTION__, dev); dev->gadget.speed = USB_SPEED_UNKNOWN; #ifdef CONFIG_ARCH_LH7A404 /* Set Port C bit 1 & 2 as output */ set_portc_ddr(1, 1); set_portc_ddr(2, 1); /* Enable USB power */ set_portc_dr(1, 0); #endif /* * C.f Chapter 18.1.3.1 Initializing the USB */ /* Disable the USB */ usb_clear(PM_USB_ENABLE, USB_PM); /* Reset APB & I/O sides of the USB */ usb_set(USB_RESET_APB | USB_RESET_IO, USB_RESET); mdelay(5); usb_clear(USB_RESET_APB | USB_RESET_IO, USB_RESET); /* Set MAXP values for each */ for (ep = 0; ep < UDC_MAX_ENDPOINTS; ep++) { struct lh7a40x_ep *ep_reg = &dev->ep[ep]; u32 csr; usb_set_index(ep); switch (ep_reg->ep_type) { case ep_bulk_in: case ep_interrupt: usb_clear(USB_IN_CSR2_USB_DMA_EN | USB_IN_CSR2_AUTO_SET, ep_reg->csr2); /* Fall through */ case ep_control: usb_write(BYTES2MAXP(ep_maxpacket(ep_reg)), USB_IN_MAXP); break; case ep_bulk_out: usb_clear(USB_OUT_CSR2_USB_DMA_EN | USB_OUT_CSR2_AUTO_CLR, ep_reg->csr2); usb_write(BYTES2MAXP(ep_maxpacket(ep_reg)), USB_OUT_MAXP); break; } /* Read & Write CSR1, just in case */ csr = usb_read(ep_reg->csr1); usb_write(csr, ep_reg->csr1); flush(ep_reg); } /* Disable interrupts */ usb_write(0, USB_IN_INT_EN); usb_write(0, USB_OUT_INT_EN); usb_write(0, USB_INT_EN); /* Enable interrupts */ usb_set(USB_IN_INT_EP0, USB_IN_INT_EN); usb_set(USB_INT_RESET_INT | USB_INT_RESUME_INT, USB_INT_EN); /* Dont enable rest of the interrupts */ /* usb_set(USB_IN_INT_EP3 | USB_IN_INT_EP1 | USB_IN_INT_EP0, USB_IN_INT_EN); usb_set(USB_OUT_INT_EP2, USB_OUT_INT_EN); */ /* Enable SUSPEND */ usb_set(PM_ENABLE_SUSPEND, USB_PM); /* Enable the USB */ usb_set(PM_USB_ENABLE, USB_PM); #ifdef CONFIG_ARCH_LH7A404 /* NOTE: DOES NOT WORK! */ /* Let host detect UDC: * Software must write a 0 to the PMR:DCP_CTRL bit to turn this * transistor on and pull the USBDP pin HIGH. */ /* usb_clear(PM_USB_DCP, USB_PM); usb_set(PM_USB_DCP, USB_PM); */ #endif }