staticint __init init(void)
{
return usb_composite_register(&zero_driver);
}
static int __init init(void) { return usb_composite_register(&zero_driver); }很简单,只是调用了usb_composite_register,传递给他的参数是zero_driver。这个结构体如下定义:
staticstruct 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,
};
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);
}
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变量,如下:
staticstruct 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,
},
};
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; //the_controller指向已经初始化好了的s3c2410_udc结构,这个结构代表了s3c2410 usb设备控制器,当然他包括struct gadget结构
int retval;
dprintk(DEBUG_NORMAL, "usb_gadget_register_driver() '%s'\n",
driver->driver.name);
/* Sanity checks */
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
/*---------------------------------------以上都是指针检查-------------------------------------------------------*/
/* Hook the driver */
udc->driver = driver;//传递过来的driver就是USB设备层定义的composite_driver,这样就联系了UDC层与USB设备层
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;
}
/* Enable udc */
s3c2410_udc_enable(udc);
return 0;
register_error:
udc->driver = NULL;
udc->gadget.dev.driver = NULL;
return retval;
}
int usb_gadget_register_driver(struct usb_gadget_driver *driver) { struct s3c2410_udc *udc = the_controller; //the_controller指向已经初始化好了的s3c2410_udc结构,这个结构代表了s3c2410 usb设备控制器,当然他包括struct gadget结构 int retval; dprintk(DEBUG_NORMAL, "usb_gadget_register_driver() '%s'\n", driver->driver.name); /* Sanity checks */ 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 /*---------------------------------------以上都是指针检查-------------------------------------------------------*/ /* Hook the driver */ udc->driver = driver;//传递过来的driver就是USB设备层定义的composite_driver,这样就联系了UDC层与USB设备层 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; } /* Enable udc */ 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中定义的,如下:
staticint __init composite_bind(struct usb_gadget *gadget)
{
struct usb_composite_dev *cdev;
int status = -ENOMEM;
cdev = kzalloc(sizeof *cdev, GFP_KERNEL); //分配内存,struct usb_composite_dev结构代表了一个USB设备
if (!cdev)
return status;
spin_lock_init(&cdev->lock);
cdev->gadget = gadget; //这个gadget也就是s3c2410_udc.c中定义的
set_gadget_data(gadget, cdev); //这个函数的功能就是是得gadget->dev->driver_data指向cdev结构。gadget->dev是struct device结构已经注册到了Linux设备驱动模型核心
INIT_LIST_HEAD(&cdev->configs); //cdev->configs是struct list_head结构指针,这个链表将链接设备的所有配置
/* preallocate control response and buffer */
cdev->req = usb_ep_alloc_request(gadget->ep0, GFP_KERNEL);
// 以上函数是非常重要的,关系着USB设备枚举。现在先不分析,当分析到USB设备枚举的时候再回头分析这个函数
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; //既然struct usb_composite_dev代表一个USB设备,他的驱动当然是Gadget功能驱动,这里是composite,在前面usb_composite_register的时候赋值zero_driver
usb_gadget_set_selfpowered(gadget); //设置USB设备为自供电设备,因为是设备mini2440开发板已经提供电源,当然是自供电了
/* interface and string IDs start at zero via kzalloc.
* we force endpoints to start unassigned; few controller
* drivers will zero ep->driver_data.
*/
usb_ep_autoconfig_reset(cdev->gadget);//这个函数主要的功能是遍历gadget端点链表,将端点的driver_data清空
/* composite gadget needs to assign strings for whole device (like
* serial number), register function drivers, potentially update
* power state and consumption, etc
*/
status = composite->bind(cdev); //这个函数调用就涉及到Gadget功能驱动层了,这里也就是zero.c,composite->bind定义与zero.c中。经过这个调用三层才真正的联系在了一起。
if (status < 0)
goto fail;
//以下代码都是设备描述符相关的,cdev->desc是truct usb_device_descriptor结构代表了一个USB设备描述符。这里用Gadget功能驱动层传递过来的参数初始化这个结构
cdev->desc = *composite->dev;
cdev->desc.bMaxPacketSize0 = gadget->ep0->maxpacket;
/* standardized runtime overrides for device ID data */
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);
/* strings can't be assigned before bind() allocates the
* releavnt identifiers
*/
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;
}
static int __init composite_bind(struct usb_gadget *gadget) { struct usb_composite_dev *cdev; int status = -ENOMEM; cdev = kzalloc(sizeof *cdev, GFP_KERNEL); //分配内存,struct usb_composite_dev结构代表了一个USB设备 if (!cdev) return status; spin_lock_init(&cdev->lock); cdev->gadget = gadget; //这个gadget也就是s3c2410_udc.c中定义的 set_gadget_data(gadget, cdev); //这个函数的功能就是是得gadget->dev->driver_data指向cdev结构。gadget->dev是struct device结构已经注册到了Linux设备驱动模型核心 INIT_LIST_HEAD(&cdev->configs); //cdev->configs是struct list_head结构指针,这个链表将链接设备的所有配置 /* preallocate control response and buffer */ cdev->req = usb_ep_alloc_request(gadget->ep0, GFP_KERNEL); // 以上函数是非常重要的,关系着USB设备枚举。现在先不分析,当分析到USB设备枚举的时候再回头分析这个函数 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; //既然struct usb_composite_dev代表一个USB设备,他的驱动当然是Gadget功能驱动,这里是composite,在前面usb_composite_register的时候赋值zero_driver usb_gadget_set_selfpowered(gadget); //设置USB设备为自供电设备,因为是设备mini2440开发板已经提供电源,当然是自供电了 /* interface and string IDs start at zero via kzalloc. * we force endpoints to start unassigned; few controller * drivers will zero ep->driver_data. */ usb_ep_autoconfig_reset(cdev->gadget);//这个函数主要的功能是遍历gadget端点链表,将端点的driver_data清空 /* composite gadget needs to assign strings for whole device (like * serial number), register function drivers, potentially update * power state and consumption, etc */ status = composite->bind(cdev); //这个函数调用就涉及到Gadget功能驱动层了,这里也就是zero.c,composite->bind定义与zero.c中。经过这个调用三层才真正的联系在了一起。 if (status < 0) goto fail; //以下代码都是设备描述符相关的,cdev->desc是truct usb_device_descriptor结构代表了一个USB设备描述符。这里用Gadget功能驱动层传递过来的参数初始化这个结构 cdev->desc = *composite->dev; cdev->desc.bMaxPacketSize0 = gadget->ep0->maxpacket; /* standardized runtime overrides for device ID data */ 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); /* strings can't be assigned before bind() allocates the * releavnt identifiers */ 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中,如下:
staticint __init zero_bind(struct usb_composite_dev *cdev)
{
int gcnum;
struct usb_gadget *gadget = cdev->gadget;
int id;
/* Allocate string descriptor numbers ... note that string
* contents can be overridden by the composite_dev glue.
*/
id = usb_string_id(cdev);
//这个函数的功能是如果cdev->next_string_id不大于254,将cdev->next_string_id加1,返回加1后的cdev->next_string_id。这里cdev->next_string_id为0。所以执行完这个函数id = 1;
if (id < 0)
return id;
strings_dev[STRING_MANUFACTURER_IDX].id = id;
device_desc.iManufacturer = id;
//strings_dev是zero定义的字符串描述符数组,以上语句作用是是得生产厂商的字符串描述符的id为1
id = usb_string_id(cdev);
if (id < 0)
return id;
strings_dev[STRING_PRODUCT_IDX].id = id;
device_desc.iProduct = id;
//以上语句作用是是得产品的字符串描述符的id为2
id = usb_string_id(cdev);
if (id < 0)
return id;
strings_dev[STRING_SERIAL_IDX].id = id;
device_desc.iSerialNumber = id;
//以上语句作用是是得生产串号的字符串描述符的id为3
setup_timer(&autoresume_timer, zero_autoresume, (unsigned long) cdev);
//电源管理相关代码,暂时不用看
/* Register primary, then secondary configuration. Note that
* SH3 only allows one config...
*/
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);
}
//以上代码尤其重要,是设置zero设备配置描述符的。这里不得不说一下zero驱动的功能,他有两种配置。一个是将主机发送给他的内容返回给主机,另外一个就是可以单独发送与接受数据。loopdefault是模块参数,默认值为0
//所以我们先看else后面的代码,这段代码设置的就是单独发送接受功能。gadget_is_sh是判断usb设备控制器是否支持复合设备,s3c2410不支持。所以现在只需要分析sourcesink_add(cdev, autoresume != 0)
//这个函数就可以了,见下面sourcesink_add(cdev, autoresume != 0)函数分析。
gcnum = usb_gadget_controller_number(gadget);
if (gcnum >= 0)
device_desc.bcdDevice = cpu_to_le16(0x0200 + gcnum);
else {
/* gadget zero is so simple (for now, no altsettings) that
* it SHOULD NOT have problems with bulk-capable hardware.
* so just warn about unrcognized controllers -- don't panic.
*
* things like configuration and altsetting numbering
* can need hardware-specific attention though.
*/
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;
}
static int __init zero_bind(struct usb_composite_dev *cdev) { int gcnum; struct usb_gadget *gadget = cdev->gadget; int id; /* Allocate string descriptor numbers ... note that string * contents can be overridden by the composite_dev glue. */ id = usb_string_id(cdev); //这个函数的功能是如果cdev->next_string_id不大于254,将cdev->next_string_id加1,返回加1后的cdev->next_string_id。这里cdev->next_string_id为0。所以执行完这个函数id = 1; if (id < 0) return id; strings_dev[STRING_MANUFACTURER_IDX].id = id; device_desc.iManufacturer = id; //strings_dev是zero定义的字符串描述符数组,以上语句作用是是得生产厂商的字符串描述符的id为1 id = usb_string_id(cdev); if (id < 0) return id; strings_dev[STRING_PRODUCT_IDX].id = id; device_desc.iProduct = id; //以上语句作用是是得产品的字符串描述符的id为2 id = usb_string_id(cdev); if (id < 0) return id; strings_dev[STRING_SERIAL_IDX].id = id; device_desc.iSerialNumber = id; //以上语句作用是是得生产串号的字符串描述符的id为3 setup_timer(&autoresume_timer, zero_autoresume, (unsigned long) cdev); //电源管理相关代码,暂时不用看 /* Register primary, then secondary configuration. Note that * SH3 only allows one config... */ 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); } //以上代码尤其重要,是设置zero设备配置描述符的。这里不得不说一下zero驱动的功能,他有两种配置。一个是将主机发送给他的内容返回给主机,另外一个就是可以单独发送与接受数据。loopdefault是模块参数,默认值为0 //所以我们先看else后面的代码,这段代码设置的就是单独发送接受功能。gadget_is_sh是判断usb设备控制器是否支持复合设备,s3c2410不支持。所以现在只需要分析sourcesink_add(cdev, autoresume != 0) //这个函数就可以了,见下面sourcesink_add(cdev, autoresume != 0)函数分析。 gcnum = usb_gadget_controller_number(gadget); if (gcnum >= 0) device_desc.bcdDevice = cpu_to_le16(0x0200 + gcnum); else { /* gadget zero is so simple (for now, no altsettings) that * it SHOULD NOT have problems with bulk-capable hardware. * so just warn about unrcognized controllers -- don't panic. * * things like configuration and altsetting numbering * can need hardware-specific attention though. */ 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;
/* allocate string ID(s) */
id = usb_string_id(cdev);
if (id < 0)
return id;
strings_sourcesink[0].id = id;
//以上初始化一下字符串描述符的id
source_sink_intf.iInterface = id;
sourcesink_driver.iConfiguration = id;
//source_sink_intf是struct usb_interface_descriptor类型的变量,代表一个接口
//sourcesink_driver是struct usb_configuration类型的变量,代表一个USB配置,注意不是配置描述符。这两个变量在f_sourcesink.c中定义
/* support autoresume for remote wakeup testing */
if (autoresume)
sourcesink_driver.bmAttributes |= USB_CONFIG_ATT_WAKEUP;
/* support OTG systems */
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配置,里面说明了配置的功能。如下:
staticstruct usb_configuration sourcesink_driver = {
.label = "source/sink",
.strings = sourcesink_strings,
.bind = sourcesink_bind_config,
.setup = sourcesink_setup,
.bConfigurationValue = 3,
.bmAttributes = USB_CONFIG_ATT_SELFPOWER,
/* .iConfiguration = DYNAMIC */
};
int __init sourcesink_add(struct usb_composite_dev *cdev, bool autoresume) { int id; /* allocate string ID(s) */ id = usb_string_id(cdev); if (id < 0) return id; strings_sourcesink[0].id = id; //以上初始化一下字符串描述符的id source_sink_intf.iInterface = id; sourcesink_driver.iConfiguration = id; //source_sink_intf是struct usb_interface_descriptor类型的变量,代表一个接口 //sourcesink_driver是struct usb_configuration类型的变量,代表一个USB配置,注意不是配置描述符。这两个变量在f_sourcesink.c中定义 /* support autoresume for remote wakeup testing */ if (autoresume) sourcesink_driver.bmAttributes |= USB_CONFIG_ATT_WAKEUP; /* support OTG systems */ 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, /* .iConfiguration = DYNAMIC */ };看完了这个数据结构,我们分析一下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;
/* Prevent duplicate configuration identifiers */
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);
//一个USB设备可以有多种配置,这句是将配置加入到设备的配置链表中
INIT_LIST_HEAD(&config->functions);
//初始化配置的functions链表,functions链表要链接struct usb_function类型的数据结构,这个数据结构也很重要,其实他代表一个USB接口
config->next_interface_id = 0;
status = config->bind(config);
//这里函数调用的是sourcesink_bind_config,这个函数的功能就是初始化一个struct usb_function结构,并且将其加入到配置的functions链表,见下面分析
if (status < 0) { //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")
: "");
//MAX_CONFIG_INTERFACES 最大接口数,定义在composite.h中,为16。每个配置可以有16个接口,一下代码遍历这个配置的所有接口,打印调试信息
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);
}
}
/* set_alt(), or next config->bind(), sets up
* ep->driver_data as needed.
*/
usb_ep_autoconfig_reset(cdev->gadget);
//这个函数的主要作用就是将cdev->gadget的所有端点的driver_data清空
done:
if (status)
DBG(cdev, "added config '%s'/%u --> %d\n", config->label,
config->bConfigurationValue, status);
return status;
}
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; /* Prevent duplicate configuration identifiers */ 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); //一个USB设备可以有多种配置,这句是将配置加入到设备的配置链表中 INIT_LIST_HEAD(&config->functions); //初始化配置的functions链表,functions链表要链接struct usb_function类型的数据结构,这个数据结构也很重要,其实他代表一个USB接口 config->next_interface_id = 0; status = config->bind(config); //这里函数调用的是sourcesink_bind_config,这个函数的功能就是初始化一个struct usb_function结构,并且将其加入到配置的functions链表,见下面分析 if (status < 0) { //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") : ""); //MAX_CONFIG_INTERFACES 最大接口数,定义在composite.h中,为16。每个配置可以有16个接口,一下代码遍历这个配置的所有接口,打印调试信息 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); } } /* set_alt(), or next config->bind(), sets up * ep->driver_data as needed. */ usb_ep_autoconfig_reset(cdev->gadget); //这个函数的主要作用就是将cdev->gadget的所有端点的driver_data清空 done: if (status) DBG(cdev, "added config '%s'/%u --> %d\n", config->label, config->bConfigurationValue, status); return status; }这个函数初始化了配置,将配置与设备联系在一起,并且打印一些调试信息。这样设备有了配置,但是我们知道一个USB设备的配置下是接口的集合。所以函数调用config->bind(config)给配置添加接口。这个函数如下:
staticint __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;
}
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);
/* REVISIT *require* function->bind? */
if (function->bind) { //如果function定义了bind函数则调用他,这里function定义了bind函数,sourcesink_bind。这个函数进行一些初始化的工作
value = function->bind(config, function);
if (value < 0) {
list_del(&function->list);
function->config = NULL;
}
} else
value = 0;
/* We allow configurations that don't work at both speeds.
* If we run into a lowspeed Linux system, treat it the same
* as full speed ... it's the function drivers that will need
* to avoid bulk and ISO transfers.
*/
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;
}
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); /* REVISIT *require* function->bind? */ if (function->bind) { //如果function定义了bind函数则调用他,这里function定义了bind函数,sourcesink_bind。这个函数进行一些初始化的工作 value = function->bind(config, function); if (value < 0) { list_del(&function->list); function->config = NULL; } } else value = 0; /* We allow configurations that don't work at both speeds. * If we run into a lowspeed Linux system, treat it the same * as full speed ... it's the function drivers that will need * to avoid bulk and ISO transfers. */ 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。如下定义:
staticint __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;
/* allocate interface ID(s) */
id = usb_interface_id(c, f);
if (id < 0)
return id;
source_sink_intf.bInterfaceNumber = id;
//usb_interface_id(c, f)实现的功能是判断config->next_interface_id是否大于16如果不是,那么执行config->interface[id] = f,在将config->next_interface_id加1返回
/* allocate endpoints */
//下面是分配端点,我们知道根据USB协议。USB设备下来是USB配置,然后是USB接口,接口是USB端点的组合,根据zero sourcesink实现的功能,接口需要连个批量端点,一个In端点一个out端点
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; /* claim */
ss->out_ep = usb_ep_autoconfig(cdev->gadget, &fs_sink_desc);
if (!ss->out_ep)
goto autoconf_fail;
ss->out_ep->driver_data = cdev; /* claim */
/* support high speed hardware */
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;
}
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; /* allocate interface ID(s) */ id = usb_interface_id(c, f); if (id < 0) return id; source_sink_intf.bInterfaceNumber = id; //usb_interface_id(c, f)实现的功能是判断config->next_interface_id是否大于16如果不是,那么执行config->interface[id] = f,在将config->next_interface_id加1返回 /* allocate endpoints */ //下面是分配端点,我们知道根据USB协议。USB设备下来是USB配置,然后是USB接口,接口是USB端点的组合,根据zero sourcesink实现的功能,接口需要连个批量端点,一个In端点一个out端点 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; /* claim */ ss->out_ep = usb_ep_autoconfig(cdev->gadget, &fs_sink_desc); if (!ss->out_ep) goto autoconf_fail; ss->out_ep->driver_data = cdev; /* claim */ /* support high speed hardware */ 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里找到合适的端点。
struct usb_composite_dev {
struct usb_gadget *gadget; //联系底层的UDC中的usb_gadget
struct usb_request *req; //端点0的传输结构,在设备枚举的时候使用
unsigned bufsiz;
struct usb_configuration *config; //USB配置
/* private: */
/* internals */
struct usb_device_descriptor desc; //设备描述符
struct list_head configs; //USB配置链表
struct usb_composite_driver *driver; //联系上层的Gadget功能驱动层
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_dev { struct usb_gadget *gadget; //联系底层的UDC中的usb_gadget struct usb_request *req; //端点0的传输结构,在设备枚举的时候使用 unsigned bufsiz; struct usb_configuration *config; //USB配置 /* private: */ /* internals */ struct usb_device_descriptor desc; //设备描述符 struct list_head configs; //USB配置链表 struct usb_composite_driver *driver; //联系上层的Gadget功能驱动层 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; };经过初始化设备已经准备好了,将mini2440插入USB主机,就开始了设备枚举.这就涉及到了主机与设备的通信。以后再分析USB设备枚举与数据传输过程。Linux USB Gadget虽然有三层软件结构。但是只有UDC层与Gadget功能驱动层作为模块注册到内核。只有USB设备层有关的文件composite.c是以头文件的形式包含在各种Gadget功能驱动里的。以前的内核代码没有USB设备层的。所有的Gadget功能驱动都必须自己处理USB设备相关的细节,代码重复率较高,所以才出现这个USB设备层以以增加代码的重用性。composite字面上是复用的意思,不知道是不是为了原因而命名的。