【Linux USB子系统 – 01】Legacy 类设备功能驱动层 – 代码流程分析

【Linux USB子系统 - 01】Legacy 类设备功能驱动层 - 代码流程分析

  • ​​一、Legacy 结构体分析​​
    • ​​1.1 USB复合设备结构体 struct usb_composite_driver​​
    • ​​1.2 USB设备描述符结构体 slinux常用命令truct ususb3.0传输速度b_device_descriptor​​
      • ​​(1) 描述符类型编号 bDescriptorType​​
      • ​​(2系统/运维) 设备类型编号 bDeviceClass​​
    • ​​1.3 字符串结构体 struc系统/运维t usb_gadget_strings​​
  • ​​二、Legacy 函数分析​define()x是什么牌子
    • ​​2.1 注册驱动 module_usb_composite_driver(zero_dusb摄像头安卓下载river)​​
    • ​​2.2 探测函数初始化 usb_composite_probe(&zero_driver)​​
    • ​​字符串逆序输出2.3 bind() 函数分析​​
      • ​​(1)DECLARE_USB_FUNCTION()​​
    • ​​2.4 unbind() 函数分析​​
    • ​​2.5 suspend() 函数分析​​
    • ​​2.6 resume() 函数分析​​

有关Linux USB子系统的架构,网上有一往篇写的很好的文章,可以参考学习下:《​​一文搞懂 USB 设备端驱动框架​​》,

盗用上面文章中的一张图,很好的归纳了usb子系统的整体架构:

接下来,我们按照这个USB架构从上到下,分别来学习下它们的代码流程:

  1. legacy 类设备功能驱动
  2. usb functiolinux系统安装ns 子类设备功能驱动
  3. Gadget 设备层
  4. USB 设备控制器层

好,我们进入正文,先来看下gadget 设备功能驱动层的代码流程。

一、字符串怎么输入Legacy 结构体分析

Legacy 类设备功能驱动代码位于:​​\kernel\drivers\usb\gadget\legacy​define()名词​.

在目录中主要是常用的USB类设备驱linux创建文件动,它是一个大类linux系统,包含了具体的功能,如​​cdc2.c、ncm.c、serial.c、audio.c​​,

主要作用是配置USB设备描述符信息,提供一linux是什么操作系统个​​usb_composite_driver​​注册到系统运维面试题及答案​composite​​层,供各子类 ​​usb function​​使用。

由此,我们可以知道,一个​composite​​ 类设备,可以对应着多个子​​usb functions​​设备。

此处,我们以 ​​zero.c​​为例,来分析下它的代码流程:

先把代码简化下,来看下 ​​Legacy usb compo字符串是什么意思site driver​​驱动代码的整体结构:

# \kernel\drivers\usb\gadget\legacy\zero.c
#define USB_SPEED_SUPER 5
#define USB_CLASS_VENDOR_SPEC 0xff
#define USB_DT_DEVICE 0x01

#ifndef CONFIG_USB_ZERO_HNPTEST
#define DRIVER_VENDOR_NUM 0x0525 /* NetChip */
#define DRIVER_PRODUCT_NUM 0xa4a0 /* Linux-USB "Gadget Zero" */
#define DEFAULT_AUTORESUME 0
#else
#define DRIVER_VENDOR_NUM 0x1a0a /* OTG test device IDs */
#define DRIVER_PRODUCT_NUM 0xbadd
#define DEFAULT_AUTORESUME 5
#endif

static struct usb_device_descriptor device_desc = {
.bLength = sizeof device_desc,
.bDescriptorType = USB_DT_DEVICE,

.bcdUSB = cpu_to_le16(0x0200),
.bDeviceClass = USB_CLASS_VENDOR_SPEC,

.idVendor = cpu_to_le16(DRIVER_VENDOR_NUM),
.idProduct = cpu_to_le16(DRIVER_PRODUCT_NUM),
.bNumConfigurations = 2,
};

static const char longname[] = "Gadget Zero";
static char serial[] = "0123456789.0123456789.0123456789";

static struct usb_string strings_dev[] = {
[USB_GADGET_MANUFACTURER_IDX].s = "",
[USB_GADGET_PRODUCT_IDX].s = longname,
[USB_GADGET_SERIAL_IDX].s = serial,
[USB_GZERO_SS_DESC].s = "source and sink data",
[USB_GZERO_LB_DESC].s = "loop input to output",
{ } /* end of list */
};
static struct usb_gadget_strings stringtab_dev = {
.language = 0x0409, /* en-us */
.strings = strings_dev,
};
static struct usb_gadget_strings *dev_strings[] = {
&stringtab_dev,
NULL,
};

