static int s3c2410_udc_read_fifo_crq(struct usb_ctrlrequest *crq) { unsigned char *outbuf = (unsigned char *)crq; int bytes_read = 0; udc_write(0, S3C2410_UDC_INDEX_REG); bytes_read = s3c2410_udc_fifo_count_out(); dprintk(DEBUG_NORMAL, "%s: fifo_count=%d\n", __func__, bytes_read); if (bytes_read > sizeof(struct usb_ctrlrequest)) bytes_read = sizeof(struct usb_ctrlrequest); readsb(S3C2410_UDC_EP0_FIFO_REG + base_addr, outbuf, bytes_read); dprintk(DEBUG_VERBOSE, "%s: len=%d %02x:%02x {%x,%x,%x}\n", __func__, bytes_read, crq->bRequest, crq->bRequestType, crq->wValue, crq->wIndex, crq->wLength); return bytes_read; }
static void s3c2410_udc_handle_ep0(struct s3c2410_udc *dev) { u32 ep0csr; struct s3c2410_ep *ep = &dev->ep[0]; struct s3c2410_request *req; struct usb_ctrlrequest crq; if (list_empty(&ep->queue)) req = NULL; else req = list_entry(ep->queue.next, struct s3c2410_request, queue); /* We make the assumption that S3C2410_UDC_IN_CSR1_REG equal to * S3C2410_UDC_EP0_CSR_REG when index is zero */ udc_write(0, S3C2410_UDC_INDEX_REG); ep0csr = udc_read(S3C2410_UDC_IN_CSR1_REG); dprintk(DEBUG_NORMAL, "ep0csr %x ep0state %s\n", ep0csr, ep0states[dev->ep0state]); /* clear stall status */ if (ep0csr & S3C2410_UDC_EP0_CSR_SENTSTL) { s3c2410_udc_nuke(dev, ep, -EPIPE); dprintk(DEBUG_NORMAL, "... clear SENT_STALL ...\n"); s3c2410_udc_clear_ep0_sst(base_addr); dev->ep0state = EP0_IDLE; return; } /* clear setup end */ if (ep0csr & S3C2410_UDC_EP0_CSR_SE) { dprintk(DEBUG_NORMAL, "... serviced SETUP_END ...\n"); s3c2410_udc_nuke(dev, ep, 0); s3c2410_udc_clear_ep0_se(base_addr); dev->ep0state = EP0_IDLE; } switch (dev->ep0state) { case EP0_IDLE: s3c2410_udc_handle_ep0_idle(dev, ep, &crq, ep0csr); break; case EP0_IN_DATA_PHASE: /* GET_DESCRIPTOR etc */ dprintk(DEBUG_NORMAL, "EP0_IN_DATA_PHASE ... what now?\n"); if (!(ep0csr & S3C2410_UDC_EP0_CSR_IPKRDY) && req) s3c2410_udc_write_fifo(ep, req); break; case EP0_OUT_DATA_PHASE: /* SET_DESCRIPTOR etc */ dprintk(DEBUG_NORMAL, "EP0_OUT_DATA_PHASE ... what now?\n"); if ((ep0csr & S3C2410_UDC_EP0_CSR_OPKRDY) && req) s3c2410_udc_read_fifo(ep, req); break; case EP0_END_XFER: dprintk(DEBUG_NORMAL, "EP0_END_XFER ... what now?\n"); dev->ep0state = EP0_IDLE; break; case EP0_STALL: dprintk(DEBUG_NORMAL, "EP0_STALL ... what now?\n"); dev->ep0state = EP0_IDLE; break; } }
static void s3c2410_udc_handle_ep0_idle(struct s3c2410_udc *dev, struct s3c2410_ep *ep, struct usb_ctrlrequest *crq, u32 ep0csr) { int len, ret, tmp; /* start control request? */ if (!(ep0csr & S3C2410_UDC_EP0_CSR_OPKRDY)) return; s3c2410_udc_nuke(dev, ep, -EPROTO); len = s3c2410_udc_read_fifo_crq(crq); if (len != sizeof(*crq)) { dprintk(DEBUG_NORMAL, "setup begin: fifo READ ERROR" " wanted %d bytes got %d. Stalling out...\n", sizeof(*crq), len); s3c2410_udc_set_ep0_ss(base_addr); return; } dprintk(DEBUG_NORMAL, "bRequest = %d bRequestType %d wLength = %d\n", crq->bRequest, crq->bRequestType, crq->wLength); /* cope with automagic for some standard requests. */ dev->req_std = (crq->bRequestType & USB_TYPE_MASK) == USB_TYPE_STANDARD; dev->req_config = 0; dev->req_pending = 1; switch (crq->bRequest) { case USB_REQ_SET_CONFIGURATION: dprintk(DEBUG_NORMAL, "USB_REQ_SET_CONFIGURATION ...\n"); if (crq->bRequestType == USB_RECIP_DEVICE) { dev->req_config = 1; s3c2410_udc_set_ep0_de_out(base_addr); } break; case USB_REQ_SET_INTERFACE: dprintk(DEBUG_NORMAL, "USB_REQ_SET_INTERFACE ...\n"); if (crq->bRequestType == USB_RECIP_INTERFACE) { dev->req_config = 1; s3c2410_udc_set_ep0_de_out(base_addr); } break; case USB_REQ_SET_ADDRESS: dprintk(DEBUG_NORMAL, "USB_REQ_SET_ADDRESS ...\n"); if (crq->bRequestType == USB_RECIP_DEVICE) { tmp = crq->wValue & 0x7F; dev->address = tmp; udc_write((tmp | S3C2410_UDC_FUNCADDR_UPDATE), S3C2410_UDC_FUNC_ADDR_REG); s3c2410_udc_set_ep0_de_out(base_addr); return; } break; case USB_REQ_GET_STATUS: dprintk(DEBUG_NORMAL, "USB_REQ_GET_STATUS ...\n"); s3c2410_udc_clear_ep0_opr(base_addr); if (dev->req_std) { if (!s3c2410_udc_get_status(dev, crq)) return; } break; case USB_REQ_CLEAR_FEATURE: s3c2410_udc_clear_ep0_opr(base_addr); if (crq->bRequestType != USB_RECIP_ENDPOINT) break; if (crq->wValue != USB_ENDPOINT_HALT || crq->wLength != 0) break; s3c2410_udc_set_halt(&dev->ep[crq->wIndex & 0x7f].ep, 0); s3c2410_udc_set_ep0_de_out(base_addr); return; case USB_REQ_SET_FEATURE: s3c2410_udc_clear_ep0_opr(base_addr); if (crq->bRequestType != USB_RECIP_ENDPOINT) break; if (crq->wValue != USB_ENDPOINT_HALT || crq->wLength != 0) break; s3c2410_udc_set_halt(&dev->ep[crq->wIndex & 0x7f].ep, 1); s3c2410_udc_set_ep0_de_out(base_addr); return; default: s3c2410_udc_clear_ep0_opr(base_addr); break; } if (crq->bRequestType & USB_DIR_IN) dev->ep0state = EP0_IN_DATA_PHASE; else dev->ep0state = EP0_OUT_DATA_PHASE; if (!dev->driver) return; /* deliver the request to the gadget driver */ ret = dev->driver->setup(&dev->gadget, crq); if (ret < 0) { if (dev->req_config) { dprintk(DEBUG_NORMAL, "config change %02x fail %d?\n", crq->bRequest, ret); return; } if (ret == -EOPNOTSUPP) dprintk(DEBUG_NORMAL, "Operation not supported\n"); else dprintk(DEBUG_NORMAL, "dev->driver->setup failed. (%d)\n", ret); udelay(5); s3c2410_udc_set_ep0_ss(base_addr); s3c2410_udc_set_ep0_de_out(base_addr); dev->ep0state = EP0_IDLE; /* deferred i/o == no response yet */ } else if (dev->req_pending) { dprintk(DEBUG_VERBOSE, "dev->req_pending... what now?\n"); dev->req_pending = 0; } dprintk(DEBUG_VERBOSE, "ep0state %s\n", ep0states[dev->ep0state]); }
/* * return: 0 = still running, 1 = queue empty, negative = errno */ static int s3c2410_udc_read_fifo(struct s3c2410_ep *ep, struct s3c2410_request *req) { u8 *buf; u32 ep_csr; unsigned bufferspace; int is_last = 1; unsigned avail; int fifo_count = 0; u32 idx; int fifo_reg; idx = ep->bEndpointAddress & 0x7F; switch (idx) { default: idx = 0; case 0: fifo_reg = S3C2410_UDC_EP0_FIFO_REG; break; case 1: fifo_reg = S3C2410_UDC_EP1_FIFO_REG; break; case 2: fifo_reg = S3C2410_UDC_EP2_FIFO_REG; break; case 3: fifo_reg = S3C2410_UDC_EP3_FIFO_REG; break; case 4: fifo_reg = S3C2410_UDC_EP4_FIFO_REG; break; } if (!req->req.length) return 1; buf = req->req.buf + req->req.actual; bufferspace = req->req.length - req->req.actual; if (!bufferspace) { dprintk(DEBUG_NORMAL, "%s: buffer full!\n", __func__); return -1; } udc_write(idx, S3C2410_UDC_INDEX_REG); fifo_count = s3c2410_udc_fifo_count_out(); dprintk(DEBUG_NORMAL, "%s fifo count : %d\n", __func__, fifo_count); if (fifo_count > ep->ep.maxpacket) avail = ep->ep.maxpacket; else avail = fifo_count; fifo_count = s3c2410_udc_read_packet(fifo_reg, buf, req, avail); /* checking this with ep0 is not accurate as we already * read a control request **/ if (idx != 0 && fifo_count < ep->ep.maxpacket) { is_last = 1; /* overflowed this request? flush extra data */ if (fifo_count != avail) req->req.status = -EOVERFLOW; } else { is_last = (req->req.length <= req->req.actual) ? 1 : 0; } udc_write(idx, S3C2410_UDC_INDEX_REG); fifo_count = s3c2410_udc_fifo_count_out(); /* Only ep0 debug messages are interesting */ if (idx == 0) dprintk(DEBUG_VERBOSE, "%s fifo count : %d [last %d]\n", __func__, fifo_count, is_last); if (is_last) { if (idx == 0) { s3c2410_udc_set_ep0_de_out(base_addr); ep->dev->ep0state = EP0_IDLE; } else { udc_write(idx, S3C2410_UDC_INDEX_REG); ep_csr = udc_read(S3C2410_UDC_OUT_CSR1_REG); udc_write(idx, S3C2410_UDC_INDEX_REG); udc_write(ep_csr & ~S3C2410_UDC_OCSR1_PKTRDY, S3C2410_UDC_OUT_CSR1_REG); } s3c2410_udc_done(ep, req, 0); } else { if (idx == 0) { s3c2410_udc_clear_ep0_opr(base_addr); } else { udc_write(idx, S3C2410_UDC_INDEX_REG); ep_csr = udc_read(S3C2410_UDC_OUT_CSR1_REG); udc_write(idx, S3C2410_UDC_INDEX_REG); udc_write(ep_csr & ~S3C2410_UDC_OCSR1_PKTRDY, S3C2410_UDC_OUT_CSR1_REG); } } return is_last; }
/* * s3c2410_udc_write_fifo * * return: 0 = still running, 1 = completed, negative = errno */ static int s3c2410_udc_write_fifo(struct s3c2410_ep *ep, struct s3c2410_request *req) { unsigned count; int is_last; u32 idx; int fifo_reg; u32 ep_csr; idx = ep->bEndpointAddress & 0x7F; switch (idx) { default: idx = 0; case 0: fifo_reg = S3C2410_UDC_EP0_FIFO_REG; break; case 1: fifo_reg = S3C2410_UDC_EP1_FIFO_REG; break; case 2: fifo_reg = S3C2410_UDC_EP2_FIFO_REG; break; case 3: fifo_reg = S3C2410_UDC_EP3_FIFO_REG; break; case 4: fifo_reg = S3C2410_UDC_EP4_FIFO_REG; break; } count = s3c2410_udc_write_packet(fifo_reg, req, ep->ep.maxpacket); /* last packet is often short (sometimes a zlp) */ if (count != ep->ep.maxpacket) is_last = 1; else if (req->req.length != req->req.actual || req->req.zero) is_last = 0; else is_last = 2; /* Only ep0 debug messages are interesting */ if (idx == 0) dprintk(DEBUG_NORMAL, "Written ep%d %d.%d of %d b [last %d,z %d]\n", idx, count, req->req.actual, req->req.length, is_last, req->req.zero); if (is_last) { /* The order is important. It prevents sending 2 packets * at the same time */ if (idx == 0) { /* Reset signal => no need to say 'data sent' */ if (!(udc_read(S3C2410_UDC_USB_INT_REG) & S3C2410_UDC_USBINT_RESET)) s3c2410_udc_set_ep0_de_in(base_addr); ep->dev->ep0state = EP0_IDLE; } else { udc_write(idx, S3C2410_UDC_INDEX_REG); ep_csr = udc_read(S3C2410_UDC_IN_CSR1_REG); udc_write(idx, S3C2410_UDC_INDEX_REG); udc_write(ep_csr | S3C2410_UDC_ICSR1_PKTRDY, S3C2410_UDC_IN_CSR1_REG); } s3c2410_udc_done(ep, req, 0); is_last = 1; } else { if (idx == 0) { /* Reset signal => no need to say 'data sent' */ if (!(udc_read(S3C2410_UDC_USB_INT_REG) & S3C2410_UDC_USBINT_RESET)) s3c2410_udc_set_ep0_ipr(base_addr); } else { udc_write(idx, S3C2410_UDC_INDEX_REG); ep_csr = udc_read(S3C2410_UDC_IN_CSR1_REG); udc_write(idx, S3C2410_UDC_INDEX_REG); udc_write(ep_csr | S3C2410_UDC_ICSR1_PKTRDY, S3C2410_UDC_IN_CSR1_REG); } } return is_last; }
int fastboot_tx_status(unsigned char *buffer, unsigned int buffer_size) { return udc_write( buffer , buffer_size); }