2,861
社区成员




在 Linux 下编写 USB 设备驱动程序需要深入理解内核的 USB 子系统和设备驱动框架。以下是详细的步骤指南,包含关键代码示例和调试技巧:
sudo apt-get install build-essential linux-headers-$(uname -r)
使用 lsusb
查看设备信息:
$ lsusb
Bus 001 Device 005: ID 1234:5678 My USB Device
记录 ID
(如 1234:5678
)和设备描述符。
#include <linux/module.h>
#include <linux/usb.h>
static int driver_probe(struct usb_interface *intf, const struct usb_device_id *id)
{
printk(KERN_INFO "USB device probed\n");
return 0;
}
static void driver_disconnect(struct usb_interface *intf)
{
printk(KERN_INFO "USB device removed\n");
}
static struct usb_device_id my_usb_table[] = {
{ USB_DEVICE(0x1234, 0x5678) }, // 替换为你的 Vendor ID 和 Product ID
{ }
};
MODULE_DEVICE_TABLE(usb, my_usb_table);
static struct usb_driver my_usb_driver = {
.name = "my_usb_driver",
.id_table = my_usb_table,
.probe = driver_probe,
.disconnect = driver_disconnect,
};
module_usb_driver(my_usb_driver);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Your Name");
obj-m += my_usb_driver.o
all:
make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules
clean:
make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean
probe 函数:设备插入时调用,完成资源初始化。
static int driver_probe(struct usb_interface *intf, const struct usb_device_id *id)
{
struct usb_device *udev = interface_to_usbdev(intf);
printk(KERN_INFO "Vendor ID: %04x, Product ID: %04x\n",
le16_to_cpu(udev->descriptor.idVendor),
le16_to_cpu(udev->descriptor.idProduct));
// 获取端点信息
struct usb_endpoint_descriptor *endpoint;
endpoint = &intf->cur_altsetting->endpoint[0].desc;
printk(KERN_INFO "Endpoint Address: 0x%02x\n", endpoint->bEndpointAddress);
return 0;
}
控制传输(发送厂商命令):
char *buffer = kmalloc(64, GFP_KERNEL);
int ret = usb_control_msg(udev,
usb_sndctrlpipe(udev, 0),
0x09, // 请求类型(Vendor-Specific)
0x21, // 请求码
0x0000, 0x0000,
buffer, 64, HZ*10);
中断传输(周期性读取数据):
struct urb *urb;
char *transfer_buffer;
// 分配 URB 和缓冲区
urb = usb_alloc_urb(0, GFP_KERNEL);
transfer_buffer = kmalloc(64, GFP_KERNEL);
// 配置端点
usb_fill_int_urb(urb, udev,
usb_rcvintpipe(udev, endpoint->bEndpointAddress),
transfer_buffer, 64,
urb_callback, NULL, 100); // 100ms 间隔
// 提交 URB
usb_submit_urb(urb, GFP_KERNEL);
static void driver_disconnect(struct usb_interface *intf)
{
struct usb_device *udev = interface_to_usbdev(intf);
printk(KERN_INFO "Disconnecting device %04x:%04x\n",
le16_to_cpu(udev->descriptor.idVendor),
le16_to_cpu(udev->descriptor.idProduct));
// 释放 URB、缓冲区等资源
}
dmesg | tail -f # 实时监控驱动日志
插入设备后检查 /sys/bus/usb/drivers/my_usb_driver/
是否出现设备目录。
sudo modprobe usbmon # 加载 usbmon 模块
sudo cat /sys/kernel/debug/usb/usbmon/0u > usb_data.log
static void urb_callback(struct urb *urb)
{
if (urb->status == 0) {
printk(KERN_INFO "Received data: %s\n", urb->transfer_buffer);
} else {
printk(KERN_WARNING "URB error: %d\n", urb->status);
}
// 重新提交 URB 实现循环传输
usb_submit_urb(urb, GFP_ATOMIC);
}
对于复杂场景,可结合用户态库 libusb
实现异步操作。
id_table
中的 Vendor/Product ID 是否正确。usb_control_msg
或 urb
的超时参数(HZ*10 表示 10 秒)。disconnect
回调中释放所有 URB 和缓冲区。Documentation/usb/usb-driver.txt
。drivers/usb/misc/
下的驱动(如 gadgetfs
示例)。通过以上步骤,你可以完成一个基础 USB 驱动程序的开发。实际开发中需结合具体设备协议(如 HID、Mass Storage)调整数据传输逻辑,并严格遵循内核同步与内存管理规范。