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. 18B20的CRC官方讲解

    理解和运用MAXIM IBUTTON产品中的循环冗余校验(CRC) 摘要 : 全部1-Wire器件,包括iButton器件,都具有唯一的8字节注册码,储存在只读存储器(ROM)中.该注册码在1-Wir ...

  2. docker nginx容器的均衡负载

    创建三个docker容器以实现nginx的负载均衡 编写nginx的dockfile [root@docker nginx]# cat Dockerfile FROM nginx RUN echo ' ...

  3. linux性能资源分析工具

    linux性能资源分析工具 1,top 2,ps 3,uptime 4,mpstat 5,pidstat 6,vmstat 7,iostat 8,netstat 9,lsof 10,sar / nmo ...

  4. 循环神经网络 —— LSTM 图片

  5. 大模型时代该用什么样的显卡 —— 实验室新进两块A800显卡

    具体如图: (这两个显卡是专为实验室的大模型方向提供的) 关于A800显卡的性能参数: (上图源自:https://www.zhihu.com/question/618932114/answer/32 ...

  6. Jax计算框架的MPI通讯的扩展库 —— mpi4jax

    地址: https://github.com/mpi4jax/mpi4jax PS. 关于这个library的性能表现并不是很清楚,没有亲自手动安装并测试过.这里只作为链接收藏之用,毕竟这个属于比较小 ...

  7. (摘抄) 源码分析multiprocessing的Value Array共享内存原理

    原文地址: http://xiaorui.cc/archives/3290 ============================================================ 摘 ...

  8. 在线flex布局----自己写的一个flex布局的小玩意,需要的私聊加关注0.0

  9. java判断文本文件编码格式

    上篇文章需要读取当前java或者配置文件的编码格式,这里主要支持UTF-8.GBK.UTF-16.Unicode等 /** * 判断文件的编码格式 * @param fileName :file * ...

  10. kafka 运维

    查看kafka topic列表 #集群需要先执行unset JMX_PORT ./kafka-topics.sh --zookeeper gitee-zookeeper:2181 --list 查看t ...