0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

深度剖析USB设备端驱动框架

strongerHuang 来源:漫谈嵌入式 作者:漫谈嵌入式 2021-06-07 14:12 次阅读

hello 大家好,今天带领大家学习一下USB设备端驱动

内核版本:4.4.94

1. Linux USB 子系统在介绍设备端驱动前,我们先来看看 Linux USB子系统。这里的子系统是相对于整个Linux kernel 来说的,而非单一设备。从整体概括了USB主机端和设备端的通信框架。

Linux kernel 中早已集成了较为完善的USB协议栈,由于其规模庞大,包含多个类别的设备驱动,所以Linux系统中的USB协议栈也被称为USB子系统。

1.1 主机端

主机端,简化抽象三层:

各种类设备驱动:mass sotrage, CDC, HID等

USB 设备驱动:USB 核心处理

主机控制器驱动:不同的USB主机控制器(OHCI/EHCI/UHCI),抽象为HDC。

1.2 设备端

设备端,也抽象为三层:

设备功能驱动:mass sotage , CDC, HID 等,对应主机端的类设备驱动

Gadget 设备驱动:中间层,向下直接和UDC通信,建立链接;向上提供通用接口,屏蔽USB请求以及传输细节。

设备控制器驱动:UDC驱动,直接处理USB设备控制器。

2. USB 设备驱动2.1 gadget 驱动框架拆解1

我们将USB 设备端驱动拆解一下。

上文提到,Gadget 设备层起着至关重要的作用。为上层提供通用的驱动框架,与下层UDC通过Gadget Interface 建立联系。

其中Compsite Framwork 提供了一个通用的usb_gadget_driver 模板,包括各种方法供上层Function driver 使用。(driver/usb/gadget/compsite.c)

从上图我们可以看出,对于USB设备端驱动开发而言,更多的关注的是Function driver这层。USB 控制相关过程,内核提供了一个中间层帮我们屏蔽掉了。

2.2 gadget 驱动框架拆解2

内核版本:Linux Kernel 4.4.94,我们以这个版本进行拆解分析

4.x 的内核相对于3.x的内核在gadget 驱动上分解的更加完善,显得目录结构,层次分明,分工合理,更便于理解。

相对于3.x 的版本,4.4.94这个内核,将原来的、driver/usb/gadget目录进行拆分。通用接口保持不变,比如compsite.c以及functions.c。将usb function driver 进行细分,分为legacy和functions。

有了这些背景,我们再看4.4.94这版内核,gadget驱动框架。

legacy:整个Gadget 设备驱动的入口。位于driver/usb/gadget/legacy下,里面给出了常用的usb类设备的驱动sample。其作用就是配置USB设备描述符信息,提供一个usb_composite_driver, 然后注册到composite层。

functions:各种usb 子类设备功能驱动。位于driver/usb/gadget/functions,里面也给出了对应的sample。其作用是配置USB子类协议的接口描述以及其他子类协议,比如uvc协议,hid等。

注意:对于一个compsite 设备一个有一个或者多个function,对应的也就有多个functions driver

从这张图上,有没有发现,设备端驱动开发似乎越来越简单了。没错,事实上,我们只需要根据legacy的源码,添加对应的usb设备描述符信息,以及其他若干配置即可。

换言之,我们只需要关心 legacy 这一丢丢就行,对于functions这层会根据业务需要略微调整,不过整体变动不大。

usb 驱动框架之所以复杂,除了需要研究各种复杂的协议,还融合了各种驱动,对于初学者来说,理解起来有点困难。事实上,光是legacy这里也包含其他驱动,比如webcam里有大名鼎鼎的 v4l2 驱动框架。

所以当我学习USB驱动框架的时候,一定要抓大放小,【把握主要脉络,忽略细节】。当我们把一个复杂的驱动逐一拆解的话,其实发现,就没有那么可怕了。

2.3 usb compsite 设备构建

为了便于理解,我们来简单了解一个usb compsite 设备的构建过程:

假设构建一个usb 复合设备,需要支持uac, uac, hid 三个功能其驱动框架。

首先,我们需要一个驱动入口 legacy,用来配置设备描述信息,支持的协议等

然后添加一个配置支持多种接口,这里支持uvc uac hid, 每个接口对应一个functions driver

最后我们把它注册到compsite 层

对于functions driver 有个usb function driver list,在内核注册function driver 时会自动添加到一个链表上。functions.c 就是用来管理所有的function drivers

3. USB gadget 驱动剖析3.1 相关数据结构

在梳理整个框架前我们先梳理一下几个重要的数据结构,从下到上依次介绍:

usb_udc:

udc 使用,内嵌usb_gadget_driver 和 usb_gadget

