问答文章1 问答文章501 问答文章1001 问答文章1501 问答文章2001 问答文章2501 问答文章3001 问答文章3501 问答文章4001 问答文章4501 问答文章5001 问答文章5501 问答文章6001 问答文章6501 问答文章7001 问答文章7501 问答文章8001 问答文章8501 问答文章9001 问答文章9501

分析usb是怎么添加一个个function-haijian0114-ChinaUnix博客_百度...

发布网友 发布时间:2022-04-25 12:32

我来回答

1个回答

热心网友 时间:2024-10-22 11:37

首先先看一下在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;
}
声明声明:本网页内容为用户发布,旨在传播知识,不代表本网认同其观点,若有侵权等问题请及时与本网联系,我们将在第一时间删除处理。E-MAIL:11247931@qq.com
LG棒棒糖GD580这么看书 lg gd580怎么用moto看小说 各种海鲜馅饺子大全 海鲜水饺都有什么馅儿的 用网上交易系统进行股票操作资金安全吗,我是在中信建投开的户 北京瀚正化妆学校包就业吗 通江车检在哪里,可以摩托车年审不? 摩托车年审在通江县哪里啊 我是四川省通江县人、我是摩托车驾驶证,以快到期,请问我在江苏无锡... 通江县哪里可以托运摩托车 每一个加油站都有一个营业执照吗? 中石化加油站办理营业执照需要什么手续? 加油站卖尿素要不要营业执照? 加油站营业执照可以有洗车服务吗 加油站营业执照丢失,怎么补办 加油站营业执照到期是否需要年检 加油站营业执照年审过期了怎么办 加油站营业执照年检都需要什么材料? 加油站营业执照几年一审 如何制作折纸灯笼 婴儿腋下有硬块 为什么用WinRAR压缩完文件后文件还是那么大 少女淋巴结有腋下小硬块,捏会痛,如何治疗 为什么电脑里的文件压缩后还是那么大? 女性腋窝里边有小硬的疙瘩,是怎么回事 为什么用winrar压缩文件后文件还是那么大,没有减少啊 13岁女生腋下长了有些小疙瘩又痒又痛是什么? 13岁女孩的腋下有硬块怎么办?严重吗?是不是癌症? 五味指的是甘、酸、什么、辛、咸? 宝宝腋窝下边长了一个硬疙瘩是怎么回事 电脑主板上fUSB接口线怎么接? 主板上插口代号front-usb , cd-in ,aux-in, sys-fan 是什么意思_百度知 ... USB无法格式化怎么办? 主板接口F-USB3.0什么意思? 电脑F_USB2的线拔出来了怎么安装回去 我的u盘怎么插入电脑的USB接口!不能用啊? 主板上 F-USB跳线接口能否改成音频输出口 新鲜花生如何保存? 如何做“企业介绍”PPT 新开的公司用ppt做个公司业务应该包括什么内容? 领导说要做ppt介绍公司的设备和产品、具体的内容怎么做 为什么给微信好友发消息对方收不到? 微信可以给朋友发消息但是看不到对方的朋友圈是为什么? 我可以给他发微信消息, 但是看不了他微信朋友圈 ,这是为什么呢? ETC提现后微信提示已到账但信用卡账户没到账是怎么回事? 您好,我的ETC卡为什么不显示余额,而是显示记账卡?绑定的手机短信功... 为什么微信关注了高速ETC,却没有显示实时交易信息? ...没有发现扣费 银行卡和微信钱都没有扣 是怎么查询这个余额 第一次使... 我的etc在微信申请的,怎么十几天了还没到? 为什么微信冲值ETC卡钱己冲值成功,但没有圈存到卡里?