文章目录
- 1、Linux USB 子系统
- 2、Linux USB 设备驱动结构
-
- 2.1、UDC 设备控制器层
- 2.2、Gadget设备层
- 2.3、Gadget 功能驱动层
1、Linux USB 子系统
Linux
系统内核中早已集成了较为完善的USB
协议栈,由于其规模庞大,包含多个类别的设备驱动,所以Linux
系统中的USB
协议栈也被称为USB
子系统。
2、Linux USB 设备驱动结构
Gadget
驱动指的是运行在设备中的固件,也就是USB
设备驱动模型。
Linux Gadget 三个软件层:
USB
设备控制器层Gadget
设备层USB
功能驱动层
完整的 USB设备端软件是由这三层软件层融合在一起来实现 USB 设备的功能,下面我们看下他们是如何串起来的。
在 USB
设备层定义了并初始化了一个结构体 struct usb_composite_driver
。这个结构体中定义了一些函数指针,并且在 USB
设备层实现了这些函数。这些函数是融合 USB
设备层与上层软件功能驱动层的关键函数。数据结构只是完成了软件架构的构建, 如果需要融合还需 要函数的调用,在这里这个函数就是usb_composite_register
。这个函数在 USB
设备层中实现,提供给上层软件功能驱动层来调用。当功能软件层调用这个函数成功后,USB
设备层与上层软件就融合在了一起,这个函数调用还触发了 USB
设备层调用 usb_gadget_register_driver
,从而完成USB
设备层与下层软件的融合。这样三层软件都融合在了一起,组成了完整的 USB
设备端软件。
2.1、UDC 设备控制器层
UDC
设备控制器层与硬件相关,由于UCD
的设计和实现不仅限于一个家厂商,不同厂商的UCD IP
核会有特性上的差异,所以UDC
驱动也分为两部分,上层是UDC Core
,它是对各类UDC IP
的功能的抽象,为Gadget
设备层提供统一接口,重要的数据结构
static struct udc {
struct usb_gadget gadget;
struct usb_gadget_driver *driver;
struct device dev;
struct list_head list;
};
udc
意为USB
设备控制器( USB Device Controller
),其结构中包含了usb_gadget
和usb_gadget_driver
两个重要的数据结构:
usb_gadget
结构体代表一个从机设备驱动,它是对控制器的抽象,向上层提供控制器的I/O
相关和非I/O
相关的两类服务,分别对应其结构成员中的usb_gadget_ops
和usb_ep
数据结构;usb_gadget_driver
结构是从gadget
设备驱动层传递下来的,是gadget
设备驱动层的核心数据结构,最终也会挂载在udc
结构中。UDC
层的一项基本任务是向上层提供usb_gadget_probe_driver()
接口函数,并实现为usb_gadget
服务的相关函数,这些函数将通过usb_gadget
结构回传到gadget
设备层。另外,UDC
层还需要提供gadget
设备的中断服务程序,在USB
协议中,传输一般都是由主机发起的,gadget
设备驱动只有通过中断来判断是否有传输请求,中断处理程序工作在整个USB gadget
驱动架构的第一现场。
由于USB
设备控制器一般是以IP
核授权的方式集成在SOC
中,所以,在Linux
系统的UDC IP
核心驱动会以平台设备的方式注册到系统中,在驱动的探测函数中完成控制器时钟及相关数据结构初始化,获得控制器的物理地址并向内核申请中断,开辟udc
结构体所需资源并初始化usb_gadget
数据结构,最后通过调用UDC
核心提供的usb_add_gadget_udc
函数来注册gadget
服务。
2.2、Gadget设备层
Gadget
设备层属于硬件无关层,相关代码在kernel/drivers/usb/gadget/composite.c
文件中实现, Gadget
设备层把Gadget
功能驱动与硬件相关的UDC
层隔离开来,并向Gadget
功能驱动提供统一的UDC
应用接口,Gadget
功能驱动着重于USB
功能的子协议实现, UDC
层则重点关注自身IP
的物理特性和工作机制。若无Gadget
设备层,每个功能驱动都要实现自己的Gadget
设备,如此将导致严重的代码重用。
Gadget
设备层与UDC
设备控制器层的交互是通过两个结构体和一个函数进行的,第一个结构体usb_gadget
在DCD
设备控制器驱动中已经初始化,另一个结构体usb_gadget_driver
会在本层中初始化,然后通过usb_gadget_probe_driver()
传入到DCD
设备控制器层赋值到udc
驱动中,将Gadget
设备驱动与DCD
设备控制器驱动相互关联起来。
另外, DCD
设备控制器驱动会调用的usb_gadget_driver
中的bind()
函数,把usb_gadget
数据结构及其服务回传到Gadget
设备层; usb_gadget_driver
中的setup()
函数指针是Gadget
设备驱动的中断服务程序的重要组成部分,设备在枚举阶段的交互都要跳转到这里, setup ()
函数指针会指向composite_setup()
函数,在其中在分类处理标准主机请求和自定义主机请求。
struct usb_gadget_driver {
(*bind)(); (*unbind)();
(*setup)(); (*disconnect)();
(*suspend)(); (*resume)();
};
Gadget
设备层与Gadget
功能驱动通过数据结构usb_composite_dev
以及函数usb_composite_probe()
进行交互:
struct usb_composite_dev {
usb_gadget *gadget;
usb_request *req;
usb_configuration *config;
usb_composite_driver *driver;
};
usb_composite_dev
结构代表一个USB gadget
设备, 该结构中包含设备描述符和配置信息,其中usb_gadget
结构的实例是从UDC
层回传而来,回传机制为UDC
层调用usb_gadget_driver
的bind()
函数指针,该函数指针指向定义在Gadget
设备层的composite_bind()
函数,该函数中首先定义了usb_composite_dev
结构的实例,再将UDC
层的usb_gadget
赋值到usb_composite_dev
中; req
成员是用于向UDC
层分配数据传输任务的,通常枚举过程中主机请求的设备信息都使用此数据结构传递到UDC
层。
usb_composite_dev
中的driver
的数据结构类型为usb_composite_driver
,它的实例是在gadget
功能驱动中定义的, 在调用usb_composite_probe()
注册函数传递到gadget
设备层,最后同样在composite_bind()
函数中赋值给usb_composite_dev
的driver
成员,完成设备和驱动的匹配,其结构如下:
struct usb_composite_driver {
usb_gadget_driver gadget_driver;
(*bind)(); (*unbind)();
(*suspend)(); (*resume)(); (*disconnect)();
};
usb_composite_driver
结构代表一个USB gadget
设备驱动,是USB gadget
设备关联Gadget
功能驱动的核心数据结构,其中的bind()
函数指针是指向Gadget
功能驱动层中的function_bind()
函数。在Gadget
设备层的核心函数usb_composite_probe()
中定义usb_gadget_driver
数据结构实例并将usb_composite_driver
的gadget_driver
成员指向它,后续底层udc
数据结构中的driver
也将指向该usb_gadget_drive
实例。
2.3、Gadget 功能驱动层
Gadget
功能驱动层位于USB gadget
驱动框架的最顶层,着重于功能相关的子协议实现,USB
协议中的接口( Interface
)的就在该层中体现, Linux
系统中实现了如下标准功能接口驱动:
- 通信设备类接口: CDC( Communication Device Class)
- Android 调试接口: ADB( Android Debug Bridge)
- 人机接口设备接口: HID( Human Interface Device)
- 媒体传输协议接口: MTP( Media Transfer Protocol)
- 大容量存储接口: UMS( USB Mass storage)
- 用户模式文件系统接口:Gadget File System
- 串行通信接口: Serial Function
- 音频类接口: Audio Class
- 视频类接口: Video Class
Gadget
设备的composite
体系提供了一套数据结构和相应的接口函数用于建立Gadget
组合设备驱动,支持一个配置下有多个功能,一个典型的应用是Android
系统中USB gadget
设备,功能驱动的设备和配置在drivers/usb/gadget/android.c
文件中实现的,功能接口包含Mass storage
、 Rndis
、Accessory
、 MTP
以及ADB
调试端口,可根据应用需求自由增减, android.c
文件定义了struct usb_configuration
数据结构的实例( android_config_driver
),它代表USB
设备的一个配置,当该文件中的android_bind()
函数被调用时,会通过usb_add_config()
和usb_add_function()
这两个函数将组合设备中所涉及到的功能驱逐一动添加到该配置中。
Gadget
功能驱动作为一个独立模块注册到内核中,模块init
函数调用usb_composite_probe()
函数,把一个usb_composite_driver
结构的实例传入Gadget
设备层, usb_composite_driver
结构中的bind()
函数也将在USB gadget
设备驱动中的composite_bind()
函数中调用,结果是成功的将三层结构串联起来。