Linux USB Gadget软件结构一文中分析Linux USB Gadget软件分为三层。这三层其中两层是与硬件无关的,分别是Gadget功能驱动层,USB设备层。一层是与硬件相关的是UDC层。每一层都提供一种关键的数据结构与函数与其他层交互。 Gadget功能驱动层: 最主要的结构是struct usb_composite_driver,这个结构在这层定义,并且实现结构中的各个函数。 USB设备层: 最主要的数据结构是struct usb_composite_dev与usb_gadget_driver。前一个代表一个USB设备,而后一个是Gadget驱动,与UDC层交互。 UDC层: 最主要的数据结构是struct usb_gadget,通常包含在其他结构体中。这个结构体代表了一个USB设备控制器的所有关于USB通信的信息。 UDC层提供usb_gadget_unregister_driver(struct usb_gadget_driver *driver)函数,这个函数由USB设备层调用,USB设备层将自己定义的struct usb_gadget_driver结构变量传递给他。USB设备层提供usb_composite_register(struct usb_composite_driver *driver)函数,这个函数由Gadget功能驱动层调用,Gadget功能驱动层将自己定义的struct usb_composite_driver 结构变量传递给他。下面详细分析一下这三层是如何结合在一起的。我们将以zero Gadget功能驱动为例子,s3c2410_udc作为底层UDC。 首先先看一下zero Gadget功能驱动,他是作为一个模块注册到内核中的,首先分析一下他的模块初始化函数:- static int __init init(void)
- {
- return usb_composite_register(&zero_driver);
- }
很简单,只是调用了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,
- };
以上函数都是在zero.c中实现的,比较重要的函数是zero_bind。目前暂时不列出这个函数,等用到的时候再说。下面看一下usb_composite_register函数,他是由USB设备层提供的,定义在composite.c中:- 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);
- }
这个函数主要的目的是初始化两个结构体变量,一个是composite_driver,这个是USB设备层定义的一个全局struct usb_gadget_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,
- },
- };
这些函数都要在USB设备层实现。usb_composite_register将composite_driver的function初始化为"zero"。driver是 struct device_driver结构体。linux设备模型中使用。名字初始化为“zero”。另外一个变量是composite,它是一个USB设备层定义的struct usb_composite_driver的指针,这样composite就指向了zero_driver。因此zero Gadget功能驱动层就和USB设备层联系到了一起。最后usb_composite_register函数调用usb_gadget_register_driver,开始向UDC层联系。这个函数定义在UDC层,系统每个UDC都要实现这样一个函数。我们看一下s3c2410_udc这个函数的实现:- 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);
-
-
- if (!udc)
- return -ENODEV;
-
- if (udc->driver)
- return -EBUSY;
-
- 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;
- }
- #if defined(MODULE)
- if (!driver->unbind) {
- printk(KERN_ERR "Invalid driver: no unbind method\n");
- return -EINVAL;
- }
- #endif
-
-
- udc->driver = driver;
- udc->gadget.dev.driver = &driver->driver;
-
-
- if ((retval = device_add(&udc->gadget.dev)) != 0) {
- printk(KERN_ERR "Error in device_add() : %d\n",retval);
- goto register_error;
- }
-
-
- 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_enable(udc);
-
- return 0;
-
- register_error:
- udc->driver = NULL;
- udc->gadget.dev.driver = NULL;
- return retval;
- }
这个函数最开始的功能是将UDC层与USB设备层联系在一起,然后调用driver->bind (&udc->gadget)函数。开始了最重要的绑定工作。只有这个函数执行完毕这三层才真正的结合在一起,USB设备正常的工作。driver就是传递过来的在USB设备层定义的composite_driver。所以driver->bind (&udc->gadget)函数是在composite.c中定义的,如下:- static int __init composite_bind(struct usb_gadget *gadget)
- {
- struct usb_composite_dev *cdev;
- int status = -ENOMEM;
-
- cdev = kzalloc(sizeof *cdev, GFP_KERNEL);
- if (!cdev)
- return status;
-
- spin_lock_init(&cdev->lock);
- cdev->gadget = gadget;
- set_gadget_data(gadget, cdev);
- INIT_LIST_HEAD(&cdev->configs);
-
-
- cdev->req = usb_ep_alloc_request(gadget->ep0, GFP_KERNEL);
-
- if (!cdev->req)
- goto fail;
- cdev->req->buf = kmalloc(USB_BUFSIZ, GFP_KERNEL);
- if (!cdev->req->buf)
- goto fail;
- cdev->req->complete = composite_setup_complete;
- gadget->ep0->driver_data = cdev;
-
- cdev->bufsiz = USB_BUFSIZ;
- cdev->driver = composite;
-
- usb_gadget_set_selfpowered(gadget);
-
-
-
-
-
- usb_ep_autoconfig_reset(cdev->gadget);
-
-
-
-
-
- status = composite->bind(cdev);
- if (status < 0)
- goto fail;
-
- cdev->desc = *composite->dev;
- cdev->desc.bMaxPacketSize0 = gadget->ep0->maxpacket;
-
-
- if (idVendor)
- cdev->desc.idVendor = cpu_to_le16(idVendor);
- if (idProduct)
- cdev->desc.idProduct = cpu_to_le16(idProduct);
- if (bcdDevice)
- cdev->desc.bcdDevice = cpu_to_le16(bcdDevice);
-
-
-
-
- if (cdev->desc.iManufacturer && iManufacturer)
- string_override(composite->strings,
- cdev->desc.iManufacturer, iManufacturer);
- if (cdev->desc.iProduct && iProduct)
- string_override(composite->strings,
- cdev->desc.iProduct, iProduct);
- if (cdev->desc.iSerialNumber && iSerialNumber)
- string_override(composite->strings,
- cdev->desc.iSerialNumber, iSerialNumber);
-
- INFO(cdev, "%s ready\n", composite->name);
- return 0;
-
- fail:
- composite_unbind(gadget);
- return status;
- }
composite_bind首先定义并初始化了struct usb_composite_dev结构体,通过cdev->gadget = gadget;这条语句将设备与底层的gadget联系在一起,通过cdev->driver = composite,这条语句将设备与Gadget功能驱动联系在一起。并且给设备端点0分配了一个struct usb_request,这个结构在USB枚举将发挥重要的作用。然后调用Gadget功能驱动层的bind函数。最后初始化了USB设备描述符。这个函数最重要的一步就是调用了Gadget功能驱动层的bind函数。这样,三个软件层才真正的联系在了一起。zero Gadget功能驱动层的 bind函数定义在zero.c中,如下:- static int __init zero_bind(struct usb_composite_dev *cdev)
- {
- int gcnum;
- struct usb_gadget *gadget = cdev->gadget;
- int id;
-
-
-
-
- id = usb_string_id(cdev);
-
- if (id < 0)
- return id;
- strings_dev[STRING_MANUFACTURER_IDX].id = id;
- device_desc.iManufacturer = id;
-
- id = usb_string_id(cdev);
- if (id < 0)
- return id;
- strings_dev[STRING_PRODUCT_IDX].id = id;
- device_desc.iProduct = id;
-
- id = usb_string_id(cdev);
- if (id < 0)
- return id;
- strings_dev[STRING_SERIAL_IDX].id = id;
- device_desc.iSerialNumber = id;
-
- setup_timer(&autoresume_timer, zero_autoresume, (unsigned long) cdev);
-
-
-
-
- if (loopdefault) {
- loopback_add(cdev, autoresume != 0);
- if (!gadget_is_sh(gadget))
- sourcesink_add(cdev, autoresume != 0);
- } else {
- sourcesink_add(cdev, autoresume != 0);
- if (!gadget_is_sh(gadget))
- loopback_add(cdev, autoresume != 0);
- }
-
-
-
- gcnum = usb_gadget_controller_number(gadget);
- if (gcnum >= 0)
- device_desc.bcdDevice = cpu_to_le16(0x0200 + gcnum);
- else {
-
-
-
-
-
-
-
- pr_warning("%s: controller '%s' not recognized\n",
- longname, gadget->name);
- device_desc.bcdDevice = cpu_to_le16(0x9999);
- }
-
-
- INFO(cdev, "%s, version: " DRIVER_VERSION "\n", longname);
-
- snprintf(manufacturer, sizeof manufacturer, "%s %s with %s",
- init_utsname()->sysname, init_utsname()->release,
- gadget->name);
-
- return 0;
- }
zero_bind函数首先就是设置了几个字符串描述符的id,然后就设置USB配置。主要调用了sourcesink_add函数,传递给的参数是cdev,就是USB设备层定义的USB设备结构体。这个函数定义在f_sourcesink.c,这个文件以头文件的形式包含在zero.c中。如下所示:- int __init sourcesink_add(struct usb_composite_dev *cdev, bool autoresume)
- {
- int id;
-
-
- id = usb_string_id(cdev);
- if (id < 0)
- return id;
- strings_sourcesink[0].id = id;
-
- source_sink_intf.iInterface = id;
- sourcesink_driver.iConfiguration = id;
-
-
-
- if (autoresume)
- sourcesink_driver.bmAttributes |= USB_CONFIG_ATT_WAKEUP;
-
-
- if (gadget_is_otg(cdev->gadget)) {
- sourcesink_driver.descriptors = otg_desc;
- sourcesink_driver.bmAttributes |= USB_CONFIG_ATT_WAKEUP;
- }
-
- return usb_add_config(cdev, &sourcesink_driver);
- }
- 在分析这个函数之前首先先看一下f_sourcesink.c中关键的一个数据结构,sourcesink_driver。他代表了一个USB配置,里面说明了配置的功能。如下:
- static struct usb_configuration sourcesink_driver = {
- .label = "source/sink",
- .strings = sourcesink_strings,
- .bind = sourcesink_bind_config,
- .setup = sourcesink_setup,
- .bConfigurationValue = 3,
- .bmAttributes = USB_CONFIG_ATT_SELFPOWER,
-
- };
看完了这个数据结构,我们分析一下sourcesink_add最后调用的函数usb_add_config(cdev, &sourcesink_driver),这个函数传递的参数一个是USB设备一个是USB配置。显然功能是给USB设备增加一个配置。函数定义在composite.c中,如下:- int __init usb_add_config(struct usb_composite_dev *cdev,
- struct usb_configuration *config)
- {
- int status = -EINVAL;
- struct usb_configuration *c;
-
- DBG(cdev, "adding config #%u '%s'/%p\n",
- config->bConfigurationValue,
- config->label, config);
-
- if (!config->bConfigurationValue || !config->bind)
- goto done;
-
-
- list_for_each_entry(c, &cdev->configs, list) {
- if (c->bConfigurationValue == config->bConfigurationValue) {
- status = -EBUSY;
- goto done;
- }
- }
-
- config->cdev = cdev;
- list_add_tail(&config->list, &cdev->configs);
-
-
- INIT_LIST_HEAD(&config->functions);
-
- config->next_interface_id = 0;
-
- status = config->bind(config);
-
- if (status < 0) {
- list_del(&config->list);
- config->cdev = NULL;
- } else {
- unsigned i;
-
- DBG(cdev, "cfg %d/%p speeds:%s%s\n",
- config->bConfigurationValue, config,
- config->highspeed ? " high" : "",
- config->fullspeed
- ? (gadget_is_dualspeed(cdev->gadget)
- ? " full"
- : " full/low")
- : "");
-
- for (i = 0; i < MAX_CONFIG_INTERFACES; i++) {
- struct usb_function *f = config->interface[i];
-
- if (!f)
- continue;
- DBG(cdev, " interface %d = %s/%p\n",
- i, f->name, f);
- }
- }
-
-
-
-
- usb_ep_autoconfig_reset(cdev->gadget);
-
- done:
- if (status)
- DBG(cdev, "added config '%s'/%u --> %d\n", config->label,
- config->bConfigurationValue, status);
- return status;
- }
这个函数初始化了配置,将配置与设备联系在一起,并且打印一些调试信息。这样设备有了配置,但是我们知道一个USB设备的配置下是接口的集合。所以函数调用config->bind(config)给配置添加接口。这个函数如下:- static int __init sourcesink_bind_config(struct usb_configuration *c)
- {
- struct f_sourcesink *ss;
- int status;
-
- ss = kzalloc(sizeof *ss, GFP_KERNEL);
- if (!ss)
- return -ENOMEM;
-
- ss->function.name = "source/sink";
- ss->function.descriptors = fs_source_sink_descs;
- ss->function.bind = sourcesink_bind;
- ss->function.unbind = sourcesink_unbind;
- ss->function.set_alt = sourcesink_set_alt;
- ss->function.disable = sourcesink_disable;
-
- status = usb_add_function(c, &ss->function);
- if (status)
- kfree(ss);
- return status;
- }
可以看出这个函数分配并初始化了一个struct f_sourcesink结构体,这个结构体包含代表接口的struct usb_function。并且初始化了struct usb_function的一下回调函数。最后调用usb_add_function(c, &ss->function);将接口添加到配置中。usb_add_function函数如下所示:- int __init usb_add_function(struct usb_configuration *config,
- struct usb_function *function)
- {
- int value = -EINVAL;
-
- DBG(config->cdev, "adding '%s'/%p to config '%s'/%p\n",
- function->name, function,
- config->label, config);
-
- if (!function->set_alt || !function->disable)
- goto done;
-
- function->config = config;
- list_add_tail(&function->list, &config->functions);
-
-
- if (function->bind) {
- value = function->bind(config, function);
- if (value < 0) {
- list_del(&function->list);
- function->config = NULL;
- }
- } else
- value = 0;
-
-
-
-
-
-
- if (!config->fullspeed && function->descriptors)
- config->fullspeed = true;
- if (!config->highspeed && function->hs_descriptors)
- config->highspeed = true;
-
- done:
- if (value)
- DBG(config->cdev, "adding '%s'/%p --> %d\n",
- function->name, function, value);
- return value;
- }
我们可以看到这个函数最主要的就是联系接口与配置。并且调用接口的bind函数,zero sourcesink配置的接口的bind为sourcesink_bind。如下定义:- static int __init
- sourcesink_bind(struct usb_configuration *c, struct usb_function *f)
- {
- struct usb_composite_dev *cdev = c->cdev;
- struct f_sourcesink *ss = func_to_ss(f);
- int id;
-
-
- id = usb_interface_id(c, f);
- if (id < 0)
- return id;
- source_sink_intf.bInterfaceNumber = id;
-
-
-
- ss->in_ep = usb_ep_autoconfig(cdev->gadget, &fs_source_desc);
- if (!ss->in_ep) {
- autoconf_fail:
- ERROR(cdev, "%s: can't autoconfigure on %s\n",
- f->name, cdev->gadget->name);
- return -ENODEV;
- }
- ss->in_ep->driver_data = cdev;
-
- ss->out_ep = usb_ep_autoconfig(cdev->gadget, &fs_sink_desc);
- if (!ss->out_ep)
- goto autoconf_fail;
- ss->out_ep->driver_data = cdev;
-
-
- if (gadget_is_dualspeed(c->cdev->gadget)) {
- hs_source_desc.bEndpointAddress =
- fs_source_desc.bEndpointAddress;
- hs_sink_desc.bEndpointAddress =
- fs_sink_desc.bEndpointAddress;
- f->hs_descriptors = hs_source_sink_descs;
- }
-
- DBG(cdev, "%s speed %s: IN/%s, OUT/%s\n",
- gadget_is_dualspeed(c->cdev->gadget) ? "dual" : "full",
- f->name, ss->in_ep->name, ss->out_ep->name);
- return 0;
- }
这个函数除了初始化接口的接口id。另外就是给接口分配端点了。这也是各层整合的最后一步了。zero sourcesink有一个配置,一个接口。这个接口有两个端点,一个in端点一个Out端点。usb_ep_autoconfig 函数就担当了分配端点的任务,他定义在epautoconf.c中,这个文件以头文件的形式包含在了zero.c中。这个函数有两个参数一个是struct usb_gadget类型的指针,一个是struct usb_endpoint_descriptor类型的指针,也就是端点描述符,这个函数根据端点描述符的信息,自动在struct usb_gadget里找到合适的端点。 经过上面的重重函数调用,现在设备终于饱满了,既有配置了,也有接口了,接口里也有相应的端点了。各层的关系也都联系起来了。但是还是有一点就是感觉有点晕。确实这么多的函数调用,不晕都没办法呀。没关系,我们来重新梳理一下各个函数之间的调用关系以及各环节整合的过程。这个整合的过程大体分为两个过程:(1) 过程方向 Gadget功能驱动层-->USB设备层-->UDC层。 以四个数据结构为基础:struct usb_composite_driver struct usb_composite_dev struct usb_gadget_driver struct usb_gadget 两个register函数为导向: usb_composite_register(&zero_driver) usb_gadget_register_driver(&composite_driver)(2) 过程方向 UDC层-->USB设备层-->Gadget功能驱动层 四个bind函数为串联点,带出一连串数据结构与初始化。这四个bind函数分配是: USB设备层的composite_bind 由UDC层的usb_gadget_register_driver函数调用。功能是分配struct usb_composite_dev cdev 并初始化。struct usb_composite_dev结构串联了UDC层的usb_gadget与Gadget功能驱动层的usb_composite_driver。并且调用下一个上层的bind Gadget功能驱动层的zero_bind 这个函数主要的任务就是用Gadget功能驱动层的USB设备信息去进一步初始化struct usb_composite_dev结构。并且引出下面两个bind函数。 另外两个bind函数都是与USB设备信息相关,一个是添加配置时调用的,一个是添加接口的时候调用的。这两个函数由sourcesink_add引出。 usb_add_config将配置添加到设备中引出config->bind:sourcesink_bind_config.这个bind分配并初始化接口,调用usb_add_function将接口添加到配置到,usb_add_function引出function->bind:sourcesink_bind 根据功能,在gadget里查找合适的端点。并进一步初始化struct usb_composite_dev。我们发现这些bind就是一个目的,初始化struct usb_composite_dev结构,使其逐渐丰满。因为这个结构代表一个USB设备。经过合适的初始化后设备才能正确的工作。经过重重初始化,三层总算整合在了一起了。这三层最终形成了一个饱满的struct usb_composite_dev结构。这个结构包含USB设备运行各种信息。包括:配置,接口,端点等。我们再来看一下这个结构:- struct usb_composite_dev {
- struct usb_gadget *gadget;
- struct usb_request *req;
- unsigned bufsiz;
-
- struct usb_configuration *config;
-
-
-
- struct usb_device_descriptor desc;
- struct list_head configs;
- struct usb_composite_driver *driver;
- u8 next_string_id;
-
-
-
-
- unsigned deactivations;
-
-
- spinlock_t lock;
- };
经过初始化设备已经准备好了,将mini2440插入USB主机,就开始了设备枚举.这就涉及到了主机与设备的通信。以后再分析USB设备枚举与数据传输过程。Linux USB Gadget虽然有三层软件结构。但是只有UDC层与Gadget功能驱动层作为模块注册到内核。只有USB设备层有关的文件composite.c是以头文件的形式包含在各种Gadget功能驱动里的。以前的内核代码没有USB设备层的。所有的Gadget功能驱动都必须自己处理USB设备相关的细节,代码重复率较高,所以才出现这个USB设备层以以增加代码的重用性。composite字面上是复用的意思,不知道是不是为了原因而命名的。
阅读(1003) | 评论(0) | 转发(0) |