static int zero_bind(struct usb_composite_dev *cdev){}
static int zero_unbind(struct usb_composite_dev *cdev){}
static void zero_suspend(struct usb_composite_dev *cdev){}
static void zero_resume(struct usb_composite_dev *cdev){}

static struct usb_composite_driver zero_driver = {
.name = "zero",
.dev = &device_desc,
.strings = dev_strings,
.max_speed = USB_SPEED_SUPER,
.bind = zero_bind,
.unbind = zero_unbind,
.suspend = zero_suspend,
.resume = zero_resume,
};
module_usb_composite_driver(zero_driver);

1.1 USB复合设备结构体 struct usb_composite_driver

在 ​​usb_composite_driver​​ 中需要重点关注的是 bind 回调函数,

设备控制器驱动会调用的​​usb_gadget_driver​​中的​​bind()​​函字符串截取数,把​​usb_gadget​​数据结构及其服务回传到​​Gadget​​设备层;

有关函数详细的功能 ,此处先不关注,我们后续分析代码流程时自然知道了。

# kernel/include/linux/usb/composite.h

/**
* struct usb_composite_driver - groups configurations into a gadget
* @name: For diagnostics, identifies the driver.
* @dev: Template descriptor for the device, including default device identifiers.
* @strings: tables of strings, keyed by identifiers assigned during @bind
* and language IDs provided in control requests. Note: The first entries
* are predefined. The first entry that may be used is USB_GADGET_FIRST_AVAIL_IDX
* @max_speed: Highest speed the driver supports.
* @needs_serial: set to 1 if the gadget needs userspace to provide
* a serial number. If one is not provided, warning will be printed.
* @bind: (REQUIRED) Used to allocate resources that are shared across the
* whole device, such as string IDs, and add its configurations using
* @usb_add_config(). This may fail by returning a negative errno
* value; it should return zero on successful initialization.
* @unbind: Reverses @bind; called as a side effect of unregistering this driver.
* @disconnect: optional driver disconnect method
* @suspend: Notifies when the host stops sending USB traffic,after function notifications
* @resume: Notifies configuration when the host restarts USB traffic, before function notifications
* @gadget_driver: Gadget driver controlling this driver
*
* Devices default to reporting self powered operation. Devices which rely
* on bus powered operation should report this in their @bind method.
*
* Before returning from @bind, various fields in the template descriptor
* may be overridden. These include the idVendor/idProduct/bcdDevice values
* normally to bind the appropriate host side driver, and the three strings
* (iManufacturer, iProduct, iSerialNumber) normally used to provide user
* meaningful device identifiers. (The strings will not be defined unless
* they are defined in @dev and @strings.) The correct ep0 maxpacket size
* is also reported, as defined by the underlying controller driver.
*/
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);
int (*unbind)(struct usb_composite_dev *);
void (*disconnect)(struct usb_composite_dev *);
void (*suspend)(struct usb_composite_dev *);
void (*resume)(struct usb_composite_dev *);
struct usb_gadget_driver gadget_driver;
};

1.2 USB设备defines描述符结构体 struct usb_device_descriptor

​usb_device_descriptor​​结构体定义如下:

# kernel/include/uapi/linux/usb/ch9.h
/* USB_DT_DEVICE: Device descriptor */
struct usb_device_descriptor {
__u8 bLength; // 该描述符结构体大小(18字节)
__u8 bDescriptorType; // 描述符类型(本结构体中固定为0x01)

__le16 bcdUSB; // USB版本号
__u8 bDeviceClass; // 设备类代码(由USB官方分配)
__u8 bDeviceSubClass; // 子类代码(由USB官方分配)
__u8 bDeviceProtocol; // 设备协议代码(由USB官方分配)
__u8 bMaxPacketSize0; // 端点0的最大包大小(有效大小为8,16,32,64)
__le16 idVendor; // 生产厂商编号(由USB官方分配)
__le16 idProduct; // 产品编号(制造厂商分配)
__le16 bcdDevice; // 设备出厂的编号
__u8 iManufacturer; // 设备厂商字符串索引
__u8 iProduct; // 产品描述字符串索引
__u8 iSerialNumber; // 设备序列号字符串索引
__u8 bNumConfigurations; // 当前速度下能支持的配置数量, 对应着 struct usb_configuration
} __attribute__ ((packed));

