mtk-usb代码分析之usb gadget

基于mt6750T,Android 7.0,kernel 3.18.35,本文主要从USB设备的角度进行分析。(代码部分有省略)

我们的android手机通过usb连入电脑,可以选择多种模式,例如传输照片(PTP),传输文件(MTP)等,那为什么我们能选择多种模式?模式之间的切换又有哪些过程?我们通过代码分析下。

一.目录结构

代码在usb/gadget/目录下,首先看下目录下都有谁,张三李四还是。。。

android.c----usb gadget的总指挥
composite.c----复合设备的函数集合
config.c----usb设备描述符相关
epautoconf.c----端点相关
/function----里面包含各种usb设备支持的function类型,包括adb,mtp,ptp等等
/udc----usb device controller,主要是udc-core.c,包含udc一系列的操作函数

 

二.代码分析之android.c

/*
* init
*/
late_initcall(init);
static int __init init(void) { struct android_dev *dev; int err; //创建android_usb类 android_class = class_create(THIS_MODULE, "android_usb"); dev = kzalloc(sizeof(*dev), GFP_KERNEL); dev->disable_depth = 1; //usb设备支持的fucntion集合 dev->functions = supported_functions; //初始化链表表头,用于链接使能的function集合 INIT_LIST_HEAD(&dev->enabled_functions); //初始化work,android_work,这个下面介绍 INIT_WORK(&dev->work, android_work); mutex_init(&dev->mutex); //创建android设备 err = android_create_device(dev); _android_dev = dev; //注册复合设备驱动 err = usb_composite_probe(&android_usb_driver); //将gadget_driver.setup函数替换为android_setup /* HACK: exchange composite's setup with ours */ composite_setup_func = android_usb_driver.gadget_driver.setup; android_usb_driver.gadget_driver.setup = android_setup; return 0; }
  • 2.1设备支持的function集合(好多功能),ffs即adb,acm可以实现usb模拟串口。

  

//以acm为例,usb设备支持多种function,每个fucntion对应配置中的一个接口,用户选择对应的一个或者多个function时,其实就是将接口添加到配置中。bing_config实现将接口描述符添加到配置描述符中。
static struct android_usb_function acm_function = {
    .name        = "acm",
    .init        = acm_function_init,
    .cleanup    = acm_function_cleanup,
    .bind_config    = acm_function_bind_config,
    .unbind_config    = acm_function_unbind_config,
    .attributes    = acm_function_attributes,
};

 

  • 2.2 android_create_device
/*
* android_create_device
*/
static
int android_create_device(struct android_dev *dev) { //定义设备目录下支持的文件属性 struct device_attribute **attrs = android_usb_attributes; struct device_attribute *attr; int err; //android_usb类下创建android0设备 dev->dev = device_create(android_class, NULL, MKDEV(0, 0), NULL, "android0"); dev_set_drvdata(dev->dev, dev); //在android0设备下创建文件属性 while ((attr = *attrs++)) { err = device_create_file(dev->dev, attr); } } return 0; }
这里着重看下function和enable属性,具体使用下面分析
function可以选择设备使能的function
enable实现接口的enable/disable

  

  • 2.3 复合设备驱动的注册
//device_desc,设备描述符
//dev_strings,设备的制造厂商、产品型号、序列号
//android_bind,设备支持的function的初始化
//max_speed,usb2.0支持high speed,usb3.0支持super speed
static struct usb_composite_driver android_usb_driver = {
    .name        = "android_usb",
    .dev        = &device_desc,
    .strings    = dev_strings,
    .bind        = android_bind,
    .unbind        = android_usb_unbind,
    .disconnect    = android_disconnect,
#if defined(CONFIG_USB_MU3D_DRV) && !defined(CONFIG_USB_MU3D_ONLY_U2_MODE)
    .max_speed    = USB_SPEED_SUPER
#else
    .max_speed    = USB_SPEED_HIGH
#endif
};
bLength,描述符的长度,这里为12byte
bDescriptorType,描述符的类型,USB_DT_DEVICE表明为设备描述符
bcdUSB,0x0200为usb2.0,0x0300为usb3.0
bDeviceClass,设备的类型,USB_CLASS_PER_INTERFACE表明使用接口描述符中的类型
idVendor,供应商id即VID
idProduct,产品id即PID
bcdDevice,设备bcd码
bNumConfigurations,设备支持的配置数量,这里为1

  

/*
* usb_composite_probe
*/
//
注册复合设备驱动 int usb_composite_probe(struct usb_composite_driver *driver) { struct usb_gadget_driver *gadget_driver; if (!driver->name) driver->name = "composite"; //gadget_driver初始化 driver->gadget_driver = composite_driver_template; gadget_driver = &driver->gadget_driver; gadget_driver->function = (char *) driver->name; gadget_driver->driver.name = driver->name; gadget_driver->max_speed = driver->max_speed; //注册gadget driver return usb_gadget_probe_driver(gadget_driver); }

  

 

  • 2.4 注册gadget driver
/*
* usb_gadget_probe_driver
*/
//
注册gadget driver int usb_gadget_probe_driver(struct usb_gadget_driver *driver) { struct usb_udc *udc = NULL; int ret; mutex_lock(&udc_lock); //遍历udc_list查找udc设备,如果udc->driver未定义则跳转到found list_for_each_entry(udc, &udc_list, list) { /* For now we take the first one */ if (!udc->driver) goto found; } mutex_unlock(&udc_lock); return -ENODEV; found: //将gadget driver与udc设备bind,啧啧,系统包办婚姻,你没有对象就直接给你分配,看看人家这福利 ret = udc_bind_to_driver(udc, driver); mutex_unlock(&udc_lock); return ret; }
/*
* udc_bind_to_driver
*/
static
int udc_bind_to_driver(struct usb_udc *udc, struct usb_gadget_driver *driver) { int ret; udc->driver = driver; udc->dev.driver = &driver->driver; udc->gadget->dev.driver = &driver->driver; //调用gadget driver的bind函数 ret = driver->bind(udc->gadget, driver); //调用gadget->ops->udc_start函数,这个跟具体的udc设备相关 ret = usb_gadget_udc_start(udc->gadget, driver); //上报KOBJ_CHANGE事件 kobject_uevent(&udc->dev.kobj, KOBJ_CHANGE); return 0; }

 

  • 2.5 usb_gadget_driver->bind(composite_bind)分析
/*
* composite_bind
*/
static
int composite_bind(struct usb_gadget *gadget, struct usb_gadget_driver *gdriver) { struct usb_composite_dev *cdev; struct usb_composite_driver *composite = to_cdriver(gdriver); int status = -ENOMEM; cdev = kzalloc(sizeof *cdev, GFP_KERNEL); spin_lock_init(&cdev->lock); cdev->gadget = gadget; set_gadget_data(gadget, cdev); INIT_LIST_HEAD(&cdev->configs); INIT_LIST_HEAD(&cdev->gstrings); //复合设备的准备工作,主要是ep0的初始化 status = composite_dev_prepare(composite, cdev); //调用composite->bind函数即android_usb_driver的bind函数,即android_bind status = composite->bind(cdev); if (cdev->use_os_string) { status = composite_os_desc_req_prepare(cdev, gadget->ep0); } update_unchanged_dev_desc(&cdev->desc, composite->dev); return 0; }
/*
* android_bind
*/
static
int android_bind(struct usb_composite_dev *cdev) { struct android_dev *dev = _android_dev; struct usb_gadget *gadget = cdev->gadget; int id, ret; /* Save the default handler */ dev->setup_complete = cdev->req->complete; //usb gadget断开连接,调用gadget->ops->pullup,usb设备通过D+/D-的上拉电阻判定设备类型,如果取消上拉相当于断开连接 usb_gadget_disconnect(gadget); //初始化设备支持的functions ret = android_init_functions(dev->functions, cdev); //下面设置设备的制造厂商,产品型号,序列号,这些可以通过用户空间重新定义 id = usb_string_id(cdev); strings_dev[STRING_MANUFACTURER_IDX].id = id; device_desc.iManufacturer = id; id = usb_string_id(cdev); strings_dev[STRING_PRODUCT_IDX].id = id; device_desc.iProduct = id; /* Default strings - should be updated by userspace */ strncpy(manufacturer_string, "Android", sizeof(manufacturer_string)-1); strncpy(product_string, "Android", sizeof(product_string) - 1); strncpy(serial_string, "0123456789ABCDEF", sizeof(serial_string) - 1); id = usb_string_id(cdev); strings_dev[STRING_SERIAL_IDX].id = id; device_desc.iSerialNumber = id; #ifdef CONFIG_USBIF_COMPLIANCE usb_gadget_clear_selfpowered(gadget); #else usb_gadget_set_selfpowered(gadget); #endif dev->cdev = cdev; return 0; }
/*
* android_init_functions
*/
static
int android_init_functions(struct android_usb_function **functions, struct usb_composite_dev *cdev) { struct android_dev *dev = _android_dev; struct android_usb_function *f; struct device_attribute **attrs; struct device_attribute *attr; int err; #ifdef CONFIG_USBIF_COMPLIANCE int index = 1; #else int index = 0; #endif //遍历支持的function列表 for (; (f = *functions++); index++) { f->dev_name = kasprintf(GFP_KERNEL, "f_%s", f->name); //在android_usb类下创建设备节点 f->dev = device_create(android_class, dev->dev, MKDEV(0, index), f, f->dev_name); //执行f->init函数 if (f->init) { err = f->init(f, cdev); } //创建节点属性 attrs = f->attributes; if (attrs) { while ((attr = *attrs++) && !err) err = device_create_file(f->dev, attr); } } return 0; }
//以acm为例
static struct android_usb_function acm_function = {
    .name        = "acm",
    .init        = acm_function_init,
    .cleanup    = acm_function_cleanup,
    .bind_config    = acm_function_bind_config,
    .unbind_config    = acm_function_unbind_config,
    .attributes    = acm_function_attributes,
};
static int acm_function_init(struct android_usb_function *f, struct usb_composite_dev *cdev)
{
    int i;
    int ret;
    struct acm_function_config *config;

    config = kzalloc(sizeof(struct acm_function_config), GFP_KERNEL);
    f->config = config;
//获取acm的instance和function
    for (i = 0; i < MAX_ACM_INSTANCES; i++) {
        config->f_acm_inst[i] = usb_get_function_instance("acm");      
        config->f_acm[i] = usb_get_function(config->f_acm_inst[i]); 
    }
    return 0;
}
/*
* usb_get_function_instance
*/
struct
usb_function_instance *usb_get_function_instance(const char *name) { return try_get_usb_function_instance(name); } static struct usb_function_instance *try_get_usb_function_instance(const char *name) { struct usb_function_driver *fd; struct usb_function_instance *fi; fi = ERR_PTR(-ENOENT); mutex_lock(&func_lock); //遍历func_list,用name进行匹配,找到对应function list_for_each_entry(fd, &func_list, list) { if (strcmp(name, fd->name)) continue; fi = fd->alloc_inst(); if (IS_ERR(fi)) module_put(fd->mod); else fi->fd = fd; break; } mutex_unlock(&func_lock); return fi; }

 


/*
* usb_get_function_instance
*/
struct usb_function *usb_get_function(struct usb_function_instance *fi)
{
    struct usb_function *f;
//调用alloc_func函数,这个函数从何而来,看2.6节的acm function分析
    f = fi->fd->alloc_func(fi);
    if ((f == NULL) || IS_ERR(f))
        return f;
    f->fi = fi;
    return f;
}

 

  • 2.6 那么acm的instance从何而来呢,我们看下function/目录下的f_acm.c文件,首先映入眼帘的是这个家伙
DECLARE_USB_FUNCTION_INIT(acm, acm_alloc_instance, acm_alloc_func);
//composite.h文件中有定义
#define DECLARE_USB_FUNCTION(_name, _inst_alloc, _func_alloc)        \
    static struct usb_function_driver _name ## usb_func = {        \
        .name = __stringify(_name),                \
        .mod  = THIS_MODULE,                    \
        .alloc_inst = _inst_alloc,                \
        .alloc_func = _func_alloc,                \
    };                                \
    MODULE_ALIAS("usbfunc:"__stringify(_name));

#define DECLARE_USB_FUNCTION_INIT(_name, _inst_alloc, _func_alloc)    \
    DECLARE_USB_FUNCTION(_name, _inst_alloc, _func_alloc)        \
    static int __init _name ## mod_init(void)            \
    { 
//usb_function_register就是把acm添加到func_list链表中 \
return usb_function_register(&_name ## usb_func); \ } \ static void __exit _name ## mod_exit(void) \ { \ usb_function_unregister(&_name ## usb_func); \ } \ module_init(_name ## mod_init); \ module_exit(_name ## mod_exit)
//将acm替换其中
DECLARE_USB_FUNCTION_INIT(acm, acm_alloc_instance, acm_alloc_func);

#define DECLARE_USB_FUNCTION(acm, acm_alloc_instance, acm_alloc_func)        \
    static struct usb_function_driver acmusb_func = {        \
        .name = __stringify(acm),                \
        .mod  = THIS_MODULE,                    \
        .alloc_inst = acm_alloc_instance,                \
//这个就是2.5节中acm的alloc_func定义,调用acm_alloc_func .alloc_func
= acm_alloc_func, \ }; \ MODULE_ALIAS("usbfunc:"__stringify(acm)); #define DECLARE_USB_FUNCTION_INIT(acm, acm_alloc_instance, acm_alloc_func) \ DECLARE_USB_FUNCTION(acm, acm_alloc_instance, acm_alloc_func) \ static int __init acmmod_init(void) \ { \ return usb_function_register(&acmusb_func); \ } \ static void __exit acmmod_exit(void) \ { \ usb_function_unregister(&acmusb_func); \ } \ module_init(acmmod_init); \ module_exit(acmmod_exit)
/*
* acm_alloc_instance
*/
//分配并注册tty设备(usb虚拟串口),一个port对应一个tty设备

static
struct usb_function_instance *acm_alloc_instance(void) { struct f_serial_opts *opts; int ret; opts = kzalloc(sizeof(*opts), GFP_KERNEL); //定义instance释放函数 opts->func_inst.free_func_inst = acm_free_instance; //分配并注册tty设备,最终usb串口以/dev/ttyGS0~/dev/ttyGS3访问 ret = gserial_alloc_line(&opts->port_num); config_group_init_type_name(&opts->func_inst.group, "", &acm_func_type); return &opts->func_inst; }
/*
* acm_alloc_func
*/
//tty设备操作函数

static
struct usb_function *acm_alloc_func(struct usb_function_instance *fi) { struct f_serial_opts *opts; struct f_acm *acm; acm = kzalloc(sizeof(*acm), GFP_KERNEL); spin_lock_init(&acm->lock); acm->port.connect = acm_connect; acm->port.disconnect = acm_disconnect; acm->port.send_break = acm_send_break; acm->port.func.name = "acm"; acm->port.func.strings = acm_strings; /* descriptors are per-instance copies */ acm->port.func.bind = acm_bind; acm->port.func.set_alt = acm_set_alt; acm->port.func.setup = acm_setup; acm->port.func.disable = acm_disable; opts = container_of(fi, struct f_serial_opts, func_inst); acm->port_num = opts->port_num; acm->port.func.unbind = acm_unbind; acm->port.func.free_func = acm_free_func; //最终返回(usb_function *)类型 return &acm->port.func; }
  • 2.7 至此android.c init代码已经分析完毕,那么用户如何选择usb模式呢,选择模式之后实际有哪些操作呢,下面继续分析

 

三.usb模式选择(用户空间操作)

  • 3.1 我们在init.mtxxx.usb.rc文件中可以看到用户空间对usb设备节点(android0)的操作,选取其中个一段进行分析
//基本流程操作就是usb disable-->设置VID,PID-->设置functions-->usb enable
#9.mtp,adb,acm
on property:sys.usb.config=mtp,adb,acm
    write /sys/class/android_usb/android0/enable 0
    write /sys/class/android_usb/android0/idVendor ${sys.usb.vid}
    write /sys/class/android_usb/android0/idProduct 200A
    write /sys/class/android_usb/android0/f_acm/instances 1
    write /sys/class/android_usb/android0/functions ${sys.usb.config}
    write /sys/class/android_usb/android0/enable 1
    start adbd
    setprop sys.usb.state ${sys.usb.config}
  • 3.2 读写enable节点操作
//首先看下android0设备节点下的enable
//enable_show,回读该节点返回usb enable/disable的状态
static ssize_t enable_show(struct device *pdev, struct device_attribute *attr,
               char *buf)
{
    struct android_dev *dev = dev_get_drvdata(pdev);
    return sprintf(buf, "%d\n", dev->enabled);
}

//往enable属性节点写1和0来实现设备的使能
//enable节点写1,主要调用android_enable函数
//enable节点写0,主要调用android_disable函数
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;
    struct android_usb_function *f;
    int enabled = 0;

    mutex_lock(&dev->mutex);

    sscanf(buff, "%d", &enabled);
    if (enabled && !dev->enabled) {

        cdev->next_string_id = 0x10;

        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;

        /* special case for meta mode */
        if (serial_string[0] == 0x0) {
            cdev->desc.iSerialNumber = 0;
        } else {
            cdev->desc.iSerialNumber = device_desc.iSerialNumber;
        }

        list_for_each_entry(f, &dev->enabled_functions, enabled_list) {
            if (f->enable)
                f->enable(f);
        }
        android_enable(dev);
        dev->enabled = true;
    } else if (!enabled && dev->enabled) {
        
        android_disable(dev);
        list_for_each_entry(f, &dev->enabled_functions, enabled_list) {
            
            if (f->disable)
                f->disable(f);
        }
        dev->enabled = false;
    } else {
        pr_err("android_usb: already %s\n",
                dev->enabled ? "enabled" : "disabled");
    }

    mutex_unlock(&dev->mutex);
    return size;
}
/*
* android_enable
*/
static
void android_enable(struct android_dev *dev) { struct usb_composite_dev *cdev = dev->cdev; if (--dev->disable_depth == 0) { //将各个function的接口信息添加到配置中 usb_add_config(cdev, &android_config_driver, android_bind_config); //通过上拉电阻实现usb主控制器能够识别设备并进行枚举 usb_gadget_connect(cdev->gadget); } }

   

/*
* android_bind_config
*/
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); return 0; } static int android_bind_enabled_functions(struct android_dev *dev, struct usb_configuration *c) { struct android_usb_function *f; int ret; //遍历设备的enabled_list列表,里面的functions就是用户空间写到android0下的functions节点的值 list_for_each_entry(f, &dev->enabled_functions, enabled_list) { //调用各个functions的bind_config函数 ret = f->bind_config(f, c); } } return 0; }
/*
* usb_add_config
*/
int
usb_add_config(struct usb_composite_dev *cdev, struct usb_configuration *config, int (*bind)(struct usb_configuration *)) { int status = -EINVAL; //复合设备添加非重复的config status = usb_add_config_only(cdev, config); //bind函数上面分析过了,就是调用各个function的bind_config函数 status = bind(config); if (status < 0) { while (!list_empty(&config->functions)) { struct usb_function *f; f = list_first_entry(&config->functions, struct usb_function, list); list_del(&f->list); if (f->unbind) { f->unbind(config, f); /* may free memory for "f" */ } } list_del(&config->list); config->cdev = NULL; } else { unsigned i; for (i = 0; i < MAX_CONFIG_INTERFACES; i++) { struct usb_function *f = config->interface[i]; if (!f) continue; } } //将gadget设备的输入输出端点reset为0 usb_ep_autoconfig_reset(cdev->gadget); return status; }
  • 3.3 以acm为例看下具体的bind_config都有哪些操作
static int acm_function_bind_config(struct android_usb_function *f, struct usb_configuration *c)
{
    int i;
    int ret = 0;
    struct acm_function_config *config = f->config;

    /*1st:Modem, 2nd:Modem, 3rd:BT, 4th:MD logger*/
    for (i = 0; i < MAX_ACM_INSTANCES; i++) {
        if (config->port_index[i] != 0) {
            ret = usb_add_function(c, config->f_acm[i]);

            config->port_index[i] = 0;
            config->port_index_on[i] = 1;
            config->instances = 0;
        }
    }
//write /sys/class/android_usb/android0/f_acm/instances 1
//config->instances_on就是就是往上面节点写入的值
    config->instances_on = config->instances;
    for (i = 0; i < config->instances_on; i++) {
//usb复合设备添加functions
        ret = usb_add_function(c, config->f_acm[i]);
    }

    return 0;
}
/*
* usb_add_function
*/
int
usb_add_function(struct usb_configuration *config, struct usb_function *function) { int value = -EINVAL; function->config = config; list_add_tail(&function->list, &config->functions); /* REVISIT *require* function->bind? */ if (function->bind) {
//调用usb_function的bind函数,即acm_alloc_func函数返回值
//最终调用acm_bind,里面实现接口、端点描述符的初始化,主控制器对设备进行枚举主要是获取各种描述符进行初始化,这里从设备的角度来看其实就是填充各类描述符 value = function->bind(config, function); if (value < 0) { list_del(&function->list); function->config = NULL; } } else value = 0; if (!config->fullspeed && function->fs_descriptors) config->fullspeed = true; if (!config->highspeed && function->hs_descriptors) config->highspeed = true; if (!config->superspeed && function->ss_descriptors) config->superspeed = true; return value; }

 

  • 3.4 对functions节点的操作
//回读functions节点,获取enabled_list列表中的functions
static ssize_t
functions_show(struct device *pdev, struct device_attribute *attr, char *buf)
{
    struct android_dev *dev = dev_get_drvdata(pdev);
    struct android_usb_function *f;
    char *buff = buf;

    mutex_lock(&dev->mutex);

    list_for_each_entry(f, &dev->enabled_functions, enabled_list)
        buff += sprintf(buff, "%s,", f->name);

    mutex_unlock(&dev->mutex);

    if (buff != buf)
        *(buff-1) = '\n';
    return buff - buf;
}
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;
    char aliases[256], *a;
    int err;
    int is_ffs;
    int ffs_enabled = 0;

    mutex_lock(&dev->mutex);

    INIT_LIST_HEAD(&dev->enabled_functions);

    strlcpy(buf, buff, sizeof(buf));
    b = strim(buf);

    while (b) {
        name = strsep(&b, ",");

        if (!name)
            continue;

        is_ffs = 0;
        strlcpy(aliases, dev->ffs_aliases, sizeof(aliases));
        a = aliases;

        while (a) {
            char *alias = strsep(&a, ",");
            if (alias && !strcmp(name, alias)) {
                is_ffs = 1;
                break;
            }
        }

        if (is_ffs) {
            if (ffs_enabled)
                continue;
            err = android_enable_function(dev, "ffs");
            if (err)
                pr_err("android_usb: Cannot enable ffs (%d)",
                                    err);
            else
                ffs_enabled = 1;
            continue;
        }
//将写入的functions添加到enabled_list链表中
        err = android_enable_function(dev, name);

    mutex_unlock(&dev->mutex);

    return size;
}

 

四.如何查看并修改usb模式

  • 4.1 在adb shell下查看usb模式
getprop |grep usb

 

  • 4.2 修改usb模式,支持一种或者多种functions,必须在init.mtxxxx.usb.rc中有定义
setprop persist.sys.usb.config xx,xx,xx
  •  4.3 打开acm连接电脑,电脑端驱动在kernel/Documentation/usb/linux-cdc-acm.inf

 

 

 

 

 

 

 

 

 

 

 

 

posted @ 2018-08-30 22:03  sh驱动小蚂蚁  阅读(4790)  评论(0编辑  收藏  举报