usb_composite_driver的创建于注册

源码:drivers/usb/legacy/serial.c

//创建usb_composite_driver
static struct usb_composite_driver gserial_driver = {
.name = "g_serial",
.dev = &device_desc,
.strings = dev_strings,
.max_speed = USB_SPEED_SUPER,
.bind = gs_bind,
.unbind = gs_unbind,
}; static int __init init(void)
{
/* We *could* export two configs; that'd be much cleaner...
* but neither of these product IDs was defined that way.
*/bConfigurationValue、class、pid等
//初始化
if (use_acm) {
serial_config_driver.label = "CDC ACM config";
serial_config_driver.bConfigurationValue = 2;
device_desc.bDeviceClass = USB_CLASS_COMM;
device_desc.idProduct =
cpu_to_le16(GS_CDC_PRODUCT_ID);
} else if (use_obex) {
serial_config_driver.label = "CDC OBEX config";
serial_config_driver.bConfigurationValue = 3;
device_desc.bDeviceClass = USB_CLASS_COMM;
device_desc.idProduct =
cpu_to_le16(GS_CDC_OBEX_PRODUCT_ID);
} else {
serial_config_driver.label = "Generic Serial config";
serial_config_driver.bConfigurationValue = 1;
device_desc.bDeviceClass = USB_CLASS_VENDOR_SPEC;
device_desc.idProduct =
cpu_to_le16(GS_PRODUCT_ID);
}
strings_dev[STRING_DESCRIPTION_IDX].s = serial_config_driver.label; //注册usb_composite_driver与usb_composite_dev
return usb_composite_probe(&gserial_driver);
}
module_init(init); static void __exit cleanup(void)
{
usb_composite_unregister(&gserial_driver);
}
module_exit(cleanup);

注意adb、mtp等功能已经通过g_ffs.c(functionfs)来与应用通信,如果没有这个的话,也可以通过g_adb.c来通信。(需要确认版本问题。)只要有合适的functionfs driver来实现。

usb_gadget_driver的创建与注册

//创建usb_gadget_driver
static const struct usb_gadget_driver composite_driver_template = {
.bind = composite_bind,
.unbind = composite_unbind, .setup = composite_setup,
.reset = composite_disconnect,
.disconnect = composite_disconnect, .suspend = composite_suspend,
.resume = composite_resume, .driver = {
.owner = THIS_MODULE,
},
}; int usb_composite_probe(struct usb_composite_driver *driver)
{
struct usb_gadget_driver *gadget_driver; if (!driver || !driver->dev || !driver->bind)
return -EINVAL; if (!driver->name)
driver->name = "composite"; 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; //注册usb_gadget_driver
return usb_gadget_probe_driver(gadget_driver);
}
EXPORT_SYMBOL_GPL(usb_composite_probe); //注册usb_gadget_driver
int usb_gadget_probe_driver(struct usb_gadget_driver *driver)
{
struct usb_udc *udc = NULL;
int ret = -ENODEV; if (!driver || !driver->bind || !driver->setup)
return -EINVAL; mutex_lock(&udc_lock);
if (driver->udc_name) {
list_for_each_entry(udc, &udc_list, list) {
ret = strcmp(driver->udc_name, dev_name(&udc->dev));
if (!ret)
break;
}
if (ret)
ret = -ENODEV;
else if (udc->driver)
ret = -EBUSY;
else
goto found;
} else {
list_for_each_entry(udc, &udc_list, list) {
/* For now we take the first one */
if (!udc->driver)
goto found;
}
} //无udc设备,则将usb_gadget_driver添加到gadget_driver_pending_list链表
if (!driver->match_existing_only) {
list_add_tail(&driver->pending, &gadget_driver_pending_list);
pr_info("udc-core: couldn't find an available UDC - added [%s] to list of pending drivers\n",
driver->function);
ret = 0;
} mutex_unlock(&udc_lock);
return ret;
found:
//udc设备与usb_gadget_driver绑定
ret = udc_bind_to_driver(udc, driver);
mutex_unlock(&udc_lock);
return ret;
}

usb_gadget的创建及注册

源码:linux4.19.123-drivers/usb/gadget/udc/s3c2410_udc.c