struct usb_udc {

struct usb_gadget_driver *driver;

struct usb_gadget *gadget;

struct device dev;

struct list_head list;

bool vbus;

};

usb gadget:

usb 底层操作,包括udc,端点请求等。

struct usb_gadget {

struct work_struct work; /* 工作队列 */

struct usb_udc *udc; /* udc */

/* readonly to gadget driver */

const struct usb_gadget_ops *ops; /*gadget 设备操作函数集*/

struct usb_ep *ep0; /* 控制端点,只对setup包响应*/

struct list_head ep_list; /* 将设备的所有端点连成链表,ep0不在其中 */

enum usb_device_speed speed; /* 高速、全速和低速 */

enum usb_device_speed max_speed; /* 最大速度 */

enum usb_device_state state;

const char *name;

struct device dev;

unsigned out_epnum; /* out ep number */

unsigned in_epnum; /* in ep number */

struct usb_otg_caps *otg_caps;

unsigned sg_supported:1;

unsigned is_otg:1;

unsigned is_a_peripheral:1;

unsigned b_hnp_enable:1;

unsigned a_hnp_support:1;

unsigned a_alt_hnp_support:1;

unsigned quirk_ep_out_aligned_size:1;

unsigned quirk_altset_not_supp:1;

unsigned quirk_stall_not_supp:1;

unsigned quirk_zlp_not_supp:1;

unsigned is_selfpowered:1;

unsigned deactivated:1;

unsigned connected:1;

};

usb_gadget_driver:

usb_gadget_driver - driver for usb ‘slave’ devices. usb 从设备驱动通用结构。

作用:提供一个通用的usb gadget driver 模板,向下注册到udc,向上给functions driver提供bind 回调等。

关注:bind 回调、function 驱动名、setup 处理请求

struct usb_gadget_driver {

char *function; /* String describing the gadget‘s function */

enum usb_device_speed max_speed; /* Highest speed the driver handles */

int (*bind)(struct usb_gadget *gadget, /* the driver’s bind callback */

struct usb_gadget_driver *driver);

void (*unbind)(struct usb_gadget *);

int (*setup)(struct usb_gadget *, /* 处理ep0 request */

const struct usb_ctrlrequest *);

void (*disconnect)(struct usb_gadget *);

void (*suspend)(struct usb_gadget *);

void (*resume)(struct usb_gadget *);

void (*reset)(struct usb_gadget *);

/* FIXME support safe rmmod */

struct device_driver driver;

};

usb_composite_driver:

usb_composite_driver ,设备驱动的入口,用来管理设备配置信息,保存设备描述符。

重点:关注 bind 方法。

struct usb_composite_driver {

const char *name; /* 驱动名字 */

const struct usb_device_descriptor *dev ; /* 设备描述符 */

struct usb_gadget_strings **strings;

enum usb_device_speed max_speed;

unsigned needs_serial:1;

int (*bind)(struct usb_composite_dev *cdev); /* bind 方法 */

int (*unbind)(struct usb_composite_dev *);

void (*disconnect)(struct usb_composite_dev *);

/* global suspend hooks */

void (*suspend)(struct usb_composite_dev *);

void (*resume)(struct usb_composite_dev *);

struct usb_gadget_driver gadget_driver; /* usb gadget driver */

};

usb_composite_dev:

内嵌gadget对象,以及usb 设备的一些配置和请求,主要用于初始化。

struct usb_composite_dev {

struct usb_gadget *gadget;

struct usb_request *req;

struct usb_request *os_desc_req;

struct usb_configuration *config; /* usb 配置信息 */

/* OS String is a custom (yet popular) extension to the USB standard. */

u8 qw_sign[OS_STRING_QW_SIGN_LEN];

u8 b_vendor_code;

struct usb_configuration *os_desc_config;

unsigned int use_os_string:1;

/* private: */

/* internals */

unsigned int suspended:1;

struct usb_device_descriptor desc; /* 设备描述符 */

struct list_head configs;

struct list_head gstrings;

struct usb_composite_driver *driver; /* composite driver */

u8 next_string_id;

char *def_manufacturer;

/* the gadget driver won‘t enable the data pullup

* while the deactivation count is nonzero.

*/

unsigned deactivations;

/* the composite driver won’t complete the control transfer‘s

* data/status stages till delayed_status is zero.

*/

int delayed_status;

/* protects deactivations and delayed_status counts*/

spinlock_t lock;

unsigned setup_pending:1;

unsigned os_desc_pending:1;

};

3.2 驱动剖析

为一个通用的usb gadget 驱动剖析,框图中只列出了两个function,如果有多个function可以继续添加。关于udc控制器部分,,没有继续画下去,注意我们始终保持一个原则,【抓大放小】,把握重要的脉络即可。

分层分块

