static inline int s3c2410_udc_fifo_count_out(void) { int tmp; tmp = udc_read(S3C2410_UDC_OUT_FIFO_CNT2_REG) << 8; tmp |= udc_read(S3C2410_UDC_OUT_FIFO_CNT1_REG); return tmp; }
static int s3c2410_udc_get_status(struct s3c2410_udc *dev, struct usb_ctrlrequest *crq) { u16 status = 0; u8 ep_num = crq->wIndex & 0x7F; u8 is_in = crq->wIndex & USB_DIR_IN; switch (crq->bRequestType & USB_RECIP_MASK) { case USB_RECIP_INTERFACE: break; case USB_RECIP_DEVICE: status = dev->devstatus; break; case USB_RECIP_ENDPOINT: if (ep_num > 4 || crq->wLength > 2) return 1; if (ep_num == 0) { udc_write(0, S3C2410_UDC_INDEX_REG); status = udc_read(S3C2410_UDC_IN_CSR1_REG); status = status & S3C2410_UDC_EP0_CSR_SENDSTL; } else { udc_write(ep_num, S3C2410_UDC_INDEX_REG); if (is_in) { status = udc_read(S3C2410_UDC_IN_CSR1_REG); status = status & S3C2410_UDC_ICSR1_SENDSTL; } else { status = udc_read(S3C2410_UDC_OUT_CSR1_REG); status = status & S3C2410_UDC_OCSR1_SENDSTL; } } status = status ? 1 : 0; break; default: return 1; } /* Seems to be needed to get it working. ouch :( */ udelay(5); udc_write(status & 0xFF, S3C2410_UDC_EP0_FIFO_REG); udc_write(status >> 8, S3C2410_UDC_EP0_FIFO_REG); s3c2410_udc_set_ep0_de_in(base_addr); return 0; }
static int fastboot_rx (unsigned char* buf, unsigned int len) { if(len == 0) { return 0; } /**********************FIXME****************************/ /************************The rx count is not sure now*******************************/ udc_read(buf, len); if (fastboot_interface && fastboot_interface->rx_handler) { fastboot_interface->rx_handler ((const char*)buf, len); } return 0; }
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; } }
/* * 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; }
static int s3c2410_udc_debugfs_seq_show(struct seq_file *m, void *p) { u32 addr_reg, pwr_reg, ep_int_reg, usb_int_reg; u32 ep_int_en_reg, usb_int_en_reg, ep0_csr; u32 ep1_i_csr1, ep1_i_csr2, ep1_o_csr1, ep1_o_csr2; u32 ep2_i_csr1, ep2_i_csr2, ep2_o_csr1, ep2_o_csr2; addr_reg = udc_read(S3C2410_UDC_FUNC_ADDR_REG); pwr_reg = udc_read(S3C2410_UDC_PWR_REG); ep_int_reg = udc_read(S3C2410_UDC_EP_INT_REG); usb_int_reg = udc_read(S3C2410_UDC_USB_INT_REG); ep_int_en_reg = udc_read(S3C2410_UDC_EP_INT_EN_REG); usb_int_en_reg = udc_read(S3C2410_UDC_USB_INT_EN_REG); udc_write(0, S3C2410_UDC_INDEX_REG); ep0_csr = udc_read(S3C2410_UDC_IN_CSR1_REG); udc_write(1, S3C2410_UDC_INDEX_REG); ep1_i_csr1 = udc_read(S3C2410_UDC_IN_CSR1_REG); ep1_i_csr2 = udc_read(S3C2410_UDC_IN_CSR2_REG); ep1_o_csr1 = udc_read(S3C2410_UDC_IN_CSR1_REG); ep1_o_csr2 = udc_read(S3C2410_UDC_IN_CSR2_REG); udc_write(2, S3C2410_UDC_INDEX_REG); ep2_i_csr1 = udc_read(S3C2410_UDC_IN_CSR1_REG); ep2_i_csr2 = udc_read(S3C2410_UDC_IN_CSR2_REG); ep2_o_csr1 = udc_read(S3C2410_UDC_IN_CSR1_REG); ep2_o_csr2 = udc_read(S3C2410_UDC_IN_CSR2_REG); seq_printf(m, "FUNC_ADDR_REG : 0x%04X\n" "PWR_REG : 0x%04X\n" "EP_INT_REG : 0x%04X\n" "USB_INT_REG : 0x%04X\n" "EP_INT_EN_REG : 0x%04X\n" "USB_INT_EN_REG : 0x%04X\n" "EP0_CSR : 0x%04X\n" "EP1_I_CSR1 : 0x%04X\n" "EP1_I_CSR2 : 0x%04X\n" "EP1_O_CSR1 : 0x%04X\n" "EP1_O_CSR2 : 0x%04X\n" "EP2_I_CSR1 : 0x%04X\n" "EP2_I_CSR2 : 0x%04X\n" "EP2_O_CSR1 : 0x%04X\n" "EP2_O_CSR2 : 0x%04X\n", addr_reg, pwr_reg, ep_int_reg, usb_int_reg, ep_int_en_reg, usb_int_en_reg, ep0_csr, ep1_i_csr1, ep1_i_csr2, ep1_o_csr1, ep1_o_csr2, ep2_i_csr1, ep2_i_csr2, ep2_o_csr1, ep2_o_csr2 ); return 0; }