这一层是与硬件相关层。相关文件s3c2410_udc.c s3c2410_udc.h。s3c2410设备控制器作为一个linux设备在这一层是作为platform设备而注册到linux设备模型中的。相关数据结构以及相关函数如下:
1 数据结构
- struct s3c2410_udc {
- spinlock_t lock;
- struct s3c2410_ep ep[S3C2410_ENDPOINTS];
- int address;
- struct usb_gadget gadget;
- struct usb_gadget_driver *driver;
- struct s3c2410_request fifo_req;
- u8 fifo_buf[EP_FIFO_SIZE];
- u16 devstatus;
- u32 port_status;
- int ep0state;
- unsigned got_irq : 1;
- unsigned req_std : 1;
- unsigned req_config : 1;
- unsigned req_pending : 1;
- u8 vbus;
- struct dentry *regs_info;
- };
- static struct s3c2410_udc memory = {
- .gadget = {
- .ops = &s3c2410_ops,
- .ep0 = &memory.ep[0].ep,
- .name = gadget_name,
- .dev = {
- .init_name = "gadget",
- },
- },
- /* control endpoint */
- .ep[0] = {
- .num = 0,
- .ep = {
- .name = ep0name,
- .ops = &s3c2410_ep_ops,
- .maxpacket = EP0_FIFO_SIZE,
- },
- .dev = &memory,
- },
- /* first group of endpoints */
- .ep[1] = {
- .num = 1,
- .ep = {
- .name = "ep1-bulk",
- .ops = &s3c2410_ep_ops,
- .maxpacket = EP_FIFO_SIZE,
- },
- .dev = &memory,
- .fifo_size = EP_FIFO_SIZE,
- .bEndpointAddress = 1,
- .bmAttributes = USB_ENDPOINT_XFER_BULK,
- },
- .ep[2] = {
- .num = 2,
- .ep = {
- .name = "ep2-bulk",
- .ops = &s3c2410_ep_ops,
- .maxpacket = EP_FIFO_SIZE,
- },
- .dev = &memory,
- .fifo_size = EP_FIFO_SIZE,
- .bEndpointAddress = 2,
- .bmAttributes = USB_ENDPOINT_XFER_BULK,
- },
- .ep[3] = {
- .num = 3,
- .ep = {
- .name = "ep3-bulk",
- .ops = &s3c2410_ep_ops,
- .maxpacket = EP_FIFO_SIZE,
- },
- .dev = &memory,
- .fifo_size = EP_FIFO_SIZE,
- .bEndpointAddress = 3,
- .bmAttributes = USB_ENDPOINT_XFER_BULK,
- },
- .ep[4] = {
- .num = 4,
- .ep = {
- .name = "ep4-bulk",
- .ops = &s3c2410_ep_ops,
- .maxpacket = EP_FIFO_SIZE,
- },
- .dev = &memory,
- .fifo_size = EP_FIFO_SIZE,
- .bEndpointAddress = 4,
- .bmAttributes = USB_ENDPOINT_XFER_BULK,
- }
- };
platform设备需要注册一个platform_driver的结构体:
- static struct platform_driver udc_driver_2410 = {
- .driver = {
- .name = "s3c2410-usbgadget",
- .owner = THIS_MODULE,
- },
- .probe = s3c2410_udc_probe,
- .remove = s3c2410_udc_remove,
- .suspend = s3c2410_udc_suspend,
- .resume = s3c2410_udc_resume,
- };
以上的数据结构以及函数是UDC的硬件层,不同的UDC采取不同的策略。s3c2410是集成的USB设备控制器,所以就是采用platform驱动的形式来注册的。如果系统是外接的USB设备控制器,那么则会采用相应总线的注册形式,比如PCI等。platform驱动的唯一目的就是分配资源以及初级初始化硬件,对于USB设备层和功能驱动层都没有影响。UDC层与USB设备层是通过另外的数据结构进行交互的。这种方式就是使用两个结构体与两个函数, 两个结构体分别是struct usb_gadget与struct usb_gadget_driver,他们都是嵌入在struct s3c2410_udc结构中的,但是是由不同软件层的代码初始化的。首先看struct usb_gadget,他是在定义memory的时候就进行了初始化,是在UDC层中初始化的。而struct usb_gadget_driver是在USB设备层中初始化的,他是通过usb_gadget_register_driver(struct usb_gadget_driver *driver)函数从USB设备层传过来然后赋值给memory的。这里出现一个关键的函数usb_gadget_register_driver(struct usb_gadget_driver *driver)这个函数就是UDC层与USB设备层进行交互的函数。设备设备层通过调用它与UDC层联系在一起。这个函数将usb_gadget与usb_gadget_driver联系在一起。向USB设备层提供usb_gadget_register_driver(struct usb_gadget_driver *driver)是UDC层的基本任务,但是UDC层要做的不仅如此,UDC层还需要提供为usb_gadget服务的相关函数,这些函数会通过usb_gadget传递给USB设备层。UDC层还需要提供USB设备的中断处理程序,中断处理尤其重要。因为所有的USB传输都是由主机发起,而有没有USB传输完全由USB中断判定,所以USB中断处理程序是整个软件架构的核心。UDC层主要提供以下的函数与数据结构:
(1) usb_gadget操作函数集合
- static const struct usb_gadget_ops s3c2410_ops = {
- .get_frame = s3c2410_udc_get_frame,
- .wakeup = s3c2410_udc_wakeup,
- .set_selfpowered = s3c2410_udc_set_selfpowered,
- .pullup = s3c2410_udc_pullup,
- .vbus_session = s3c2410_udc_vbus_session,
- .vbus_draw = s3c2410_vbus_draw,
- };
(2) 端点操作函数集合
- static const struct usb_ep_ops s3c2410_ep_ops = {
- .enable = s3c2410_udc_ep_enable,
- .disable = s3c2410_udc_ep_disable,
- .alloc_request = s3c2410_udc_alloc_request,
- .free_request = s3c2410_udc_free_request,
- .queue = s3c2410_udc_queue,
- .dequeue = s3c2410_udc_dequeue,
- .set_halt = s3c2410_udc_set_halt,
- };
- static irqreturn_t s3c2410_udc_irq(int dummy, void *_dev)
二 USB设备层
USB设备层,虽然名字上与设备相关。但是属于硬件无关层。这一层相关的代码是composite.c,composite.h。这一层的功能是隔离Gadget功能驱动与硬件相关层。使得功能驱动直接与USB设备层交互不用考虑硬件的相关细节。还有USB设备层提供了USB设备的一些基本数据结构,不同的Gadget功能驱动可以共同调用。如果没有这一层,则每一个功能驱动都需要实现自己的USB设备,导致了代码重用率很高。这一层向下与UDC层进行交互,向上与Gadget功能驱动层进行交互。在UDC层已经介绍了USB设备层向下与UDC层交互方式主要是通过调用usb_gadget_register_driver(struct usb_gadget_driver *driver),这个函数是UDC层提供的。而这个函数传递的参数就是一个usb_gadget_driver的结构体。以下是这个结构体定义:
- struct usb_gadget_driver {
- char *function;
- enum usb_device_speed speed;
- int (*bind)(struct usb_gadget *);
- void (*unbind)(struct usb_gadget *);
- int (*setup)(struct usb_gadget *,
- const struct usb_ctrlrequest *);
- void (*disconnect)(struct usb_gadget *);
- void (*suspend)(struct usb_gadget *);
- void (*resume)(struct usb_gadget *);
- /* FIXME support safe rmmod */
- struct device_driver driver;
- };
- static struct usb_gadget_driver composite_driver = {
- .speed = USB_SPEED_HIGH,
- .bind = composite_bind,
- .unbind = __exit_p(composite_unbind),
- .setup = composite_setup,
- .disconnect = composite_disconnect,
- .suspend = composite_suspend,
- .resume = composite_resume,
- .driver = {
- .owner = THIS_MODULE,
- },
- };
(1) 数据结构
- struct usb_composite_dev {
- struct usb_gadget *gadget;
- struct usb_request *req;
- unsigned bufsiz;
- struct usb_configuration *config;
- /* private: */
- /* internals */
- struct usb_device_descriptor desc;
- struct list_head configs;
- struct usb_composite_driver *driver;
- u8 next_string_id;
- /* the gadget driver won't enable the data pullup
- * while the deactivation count is nonzero.
- */
- unsigned deactivations;
- /* protects at least deactivation count */
- spinlock_t lock;
- };
- struct usb_composite_driver {
- const char *name;
- const struct usb_device_descriptor *dev;
- struct usb_gadget_strings **strings;
- /* REVISIT: bind() functions can be marked __init, which
- * makes trouble for section mismatch analysis. See if
- * we can't restructure things to avoid mismatching...
- */
- int (*bind)(struct usb_composite_dev *);
- int (*unbind)(struct usb_composite_dev *);
- /* global suspend hooks */
- void (*suspend)(struct usb_composite_dev *);
- void (*resume)(struct usb_composite_dev *);
- };
(2) 函数
- int __init usb_composite_register(struct usb_composite_driver *driver)
- {
- if (!driver || !driver->dev || !driver->bind || composite)
- return -EINVAL;
- if (!driver->name)
- driver->name = "composite";
- composite_driver.function = (char *) driver->name;
- composite_driver.driver.name = driver->name;
- composite = driver;
- return usb_gadget_register_driver(&composite_driver);
- }
三 Gadget 功能驱动层
Gadget 功能驱动层是USB Gadget软件结构的最上层。主要是实现USB设备的功能,这一层通常与linux内核的其他层有密切的联系。模拟U盘的gadget就与文件系统层与块IO层有着联系。这里主要介绍最简单的Gadget 功能驱动zero。这一层包括zero.c。该驱动是作为一个模块注册到内核的,首先看一下他的模块初始化函数:
- static int __init init(void)
- {
- return usb_composite_register(&zero_driver);
- }
- static struct usb_composite_driver zero_driver = {
- .name = "zero",
- .dev = &device_desc,
- .strings = dev_strings,
- .bind = zero_bind,
- .unbind = zero_unbind,
- .suspend = zero_suspend,
- .resume = zero_resume,
- };