基於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