结合结构体定义,我们再来看下zero.c中的 device_desc都是怎么配置的字符串类型

static struct usb_device_descriptor device_desc = {
.bLength = sizeof device_desc, // device_desc 结构体的大小
.bDescriptorType = USB_DT_DEVICE, // 描述符类型编号:0x01, 定义在 kernel/include/uapi/linux/usb/ch9.h 中
.bcdUSB = cpu_to_le16(0x0200), // USB版本号: 0x0200 ,对应着USB2.0
.bDeviceClass = USB_CLASS_VENDOR_SPEC, // 设备类版本号:0xff
.idVendor = cpu_to_le16(DRIVER_VENDOR_NUM), // 厂商编号: 0x0525
.idProduct = cpu_to_le16(DRIVER_PRODUCT_NUM),// 产品编号: 0xa4a0
.bNumConfigurations = 2, // 配置数量:2
};

(1) 描述符类型编号 bDescriptorType

代码中​​bDescriptorType​​​ 定义在 ​​kernel/includlinux是什么操作系统e/uapi/liusb摄像头nux/usb/ch9.h​​ 中,如下linux是什么操作系统

/* Descriptor types ... USB 2.0 spec table 9.5*/
#define USB_DT_DEVICE 0x01 // 设备
#define USB_DT_CONFIG 0x02 // 配置
#define USB_DT_STRING 0x03 // 字符串
#define USB_DT_INTERFACE 0x04 // 接口
#define USB_DT_ENDPOINT 0x05 // 端点
#define USB_DT_DEVICE_QUALIFIER 0x06
#define USB_DT_OTHER_SPEED_CONFIG 0x07
#define USB_DT_INTERFACE_POWER 0x08 // 供电
/* these are from a minor usb 2.0 revision (ECN) */
#define USB_DT_OTG 0x09 // OTG
#define USB_DT_DEBUG 0x0a
#define USB_DT_INTERFACE_ASSOCIATION 0x0b // AOA
/* these are from the Wireless USB spec */
#define USB_DT_SECURITY 0x0c
#define USB_DT_KEY 0x0d
#define USB_DT_ENCRYPTION_TYPE 0x0e
#define USB_DT_BOS 0x0f
#define USB_DT_DEVICE_CAPABILITY 0x10
#define USB_DT_WIRELESS_ENDPOINT_COMP 0x11
#define USB_DT_WIRE_ADAPTER 0x21
#define USB_DT_RPIPE 0x22
#define USB_DT_CS_RADIO_CONTROL 0x23
/* From the T10 UAS specification */
#define USB_DT_PIPE_USAGE 0x24
/* From the USB 3.0 spec */
#define USB_DT_SS_ENDPOINT_COMP 0x30

/* Conventional codes for class-specific descriptors. The convention is
* defined in the USB "Common Class" Spec (3.11). Individual class specs
* are authoritative for their usage, not the "common class" writeup.
*/
#define USB_DT_CS_DEVICE (USB_TYPE_CLASS | USB_DT_DEVICE)
#define USB_DT_CS_CONFIG (USB_TYPE_CLASS | USB_DT_CONFIG)
#define USB_DT_CS_STRING (USB_TYPE_CLASS | USB_DT_STRING)
#define USB_DT_CS_INTERFACE (USB_TYPE_CLASS | USB_DT_INTERFACE)
#define USB_DT_CS_ENDPOINT (USB_TYPE_CLASS | USB_DT_ENDPOINT)

有关​​bDescriptorType​​ 的类型编号,在代码中出usb3.0传输速度注释了​​USB2.0 Spe字符串类型c Table 9.5​​,那我们就找到Spec来瞧瞧。

USB2.0 Spec下载地址:《​​USB 2.0 Specification​​》《​​usb_20_20210701.zip​​》

在​​uusb接口sb_20_20210701/usb_20.pdf​​ 文档define在c语言中是什么意思第251页:​​Table 9defined在python中是什么意思-5. Descriptor Types​​ 中定义了:

不过文档中也没有对些有详细解释,因些,我在前面代码中添加了我自已的理解


                                            【Linux USB子系统 - 01】Legacy 类设备功能驱动层 - 代码流程分析

其他的Spec我就不一一看了,估计也没有详细解释。