上下分层,左右分离的思想。

设备功能驱动

legacy 驱动入口

functions 驱动实现

Gadget 设备层:最重要的是compsite_bind 方法,承上启下的作用。

udc 设备控制器层。usb 协议的真正处理。

驱动走向

向下:usb_composite_driver -》 usb_gadget_driver-》usb_udc

向上回调:udc_bind_to_driver -》 composite_bind -》 webcam_bind其中其主要作用的两个结构就是usb_gadget_driver 和 usb_compsite_dev。前者向下注册到udc list 里面,与udc控制器建立绑定关系;后者向上提供接口,供上层配置usb 设备的各种functions 和其他配置信息。

代码分析

注册usb_composite_driver

module_usb_composite_driver(webcam_driver)

module_driver(webcam_driver, usb_composite_probe,

usb_composite_unregister)

usb_composite_probe

usb_composite_probe(webcam_driver);

driver-》gadget_driver = composite_driver_template;

gadget_driver = &driver-》gadget_driver;

。。。

usb_gadget_probe_driver(composite_driver_template);

udc_bind_to_driver(udc, driver);

composite_driver_template-》bind(udc-》gadget, composite_driver_template);

usb_gadget_udc_start(udc);

composite_bind

composite_bind(udc-》gadget,composite_driver_template);

cdev-》gadget = gadget;

composite_dev_prepare(webcam_driver,cdev);

cdev-》req = usb_ep_alloc_request(gadget-》ep0, GFP_KERNEL); /* 申请端点0 */

cdev-》req-》complete = composite_setup_complete;

cdev-》driver = webcam_driver;

usb_ep_autoconfig_reset(gadget);

webcam_driver-》bind(cdev);

webcam_bind

webcam_bind(cdev);

usb_get_function_instance(“uvc”);

try_get_usb_function_instance(“uvc”);

uvc_alloc_inst();

usb_add_config();

webcam_config_bind();

usb_get_function();

usb_add_function();

others_config_bind();

其他

关于function driver 我们这里没有详细介绍,这个框图只是一个通用的usb 设备驱动框架图,对于具体的usb function driver 我们这里没有做具体分析。

以f_uvc简单举例,详细过程见内核源码。

DECLARE_USB_FUNCTION_INIT(uvc, uvc_alloc_inst, uvc_alloc);

DECLARE_USB_FUNCTION_INIT(uvc, uvc_alloc_inst, uvc_alloc);

usb_function_register(&uvcusb_func);

list_for_each_entry(fd, &func_list, list)

list_add_tail();

DECLARE_USB_FUNCTION_INIT

一个通用的驱动模板,用来注册usb_function_driver,并添加到func_list上。

#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)

{

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)

4. 总结本文以拆解的方式,逐步剥离 usb 设备端驱动框架,带领大家来重新认识usb 设备端驱动,同时给出了一个 compsite 设备的通用驱动框架模型,并从源码层次分析整个驱动流程。

有关USB 或者 其他类似的高级驱动,笔者有个建议,在初学时一点更要【把握主次,忽略细节】。

比如一个复合的usb 设备可能包含,uvc,uac,hid,等等,视频有uvc function驱动和v4l2驱动,uac也有相应的驱动,衍生展开会非常复杂。

所以当我们先掌握设备端驱动框架以及流程,等后面需要加入其他usb function 驱动再去研究其协议或者驱动,以及衍生驱动。

编辑:jq

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • usb
    usb
    +关注

    关注

    60

    文章

    7961

    浏览量

    265111
  • Linux
    +关注

    关注

    87

    文章

    11322

    浏览量

    209867

原文标题:一文搞懂 USB 设备端驱动框架

文章出处:【微信号:strongerHuang,微信公众号:strongerHuang】欢迎添加关注!文章转载请注明出处。