static const struct usb_ep_ops s3c2410_ep_ops = {
.enable = s3c2410_udc_ep_enable,
.disable = s3c2410_udc_ep_disable, .alloc_request = s3c2410_udc_alloc_request,
.free_request = s3c2410_udc_free_request, .queue = s3c2410_udc_queue,
.dequeue = s3c2410_udc_dequeue, .set_halt = s3c2410_udc_set_halt,
}; static const struct usb_gadget_ops s3c2410_ops = {
.get_frame = s3c2410_udc_get_frame,
.wakeup = s3c2410_udc_wakeup,
.set_selfpowered = s3c2410_udc_set_selfpowered,
.pullup = s3c2410_udc_pullup,
.vbus_session = s3c2410_udc_vbus_session,
.vbus_draw = s3c2410_vbus_draw,
.udc_start = s3c2410_udc_start,
.udc_stop = s3c2410_udc_stop,
}; /*---------------------------------------------------------------------------*/
static struct s3c2410_udc memory = {
//usb_gadget初始化
.gadget = {
.ops = &s3c2410_ops,
.ep0 = &memory.ep[0].ep,
.name = gadget_name,
.dev = {
.init_name = "gadget",
},
}, /* control endpoint */
.ep[0] = {
.num = 0,
.ep = {
.name = ep0name,
.ops = &s3c2410_ep_ops,
.maxpacket = EP0_FIFO_SIZE,
.caps = USB_EP_CAPS(USB_EP_CAPS_TYPE_CONTROL,
USB_EP_CAPS_DIR_ALL),
},
.dev = &memory,
}, /* first group of endpoints */
.ep[1] = {
.num = 1,
.ep = {
.name = "ep1-bulk",
.ops = &s3c2410_ep_ops,
.maxpacket = EP_FIFO_SIZE,
.caps = USB_EP_CAPS(USB_EP_CAPS_TYPE_BULK,
USB_EP_CAPS_DIR_ALL),
},
.dev = &memory,
.fifo_size = EP_FIFO_SIZE,
.bEndpointAddress = 1,
.bmAttributes = USB_ENDPOINT_XFER_BULK,
},
.ep[2] = {
.num = 2,
.ep = {
.name = "ep2-bulk",
.ops = &s3c2410_ep_ops,
.maxpacket = EP_FIFO_SIZE,
.caps = USB_EP_CAPS(USB_EP_CAPS_TYPE_BULK,
USB_EP_CAPS_DIR_ALL),
},
.dev = &memory,
.fifo_size = EP_FIFO_SIZE,
.bEndpointAddress = 2,
.bmAttributes = USB_ENDPOINT_XFER_BULK,
},
.ep[3] = {
.num = 3,
.ep = {
.name = "ep3-bulk",
.ops = &s3c2410_ep_ops,
.maxpacket = EP_FIFO_SIZE,
.caps = USB_EP_CAPS(USB_EP_CAPS_TYPE_BULK,
USB_EP_CAPS_DIR_ALL),
},
.dev = &memory,
.fifo_size = EP_FIFO_SIZE,
.bEndpointAddress = 3,
.bmAttributes = USB_ENDPOINT_XFER_BULK,
},
.ep[4] = {
.num = 4,
.ep = {
.name = "ep4-bulk",
.ops = &s3c2410_ep_ops,
.maxpacket = EP_FIFO_SIZE,
.caps = USB_EP_CAPS(USB_EP_CAPS_TYPE_BULK,
USB_EP_CAPS_DIR_ALL),
},
.dev = &memory,
.fifo_size = EP_FIFO_SIZE,
.bEndpointAddress = 4,
.bmAttributes = USB_ENDPOINT_XFER_BULK,
} };
/*
* probe - binds to the platform device
*/
static int s3c2410_udc_probe(struct platform_device *pdev)
{
struct s3c2410_udc *udc = &memory;
struct device *dev = &pdev->dev;
int retval;
int irq; dev_dbg(dev, "%s()\n", __func__); ...... //创建/注册udc,注册usb_gadget
retval = usb_add_gadget_udc(&pdev->dev, &udc->gadget);
if (retval)
goto err_add_udc; ...... return 0; err_add_udc:
if (udc_info && !udc_info->udc_command &&
gpio_is_valid(udc_info->pullup_pin))
gpio_free(udc_info->pullup_pin);
err_vbus_irq:
if (udc_info && udc_info->vbus_pin > 0)
free_irq(gpio_to_irq(udc_info->vbus_pin), udc);
err_gpio_claim:
if (udc_info && udc_info->vbus_pin > 0)
gpio_free(udc_info->vbus_pin);
err_int:
free_irq(IRQ_USBD, udc);
err_map:
iounmap(base_addr);
err_mem:
release_mem_region(rsrc_start, rsrc_len); return retval;
}

