从零开始:Linux USB 驱动开发详细实战步骤
适用于:Linux 内核 >= 5.x,支持 USB host 的 x86 / ARM 设备,适配 USB 通用 HID/批量传输设备。
实战目标:编写一个可识别 USB 设备并与其通信的 Linux 驱动模块。
一、基础准备
1. 环境依赖
- Ubuntu / Debian / CentOS 等主流 Linux 系统
- 已安装内核开发工具包(linux-headers-$(uname -r))
- 编译工具链:gcc、make
- 支持 USB 的目标设备或虚拟机
- 一个 USB 设备(如 U 盘、HID 外设等)
2. 关键知识
- USB 协议基础(HID / bulk / interrupt / control)
- Linux 驱动开发框架:模块加载、热插拔机制
- 内核 API:usb_register_driver()、usb_alloc_urb() 等
二、驱动架构理解
Linux 中的 USB 驱动基于 usb_driver 结构进行注册,使用 probe() 与 disconnect() 处理设备插拔。
struct usb_driver {
const char *name;
int (*probe)(struct usb_interface *, const struct usb_device_id *);
void (*disconnect)(struct usb_interface *);
const struct usb_device_id *id_table;
struct device_driver driver;
};
三、实战开发:编写 USB 驱动
1. 创建驱动目录与 Makefile
mkdir usb_driver_demo && cd usb_driver_demo
touch usb_drv.c Makefile
Makefile 内容:
obj-m += usb_drv.o
KDIR := /lib/modules/$(shell uname -r)/build
PWD := $(shell pwd)
all:
make -C $(KDIR) M=$(PWD) modules
clean:
make -C $(KDIR) M=$(PWD) clean
2. 编写驱动源码(usb_drv.c)
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/usb.h>
#define USB_VENDOR_ID 0xXXXX // 替换为你的设备 VID
#define USB_PRODUCT_ID 0xYYYY // 替换为你的设备 PID
static struct usb_device_id usb_table[] = {
{ USB_DEVICE(USB_VENDOR_ID, USB_PRODUCT_ID) },
{} // 终止
};
MODULE_DEVICE_TABLE(usb, usb_table);
static int usb_drv_probe(struct usb_interface *interface,
const struct usb_device_id *id)
{
printk(KERN_INFO "[USB_DRV] USB device plugged in.\n");
return 0;
}
static void usb_drv_disconnect(struct usb_interface *interface)
{
printk(KERN_INFO "[USB_DRV] USB device removed.\n");
}
static struct usb_driver usb_drv = {
.name = "usb_simple_driver",
.id_table = usb_table,
.probe = usb_drv_probe,
.disconnect = usb_drv_disconnect,
};
static int __init usb_drv_init(void)
{
return usb_register(&usb_drv);
}
static void __exit usb_drv_exit(void)
{
usb_deregister(&usb_drv);
}
module_init(usb_drv_init);
module_exit(usb_drv_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("YourName");
MODULE_DESCRIPTION("A simple USB driver example");
四、查看 USB 设备 ID
在终端中插入你的 USB 设备后执行:
lsusb
样例输出:
Bus 001 Device 007: ID 046d:c534 Logitech, Inc. Unifying Receiver
将 046d(VID)与 c534(PID)填写进源码中。
五、驱动编译与加载
make
sudo insmod usb_drv.ko
dmesg | tail
输出示例:
[USB_DRV] USB device plugged in.
拔出设备时输出:
[USB_DRV] USB device removed.
六、增强功能(可选进阶)
- 读取配置描述符:
- 使用 usb_control_msg() 发送 GET_DESCRIPTOR 请求。
- 传输数据(Bulk/HID):
- 利用 usb_bulk_msg() 或 usb_interrupt_msg() 进行读写通信。
- 异步传输:
- 使用 usb_alloc_urb()、usb_submit_urb()、usb_kill_urb() 等进行 URB 操作。
七、卸载驱动
sudo rmmod usb_drv
make clean
八、总结与建议
项目 | 建议 |
开发模式 | 优先开发为模块形式,便于调试 |
调试工具 | dmesg、lsusb、usbmon |
多设备支持 | 通过扩展 usb_device_id 表进行支持 |
安全性 | 勿操作用户态数据地址,注意 NULL 指针判断 |
九、参考资料
- Linux Kernel 文档:USB subsystem
- 《Linux 设备驱动开发详解(第3版)》
- USB Made Simple