(2)usb摄像头安卓下载 设备类型编号 bDeviceClass

各设备类型所对应的功字符串反转能均以注释的方式写在下面代码中了,就不缀述了:

/* Device and/or Interface Class codes
* as found in bDeviceClass or bInterfaceClass
* and defined by www.usb.org documents */
#define USB_CLASS_PER_INTERFACE 0 /* for DeviceClass */
#define USB_CLASS_AUDIO 1 // 音频类
#define USB_CLASS_COMM 2 // 通信类
#define USB_CLASS_HID 3 // 人机接口类
#define USB_CLASS_PHYSICAL 5 // 物理类
#define USB_CLASS_STILL_IMAGE 6 // 图像类
#define USB_CLASS_PRINTER 7 // 打印机类
#define USB_CLASS_MASS_STORAGE 8 // 大数据存储类
#define USB_CLASS_HUB 9 // 集线器类
#define USB_CLASS_CDC_DATA 0x0a // CDC数据类
#define USB_CLASS_CSCID 0x0b // 智能卡类 /* chip+ smart card */
#define USB_CLASS_CONTENT_SEC 0x0d // 定全类 /* content security */
#define USB_CLASS_VIDEO 0x0e // 诊断设备类
#define USB_CLASS_WIRELESS_CONTROLLER 0xe0 // 无线控制器类
#define USB_CLASS_MISC 0xef // 混杂设备类
#define USB_CLASS_APP_SPEC 0xfe // 特定应用类(包含线外的桥接器等)
#define USB_CLASS_VENDOR_SPEC 0xff // 厂商定义的设备
#define USB_SUBCLASS_VENDOR_SPEC 0xff

1.3 字符串结构define在c语言中是什么意思体 struct usb_gadget_strings

在 ​​usdefine用法b_gadget_strings​​​ 中,主要存储的是USB中所需要的字符串信息,​​usb_string​linux​ 可以理解为一个大的字符串数结构字符串怎么定义体。

static const char longname[] = "Gadget Zero";
static char serial[] = "0123456789.0123456789.0123456789";
#define USB_GZERO_SS_DESC (USB_GADGET_FIRST_AVAIL_IDX + 0)
#define USB_GZERO_LB_DESC (USB_GADGET_FIRST_AVAIL_IDX + 1)

static struct usb_string strings_dev[] = {
[USB_GADGET_MANUFACTURER_IDX].s = "",
[USB_GADGET_PRODUCT_IDX].s = longname,
[USB_GADGET_SERIAL_IDX].s = serial,
[USB_GZERO_SS_DESC].s = "source and sink data",
[USB_GZERO_LB_DESC].s = "loop input to output",
{ } /* end of list */
};
static struct usb_gadget_strings stringtab_dev = {
.language = 0x0409, /* en-us */
.strings = strings_dev,
};
static struct usb_gadget_strings *dev_strings[] = {
&stringtab_dev,
NULL,
};

字符串索引定主义如下:

# include/linux/usb/composite.h
/* predefined index for usb_composite_driver */
enum {
USB_GADGET_MANUFACTURER_IDX = 0,
USB_GADGET_PRODUCT_IDX,
USB_GADGET_SERIAL_IDX,
USB_GADGET_FIRST_AVAIL_IDX,
};

二、Legacy 函数分析系统运维面试题及答案

分析完上面的结构体,其实就很好理解了,在Legacy 类设备功能驱动层中,其核心就是​​struct usb_composidefinex是什么牌子te_driver​​ 这个结构体。

static struct usb_composite_driver zero_driver = {
.name = "zero",
.dev = &device_desc,
.strings = dev_strings,
.max_speed = USB_SPEED_SUPER,
.bind = zero_bind,
.unbind = zero_unbind,
.suspend = zero_suspend,
.resume = zero_resume,
};

当有子设备要加入这个 类设备中时,就会使用​​device_desc​​中定义好的设备描述符,其中定义了PID/VID等信息,USB版本号,USB能够使用的配置等信息。

同时设备工作时,调用的是 ​​bind、unbind、suspend、resume​​中定义的这几个方法linux创建文件linux

这就很好defined在python中是什么意思理解了。

接下来,我们来看下 Legacy中通用的​​bind、unbind、suspend、resume​​这些方法的实现

注意,此处我们分析的是​​zero.c​​中的函数方法,其他类的(如​​CDC,NCM​​等)各自函数实现可能会有所不同。