usb_udc的创建及注册

源码:linux-4.19.123-drivers/usb/gadget/udc/core.c

int usb_add_gadget_udc(struct device *parent, struct usb_gadget *gadget)
{
return usb_add_gadget_udc_release(parent, gadget, NULL);
}
EXPORT_SYMBOL_GPL(usb_add_gadget_udc); /**
* usb_add_gadget_udc_release - adds a new gadget to the udc class driver list
* @parent: the parent device to this udc. Usually the controller driver's
* device.
* @gadget: the gadget to be added to the list.
* @release: a gadget release function.
*
* Returns zero on success, negative errno otherwise.
* Calls the gadget release function in the latter case.
*/
int usb_add_gadget_udc_release(struct device *parent, struct usb_gadget *gadget,
void (*release)(struct device *dev))
{
struct usb_udc *udc;
int ret = -ENOMEM; dev_set_name(&gadget->dev, "gadget");
INIT_WORK(&gadget->work, usb_gadget_state_work);
gadget->dev.parent = parent; if (release)
gadget->dev.release = release;
else
gadget->dev.release = usb_udc_nop_release; device_initialize(&gadget->dev); //创建usb_udc
udc = kzalloc(sizeof(*udc), GFP_KERNEL);
if (!udc)
goto err_put_gadget; device_initialize(&udc->dev);
udc->dev.release = usb_udc_release;
udc->dev.class = udc_class;
udc->dev.groups = usb_udc_attr_groups;
udc->dev.parent = parent;
ret = dev_set_name(&udc->dev, "%s", kobject_name(&parent->kobj));
if (ret)
goto err_put_udc; ret = device_add(&gadget->dev);
if (ret)
goto err_put_udc; udc->gadget = gadget;
gadget->udc = udc; mutex_lock(&udc_lock);
//将新创建的usb_udc添加到udc_list链表中
list_add_tail(&udc->list, &udc_list); ret = device_add(&udc->dev);
if (ret)
goto err_unlist_udc; usb_gadget_set_state(gadget, USB_STATE_NOTATTACHED);
udc->vbus = true; /* pick up one of pending gadget drivers */
ret = check_pending_gadget_drivers(udc);
if (ret)
goto err_del_udc; mutex_unlock(&udc_lock); return 0; err_del_udc:
device_del(&udc->dev); err_unlist_udc:
list_del(&udc->list);
mutex_unlock(&udc_lock); device_del(&gadget->dev); err_put_udc:
put_device(&udc->dev); err_put_gadget:
put_device(&gadget->dev);
return ret;
}

小结

至此,已完成usb_gadget_driver、usb_composite_driver、usb_gadget、usb_udc等几个核心结构体的创建及注册。后面将介绍usb_composite_dev等的创建及注册,以及usb_gadget_driver与usb_udc的绑定过程。

