linux内核版本是2.6.32.2
1、platform_driver_register(&udc_driver_24x0);
UDC驱动是作为platform driver向platform子系统注册的,因此需要实现platform driver。
其中以s3c2410_udc_probe和s3c2410_udc_remove最为重要
static int s3c2410_udc_probe(struct platform_device *pdev) { struct s3c2410_udc *udc = &memory; //s3c2410的UDC设备,在其中对usb gadget设备对象和端点进行了初始化 struct device *dev = &pdev->dev; int retval; int irq; dev_dbg(dev, "%s()\n", __func__); //获取总线时钟并使能 usb_bus_clock = clk_get(NULL, "usb-bus-gadget"); if (IS_ERR(usb_bus_clock)) { dev_err(dev, "failed to get usb bus clock source\n"); return PTR_ERR(usb_bus_clock); } clk_enable(usb_bus_clock); //获取设备时钟并使能 udc_clock = clk_get(NULL, "usb-device"); if (IS_ERR(udc_clock)) { dev_err(dev, "failed to get udc clock source\n"); return PTR_ERR(udc_clock); } clk_enable(udc_clock); mdelay(10); dev_dbg(dev, "got and enabled clocks\n"); if (strncmp(pdev->name, "s3c2440", 7) == 0) { dev_info(dev, "S3C2440: increasing FIFO to 128 bytes\n"); memory.ep[1].fifo_size = S3C2440_EP_FIFO_SIZE; memory.ep[2].fifo_size = S3C2440_EP_FIFO_SIZE; memory.ep[3].fifo_size = S3C2440_EP_FIFO_SIZE; memory.ep[4].fifo_size = S3C2440_EP_FIFO_SIZE; } spin_lock_init (&udc->lock);//初始化设备的自旋锁 udc_info = pdev->dev.platform_data; rsrc_start = S3C2410_PA_USBDEV;//s3c2410 UDC端口的起始地址 rsrc_len = S3C24XX_SZ_USBDEV;//s3c2410 端口地址长度 if (!request_mem_region(rsrc_start, rsrc_len, gadget_name)) return -EBUSY; base_addr = ioremap(rsrc_start, rsrc_len); if (!base_addr) { retval = -ENOMEM; goto err_mem; } device_initialize(&udc->gadget.dev);//初始化设备对象 udc->gadget.dev.parent = &pdev->dev;//当前UDC设备的父设备对象是platform device udc->gadget.dev.dma_mask = pdev->dev.dma_mask; the_controller = udc; platform_set_drvdata(pdev, udc); //驱动和设备绑定,在platform_device结构中保存udc 设备对象 s3c2410_udc_disable(udc); s3c2410_udc_reinit(udc); /* irq setup after old hardware state is cleaned up */ retval = request_irq(IRQ_USBD, s3c2410_udc_irq, IRQF_DISABLED, gadget_name, udc); if (retval != 0) { dev_err(dev, "cannot get irq %i, err %d\n", IRQ_USBD, retval); retval = -EBUSY; goto err_map; } dev_dbg(dev, "got irq %i\n", IRQ_USBD); if (udc_info && udc_info->vbus_pin > 0) { retval = gpio_request(udc_info->vbus_pin, "udc vbus"); if (retval < 0) { dev_err(dev, "cannot claim vbus pin\n"); goto err_int; } irq = gpio_to_irq(udc_info->vbus_pin); if (irq < 0) { dev_err(dev, "no irq for gpio vbus pin\n"); goto err_gpio_claim; } retval = request_irq(irq, s3c2410_udc_vbus_irq, IRQF_DISABLED | IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING | IRQF_SHARED, gadget_name, udc); if (retval != 0) { dev_err(dev, "can't get vbus irq %d, err %d\n",irq, retval); retval = -EBUSY; goto err_gpio_claim; } dev_dbg(dev, "got irq %i\n", irq); } else { udc->vbus = 1; } if (s3c2410_udc_debugfs_root) { udc->regs_info = debugfs_create_file("registers", S_IRUGO, s3c2410_udc_debugfs_root, udc, &s3c2410_udc_debugfs_fops); if (!udc->regs_info) dev_warn(dev, "debugfs file creation failed\n"); } dev_dbg(dev, "probe ok\n"); return 0; err_gpio_claim: if (udc_info && udc_info->vbus_pin > 0) gpio_free(udc_info->vbus_pin); err_int: free_irq(IRQ_USBD, udc); err_map: iounmap(base_addr); err_mem: release_mem_region(rsrc_start, rsrc_len); return retval; }
从s3c2410_udc_probe函数可以看出,probe函数主要完成的就是将platform_device设备对象和UDC 设备对象建立关系,UDC 设备和驱动的一些初始化工作,并申请驱动所需要的资源,如端口区间,中断号等,并将中断函数和中断号绑定。这个中断处理函数很重要,所有的操作都将从中断函数入口。
static int s3c2410_udc_remove(struct platform_device *pdev) { struct s3c2410_udc *udc = platform_get_drvdata(pdev); unsigned int irq; dev_dbg(&pdev->dev, "%s()\n", __func__); if (udc->driver)//设备驱动的usb_gadget_driver对象,说明对象正在使用 return -EBUSY; debugfs_remove(udc->regs_info);//移除debugfs文件系统中建立的文件 if (udc_info && udc_info->vbus_pin > 0) { irq = gpio_to_irq(udc_info->vbus_pin); free_irq(irq, udc); } //释放中断 free_irq(IRQ_USBD, udc); //释放端口资源 iounmap(base_addr); release_mem_region(rsrc_start, rsrc_len); //解除绑定 platform_set_drvdata(pdev, NULL); //释放时钟 if (!IS_ERR(udc_clock) && udc_clock != NULL) { clk_disable(udc_clock); clk_put(udc_clock); udc_clock = NULL; } if (!IS_ERR(usb_bus_clock) && usb_bus_clock != NULL) { clk_disable(usb_bus_clock); clk_put(usb_bus_clock); usb_bus_clock = NULL; } dev_dbg(&pdev->dev, "%s: remove ok\n", __func__); return 0; }可以看出,remove函数基本上是probe函数的逆操作,将probe函数中申请的资源释放掉。
2、UDC驱动程序还需要为上层实现usb_gadget_register_driver和usb_gadget_unregister_driver两个gadget driver注册接口,这两个函数将实现gadget driver和udc driver绑定。
int usb_gadget_register_driver(struct usb_gadget_driver *driver) { struct s3c2410_udc *udc = the_controller; int retval; dprintk(DEBUG_NORMAL, "usb_gadget_register_driver() '%s'\n", driver->driver.name); /* Sanity checks */ if (!udc) return -ENODEV; //UDC设备只能绑定一个gadget driver对象 if (udc->driver) return -EBUSY; //检查gadget driver是否实现了绑定函数、setup函数 //同时低速设备也不支持gadget drivers if (!driver->bind || !driver->setup || driver->speed < USB_SPEED_FULL) { printk(KERN_ERR "Invalid driver: bind %p setup %p speed %d\n", driver->bind, driver->setup, driver->speed); return -EINVAL; } //支持卸载的话还要实现unbind函数 #if defined(MODULE) if (!driver->unbind) { printk(KERN_ERR "Invalid driver: no unbind method\n"); return -EINVAL; } #endif /* Hook the driver */ udc->driver = driver; udc->gadget.dev.driver = &driver->driver; //这里赋值的driver是struct device_driver结构,供linux设备模型使用 /* Bind the driver */ if ((retval = device_add(&udc->gadget.dev)) != 0) { printk(KERN_ERR "Error in device_add() : %d\n",retval); goto register_error; } //udc->gadget.dev是struct device 结构,这是向linux设备模型核心注册设备 dprintk(DEBUG_NORMAL, "binding gadget driver '%s'\n", driver->driver.name); if ((retval = driver->bind (&udc->gadget)) != 0) { device_del(&udc->gadget.dev); goto register_error; } //s3c2410_udc层向设备层传递usb_gadget /* Enable udc */ s3c2410_udc_enable(udc); return 0; register_error: udc->driver = NULL; udc->gadget.dev.driver = NULL; return retval; }
int usb_gadget_unregister_driver(struct usb_gadget_driver *driver) { struct s3c2410_udc *udc = the_controller; if (!udc) return -ENODEV; //驱动必须和注册时的驱动是一致的,同时实现了unbind函数 if (!driver || driver != udc->driver || !driver->unbind) return -EINVAL; dprintk(DEBUG_NORMAL,"usb_gadget_register_driver() '%s'\n", driver->driver.name); driver->unbind(&udc->gadget); device_del(&udc->gadget.dev); udc->driver = NULL; /* Disable udc */ s3c2410_udc_disable(udc); return 0; }
static irqreturn_t s3c2410_udc_irq(int dummy, void *_dev) { struct s3c2410_udc *dev = _dev; int usb_status; int usbd_status; int pwr_reg; int ep0csr; int i; u32 idx; unsigned long flags; //自旋锁,保护dev这个结构避免并发引起的竞态, //因为是单处理器。这里的自旋锁退化成了一个禁止内核抢占的开关,上锁就是禁止内核抢占 spin_lock_irqsave(&dev->lock, flags); /* Driver connected ? */ //当没有初始化好USB设备而发生中断时,清除中断标志 if (!dev->driver) { /* Clear interrupts */ udc_write(udc_read(S3C2410_UDC_USB_INT_REG), S3C2410_UDC_USB_INT_REG); udc_write(udc_read(S3C2410_UDC_EP_INT_REG), S3C2410_UDC_EP_INT_REG); } /* Save index */ idx = udc_read(S3C2410_UDC_INDEX_REG); /* Read status registers */ usb_status = udc_read(S3C2410_UDC_USB_INT_REG); usbd_status = udc_read(S3C2410_UDC_EP_INT_REG); pwr_reg = udc_read(S3C2410_UDC_PWR_REG); udc_writeb(base_addr, S3C2410_UDC_INDEX_EP0, S3C2410_UDC_INDEX_REG); ep0csr = udc_read(S3C2410_UDC_IN_CSR1_REG); dprintk(DEBUG_NORMAL, "usbs=%02x, usbds=%02x, pwr=%02x ep0csr=%02x\n", usb_status, usbd_status, pwr_reg, ep0csr); /* * Now, handle interrupts. There's two types : * - Reset, Resume, Suspend coming -> usb_int_reg * - EP -> ep_int_reg */ /* RESET */ if (usb_status & S3C2410_UDC_USBINT_RESET) { /* two kind of reset : * - reset start -> pwr reg = 8 * - reset end -> pwr reg = 0 **/ dprintk(DEBUG_NORMAL, "USB reset csr %x pwr %x\n", ep0csr, pwr_reg); dev->gadget.speed = USB_SPEED_UNKNOWN; udc_write(0x00, S3C2410_UDC_INDEX_REG); udc_write((dev->ep[0].ep.maxpacket & 0x7ff) >> 3, S3C2410_UDC_MAXP_REG); dev->address = 0; dev->ep0state = EP0_IDLE; dev->gadget.speed = USB_SPEED_FULL; /* clear interrupt */ udc_write(S3C2410_UDC_USBINT_RESET, S3C2410_UDC_USB_INT_REG); udc_write(idx, S3C2410_UDC_INDEX_REG); spin_unlock_irqrestore(&dev->lock, flags); return IRQ_HANDLED; } /* RESUME */ if (usb_status & S3C2410_UDC_USBINT_RESUME) { dprintk(DEBUG_NORMAL, "USB resume\n"); /* clear interrupt */ udc_write(S3C2410_UDC_USBINT_RESUME, S3C2410_UDC_USB_INT_REG); if (dev->gadget.speed != USB_SPEED_UNKNOWN && dev->driver && dev->driver->resume) dev->driver->resume(&dev->gadget); } /* SUSPEND */ if (usb_status & S3C2410_UDC_USBINT_SUSPEND) { dprintk(DEBUG_NORMAL, "USB suspend\n"); /* clear interrupt */ udc_write(S3C2410_UDC_USBINT_SUSPEND, S3C2410_UDC_USB_INT_REG); if (dev->gadget.speed != USB_SPEED_UNKNOWN && dev->driver && dev->driver->suspend) dev->driver->suspend(&dev->gadget); dev->ep0state = EP0_IDLE; } /* EP */ /* control traffic */ /* check on ep0csr != 0 is not a good idea as clearing in_pkt_ready * generate an interrupt */ if (usbd_status & S3C2410_UDC_INT_EP0) { dprintk(DEBUG_VERBOSE, "USB ep0 irq\n"); /* Clear the interrupt bit by setting it to 1 */ udc_write(S3C2410_UDC_INT_EP0, S3C2410_UDC_EP_INT_REG); s3c2410_udc_handle_ep0(dev); } /* endpoint data transfers */ for (i = 1; i < S3C2410_ENDPOINTS; i++) { u32 tmp = 1 << i; if (usbd_status & tmp) { dprintk(DEBUG_VERBOSE, "USB ep%d irq\n", i); /* Clear the interrupt bit by setting it to 1 */ udc_write(tmp, S3C2410_UDC_EP_INT_REG); s3c2410_udc_handle_ep(&dev->ep[i]); } } dprintk(DEBUG_VERBOSE, "irq: %d s3c2410_udc_done.\n", IRQ_USBD); /* Restore old index */ udc_write(idx, S3C2410_UDC_INDEX_REG); spin_unlock_irqrestore(&dev->lock, flags); return IRQ_HANDLED; }
4、端点操作函数
首先来看中断函数中涉及的两个函数,一个是端点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; } }
static void s3c2410_udc_handle_ep(struct s3c2410_ep *ep) { struct s3c2410_request *req; int is_in = ep->bEndpointAddress & USB_DIR_IN; u32 ep_csr1; u32 idx; if (likely (!list_empty(&ep->queue))) req = list_entry(ep->queue.next, struct s3c2410_request, queue); else req = NULL; idx = ep->bEndpointAddress & 0x7F; if (is_in) {//需要向主机发送数据 udc_write(idx, S3C2410_UDC_INDEX_REG); ep_csr1 = udc_read(S3C2410_UDC_IN_CSR1_REG); dprintk(DEBUG_VERBOSE, "ep%01d write csr:%02x %d\n", idx, ep_csr1, req ? 1 : 0); if (ep_csr1 & S3C2410_UDC_ICSR1_SENTSTL) { dprintk(DEBUG_VERBOSE, "st\n"); udc_write(idx, S3C2410_UDC_INDEX_REG); udc_write(ep_csr1 & ~S3C2410_UDC_ICSR1_SENTSTL, S3C2410_UDC_IN_CSR1_REG); return; } if (!(ep_csr1 & S3C2410_UDC_ICSR1_PKTRDY) && req) { s3c2410_udc_write_fifo(ep,req); } } else {//从主机接收数据 udc_write(idx, S3C2410_UDC_INDEX_REG); ep_csr1 = udc_read(S3C2410_UDC_OUT_CSR1_REG); dprintk(DEBUG_VERBOSE, "ep%01d rd csr:%02x\n", idx, ep_csr1); if (ep_csr1 & S3C2410_UDC_OCSR1_SENTSTL) { udc_write(idx, S3C2410_UDC_INDEX_REG); udc_write(ep_csr1 & ~S3C2410_UDC_OCSR1_SENTSTL, S3C2410_UDC_OUT_CSR1_REG); return; } if ((ep_csr1 & S3C2410_UDC_OCSR1_PKTRDY) && req) { s3c2410_udc_read_fifo(ep,req); } } }
主要分析queue这个函数,因为上层主要和这个函数打交道,接收或发送数据都需要对应的端点队列提交请求
static int s3c2410_udc_queue(struct usb_ep *_ep, struct usb_request *_req, gfp_t gfp_flags) { struct s3c2410_request *req = to_s3c2410_req(_req); struct s3c2410_ep *ep = to_s3c2410_ep(_ep); struct s3c2410_udc *dev; u32 ep_csr = 0; int fifo_count = 0; unsigned long flags; if (unlikely (!_ep || (!ep->desc && ep->ep.name != ep0name))) { dprintk(DEBUG_NORMAL, "%s: invalid args\n", __func__); return -EINVAL; } dev = ep->dev; if (unlikely (!dev->driver || dev->gadget.speed == USB_SPEED_UNKNOWN)) { return -ESHUTDOWN; } local_irq_save (flags); if (unlikely(!_req || !_req->complete || !_req->buf || !list_empty(&req->queue))) { if (!_req) dprintk(DEBUG_NORMAL, "%s: 1 X X X\n", __func__); else { dprintk(DEBUG_NORMAL, "%s: 0 %01d %01d %01d\n", __func__, !_req->complete,!_req->buf, !list_empty(&req->queue)); } local_irq_restore(flags); return -EINVAL; } _req->status = -EINPROGRESS; _req->actual = 0; dprintk(DEBUG_VERBOSE, "%s: ep%x len %d\n", __func__, ep->bEndpointAddress, _req->length); if (ep->bEndpointAddress) { udc_write(ep->bEndpointAddress & 0x7F, S3C2410_UDC_INDEX_REG); ep_csr = udc_read((ep->bEndpointAddress & USB_DIR_IN) ? S3C2410_UDC_IN_CSR1_REG : S3C2410_UDC_OUT_CSR1_REG); fifo_count = s3c2410_udc_fifo_count_out(); } else { udc_write(0, S3C2410_UDC_INDEX_REG); ep_csr = udc_read(S3C2410_UDC_IN_CSR1_REG); fifo_count = s3c2410_udc_fifo_count_out(); } /* kickstart this i/o queue? */ if (list_empty(&ep->queue) && !ep->halted) { if (ep->bEndpointAddress == 0 /* ep0 */) { switch (dev->ep0state) { case EP0_IN_DATA_PHASE: if (!(ep_csr&S3C2410_UDC_EP0_CSR_IPKRDY) && s3c2410_udc_write_fifo(ep, req)) { dev->ep0state = EP0_IDLE; req = NULL; } break; case EP0_OUT_DATA_PHASE: if ((!_req->length) || ((ep_csr & S3C2410_UDC_OCSR1_PKTRDY) && s3c2410_udc_read_fifo(ep, req))) { dev->ep0state = EP0_IDLE; req = NULL; } break; default: local_irq_restore(flags); return -EL2HLT; } } else if ((ep->bEndpointAddress & USB_DIR_IN) != 0 && (!(ep_csr&S3C2410_UDC_OCSR1_PKTRDY)) && s3c2410_udc_write_fifo(ep, req)) { req = NULL; } else if ((ep_csr & S3C2410_UDC_OCSR1_PKTRDY) && fifo_count && s3c2410_udc_read_fifo(ep, req)) { req = NULL; } } /* pio or dma irq handler advances the queue. */ if (likely (req != 0)) list_add_tail(&req->queue, &ep->queue); local_irq_restore(flags); dprintk(DEBUG_VERBOSE, "%s ok\n", __func__); return 0; }
static void s3c2410_udc_done(struct s3c2410_ep *ep, struct s3c2410_request *req, int status) { unsigned halted = ep->halted; list_del_init(&req->queue);//将这个请求从端点请求队列中删除 if (likely (req->req.status == -EINPROGRESS)) req->req.status = status; else status = req->req.status; ep->halted = 1; req->req.complete(&ep->ep, &req->req); ep->halted = halted; }
总结:
UDC设备驱动层的源码就分析得差不多了,其他很多函数都是操作寄存器,与UDC设备密切相关,但总的来说完成的功能都是一致的。可以发现,在UDC设备驱动层主要需要做以下几个工作:
1. 对usb_gadget、usb_ep、usb_request三个标准数据结构进行封装,根据自己UDC的一些设备特性,设计对应的自己的数据结构;
2. 实现platform_driver数据结构中的函数,将UDC设备驱动向platform系统进行注册;
3. 实现usb_gadget_ops函数集,这些函数主要是操作UDC设备的一些特性(针对设备);
4. 实现usb_ep_ops函数集,这些函数主要是操作端点的功能,如请求分配和提交等(针对端点);
5. 实现UDC设备的中断处理函数,这个函数基本上就是UDC设备驱动的核心;
6.实现上层功能驱动注册接口函数:
int usb_gadget_register_driver(struct usb_gadget_driver *driver)
int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)