2.1 注册驱动 molinux常用命令dule字符串长度_usb_composite_dridefine用法ver(zero_driver)

向USB子系统,注册zero_drdefine在c语言中的用法iver composite driver设备。

# kernel/include/linux/usb/composite.h
/**
* module_usb_composite_driver() - Helper macro for registering a USB gadget
* composite driver
* @__usb_composite_driver: usb_composite_driver struct
*
* Helper macro for USB gadget composite drivers which do not do anything
* special in module init/exit. This eliminates a lot of boilerplate. Each
* module may only use this macro once, and calling it replaces module_init()
* and module_exit()
*/
#define module_usb_composite_driver(__usb_composite_driver) \
module_driver(__usb_composite_driver, usb_composite_probe, \
usb_composite_unregister)
# kernel/include/linux/device.h
#define module_driver(__driver, __register, __unregister, ...) \
static int __init __driver##_init(void) \
{ \
return __register(&(__driver) , ##__VA_ARGS__); \
} \
module_init(__driver##_init); \
static void __exit __driver##_exit(void) \
{ \
__unregister(&(__driver) , ##__VA_ARGS__); \
} \
module_exit(__driver##_exit);

可以看出通过 ​​module_usb_composite_driver(zlinux系统安装ero_driver)​​​ 函数系统运维工资一般多少,直接调用 ​​usb_composi系统运维工程师t字符串反转e_probe()​​​函数,传参 ​​&系统运维工程师面试问题及答案zero系统运维工程师_driver​​.

2.2 探测函数初始化 usb_composite_probe(&zero_driver)

其函数运行过字符串是什么意思程为:

  1. 如果未指定​​driver->name​​​, 则默认配置为​​composite​​​,此处我们配置过了为​​zer字符串逆序输出o​
  2. 将​​driver​​​ 中系统运维工作内容的​usb接口接线图​gadge字符串怎么定义t_driver​​​ 赋予通用的结构体:​​struct usb_gadget_driver composidefineste_driver_template​
  3. 配置 ​​gadget_driver​​​ 通用结构体中的 ​​name​
  4. 使用默认结构体进行​​probe​​初始化
# kernel/drivers/usb/gadget/composite.c
int usb_composite_probe(struct usb_composite_driver *driver)
{
struct usb_gadget_driver *gadget_driver;
// 1. 如果未指定driver->name, 则默认配置为composite,此处我们配置过了为zero
if (!driver->name)
driver->name = "composite";
// 2. 将driver 中的gadget_driver 予通用的结构体:struct usb_gadget_driver composite_driver_template
driver->gadget_driver = composite_driver_template; // 定义在 ./drivers/usb/gadget/composite.c +2203中
gadget_driver = &driver->gadget_driver;

// 3. 配置 gadget_driver 通用结构体中的 name
gadget_driver->function = (char *) driver->name;
gadget_driver->driver.name = driver->name;
gadget_driver->max_speed = driver->max_speed;

// 4. 使用默认结构体进行probe初始化
return usb_gadget_probe_driver(gadget_driver);
-------------------> // # ./drivers/usb/gadget/udc/core.c +1262
list_for_each_entry(udc, &udc_list, list) {
/* For now we take the first one */
if (!udc->driver)
goto found;
}
ret = udc_bind_to_driver(udc, driver);
==============> //# ./drivers/usb/gadget/udc/core.c +1202
+ dev_dbg(&udc->dev, "registering UDC driver [%s]\n",
+ driver->function);
+
+ udc->driver = driver;
+ udc->dev.driver = &driver->driver;
+ udc->gadget->dev.driver = &driver->driver;

+ ret = driver->bind(udc->gadget, driver);
+ ret = usb_gadget_udc_start(udc);
+ usb_udc_connect_control(udc);

+ kobject_uevent(&udc->dev.kobj, KOBJ_CHANGE);
+ return 0;
<==============
<-------------------
}
EXPORT_SYMBOL_GPL(usb_composite_probe);

2.3 bi字符串类型nd() 函数分析

bind函数,在代码中注释如下字符串:

* @bind: (REQUIRED) Used to allocate resources that are shared across the
* whole device, such as string IDs, and add its configurations using @usb_add_config().
* This may fail by returning a negative errno value; it should return zero on successful initialization.

我们来看下它的具体代码,实现步骤如下:

  1. 统计​​struct uslinux删除文件命令b_string strings_dev[]​​​字符串结构体中字符串的数量,保存在 ​​cdev->next_string_id​​中
  2. 创建定时器,函数对应​​zero_autoresume()​​​,传入的私有数据​​cdev​
  3. 寻找并获取​​name=SourceSink​​​的​​usdefine在c语言中是什么意思b function​​​的​​source_sink_alloc_inst()​​​ 函数,函define翻译数指什保存在​​func_inst_ss​​ 中
  4. 通过函数​​func_inst_ss​​​ 找到​​SourceSink​​​ 对应的 ​​struct f_ss_opts*​​ 结构体。
  5. 获取 ​​SourceSink​​​ 的 ​​static struct usb_function *​linux是什么操作系统​结构体保存在​​func_ss​​中
  6. usb-c找并获取​​name=Loopback​define()​​的​​usb function​​​的​​loopblinux系统ack_alloc()​​​ 函数,函数指什保存在​​func_inst_lb​​ 中
  7. 通过函数​​func_inst_lb​​​找define在c语言中的用法到​​Loopback​​​对应的 ​​struct f_ss_opts*​​ 结构体
  8. 获取 ​​Loopback​​​的 ​​static struct usb_function *​​​结构体保存在​​func_lb​​ 中
  9. 如果支持​​autoreusb是什么sume​​​,则配置​​sourcesink_driver​​​ 和 ​​loopdefinesback_driver​​​的​​bmAttributes​​ 支持自动唤醒
  10. 判断是否是​​OTG​​​设备,如果是,配置​​sourcesink_driver​​​ 和 ​​loopback_driver​​​的​​bmAttributes​​ 支持自动唤醒
  11. 添加​linux必学的60个命令​sourcesink_driver​​​ 和 ​​l字符串怎么定义oopback_driver​​ 配置,注意顺序
  12. 添加​系统运维面试题及答案​sourcesusb是什么ink usb function​​​功能,​​usb_configuration​​​配置信息为:​​sourcesink_driver​​​, ​​usb_function​​​结构体为​​func_sslinux
  13. 添加​​loopback usb function​​​功能,​​usb_conflinux操作系统基础知识iguration​​​配置信息为:​​loopback_driver​​​, ​​usb_function​​​结构体为​​func_lb​
  14. 判断是否需要更新 ​​PID/VID/Strings​​​等配置信息,​​coverwrite​​​ 定义在​​include/linux/usb/composite.h +linux是什么操作系统534​​,在文件系统中会以节点的形式供动态修改
static int zero_bind(struct usb_composite_dev *cdev)
{
// 1. 统计struct usb_string strings_dev[]字符串结构体中字符串的数量,保存在 cdev->next_string_id中。
/* Allocate string descriptor numbers ... note that string contents can be overridden by the composite_dev glue.*/
status = usb_string_ids_tab(cdev, strings_dev);

// strings_dev 中的 id是自动分配的,分别是1,2,3
device_desc.iManufacturer = strings_dev[USB_GADGET_MANUFACTURER_IDX].id; // 0
device_desc.iProduct = strings_dev[USB_GADGET_PRODUCT_IDX].id; // 1
device_desc.iSerialNumber = strings_dev[USB_GADGET_SERIAL_IDX].id; // 2

// 2. 创建定时器,函数对应zero_autoresume(),传入的私有数据cdev
setup_timer(&autoresume_timer, zero_autoresume, (unsigned long) cdev);

// 3. 寻找并获取name=SourceSink的usb function的source_sink_alloc_inst() 函数,函数指什保存在func_inst_ss 中
func_inst_ss = usb_get_function_instance("SourceSink");
// 其定义在 kernel/drivers/usb/gadget/function/f_sourcesink.c
// DECLARE_USB_FUNCTION(SourceSink, source_sink_alloc_inst, source_sink_alloc_func);

// 4. 通过函数func_inst_ss 找到SourceSink 对应的 struct f_ss_opts* 结构体
ss_opts = container_of(func_inst_ss, struct f_ss_opts, func_inst);
ss_opts->pattern = gzero_options.pattern;
ss_opts->isoc_interval = gzero_options.isoc_interval; // #define GZERO_ISOC_INTERVAL 4
ss_opts->isoc_maxpacket = gzero_options.isoc_maxpacket; // #define GZERO_ISOC_MAXPACKET 1024
ss_opts->isoc_mult = gzero_options.isoc_mult;
ss_opts->isoc_maxburst = gzero_options.isoc_maxburst;
ss_opts->bulk_buflen = gzero_options.bulk_buflen;

// 5. 获取 SourceSink 的 static struct usb_function *结构体保存在func_ss中
func_ss = usb_get_function(func_inst_ss);

// 6. 寻找并获取name=Loopback的usb function的loopback_alloc() 函数,函数指什保存在func_inst_lb 中
func_inst_lb = usb_get_function_instance("Loopback");
// 定义在 kernel/drivers/usb/gadget/function/f_loopback.c 中
// DECLARE_USB_FUNCTION(Loopback, loopback_alloc_instance, loopback_alloc);

// 7. 通过函数func_inst_lb找到Loopback对应的 struct f_ss_opts* 结构体
lb_opts = container_of(func_inst_lb, struct f_lb_opts, func_inst);
lb_opts->bulk_buflen = gzero_options.bulk_buflen;
lb_opts->qlen = gzero_options.qlen;

// 8. 获取 Loopback的 static struct usb_function *结构体保存在func_lb 中
func_lb = usb_get_function(func_inst_lb);

sourcesink_driver.iConfiguration = strings_dev[USB_GZERO_SS_DESC].id;
loopback_driver.iConfiguration = strings_dev[USB_GZERO_LB_DESC].id;

// 9. 如果支持autoresume,则配置sourcesink_driver 和 loopback_driver的bmAttributes 支持自动唤醒
/* support autoresume for remote wakeup testing */
sourcesink_driver.bmAttributes &= ~USB_CONFIG_ATT_WAKEUP;
loopback_driver.bmAttributes &= ~USB_CONFIG_ATT_WAKEUP;
sourcesink_driver.descriptors = NULL;
loopback_driver.descriptors = NULL;
if (autoresume) {
sourcesink_driver.bmAttributes |= USB_CONFIG_ATT_WAKEUP;
loopback_driver.bmAttributes |= USB_CONFIG_ATT_WAKEUP;
autoresume_step_ms = autoresume * 1000;
}
// 10. 判断是否是OTG设备,如果是,配置sourcesink_driver 和 loopback_driver的bmAttributes 支持自动唤醒
/* support OTG systems */
if (gadget_is_otg(cdev->gadget)) {
if (!otg_desc[0]) {
struct usb_descriptor_header *usb_desc;

usb_desc = usb_otg_descriptor_alloc(cdev->gadget);
if (!usb_desc) {
status = -ENOMEM;
goto err_conf_flb;
}
usb_otg_descriptor_init(cdev->gadget, usb_desc);
otg_desc[0] = usb_desc;
otg_desc[1] = NULL;
}
sourcesink_driver.descriptors = otg_desc;
sourcesink_driver.bmAttributes |= USB_CONFIG_ATT_WAKEUP;
loopback_driver.descriptors = otg_desc;
loopback_driver.bmAttributes |= USB_CONFIG_ATT_WAKEUP;
}

// 11. 添加sourcesink_driver 和 loopback_driver 配置,注意顺序
/* Register primary, then secondary configuration. Note that
* SH3 only allows one config... */
if (loopdefault) {
usb_add_config_only(cdev, &loopback_driver);
usb_add_config_only(cdev, &sourcesink_driver);
} else {
usb_add_config_only(cdev, &sourcesink_driver);
usb_add_config_only(cdev, &loopback_driver);
}
// 12. 添加sourcesink usb function功能,usb_configuration配置信息为:sourcesink_driver, usb_function结构体为func_ss
status = usb_add_function(&sourcesink_driver, func_ss);
usb_ep_autoconfig_reset(cdev->gadget);

// 13. 添加loopback usb function功能,usb_configuration配置信息为:loopback_driver, usb_function结构体为func_lb
status = usb_add_function(&loopback_driver, func_lb);
usb_ep_autoconfig_reset(cdev->gadget);
// 14. 判断是否需要更新 PID/VID/Strings等配置信息,coverwrite 定义在include/linux/usb/composite.h +534,在文件系统中会以节点的形式供动态修改
usb_composite_overwrite_options(cdev, &coverwrite);

INFO(cdev, "%s, version: " DRIVER_VERSION "\n", longname);
return 0;
}

(1)DECLARE_USB_FUlinuxNCTION()

可以看出,通过 ​​DECLARE_USB_FUNCTION​​​ 和 ​​DECLARE_USB_define什么意思FUNCTION_INIT​​​ 分别能够自动字符串长度构建一个 ​​struct usb_function_driver​​​ 结构体和添加一个​​module​​模块

# kernel/include/linux/usb/composite.h

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

而前面代码中的​​SourceSink​​​ 这个​​usb function​​就linux创建文件是通过这种方式添加的,定义如下:

DECLARE_USB_FUNCTION(SourceSink, source_sink_alloc_inst, source_sink_alloc_func);

static struct usb_function *source_sink_alloc_func(struct usb_function_instance *fi)
{
struct f_sourcesink *ss;
struct f_ss_opts *ss_opts;

ss = kzalloc(sizeof(*ss), GFP_KERNEL);
if (!ss)
return ERR_PTR(-ENOMEM);

ss_opts = container_of(fi, struct f_ss_opts, func_inst);

mutex_lock(&ss_opts->lock);
ss_opts->refcnt++;
mutex_unlock(&ss_opts->lock);

ss->pattern = ss_opts->pattern;
ss->isoc_interval = ss_opts->isoc_interval;
ss->isoc_maxpacket = ss_opts->isoc_maxpacket;
ss->isoc_mult = ss_opts->isoc_mult;
ss->isoc_maxburst = ss_opts->isoc_maxburst;
ss->buflen = ss_opts->bulk_buflen;

ss->function.name = "source/sink";
ss->function.bind = sourcesink_bind;
ss->function.set_alt = sourcesink_set_alt;
ss->function.get_alt = sourcesink_get_alt;
ss->function.disable = sourcesink_disable;
ss->function.setup = sourcesink_setup;
ss->function.strings = sourcesink_strings;

ss->function.free_func = sourcesink_free_func;

return &ss->function;
}

static struct usb_function_instance *source_sink_alloc_inst(void)
{
struct f_ss_opts *ss_opts;

ss_opts = kzalloc(sizeof(*ss_opts), GFP_KERNEL);
if (!ss_opts)
return ERR_PTR(-ENOMEM);
mutex_init(&ss_opts->lock);
ss_opts->func_inst.free_func_inst = source_sink_free_instance;
ss_opts->isoc_interval = GZERO_ISOC_INTERVAL;
ss_opts->isoc_maxpacket = GZERO_ISOC_MAXPACKET;
ss_opts->bulk_buflen = GZERO_BULK_BUFLEN;

config_group_init_type_name(&ss_opts->func_inst.group, "",
&ss_func_type);

return &ss_opts->func_inst;
}

通过这个宏控,等同于实现了如下代码:

static struct usb_function_driver SourceSinkusb_func = {
.name = __stringify(SourceSink),
.mod = THIS_MODULE,
.alloc_inst = source_sink_alloc_inst,
.alloc_func = source_sink_alloc_func,
};

2.define翻译4 unbind() 函数分析

static int zero_unbind(struct usb_composite_dev *cdev)
{
del_timer_sync(&autoresume_timer);
if (!IS_ERR_OR_NULL(func_ss))
usb_put_function(func_ss);
usb_put_function_instance(func_inst_ss);
if (!IS_ERR_OR_NULL(func_lb))
usb_put_function(func_lb);
usb_put_function_instance(func_inst_lb);
kfree(otg_desc[0]);
otg_desc[0] = NULL;

return 0;
}

2.5 suspend() 函define用法数分析

static void zero_suspend(struct usb_composite_dev *cdev)
{
if (cdev->gadget->speed == USB_SPEED_UNKNOWN)
return;

if (autoresume) {
if (max_autoresume &&
(autoresume_step_ms > max_autoresume * 1000))
autoresume_step_ms = autoresume * 1000;

mod_timer(&autoresume_timer, jiffies +
msecs_to_jiffies(autoresume_step_ms));
DBG(cdev, "suspend, wakeup in %d milliseconds\n",
autoresume_step_ms);

autoresume_step_ms += autoresume_interval_ms;
} else
DBG(cdev, "%s\n", __func__);
}

2.6 resume() 函数分析

static void zero_resume(struct usb_composite_dev *cdev)
{
DBG(cdev, "%s\n", __func__);
del_timer(&autoresume_timer);
}

参考:

《​​一文搞懂 USB 设备端驱动框架​​》

《​​USB的usb3.0传输速度描述符详解总结​​》usb接口接线图

《​​USB 设备驱动开发之几个重要结构体分析​​》

《​​USB设备的各define用法种描述符​​》