gadget驱动框架(二)的更多相关文章

  1. I2C驱动框架(二)

    参考:I2C子系统之I2C bus初始化——I2C_init() 在linux内核启动的时候最先执行的和I2C子系统相关的函数应该是driver/i2c/i2c-core.c文件中的i2c_init( ...

  2. Linux USB ECM Gadget 驱动介绍

    ​1 USB ECM介绍 USB ECM,属于USB-IF定义的CDC(Communication Device Class)下的一个子类:Ethernet Networking Control Mo ...

  3. Linux下USB驱动框架分析【转】

    转自:http://blog.csdn.net/brucexu1978/article/details/17583407 版权声明:本文为博主原创文章,未经博主允许不得转载. http://www.c ...

  4. I2C驱动框架(四)

    参考:I2C子系统之platform_driver初始化——I2C_adap_s3c_init() 在完成platform_device的添加之后,i2c子系统将进行platform_driver的注 ...

  5. Linux Framebuffer驱动剖析之二—驱动框架、接口实现和使用

    深入分析LinuxFramebuffer子系统的驱动框架.接口实现和使用. 一.LinuxFramebuffer的软件需求 上一篇文章详细阐述了LinuxFramebuffer的软件需求(请先理解第一 ...

  6. uart驱动框架分析(二)uart_add_one_port

    作者:lizuobin (百问网论坛答疑助手) 原文: https://blog.csdn.net/lizuobin2/article/details/51801183 (所用开发板:mini2440 ...

  7. Linux Framebuffer驱动框架之二软件架构(未完待续)【转】

    本文转载自:http://blog.csdn.net/gqb_driver/article/details/12918547 /************************************ ...

  8. 【原创】Linux PCI驱动框架分析(二)

    背 景 Read the fucking source code! --By 鲁迅 A picture is worth a thousand words. --By 高尔基 说明: Kernel版本 ...

  9. lcd驱动框架

    目录 lcd驱动框架 框图 程序分析 入口 打开open 读read 初始化registered_fb 注册 小结 程序设计 测试 方式一操作fb0 方式二操作tty 方式三操作终端 完整程序 tit ...

  10. Linux USB驱动框架分析 【转】

    转自:http://blog.chinaunix.net/uid-11848011-id-96188.html 初次接触与OS相关的设备驱动编写,感觉还挺有意思的,为了不至于忘掉看过的东西,笔记跟总结 ...

随机推荐

  1. 【Tutorial C】01 概述

    历史 History 欢迎来到C语言的世界!C语言是一种强大的专业化编程语言,深受业余和专业编程人员的欢迎. 在学习之前先让我们了解和认识它! C语言的原型是A语言(ALGOL 60语言). 1963 ...

  2. MyBatis-Plus删除操作的几种基本方法

    delete删除的三种方法 一.根据 id 删除 @Test void deleteById(Integer id) { empMapper.deleteById(new Emp().getId()) ...

  3. AI大模型的技术之母 —— Attention Is All You Need —— Tansformer

    论文地址: https://arxiv.org/abs/1706.03762

  4. LeetCode 上1769号 面试编程题,python编程

    原题地址: https://leetcode-cn.com/problems/minimum-number-of-operations-to-move-all-balls-to-each-box/ - ...

  5. 强化学习:一种新的并行算法下的参数同步更新方式——半异步更新方式——( 同步、异步 -> 半异步 )

    Abstract: 并行算法下的参数同步方式一般有同步更新和异步更新两种方式,本文在此基础之上提出了一种新的参数同步方式--半异步更新方式. Introduction: 这里用神经网络举例子,也就是神 ...

  6. C语言编写Linux终端环境下无缓冲键盘输入 ,并识别上下左右光标键

    自己重构了游戏<2048>并且重构了它的最好启发式AI解法,并上传到了Gitee中的 鬼&泣 / 2048-heuristic的devilmaycry分支,在这个过程中编写了一个C ...

  7. Java项目生产启动、关闭脚本

    1.直接启动 #!/bin/bash #这里可替换为你自己的执行程序,其他代码无需更改 APP_NAME=XXXX-api-1.0.jar #使用说明,用来提示输入参数 usage() { echo ...

  8. ComfyUI插件:ComfyUI_Noise节点

    前言: 学习ComfyUI是一场持久战,ComfyUI_Noise是对ComfyUI中的噪声进行控制的一个插件库,该库可以完成图像噪声的反推,并通过采样再以几乎无损的方式返回原图,通过该库的使用可以更 ...

  9. Synology NAS GitLab 配置

    安装 安装的时候会提示服务器名.root用户名等,这步服务器名千万不要写错,不然会登不上去,提示 502. root 密码 网上有很多说 root 密码怎么获取的,但是都不适用. 实际上是第一个访问 ...

  10. 工作常用SQL

    工作常用SQL Excel生成SQL 这个好用 ="insert into t_gk_mapping(id,gk_project_name,gk_project_code,main_proj ...