开发Linux USB设备驱动需理解USB子系统架构,包括usbcore、HCD和设备驱动三部分;通过定义usb_driver结构体并实现probe和disconnect回调,可注册驱动匹配特定VID/PID设备;在probe中获取设备信息并利用URB进行控制、批量等传输;使用usb_control_msg发送控制请求,结合Makefile编译为模块后通过insmod加载,dmesg查看日志,完成设备识别与通信。

开发Linux下的USB设备驱动,需要理解内核中USB子系统的架构以及如何与硬件交互。Linux提供了一套完整的API和框架来支持USB驱动开发,开发者只需关注设备特性的实现,底层通信由内核处理。
理解Linux USB子系统结构
Linux的USB子系统位于/drivers/usb目录下,核心组件包括:
- USB核心(usbcore):负责管理USB总线、设备枚举、带宽分配等通用任务
- 主机控制器驱动(HCD):如EHCI、XHCI,控制物理主机控制器硬件
- 设备驱动:面向具体设备,比如U盘、摄像头、串口适配器等
当插入USB设备时,内核通过描述符识别设备类型,并尝试匹配已注册的驱动。匹配成功后调用驱动的probe函数进行初始化。
编写一个简单的USB设备驱动
最基础的USB驱动通常基于usb_driver结构体注册,并实现probe和disconnect回调。
示例代码框架:
#include#include / 定义支持的设备ID / static const struct usb_device_id my_usb_table[] = { { USB_DEVICE(0x1234, 0x5678) }, / VID, PID / { } / 表结束 / }; MODULE_DEVICE_TABLE(usb, my_usb_table);
/ Probe函数:设备连接时调用 / static int my_probe(struct usb_interface interface, const struct usb_device_id id) { printk(KERN_INFO "My USB Device Connected: %04x:%04x\n", id->idVendor, id->idProduct); return 0; / 成功返回0 / }
/ Disconnect函数:设备拔出时调用 / static void my_disconnect(struct usb_interface *interface) { printk(KERN_INFO "My USB Device Disconnected\n"); }
/ 驱动结构体 / static struct usb_driver my_usb_driver = { .name = "my_usb_driver", .id_table = my_usb_table, .probe = my_probe, .disconnect = my_disconnect, };
/ 模块加载 / static int __init my_init(void) { return usb_register(&my_usb_driver); }
/ 模块卸载 / static void __exit my_exit(void) { usb_deregister(&my_usb_driver); }
module_init(my_init); module_exit(my_exit); MODULE_LICENSE("GPL");
这个驱动会在系统插入指定VID/PID的设备时打印消息。你可以将其编译为模块,使用make和insmod加载测试。
获取设备信息与数据传输
在probe函数中,可通过interface_to_usbdev(interface)获取struct usb_device指针,进而访问设备描述符、配置等信息。
本文档主要讲述的是Android linux内核介绍;Android内核是基于Linux 2.6内核的(目前最新开发版本是2.6.31),它是一个增强内核版本,除了修改部分Bug外,它提供了用于支持Android平台的设备驱动,希望本文档会给有需要的朋友带来帮助;感兴趣的朋友可以过来看看
常用操作包括:
- 读取描述符:usb_get_descriptor() 获取设备、接口或端点信息
- 提交URB(USB请求块):用于发送控制、中断、批量或等时传输
- 端点通信:通过端点地址确定数据流向和类型
例如,向控制端点发送命令:
int ret;
u8 cmd = 0x01;
ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
0x09, // 请求
USB_TYPE_VENDOR | USB_DIR_OUT,
0x1234, 0x5678, // wValue, wIndex
&cmd, sizeof(cmd), // 数据指针和长度
1000); // 超时ms
if (ret < 0)
printk(KERN_ERR "Control request failed\n");
编译与调试技巧
将驱动保存为my_usb_driver.c,编写Makefile:
obj-m += my_usb_driver.o
KDIR := /lib/modules/$(shell uname -r)/build
all:
$(MAKE) -C $(KDIR) M=$(PWD) modules
clean:
$(MAKE) -C $(KDIR) M=$(PWD) clean
编译后使用以下命令加载并查看日志:
- sudo insmod my_usb_driver.ko
- dmesg | tail 查看内核输出
- lsmod | grep my_usb_driver 确认模块加载
- sudo rmmod my_usb_driver 卸载模块
使用lsusb可列出当前USB设备及其VID/PID,帮助确认目标设备是否存在。
基本上就这些。掌握USB驱动开发的关键是熟悉描述符结构、URB机制和内核提供的API。从简单探测开始,逐步实现数据交互,就能完成实际功能驱动。










