全部博文(19)
分类: 嵌入式
2014-11-13 15:30:07
原文地址:分析usb是怎么添加一个个function 作者:haijian0114
分析一个个function是怎么添加到config中的
首先先看一下在system/core/rootdir/etc/init.qcom.usb.rc文件的配置
on property:sys.usb.config=diag,serial_smd,serial_tty,mass_storage,adb
write /sys/class/android_usb/android0/enable 0
write /sys/class/android_usb/android0/idVendor 05C6
write /sys/class/android_usb/android0/idProduct 9027
write /sys/class/android_usb/android0/f_diag/clients diag
write /sys/class/android_usb/android0/f_serial/transports smd,tty
write /sys/class/android_usb/android0/functions mass_storage,diag,adb,serial
write /sys/class/android_usb/android0/enable 1
start adbd
setprop sys.usb.state $sys.usb.config
从配置中可以看出先往enable里写0,再对一些配置文件写对应的内容,最后往enable里写1
往enable里写0和写1时调用下面函数
static ssize_t enable_store(struct device *pdev, struct device_attribute *attr,
const char *buff, size_t size)
{
struct android_dev *dev = dev_get_drvdata(pdev);
struct usb_composite_dev *cdev = dev->cdev;
int enabled = 0;
sscanf(buff, "%d", &enabled);//写0时enable为false,写1时enable为true
if (enabled && !dev->enabled) {//写1时进入
/* update values in composite driver's copy of device descriptor */
cdev->desc.idVendor = device_desc.idVendor;
cdev->desc.idProduct = device_desc.idProduct;
cdev->desc.bcdDevice = device_desc.bcdDevice;
cdev->desc.bDeviceClass = device_desc.bDeviceClass;
cdev->desc.bDeviceSubClass = device_desc.bDeviceSubClass;
cdev->desc.bDeviceProtocol = device_desc.bDeviceProtocol;
if (usb_add_config(cdev, &android_config_driver,
android_bind_config))//向composite_dev添加这个配置
return size;
usb_gadget_connect(cdev->gadget);
dev->enabled = true;
} else if (!enabled && dev->enabled) {//写0时会进入
usb_gadget_disconnect(cdev->gadget);//通过软件和host断开连接
usb_remove_config(cdev, &android_config_driver);//移除已有的配置
dev->enabled = false;//设备enable为false
} else {
pr_err("android_usb: already %s\n",
dev->enabled ? "enabled" : "disabled");
}
return size;
}
在往enable写1之前,会先往functions里写入要使能的function的名字,从而调用functions_store()函数
static ssize_t functions_store(struct device *pdev, struct device_attribute *attr,
const char *buff, size_t size)
{
struct android_dev *dev = dev_get_drvdata(pdev);
char *name;
char buf[256], *b;
int err;
INIT_LIST_HEAD(&dev->enabled_functions);
strlcpy(buf, buff, sizeof(buf));
b = strim(buf);//删除buf中的空格?
while (b) {
name = strsep(&b, ",");
if (name) {
err = android_enable_function(dev, name);//根据我们写入的function的名字调用这个函数
if (err)
pr_err("android_usb: Cannot enable '%s'", name);
}
}
return size;
}
static int android_enable_function(struct android_dev *dev, char *name)
{
struct android_usb_function **functions = dev->functions;//系统一启动时在init函数中初始化的一堆function但没有使能
struct android_usb_function *f;
while ((f = *functions++)) {
if (!strcmp(name, f->name)) {//通过查找看写入的function是否在初始化的function中
list_add_tail(&f->enabled_list, &dev->enabled_functions);//是的话把该function加入enabled_function中,这里已经把我们写入的function挂接到enabled_functions链表中了
return 0;
}
}
return -EINVAL;
}
最后会往enable里写1,又会再次调用到enable_store()函数,这次就会调用到usb_add_config()函数
usb_add_config(cdev, &android_config_driver, android_bind_config)
int usb_add_config(struct usb_composite_dev *cdev,
struct usb_configuration *config,
int (*bind)(struct usb_configuration *))
{
int status = -EINVAL;
struct usb_configuration *c;
DBG(cdev, "adding config #%u '%s'/%p\n",
config->bConfigurationValue,
config->label, config);
if (!config->bConfigurationValue || !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;//把congfig->cdev指向composite_dev,使config和composite_dev关联起来
list_add_tail(&config->list, &cdev->configs);//把这个配置加入composite_dev下
INIT_LIST_HEAD(&config->functions);//初始化config
config->next_interface_id = 0;
memset(config->interface, '\0', sizeof(config->interface));
status = bind(config);//调用android_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);
}
}
/* set_alt(), or next bind(), sets up
* ep->driver_data as needed.
*/
usb_ep_autoconfig_reset(cdev->gadget);
done:
if (status)
DBG(cdev, "added config '%s'/%u --> %d\n", config->label,
config->bConfigurationValue, status);
return status;
}
static int android_bind_config(struct usb_configuration *c)
{
struct android_dev *dev = _android_dev;
int ret = 0;
ret = android_bind_enabled_functions(dev, c);//调用这个函数
if (ret)
return ret;
return 0;
}
static int
android_bind_enabled_functions(struct android_dev *dev,
struct usb_configuration *c)
{
struct android_usb_function *f;
int ret;
list_for_each_entry(f, &dev->enabled_functions, enabled_list) {
ret = f->bind_config(f, c);//通过轮询调用所有function的bind_config函数来让function和config绑定
if (ret) {
pr_err("%s: %s failed", __func__, f->name);
return ret;
}
}
return 0;
}
举其中一个function的bind_config为例子
static struct android_usb_function mass_storage_function = {
.name = "mass_storage",
.init = mass_storage_function_init,
.cleanup = mass_storage_function_cleanup,
.bind_config = mass_storage_function_bind_config,
.attributes = mass_storage_function_attributes,
};
所以调用的是mass_storage_function_bind_config函数
static int mass_storage_function_bind_config(struct android_usb_function *f,
struct usb_configuration *c)
{
struct mass_storage_function_config *config = f->config;
return fsg_bind_config(c->cdev, c, config->common);//这里调用到f_mass_storage.c中的函数
}
static int fsg_bind_config(struct usb_composite_dev *cdev,
struct usb_configuration *c,
struct fsg_common *common)
{
struct fsg_dev *fsg;
int rc;
fsg = kzalloc(sizeof *fsg, GFP_KERNEL);
if (unlikely(!fsg))
return -ENOMEM;
fsg->function.name = "mass_storage";//对usb_function进行一堆初始化
fsg->function.strings = fsg_strings_array;
fsg->function.bind = fsg_bind;
fsg->function.unbind = fsg_unbind;
fsg->function.setup = fsg_setup;
fsg->function.set_alt = fsg_set_alt;
fsg->function.disable = fsg_disable;
fsg->common = common;
/*
* Our caller holds a reference to common structure so we
* don't have to be worry about it being freed until we return
* from this function. So instead of incrementing counter now
* and decrement in error recovery we increment it only when
* call to usb_add_function() was successful.
*/
rc = usb_add_function(c, &fsg->function);//把该usb_function添加到composite_dev下的config中
if (unlikely(rc))
kfree(fsg);
else
fsg_common_get(fsg->common);
return rc;
}
int 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;//把function下的config指向这个config,使function和config关联起来
list_add_tail(&function->list, &config->functions);//把usb_function添加到config下,就是这里了一个个功能和config关联起来了
/* REVISIT *require* function->bind? */
if (function->bind) {
value = function->bind(config, function);//调用function下的绑定函数,使两者绑定,这里是fsg_bind
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;
}
static int fsg_bind(struct usb_configuration *c, struct usb_function *f)
{
struct fsg_dev *fsg = fsg_from_func(f);
struct usb_gadget *gadget = c->cdev->gadget;
int i;
struct usb_ep *ep;
fsg->gadget = gadget;
/* New interface */
i = usb_interface_id(c, f);//为该function分配interface_id
if (i < 0)
return i;
fsg_intf_desc.bInterfaceNumber = i;
fsg->interface_number = i;
/* Find all the endpoints we will use */
ep = usb_ep_autoconfig(gadget, &fsg_fs_bulk_in_desc);
if (!ep)
goto autoconf_fail;
ep->driver_data = fsg->common; /* claim the endpoint */
fsg->bulk_in = ep;
ep = usb_ep_autoconfig(gadget, &fsg_fs_bulk_out_desc);
if (!ep)
goto autoconf_fail;
ep->driver_data = fsg->common; /* claim the endpoint */
fsg->bulk_out = ep;
/* Copy descriptors */
f->descriptors = usb_copy_descriptors(fsg_fs_function);
if (unlikely(!f->descriptors))
return -ENOMEM;
if (gadget_is_dualspeed(gadget)) {
/* Assume endpoint addresses are the same for both speeds */
fsg_hs_bulk_in_desc.bEndpointAddress =
fsg_fs_bulk_in_desc.bEndpointAddress;
fsg_hs_bulk_out_desc.bEndpointAddress =
fsg_fs_bulk_out_desc.bEndpointAddress;
f->hs_descriptors = usb_copy_descriptors(fsg_hs_function);
if (unlikely(!f->hs_descriptors)) {
usb_free_descriptors(f->descriptors);
return -ENOMEM;
}
}
return 0;
autoconf_fail:
ERROR(fsg, "unable to autoconfigure all endpoints\n");
return -ENOTSUPP;
}
到此结束