收藏 人收藏

    评论

    相关推荐

    在边缘设备上设计和部署深度神经网络的实用框架

    ‍‍‍‍ 机器学习和深度学习应用程序正越来越多地从云端转移到靠近数据源头的嵌入式设备。随着边缘计算市场的快速扩张,多种因素正在推动边缘人工智能的增长,包括可扩展性、对实时人工智能应用的不断增长的需求
    的头像 发表于 12-20 11:28 199次阅读

    USB驱动问题:设备无法识别的全面指南!

    今天我把USB驱动问题,关于设备无法识别方面做一个全面指南供大家参考。连接USB无法识别模组设备,是不是
    的头像 发表于 11-26 12:35 418次阅读
    <b class='flag-5'>USB</b><b class='flag-5'>驱动</b>问题:<b class='flag-5'>设备</b>无法识别的全面指南!

    基于RT-Thread的usb设备msc驱动测试

    msc驱动简介:USBMSC(MassStorageClass)是一种USB设备类别,用于在计算机和外部存储设备之间进行数据传输。USBMSC允许外部存储
    的头像 发表于 11-12 01:07 284次阅读
    基于RT-Thread的<b class='flag-5'>usb</b><b class='flag-5'>设备</b>msc<b class='flag-5'>驱动</b>测试

    揭秘动态化跨框架在鸿蒙系统下的高性能解决方案

    作者:京东科技 胡大海 前言 动态化跨框架 (后文统称“ 动态化” ) 是一个由京东金融大前端团队全自主研发的,一份代码,可以在 HarmonyOS、 iOS、Android、Web四运行的跨
    的头像 发表于 10-08 13:46 887次阅读
    揭秘动态化跨<b class='flag-5'>端</b><b class='flag-5'>框架</b>在鸿蒙系统下的高性能解决方案

    linux系统的设备驱动一般分几类

    视频设备驱动 USB设备驱动 其他设备驱动 下面将
    的头像 发表于 08-30 15:13 465次阅读

    MEMS 可编程振荡器的卓越代表:SiT9121 系列(1 to 220 MHZ)深度剖析

    MEMS 可编程振荡器的卓越代表:SiT9121 系列(1 to 220 MHZ)深度剖析
    的头像 发表于 08-13 10:56 560次阅读
    MEMS 可编程振荡器的卓越代表:SiT9121 系列(1 to 220 MHZ)<b class='flag-5'>深度</b><b class='flag-5'>剖析</b>

    探索巅峰性能 | 迅为RK3588开发板深度剖析

    探索巅峰性能 | 迅为RK3588开发板深度剖析
    的头像 发表于 08-12 14:07 929次阅读
    探索巅峰性能 | 迅为RK3588开发板<b class='flag-5'>深度</b><b class='flag-5'>剖析</b>

    NVIDIA推出全新深度学习框架fVDB

    在 SIGGRAPH 上推出的全新深度学习框架可用于打造自动驾驶汽车、气候科学和智慧城市的 AI 就绪型虚拟表示。
    的头像 发表于 08-01 14:31 636次阅读

    表面贴装低相位噪音晶体振荡器 DSO531SHH 深度剖析

    表面贴装低相位噪音晶体振荡器 DSO531SHH 深度剖析
    的头像 发表于 07-26 14:12 411次阅读
    表面贴装低相位噪音晶体振荡器 DSO531SHH <b class='flag-5'>深度</b><b class='flag-5'>剖析</b>

    TensorFlow与PyTorch深度学习框架的比较与选择

    深度学习作为人工智能领域的一个重要分支,在过去十年中取得了显著的进展。在构建和训练深度学习模型的过程中,深度学习框架扮演着至关重要的角色。TensorFlow和PyTorch是目前最受
    的头像 发表于 07-02 14:04 988次阅读

    ArmSoM系列板卡 嵌入式Linux驱动开发实战指南 之 字符设备驱动

    字符设备驱动 本章,我们将学习字符设备使用、字符设备驱动相关的概念,理解字符设备
    的头像 发表于 04-10 09:53 1088次阅读
    ArmSoM系列板卡 嵌入式Linux<b class='flag-5'>驱动</b>开发实战指南 之 字符<b class='flag-5'>设备</b><b class='flag-5'>驱动</b>

    CY7C68013A通过USB与平板设备通信,平板能找到该USB设备但显示无驱动的原因?

    使用贵司的CY7C68013A通过USB 与平板设备(安卓设备)通信时遇见问题,平板能找到该USB设备,但是显示无
    发表于 02-27 06:35

    《RT-Thread设备驱动开发指南》基础篇--以先楫bsp的hwtimer设备为例

    一、概述(一)RT-Thread设备驱动《RT-Thread设备驱动开发指南》书籍是RT-thread官方出品撰写,系统讲解RT-threadIO
    的头像 发表于 02-24 08:16 1719次阅读
    《RT-Thread<b class='flag-5'>设备</b><b class='flag-5'>驱动</b>开发指南》基础篇--以先楫bsp的hwtimer<b class='flag-5'>设备</b>为例

    如何使用UART将TRAVEOTM T 2G设备深度睡眠中唤醒

    此代码示例说明如何使用 UART 将 TRAVEOTM T 2G 设备深度睡眠中唤醒。 在活动模式下,TRAVEOTM T 2G 设备通过 UART 接收数据并回显接收到的数据。 MCU 在接收
    发表于 01-31 06:08

    USB设备之间是怎么同步时钟的?所有USB设备的时钟频率都是一致的吗?

    USB设备之间是怎么同步时钟的?是所有USB设备的时钟频率都是一致的吗? USB设备之间的时钟同
    的头像 发表于 01-16 14:42 2473次阅读