Chinaunix首页 | 论坛 | 博客
  • 博客访问: 5333
  • 博文数量: 2
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 12
  • 用 户 组: 普通用户
  • 注册时间: 2013-12-27 09:53
文章分类
文章存档

2015年(1)

2013年(1)

我的朋友
最近访客

分类: 嵌入式

2015-04-16 08:56:12

分析一个个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);//0enablefalse,写1enabletrue

       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;//设备enablefalse

       } else {

              pr_err("android_usb: already %s\n",

                            dev->enabled ? "enabled" : "disabled");

       }

       return size;

}

 

在往enable1之前,会先往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,使configcomposite_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);//通过轮询调用所有functionbind_config函数来让functionconfig绑定

              if (ret) {

                     pr_err("%s: %s failed", __func__, f->name);

                     return ret;

              }

       }

       return 0;

}

 

 

 

举其中一个functionbind_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,使functionconfig关联起来

       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;

}

到此结束

阅读(1115) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~