一. 简介
在 Linux 嵌入式开发中,USB 设备驱动的实现需要遵循 Linux 内核的 USB 子系统框架。USB 驱动通常分为USB 主机端驱动 (Host Driver)和USB 设备端驱动(Device Driver),这里主要学习实现 usb设备驱动框架。
前面几篇文章简单学习了 Linux下usb设备驱动相关的内容。本文开始用示例代码实现一个简单 usb设备驱动框架。
二. Linux下usb设备驱动实现方法
当usb设备驱动注册到内核后,内核的 USB 核心(USB Core)会负责处理底层的 USB 协议、总线枚举、设备发现等复杂工作。当有匹配的设备插入时,USB Core 会通知你的驱动,然后你的驱动再处理与该设备特定的数据交互。
1. usb设备驱动注册与注销
使用 module_init 和module_exit 进行驱动的加载和卸载,核心是注册 usb_gadget_driver结构体。分别调用usb_register_driver()函数
和usb_deregister()
函数。
2. 描述符定义,端点配置
定义设备的各种描述符,包括设备描述符、配置描述符、接口描述符和端点描述符等,用于向上位机描述设备能力。
根据设备功能需求配置 USB 端点(Endpoint),包括控制端点、批量端点、中断端点等。
3. usb设备匹配与绑定(probe函数实现)
当 USB 设备插入并枚举完成后,内核会根据设备的 ID 信息(如厂商 ID、产品 ID)或设备树 compatible 属性,匹配对应的 usb_driver。
匹配成功后,调用驱动的 probe 函数,完成设备初始化(如申请资源、注册字符设备、初始化端点等)。
4. 数据传输
通过 Gadget API 实现与主机的数据收发,通常使用usb_request
结构。
5. 设备卸载(disconnect函数实现)
当设备拔出或驱动卸载时,内核调用 disconnect 函数,释放 probe函数中申请的资源(如内存、中断、字符设备等)。
6. 提供与用户空间交互的接口函数
例如,实现一套字符设备框架代码(提供用户空间可访问设备的接口,open,read,write,ioctrl,close函数等)。
三. Linux下usb设备驱动框架示例
USB 驱动本质是内核模块,通过usb_driver 结构体定义驱动行为。并通过usb_register()注册到内
核。
1. 定义usb设备私有数据结构体
usb设备私有数据结构,存储设备相关信息:
//定义usb私有数据结构(存储于设备相关信息)
struct usb_dev {
struct usb_device *udev; //usb设备指针
struct usb_interface *intf;//接口指针
struct urb *read_urb; //URB传输块
unsigned char *read_buf; //读缓冲区
size_t read_buf_size; //缓冲区大小
__u8 bulk_in_endpointAddr;//批量输入端点地址
__u8 bulk_out_endpointAddr;//批量输出端点地址
};
2. 填充 struct usb_driver结构体成员
填充struct usb_driver结构体中的成员,包括设备 id 表,probe函数,disconnect函数:
static struct usb_device_id my_id_table[] = {
{USB_DEVICE(0x1234, 0x0a0b)}, //支持VID=0x1234,PID=0x0a0b的设备
{} //终止条目(必须存在)
};
static struct usb_driver my_usb_driver = {
.name = "usb_dev", //驱动名称,必须是唯一的
.probe = my_usb_probe,//当设备插入且匹配时调用
.disconnect = my_usb_disconnect,//当设备拔出时调用
.id_table = my_id_table, //该驱动支持那些设备
};
//告诉内核这个驱动支持这些设备
//当新的USB设备插入系统时,内核可以通过该表进行驱动匹配
MODULE_DEVICE_TABLE(usb, my_id_table);
可以看出,struct usb_driver结构体中 id_table成员用于进行 usb驱动与设备进行匹配使用的。
probe函数是当驱动与设备匹配成功后,会运行的接口。
disconnect函数是当设备被拔出时会被调用到的接口。