📄 s3c2410_udc.c
字号:
spin_lock_irqsave (&udc->lock, flags); list_for_each_entry (req, &ep->queue, queue) { if (&req->req == _req) { list_del_init (&req->queue); _req->status = -ECONNRESET; retval = 0; break; } } spin_unlock_irqrestore (&udc->lock, flags); if (retval == 0) { dprintk( "dequeued req %p from %s, len %d buf %p\n", req, _ep->name, _req->length, _req->buf); _req->complete (_ep, _req); } return retval;}static ints3c2410_set_halt (struct usb_ep *_ep, int value){ struct s3c2410_ep *ep; printk("s3c2410_set_halt(ep=%p)\n", _ep); if (!_ep) return -EINVAL; if (!the_controller->driver) return -ESHUTDOWN; ep = container_of (_ep, struct s3c2410_ep, ep); if (!value) ep->halted = 0; else if (ep->desc && (ep->desc->bEndpointAddress & USB_DIR_IN) && !list_empty (&ep->queue)) return -EAGAIN; else ep->halted = 1; /* FIXME clear emulated data toggle too */ return 0;}static const struct usb_ep_ops s3c2410_ep_ops = { .enable = s3c2410_enable, .disable = s3c2410_disable, .alloc_request = s3c2410_alloc_request, .free_request = s3c2410_free_request, .alloc_buffer = s3c2410_alloc_buffer, .free_buffer = s3c2410_free_buffer, /* map, unmap, ... eventually hook the "generic" dma calls */ .queue = s3c2410_queue, .dequeue = s3c2410_dequeue, .set_halt = s3c2410_set_halt,};/*-------------------------------------------------------------------------*//* there are both host and device side versions of this call ... */static int s3c2410_g_get_frame (struct usb_gadget *_gadget){ struct timeval tv; printk("s3c2410_g_get_frame()\n"); do_gettimeofday (&tv); return tv.tv_usec / 1000;}static int s3c2410_wakeup (struct usb_gadget *_gadget){ struct s3c2410_udc *udc; printk("s3c2410_wakeup()\n"); udc = container_of (_gadget, struct s3c2410_udc, gadget); // udc->port_status |= (1 << USB_PORT_FEAT_C_SUSPEND); return 0;}static int s3c2410_set_selfpowered (struct usb_gadget *_gadget, int value){ struct s3c2410_udc *udc; printk("s3c2410_set_selfpowered()\n"); udc = container_of (_gadget, struct s3c2410_udc, gadget); if (value) udc->devstatus |= (1 << USB_DEVICE_SELF_POWERED); else udc->devstatus &= ~(1 << USB_DEVICE_SELF_POWERED); return 0;}static void nop_release (struct device *dev){ dprintk("%s %s\n", __FUNCTION__, dev->bus_id);}static const struct usb_gadget_ops s3c2410_ops = { .get_frame = s3c2410_g_get_frame, .wakeup = s3c2410_wakeup, .set_selfpowered = s3c2410_set_selfpowered,};/*-------------------------------------------------------------------------*//* "function" sysfs attribute */static ssize_tshow_function (struct device *_dev, char *buf){ struct s3c2410_udc *udc = the_controller; printk("s3c2410_show_function(dev=%p)\n", _dev); if (!udc->driver->function || strlen (udc->driver->function) > PAGE_SIZE) return 0; return snprintf (buf, PAGE_SIZE, "%s\n", udc->driver->function);}DEVICE_ATTR (function, S_IRUGO, show_function, NULL);/*-------------------------------------------------------------------------*//* * Driver registration/unregistration. * * This is basically hardware-specific; there's usually only one real USB * device (not host) controller since that's how USB devices are intended * to work. So most implementations of these api calls will rely on the * fact that only one driver will ever bind to the hardware. But curious * hardware can be built with discrete components, so the gadget API doesn't * require that assumption. *//* caller must hold lock */static voidstop_activity (struct s3c2410_udc *udc, struct usb_gadget_driver *driver){ struct s3c2410_ep *ep; printk("stop_activity()\n"); /* prevent any more requests */ udc->address = 0; /* The timer is left running so that outstanding URBs can fail */ /* nuke any pending requests first, so driver i/o is quiesced */ list_for_each_entry (ep, &udc->gadget.ep_list, ep.ep_list) nuke (udc, ep); /* driver now does any non-usb quiescing necessary */ if (driver) { spin_unlock (&udc->lock); driver->disconnect (&udc->gadget); spin_lock (&udc->lock); }}intusb_gadget_register_driver (struct usb_gadget_driver *driver){ struct s3c2410_udc *udc = the_controller; int retval, i; printk("usb_gadget_register_driver() '%s'\n", driver->driver.name); if (!udc) return -EINVAL; if (udc->driver) return -EBUSY; if (!driver->bind || !driver->unbind || !driver->setup || driver->speed == USB_SPEED_UNKNOWN) return -EINVAL; udc->gadget.name = gadget_name; udc->gadget.ops = &s3c2410_ops; udc->gadget.is_dualspeed = 1; udc->gadget.dev.release = nop_release; udc->devstatus = 0; INIT_LIST_HEAD (&udc->gadget.ep_list); for (i = 0; i < S3C2410_ENDPOINTS; i++) { struct s3c2410_ep *ep = &udc->ep[i]; if (!ep_name[i]) break; ep->ep.name = ep_name[i]; ep->ep.ops = &s3c2410_ep_ops; list_add_tail (&ep->ep.ep_list, &udc->gadget.ep_list); ep->halted = ep->already_seen = ep->setup_stage = 0; ep->ep.maxpacket = ~0; ep->last_io = jiffies; ep->gadget = &udc->gadget; ep->dev = udc; ep->desc = 0; INIT_LIST_HEAD (&ep->queue); } udc->gadget.ep0 = &udc->ep[0].ep; udc->ep[0].ep.maxpacket = 16; list_del_init (&udc->ep[0].ep.ep_list); INIT_LIST_HEAD(&udc->fifo_req.queue); udc->driver = driver; udc->gadget.dev.driver = &driver->driver; dprintk( "binding gadget driver '%s'\n", driver->driver.name); if ((retval = driver->bind (&udc->gadget)) != 0) { udc->driver = 0; udc->gadget.dev.driver = 0; return retval; } driver->driver.bus = 0; udc->driver = driver; udc->gadget.dev.driver = &driver->driver;/* driver_register (&driver->driver); device_bind_driver (&udc->gadget.dev);*/ retval = driver->bind(&udc->gadget); if (retval) { dprintk("bind to driver %s --> error %d\n", driver->driver.name, retval); udc->driver = 0; udc->gadget.dev.driver = 0; return retval; }#if 0 /* khubd will enumerate this in a while */ udc->port_status |= USB_PORT_STAT_CONNECTION | (1 << USB_PORT_FEAT_C_CONNECTION);#endif return 0;}EXPORT_SYMBOL (usb_gadget_register_driver);intusb_gadget_unregister_driver (struct usb_gadget_driver *driver){ struct s3c2410_udc *udc = the_controller; unsigned long flags; if (!udc) return -ENODEV; if (!driver || driver != udc->driver) return -EINVAL; printk("usb_gadget_register_driver() '%s'\n", driver->driver.name); spin_lock_irqsave (&udc->lock, flags); stop_activity (udc, driver);/* udc->port_status &= ~USB_PORT_STAT_CONNECTION; udc->port_status |= (1 << USB_PORT_FEAT_C_CONNECTION);*/ spin_unlock_irqrestore (&udc->lock, flags); driver->unbind (&udc->gadget); udc->driver = 0; device_release_driver (&udc->gadget.dev); driver_unregister (&driver->driver); return 0;}EXPORT_SYMBOL (usb_gadget_unregister_driver);#undef is_enabledint s3c2410_set_fifo_mode (struct usb_gadget *gadget, int mode){ return -ENOSYS;}EXPORT_SYMBOL (s3c2410_set_fifo_mode);/*-------------------------------------------------------------------------*//*-------------------------------------------------------------------------*/#define EP0_FIFO_SIZE 16#define BULK_FIFO_SIZE 64static struct s3c2410_udc memory;static inline void clear_ep_state (struct s3c2410_udc *dev){ unsigned i; /* hardware SET_{CONFIGURATION,INTERFACE} automagic resets endpoint * fifos, and pending transactions mustn't be continued in any case. */ for (i = 1; i < 5; i++) nuke(dev, &dev->ep[i]);}enum ep0_state { EP0_IDLE, EP0_IN_DATA_PHASE, EP0_OUT_DATA_PHASE, EP0_END_XFER, EP0_STALL,};static inline void ep0_idle (struct s3c2410_udc *dev){ dev->ep0state = EP0_IDLE;}static inline int windex_to_ep_num( __u16 w ) { return (int) ( w & 0x000F); }static inline void udc_change_index(int index, int *backup){ if (backup) *backup = __raw_readl(S3C2410_UDC_INDEX_REG); if ((index >= 0) && (index <= 5)) __raw_writel(index, S3C2410_UDC_INDEX_REG);}static inline int fifo_count_out(void){ int tmp; tmp = __raw_readl(S3C2410_UDC_OUT_FIFO_CNT2_REG) << 8; tmp |= __raw_readl(S3C2410_UDC_OUT_FIFO_CNT1_REG); return tmp & 0xffff;}static inline void out_pkt_ack(int last){ __raw_writel(S3C2410_UDC_EP0_CSR_SOPKTRDY | (last)?S3C2410_UDC_EP0_CSR_DE:0, S3C2410_UDC_EP0_CSR_REG);}/* * read_fifo_crq() * Read 1-8 bytes out of EP0 FIFO and put in request. * Called to do the initial read of setup requests * from the host. Return number of bytes read. * * Like write fifo above, this driver uses multiple * reads checked agains the count register with an * overall timeout. * */static intread_fifo_crq(struct usb_ctrlrequest *crq){ int bytes_read = 0; int fifo_count = 0; int i; // , ep; unsigned char *pOut = (unsigned char*)crq; udc_change_index(0, NULL); fifo_count = fifo_count_out(); BUG_ON( fifo_count > 8 ); dprintk("read_fifo_crq(): fifo_count=%d\n", fifo_count ); while( fifo_count-- ) { i = 0; do { *pOut = (unsigned char) __raw_readl(S3C2410_UDC_EP0_FIFO_REG); udelay( 10 ); i++; } while((fifo_count_out() != fifo_count) && (i < 10)); if ( i == 10 ) { printk("read_fifo(): read failure\n"); // usbd_info.stats.ep0_fifo_read_failures++; } pOut++; bytes_read++; } dprintk("read_fifo_crq(): len=%d %02x:%02x {%x,%x,%x}\n", bytes_read, crq->bRequest, crq->bRequestType, crq->wValue, crq->wIndex, crq->wLength); // usbd_info.stats.ep0_bytes_read++; return bytes_read;}static void 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 = 0; else req = list_entry(ep->queue.next, struct s3c2410_request, queue); S3C2410_UDC_SETIX(EP0); ep0csr = __raw_readl(S3C2410_UDC_IN_CSR1_REG); /* clear stall status */ if (ep0csr & S3C2410_UDC_EP0_CSR_SENTSTL) { nuke(dev, ep); clear_ep0_sst;/* del_timer(&dev->timer);*/ ep0_idle(dev); } if (ep0csr & S3C2410_UDC_EP0_CSR_SE && dev->ep0state != EP0_IDLE) { clear_ep0_se;/* del_timer(&dev->timer);*/ ep0_idle(dev); } switch (dev->ep0state) { case EP0_IDLE: /* start control request? */ if (ep0csr & S3C2410_UDC_EP0_CSR_OPKRDY) { int len, ret, tmp;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -