从零开始: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.





六、增强功能(可选进阶)



  1. 读取配置描述符:
  2. 使用 usb_control_msg() 发送 GET_DESCRIPTOR 请求。
  3. 传输数据(Bulk/HID):
  4. 利用 usb_bulk_msg() 或 usb_interrupt_msg() 进行读写通信。
  5. 异步传输:
  6. 使用 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