编写Linux下usb设备驱动方法:probe函数中要进行的工作

一. 简介

前一篇文章简单学习了 Linux下usb设备驱动实现流程,文章如下:

编写Linux下usb设备驱动方法:usb设备驱动实现流程-CSDN博客

本文来学习一下 usb设备驱动的 probe函数要完成的任务。

当usb主控制器检测到设备与 驱动相匹配时,就会执行usb的 probe函数。

二. 编写Linux下usb设备驱动的方法:probe函数中要进行的工作

当 USB主控制器驱动发现一个设备与你的 id_table 匹配时,probe函数就会执行。probe函数的主要任务:

(1) 验证设备基本信息(合法性检查)

在进行资源分配前,需先确认设备的硬件特性是否符合驱动预期,避免对不兼容设备进行错误初始化:

  • 检查设备描述符:验证设备的接口数量、端点类型、传输能力等是否与驱动支持的范围匹配(例如驱动只支持中断端点,需检查设备是否存在中断端点)。
  • 确认端点参数:通过 usb_interface 的 cur_altsetting 成员获取当前接口的端点描述符,检查端点地址、最大包长(wMaxPacketSize)、中断间隔(bInterval)等是否符合驱动设计(例如确保缓冲区大小不超过端点最大包长)。
  • 检查设备版本 / 功能:对于复杂设备(如带多个配置的 USB 设备),可能需要验证设备固件版本、支持的功能集等。
(2) 分配与初始化驱动私有数据结构: 使用 kzallocdevm_kzalloc
  • 分配私有数据内存:使用 kzalloc分配内存(确保初始化为 0,避免野指针)。
  • 关联核心对象:将 usb_device、usb_interface等核心结构体指针存入私有数据(需通过 usb_get_dev 增加设备引用计数,确保设备不被意外释放)。
  • 初始化关键成员 :如数据传输缓冲区大小、URB 指针初始化为 NULL 等。
(3) 初始化数据传输机制(URB 准备)

USB 设备的核心功能是数据传输,probe函数需为传输准备好 URB(USB Request Block,USB 请求块)------ 内核中 USB 传输的 "载体":

  • 分配 URB:通过 usb_alloc_urb 分配与端点类型匹配的 URB(如中断端点用 usb_alloc_urb(0, ...),等时端点需指定 iso 包数量)。
  • 填充 URB:根据端点类型调用对应的填充函数(如中断端点用 usb_fill_int_urb,批量端点用 usb_fill_bulk_urb ),设置传输方向、缓冲区、完成回调函数等。
  • 关联 URB 与私有数据:将私有数据设为 URB 的 context,便于回调函数中访问设备资源。

usb四种传输类型中,控制传输和批量传输,可以不用进行URB传输块的分配,填充,关联等刚工作。可以使用 usb内核提供的函数接口进行传输:

控制传输可以使用 usb_control_msg()函数 进行传输,批量传输可以使用 usb_bulk_msg() 函数进行传输(在使用 usb_control_msg()函数或 usb_bulk_msg()函数进行 USB 控制传输时,USB 内核已经封装了 URB(USB Request Block)的分配、填充、提交和释放等底层工作,开发者无需手动操作 URB 结构)。

(4) 注册用户空间接口(可选)

若驱动需要与用户空间程序交互(如通过 ioctl 发送命令、读写数据),probe 函数需注册字符设备、sysfs 节点或其他接口:

**字符设备注册:**通过 cdev_init、cdev_add 注册字符设备,关联文件操作结构体(file_operations),让用户空间可通过 /dev/xxx 访问。

**sysfs 节点创建:**通过 sysfs_create_group 等函数创建属性文件,暴露设备状态或配置参数(如 echo 1 > /sys/class/myusb/enable 开启设备)。

(5) 启动数据传输(可选)

对于需要 "设备插入后立即开始工作" 的场景(如传感器设备周期性上报数据),probe函数可在初始化完成后直接提交 URB,启动首次数据传输: