int udc_endpoint_write(struct usb_endpoint_instance *endpoint) { int ret = 0; /* Transmit only if the hardware is available */ if (endpoint->tx_urb && endpoint->state == 0) { unsigned int ep = endpoint->endpoint_address & USB_ENDPOINT_NUMBER_MASK; u16 peri_txcsr = readw(&musbr->ep[ep].epN.txcsr); /* Error conditions */ if (peri_txcsr & MUSB_TXCSR_P_UNDERRUN) { peri_txcsr &= ~MUSB_TXCSR_P_UNDERRUN; writew(peri_txcsr, &musbr->ep[ep].epN.txcsr); } if (debug_level > 1) musb_print_txcsr(peri_txcsr); /* Check if a packet is waiting to be sent */ if (!(peri_txcsr & MUSB_TXCSR_TXPKTRDY)) { u32 length; u8 *data; struct urb *urb = endpoint->tx_urb; unsigned int remaining_packet = urb->actual_length - endpoint->sent; if (endpoint->tx_packetSize < remaining_packet) length = endpoint->tx_packetSize; else length = remaining_packet; data = (u8 *) urb->buffer; data += endpoint->sent; /* common musb fifo function */ write_fifo(ep, length, data); musb_peri_tx_ready(ep); endpoint->last = length; /* usbd_tx_complete will take care of updating 'sent' */ usbd_tx_complete(endpoint); } musb_peri_wait_tx_done(ep); } else { if (debug_level > 0) serial_printf("ERROR : %s Problem with urb %p " "or ep state %d\n", __PRETTY_FUNCTION__, endpoint->tx_urb, endpoint->state); } return ret; }
static void S3C24X0_udc_epn(int ep) { struct usb_endpoint_instance *endpoint; struct urb *urb; u32 ep_csr1; if (ep >= S3C24X0_UDC_NUM_ENDPOINTS) return; endpoint = &udc_device->bus->endpoint_array[ep]; S3C24X0_UDC_SETIX(ep); if (endpoint->endpoint_address & USB_DIR_IN) { /* IN transfer (device to host) */ ep_csr1 = inl(S3C24X0_UDC_IN_CSR1_REG); debug("for ep=%u, CSR1=0x%x ", ep, ep_csr1); urb = endpoint->tx_urb; if (ep_csr1 & S3C24X0_UDC_ICSR1_SENTSTL) { /* Stall handshake */ debug("stall\n"); outl(0x00, S3C24X0_UDC_IN_CSR1_REG); return; } if (!(ep_csr1 & S3C24X0_UDC_ICSR1_PKTRDY) && urb && urb->actual_length) { debug("completing previously send data "); usbd_tx_complete(endpoint); /* push pending data into FIFO */ if ((endpoint->last == endpoint->tx_packetSize) && (urb->actual_length - endpoint->sent - endpoint->last == 0)) { endpoint->sent += endpoint->last; /* Write 0 bytes of data (ZLP) */ debug("ZLP "); outl(ep_csr1|S3C24X0_UDC_ICSR1_PKTRDY, S3C24X0_UDC_IN_CSR1_REG); } else { /* write actual data to fifo */ debug_urb_buffer("TX_DATA", endpoint); S3C24X0_write_noniso_tx_fifo(endpoint); outl(ep_csr1|S3C24X0_UDC_ICSR1_PKTRDY, S3C24X0_UDC_IN_CSR1_REG); } } debug("\n"); } else { /* OUT transfer (host to device) */ ep_csr1 = inl(S3C24X0_UDC_OUT_CSR1_REG); debug("for ep=%u, CSR1=0x%x ", ep, ep_csr1); urb = endpoint->rcv_urb; if (ep_csr1 & S3C24X0_UDC_OCSR1_SENTSTL) { /* Stall handshake */ outl(0x00, S3C24X0_UDC_IN_CSR1_REG); return; } if ((ep_csr1 & S3C24X0_UDC_OCSR1_PKTRDY) && urb) { /* Read pending data from fifo */ u32 fifo_count = fifo_count_out(); int is_last = 0; u32 i, urb_avail = urb->buffer_length - urb->actual_length; u8 *cp = urb->buffer + urb->actual_length; if (fifo_count < endpoint->rcv_packetSize) is_last = 1; debug("fifo_count=%u is_last=%, urb_avail=%u)\n", fifo_count, is_last, urb_avail); if (fifo_count < urb_avail) urb_avail = fifo_count; for (i = 0; i < urb_avail; i++) *cp++ = inb(ep_fifo_reg[ep]); if (is_last) outl(ep_csr1 & ~S3C24X0_UDC_OCSR1_PKTRDY, S3C24X0_UDC_OUT_CSR1_REG); usbd_rcv_complete(endpoint, urb_avail, 0); } } urb = endpoint->rcv_urb; }
/* * If the endpoint has an active tx_urb, then the next packet of data from the * URB is written to the tx FIFO. * The total amount of data in the urb is given by urb->actual_length. * The maximum amount of data that can be sent in any one packet is given by * endpoint->tx_packetSize. * The number of data bytes from this URB that have already been transmitted * is given by endpoint->sent. * endpoint->last is updated by this routine with the number of data bytes * transmitted in this packet. */ static int udc_write_urb(struct usb_endpoint_instance *endpoint) { struct urb *urb = endpoint->tx_urb; int ep_num = endpoint->endpoint_address & USB_ENDPOINT_NUMBER_MASK; u32 *data32 = (u32 *) urb->buffer; u8 *data8 = (u8 *) urb->buffer; unsigned int i, n, w, b, is_short; int timeout = 2000; /* 2ms */ if (!urb || !urb->actual_length) return -1; n = MIN(urb->actual_length - endpoint->sent, endpoint->tx_packetSize); if (n <= 0) return -1; usbdbg("write urb on ep %d", ep_num); #if defined(USBDDBG) && defined(USBDPARANOIA) usbdbg("urb: buf %p, buf_len %d, actual_len %d", urb->buffer, urb->buffer_length, urb->actual_length); usbdbg("endpoint: sent %d, tx_packetSize %d, last %d", endpoint->sent, endpoint->tx_packetSize, endpoint->last); #endif is_short = n != endpoint->tx_packetSize; w = n / 4; b = n % 4; usbdbg("n %d%s w %d b %d", n, is_short ? "-s" : "", w, b); udc_dump_buffer("urb write", data8 + endpoint->sent, n); /* Prepare for data send */ if (ep_num) writel(UDCCSR_PC ,UDCCSN(ep_num)); for (i = 0; i < w; i++) writel(data32[endpoint->sent / 4 + i], UDCDN(ep_num)); for (i = 0; i < b; i++) writeb(data8[endpoint->sent + w * 4 + i], UDCDN(ep_num)); /* Set "Packet Complete" if less data then tx_packetSize */ if (is_short) writel(ep_num ? UDCCSR_SP : UDCCSR0_IPR, UDCCSN(ep_num)); /* Wait for data sent */ if (ep_num) { while (!(readl(UDCCSN(ep_num)) & UDCCSR_PC)) { if (timeout-- == 0) return -1; else udelay(1); } } endpoint->last = n; if (ep_num) { usbd_tx_complete(endpoint); } else { endpoint->sent += n; endpoint->last -= n; } if (endpoint->sent >= urb->actual_length) { urb->actual_length = 0; endpoint->sent = 0; endpoint->last = 0; } if ((endpoint->sent >= urb->actual_length) && (!ep_num)) { usbdbg("ep0 IN stage done"); if (is_short) ep0state = EP0_IDLE; else ep0state = EP0_XFER_COMPLETE; } return 0; }
static void s3c2410_udc_epn(int ep) { struct usb_endpoint_instance *endpoint; struct urb *urb; u32 ep_csr1; if (ep >= S3C2410_UDC_NUM_ENDPOINTS) return; endpoint = &udc_device->bus->endpoint_array[ep]; S3C2410_UDC_SETIX(ep); if (endpoint->endpoint_address & USB_DIR_IN) { /* IN transfer (device to host) */ ep_csr1 = inl(S3C2410_UDC_IN_CSR1_REG); debug("for ep=%u, IN_CSR1=0x%x ", ep, ep_csr1); urb = endpoint->tx_urb; if (ep_csr1 & S3C2410_UDC_ICSR1_SENTSTL) { /* Stall handshake */ debug("stall\n"); outl(0x00, S3C2410_UDC_IN_CSR1_REG); return; } if (!(ep_csr1 & S3C2410_UDC_ICSR1_PKTRDY) && urb && urb->actual_length) { debug("completing previously send data "); usbd_tx_complete(endpoint); /* push pending data into FIFO */ if ((endpoint->last == endpoint->tx_packetSize) && (urb->actual_length - endpoint->sent - endpoint->last == 0)) { endpoint->sent += endpoint->last; /* Write 0 bytes of data (ZLP) */ debug("ZLP "); outl(ep_csr1|S3C2410_UDC_ICSR1_PKTRDY, S3C2410_UDC_IN_CSR1_REG); } else { /* write actual data to fifo */ debug_urb_buffer("TX_DATA", endpoint); s3c2410_write_noniso_tx_fifo(endpoint); outl(ep_csr1|S3C2410_UDC_ICSR1_PKTRDY, S3C2410_UDC_IN_CSR1_REG); } } debug("\n"); } else { /* OUT transfer (host to device) */ ep_csr1 = inl(S3C2410_UDC_OUT_CSR1_REG); debug("for ep=%u, OUT_CSR1=0x%x ", ep, ep_csr1); urb = endpoint->rcv_urb; if (ep_csr1 & S3C2410_UDC_OCSR1_SENTSTL) { /* Stall handshake */ debugX("SENT STALL\n"); outl(0x00, S3C2410_UDC_IN_CSR1_REG); return; } if ((ep_csr1 & S3C2410_UDC_OCSR1_PKTRDY) && urb) { /* Read pending data from fifo */ u32 fifo_count = fifo_count_out(); int is_last = 0; u32 i, urb_avail = urb->buffer_length - urb->actual_length; u8 *cp = urb->buffer + urb->actual_length; if (fifo_count < endpoint->rcv_packetSize) is_last = 1; debug("fifo_count=%u is_last=%d, urb_avail=%u\n", fifo_count, is_last, urb_avail); if (fifo_count < urb_avail) urb_avail = fifo_count; for (i = 0; i < urb_avail; i++) *cp++ = inb(ep_fifo_reg[ep]); /* if (is_last) */ /* * Once the MCU reads the packet from FIFO, * this bit should be cleared */ #ifndef AUTO_CLEAR outl(ep_csr1 & ~S3C2410_UDC_OCSR1_PKTRDY, S3C2410_UDC_OUT_CSR1_REG); #endif usbd_rcv_complete(endpoint, urb_avail, 0); /* FIXME is there a better way to notify that, * we have got data */ usbd_device_event_irq(udc_device, DEVICE_FUNCTION_PRIVATE, 0); } } urb = endpoint->rcv_urb; }