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 mxc_udc_recv_setup(void) { setup_packet *s = &ep0_urb->device_request; mxc_udc_read_setup_pkt(s); if (s->wLength) { mxc_udc.ep0_dir = (s->bmRequestType & USB_DIR_IN) ? USB_DIR_OUT : USB_DIR_IN; mxc_udc_queue_update(0, NULL, 0, 0xffffffff); } if (ep0_recv_setup(ep0_urb)) { mxc_ep0_stall(); return; } switch (s->bRequest) { case USB_REQ_GET_STATUS: if ((s->bmRequestType & (USB_DIR_IN | USB_TYPE_MASK)) != (USB_DIR_IN | USB_TYPE_STANDARD)) break; ch9getstatus(s->bmRequestType, s->wValue, s->wIndex, s->wLength); return; case USB_REQ_SET_ADDRESS: if (s->bmRequestType != (USB_DIR_OUT | USB_TYPE_STANDARD | USB_RECIP_DEVICE)) break; mxc_udc.setaddr = 1; mxc_udc.ep0_dir = USB_DIR_IN; mxc_udc_queue_update(0, NULL, 0, 0xffffffff); usbd_device_event_irq(udc_device, DEVICE_ADDRESS_ASSIGNED, 0); return; case USB_REQ_SET_CONFIGURATION: usbd_device_event_irq(udc_device, DEVICE_CONFIGURED, 0); case USB_REQ_CLEAR_FEATURE: case USB_REQ_SET_FEATURE: { int rc = -1; if ((s->bmRequestType & (USB_RECIP_MASK | USB_TYPE_MASK)) == (USB_RECIP_ENDPOINT | USB_TYPE_STANDARD)) rc = 0; else if ((s->bmRequestType & (USB_RECIP_MASK | USB_TYPE_MASK)) == (USB_RECIP_DEVICE | USB_TYPE_STANDARD)) rc = 0; else break; if (rc == 0) { mxc_udc.ep0_dir = USB_DIR_IN; mxc_udc_queue_update(0, NULL, 0, 0xffffffff); } return; } default: break; } if (s->wLength) { mxc_udc.ep0_dir = (s->bmRequestType & USB_DIR_IN) ? USB_DIR_IN : USB_DIR_OUT; mxc_udc_queue_update(0, ep0_urb->buffer, ep0_urb->actual_length, 0xffffffff); ep0_urb->actual_length = 0; } else { mxc_udc.ep0_dir = USB_DIR_IN; mxc_udc_queue_update(0, NULL, 0, 0xffffffff); } }
static void mxc_udc_recv_setup(void) { struct usb_device_request *s = &ep0_urb->device_request; mxc_udc_read_setup_pkt(s); if (s->wLength) { /* If has a data phase, * then prime a dtd for status stage which has zero length DATA0. * The direction of status stage should oppsite to direction of data phase. */ mxc_udc.ep0_dir = (s->bmRequestType & USB_DIR_IN) ? USB_DIR_OUT : USB_DIR_IN; mxc_udc_queue_update(0, NULL, 0, 0xffffffff); } if (ep0_recv_setup(ep0_urb)) { mxc_ep0_stall(); return; } switch (s->bRequest) { case USB_REQ_GET_STATUS: if ((s->bmRequestType & (USB_DIR_IN | USB_TYPE_MASK)) != (USB_DIR_IN | USB_TYPE_STANDARD)) break; ch9getstatus(s->bmRequestType, s->wValue, s->wIndex, s->wLength); DBG("[SETUP] REQ_GET_STATUS\n"); return; case USB_REQ_SET_ADDRESS: if (s->bmRequestType != (USB_DIR_OUT | USB_TYPE_STANDARD | USB_RECIP_DEVICE)) break; mxc_udc.setaddr = 1; mxc_udc.ep0_dir = USB_DIR_IN; mxc_udc_queue_update(0, NULL, 0, 0xffffffff); usbd_device_event_irq(udc_device, DEVICE_ADDRESS_ASSIGNED, 0); DBG("[SETUP] REQ_SET_ADDRESS\n"); return; case USB_REQ_SET_CONFIGURATION: usbd_device_event_irq(udc_device, DEVICE_CONFIGURED, 0); DBG("[SETUP] REQ_SET_CONFIGURATION\n"); case USB_REQ_CLEAR_FEATURE: case USB_REQ_SET_FEATURE: { int rc = -1; if ((s->bmRequestType & (USB_RECIP_MASK | USB_TYPE_MASK)) == (USB_RECIP_ENDPOINT | USB_TYPE_STANDARD)) rc = 0; else if ((s->bmRequestType & (USB_RECIP_MASK | USB_TYPE_MASK)) == (USB_RECIP_DEVICE | USB_TYPE_STANDARD)) rc = 0; else break; if (rc == 0) { mxc_udc.ep0_dir = USB_DIR_IN; mxc_udc_queue_update(0, NULL, 0, 0xffffffff); } return; } default: break; } if (s->wLength) { mxc_udc.ep0_dir = (s->bmRequestType & USB_DIR_IN) ? USB_DIR_IN : USB_DIR_OUT; mxc_udc_queue_update(0, ep0_urb->buffer, ep0_urb->actual_length, 0xffffffff); ep0_urb->actual_length = 0; } else { mxc_udc.ep0_dir = USB_DIR_IN; mxc_udc_queue_update(0, NULL, 0, 0xffffffff); } }
static void musb_peri_ep0_rx(void) { /* * This is the completion of the data OUT / RX * * Host is sending data to ep0 that is not * part of setup. This comes from the cdc_recv_setup * op that is device specific. * * Pass the data back to driver ep0_recv_setup which * should give the cdc_recv_setup the chance to handle * the rx */ u16 csr0; u16 count0; if (debug_level > 3) { if (0 != ep0_urb->actual_length) { serial_printf("%s finished ? %d of %d\n", __PRETTY_FUNCTION__, ep0_urb->actual_length, ep0_urb->device_request.wLength); } } if (ep0_urb->device_request.wLength == ep0_urb->actual_length) { musb_peri_ep0_last(); SET_EP0_STATE(IDLE); ep0_recv_setup(ep0_urb); return; } csr0 = readw(&musbr->ep[0].ep0.csr0); if (!(MUSB_CSR0_RXPKTRDY & csr0)) return; count0 = readw(&musbr->ep[0].ep0.count0); if (count0) { struct usb_endpoint_instance *endpoint; u32 length; u8 *data; endpoint = ep0_endpoint; if (endpoint && endpoint->rcv_urb) { struct urb *urb = endpoint->rcv_urb; unsigned int remaining_space = urb->buffer_length - urb->actual_length; if (remaining_space) { int urb_bad = 0; /* urb is good */ if (count0 > remaining_space) length = remaining_space; else length = count0; data = (u8 *) urb->buffer_data; data += urb->actual_length; /* The common musb fifo reader */ read_fifo(0, length, data); musb_peri_ep0_ack_req(); /* * urb's actual_length is updated in * usbd_rcv_complete */ usbd_rcv_complete(endpoint, length, urb_bad); } else { if (debug_level > 0) serial_printf("ERROR : %s no space in " "rcv buffer\n", __PRETTY_FUNCTION__); } } else { if (debug_level > 0) serial_printf("ERROR : %s problem with " "endpoint\n", __PRETTY_FUNCTION__); } } else { if (debug_level > 0) serial_printf("ERROR : %s with nothing to do\n", __PRETTY_FUNCTION__); } }
static void musb_peri_ep0_idle(void) { u16 count0; int err; u16 csr0; /* * Verify addresses * A lot of confusion can be caused if the address * in software, udc layer, does not agree with the * hardware. Since the setting of the hardware address * must be set after the set address request, the * usb state machine is out of sync for a few frame. * It is a good idea to run this check when changes * are made to the state machine. */ if ((debug_level > 0) && (ep0_state != SET_ADDRESS)) { u8 faddr; faddr = readb(&musbr->faddr); if (udc_device->address != faddr) { serial_printf("ERROR : %s addresses do not" "match sw %d vs hw %d\n", __PRETTY_FUNCTION__, udc_device->address, faddr); udelay(1000 * 1000); hang(); } } csr0 = readw(&musbr->ep[0].ep0.csr0); if (!(MUSB_CSR0_RXPKTRDY & csr0)) goto end; count0 = readw(&musbr->ep[0].ep0.count0); if (count0 == 0) goto end; if (count0 != 8) { if ((debug_setup) && (debug_level > 1)) serial_printf("WARN : %s SETUP incorrect size %d\n", __PRETTY_FUNCTION__, count0); musb_peri_ep0_stall(); goto end; } read_fifo(0, count0, &ep0_urb->device_request); if (debug_level > 2) print_usb_device_request(&ep0_urb->device_request); if (ep0_urb->device_request.wLength == 0) { err = ep0_recv_setup(ep0_urb); /* Zero data request */ musb_peri_ep0_zero_data_request(err); } else { /* Is data coming or going ? */ u8 reqType = ep0_urb->device_request.bmRequestType; if (USB_REQ_DEVICE2HOST == (reqType & USB_REQ_DIRECTION_MASK)) { err = ep0_recv_setup(ep0_urb); /* Device to host */ musb_peri_ep0_tx_data_request(err); } else { /* * Host to device * * The RX routine will call ep0_recv_setup * when the data packet has arrived. */ musb_peri_ep0_rx_data_request(); } } end: return; }
static void udc_handle_ep0(struct usb_endpoint_instance *endpoint) { u32 udccsr0 = readl(UDCCSR0); u32 *data = (u32 *) &ep0_urb->device_request; int i; usbdbg("udccsr0 %x", udccsr0); /* Clear stall status */ if (udccsr0 & UDCCSR0_SST) { usberr("clear stall status"); writel(UDCCSR0_SST, UDCCSR0); ep0state = EP0_IDLE; } /* previous request unfinished? non-error iff back-to-back ... */ if ((udccsr0 & UDCCSR0_SA) != 0 && ep0state != EP0_IDLE) ep0state = EP0_IDLE; switch (ep0state) { case EP0_IDLE: udccsr0 = readl(UDCCSR0); /* Start control request? */ if ((udccsr0 & (UDCCSR0_OPC | UDCCSR0_SA | UDCCSR0_RNE)) == (UDCCSR0_OPC | UDCCSR0_SA | UDCCSR0_RNE)) { /* Read SETUP packet. * SETUP packet size is 8 bytes (aka 2 words) */ usbdbg("try reading SETUP packet"); for (i = 0; i < 2; i++) { if ((readl(UDCCSR0) & UDCCSR0_RNE) == 0) { usberr("setup packet too short:%d", i); goto stall; } data[i] = readl(UDCDR0); } writel(readl(UDCCSR0) | UDCCSR0_OPC | UDCCSR0_SA, UDCCSR0); if ((readl(UDCCSR0) & UDCCSR0_RNE) != 0) { usberr("setup packet too long"); goto stall; } udc_dump_buffer("ep0 setup read", (u8 *) data, 8); if (ep0_urb->device_request.wLength == 0) { usbdbg("Zero Data control Packet\n"); if (ep0_recv_setup(ep0_urb)) { usberr("Invalid Setup Packet\n"); udc_dump_buffer("ep0 setup read", (u8 *)data, 8); goto stall; } writel(UDCCSR0_IPR, UDCCSR0); ep0state = EP0_IDLE; } else { /* Check direction */ if ((ep0_urb->device_request.bmRequestType & USB_REQ_DIRECTION_MASK) == USB_REQ_HOST2DEVICE) { ep0state = EP0_OUT_DATA; ep0_urb->buffer = (u8 *)ep0_urb->buffer_data; ep0_urb->buffer_length = sizeof(ep0_urb->buffer_data); ep0_urb->actual_length = 0; writel(UDCCSR0_IPR, UDCCSR0); } else { /* The ep0_recv_setup function has * already placed our response packet * data in ep0_urb->buffer and the * packet length in * ep0_urb->actual_length. */ if (ep0_recv_setup(ep0_urb)) { stall: usberr("Invalid setup packet"); udc_dump_buffer("ep0 setup read" , (u8 *) data, 8); ep0state = EP0_IDLE; writel(UDCCSR0_SA | UDCCSR0_OPC | UDCCSR0_FST | UDCCS0_FTF, UDCCSR0); return; } endpoint->tx_urb = ep0_urb; endpoint->sent = 0; usbdbg("EP0_IN_DATA"); ep0state = EP0_IN_DATA; if (udc_write_urb(endpoint) < 0) goto stall; } } return; } else if ((udccsr0 & (UDCCSR0_OPC | UDCCSR0_SA)) == (UDCCSR0_OPC|UDCCSR0_SA)) { usberr("Setup Active but no data. Stalling ....\n"); goto stall; } else { usbdbg("random early IRQs"); /* Some random early IRQs: * - we acked FST * - IPR cleared * - OPC got set, without SA (likely status stage) */ writel(udccsr0 & (UDCCSR0_SA | UDCCSR0_OPC), UDCCSR0); } break; case EP0_OUT_DATA: if ((udccsr0 & UDCCSR0_OPC) && !(udccsr0 & UDCCSR0_SA)) { if (udc_read_urb_ep0()) { read_complete: ep0state = EP0_IDLE; if (ep0_recv_setup(ep0_urb)) { /* Not a setup packet, stall next * EP0 transaction */ udc_dump_buffer("ep0 setup read", (u8 *) data, 8); usberr("can't parse setup packet\n"); goto stall; } } } else if (!(udccsr0 & UDCCSR0_OPC) && !(udccsr0 & UDCCSR0_IPR)) { if (ep0_urb->device_request.wLength == ep0_urb->actual_length) goto read_complete; usberr("Premature Status\n"); ep0state = EP0_IDLE; } break; case EP0_IN_DATA: /* GET_DESCRIPTOR etc */ if (udccsr0 & UDCCSR0_OPC) { writel(UDCCSR0_OPC | UDCCSR0_FTF, UDCCSR0); usberr("ep0in premature status"); ep0state = EP0_IDLE; } else { /* irq was IPR clearing */ if (udc_write_urb(endpoint) < 0) { usberr("ep0_write_error\n"); goto stall; } } break; case EP0_XFER_COMPLETE: writel(UDCCSR0_IPR, UDCCSR0); ep0state = EP0_IDLE; break; default: usbdbg("Default\n"); } writel(USIR0_IR0, USIR0); }