static void S3C24X0_udc_ep0(void) { u_int8_t ep0csr; struct usb_endpoint_instance *ep0 = udc_device->bus->endpoint_array; S3C24X0_UDC_SETIX(0); ep0csr = inl(S3C24X0_UDC_IN_CSR1_REG); /* clear stall status */ if (ep0csr & S3C24X0_UDC_EP0_CSR_SENTSTL) { /* serial_printf("Clearing SENT_STALL\n"); */ clear_ep0_sst(); if (ep0csr & S3C24X0_UDC_EP0_CSR_SOPKTRDY) clear_ep0_opr(); ep0->state = EP0_IDLE; return; } /* clear setup end */ if (ep0csr & S3C24X0_UDC_EP0_CSR_SE /* && ep0->state != EP0_IDLE */) { /* serial_printf("Clearing SETUP_END\n"); */ clear_ep0_se(); #if 1 if (ep0csr & S3C24X0_UDC_EP0_CSR_SOPKTRDY) { /* Flush FIFO */ while (inl(S3C24X0_UDC_OUT_FIFO_CNT1_REG)) inl(S3C24X0_UDC_EP0_FIFO_REG); clear_ep0_opr(); } #endif ep0->state = EP0_IDLE; return; } /* Don't ever put [serial] debugging in non-error codepaths here, it * will violate the tight timing constraints of this USB Device * controller (and lead to bus enumeration failures) */ switch (ep0->state) { int i, fifo_count; unsigned char *datap; case EP0_IDLE: if (!(ep0csr & S3C24X0_UDC_EP0_CSR_OPKRDY)) break; datap = (unsigned char *) &ep0_urb->device_request; /* host->device packet has been received */ /* pull it out of the fifo */ fifo_count = fifo_count_out(); for (i = 0; i < fifo_count; i++) { *datap = (unsigned char)inl(S3C24X0_UDC_EP0_FIFO_REG); datap++; } if (fifo_count != 8) { debug("STRANGE FIFO COUNT: %u bytes\n", fifo_count); set_ep0_ss(); return; } if (ep0_urb->device_request.wLength == 0) { if (ep0_recv_setup(ep0_urb)) { /* Not a setup packet, stall next EP0 transaction */ debug("can't parse setup packet1\n"); set_ep0_ss(); set_ep0_de_out(); ep0->state = EP0_IDLE; return; } /* There are some requests with which we need to deal * manually here */ switch (ep0_urb->device_request.bRequest) { case USB_REQ_SET_CONFIGURATION: if (!ep0_urb->device_request.wValue) usbd_device_event_irq(udc_device, DEVICE_DE_CONFIGURED, 0); else usbd_device_event_irq(udc_device, DEVICE_CONFIGURED, 0); break; case USB_REQ_SET_ADDRESS: udc_set_address(udc_device->address); usbd_device_event_irq(udc_device, DEVICE_ADDRESS_ASSIGNED, 0); break; default: break; } set_ep0_de_out(); ep0->state = EP0_IDLE; } else { if ((ep0_urb->device_request.bmRequestType & USB_REQ_DIRECTION_MASK) == USB_REQ_HOST2DEVICE) { clear_ep0_opr(); ep0->state = EP0_OUT_DATA_PHASE; ep0_urb->buffer = ep0_urb->buffer_data; ep0_urb->buffer_length = sizeof(ep0_urb->buffer_data); ep0_urb->actual_length = 0; } else { ep0->state = EP0_IN_DATA_PHASE; if (ep0_recv_setup(ep0_urb)) { /* Not a setup packet, stall next EP0 transaction */ debug("can't parse setup packet2\n"); set_ep0_ss(); //set_ep0_de_out(); ep0->state = EP0_IDLE; return; } clear_ep0_opr(); ep0->tx_urb = ep0_urb; ep0->sent = ep0->last = 0; if (S3C24X0_write_noniso_tx_fifo(ep0)) { ep0->state = EP0_IDLE; set_ep0_de_in(); } else set_ep0_ipr(); } } break; case EP0_IN_DATA_PHASE: if (!(ep0csr & S3C24X0_UDC_EP0_CSR_IPKRDY)) { ep0->sent += ep0->last; if (S3C24X0_write_noniso_tx_fifo(ep0)) { ep0->state = EP0_IDLE; set_ep0_de_in(); } else set_ep0_ipr(); } break; case EP0_OUT_DATA_PHASE: if (ep0csr & S3C24X0_UDC_EP0_CSR_OPKRDY) { u32 urb_avail = ep0_urb->buffer_length - ep0_urb->actual_length; u_int8_t *cp = ep0_urb->buffer + ep0_urb->actual_length; int i, fifo_count; fifo_count = fifo_count_out(); if (fifo_count < urb_avail) urb_avail = fifo_count; for (i = 0; i < urb_avail; i++) *cp++ = inl(S3C24X0_UDC_EP0_FIFO_REG); ep0_urb->actual_length += urb_avail; if (fifo_count < ep0->rcv_packetSize || ep0_urb->actual_length >= ep0_urb->device_request.wLength) { ep0->state = EP0_IDLE; if (ep0_recv_setup(ep0_urb)) { /* Not a setup packet, stall next EP0 transaction */ debug("can't parse setup packet3\n"); set_ep0_ss(); //set_ep0_de_out(); return; } set_ep0_de_out(); } else clear_ep0_opr(); } break; case EP0_END_XFER: ep0->state = EP0_IDLE; break; case EP0_STALL: //set_ep0_ss; ep0->state = EP0_IDLE; break; } }
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; }
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; }