Linux 下如何编写一个 USB 设备的驱动程序?

码上好不好 2025-04-24 14:30:22

Linux 下如何编写一个 USB 设备的驱动程序?

...全文
249 1 打赏 收藏 转发到动态 举报
AI 作业
写回复
用AI写文章
1 条回复
切换为时间正序
请发表友善的回复…
发表回复
  • 打赏
  • 举报
回复

在 Linux 下编写 USB 设备驱动程序需要深入理解内核的 USB 子系统和设备驱动框架。以下是详细的步骤指南,包含关键代码示例和调试技巧:


1. 环境准备

(1) 安装工具和内核头文件

sudo apt-get install build-essential linux-headers-$(uname -r)

(2) 获取设备信息

使用 lsusb 查看设备信息:

$ lsusb
Bus 001 Device 005: ID 1234:5678 My USB Device

记录 ID(如 1234:5678)和设备描述符。


2. USB 驱动框架基础

(1) 内核模块骨架

#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");

(2) 编译 Makefile

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

3. 关键实现步骤

(1) 设备探测与绑定

  • 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;
    }
    

(2) 数据传输

  • 控制传输(发送厂商命令):

    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);
    

(3) 资源释放

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、缓冲区等资源
}

4. 调试与测试

(1) 查看内核日志

dmesg | tail -f  # 实时监控驱动日志

(2) 验证设备绑定

插入设备后检查 /sys/bus/usb/drivers/my_usb_driver/ 是否出现设备目录。

(3) 使用 usbmon 抓包

sudo modprobe usbmon  # 加载 usbmon 模块
sudo cat /sys/kernel/debug/usb/usbmon/0u > usb_data.log

5. 高级功能

(1) 异步传输(URB 回调)

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);
}

(2) 同步传输(使用 libusb 替代)

对于复杂场景,可结合用户态库 libusb 实现异步操作。


6. 常见问题解决

  • 设备未被识别:检查 id_table 中的 Vendor/Product ID 是否正确。
  • 传输超时:调整 usb_control_msgurb 的超时参数(HZ*10 表示 10 秒)。
  • 内存泄漏:确保在 disconnect 回调中释放所有 URB 和缓冲区。

7. 扩展学习

  • 内核文档:阅读 Documentation/usb/usb-driver.txt
  • 示例代码:参考 drivers/usb/misc/ 下的驱动(如 gadgetfs 示例)。
  • 协议规范:根据设备类型(如 HID、CDC)实现特定协议。

通过以上步骤,你可以完成一个基础 USB 驱动程序的开发。实际开发中需结合具体设备协议(如 HID、Mass Storage)调整数据传输逻辑,并严格遵循内核同步与内存管理规范。

第一章 走进linux 1.1 GNU与Linux的成长 1.2 Linux的开发模式和运作机制 1.3走进Linux内核 1.4 分析Linux内核的意义 1.5 Linux内核结构 1.6 Linux内核源代码 1.7 Linux内核源代码分析工具 第二章 Linux运行的硬件基础 2.1 i386的寄存器 2.2 内存地址 2.3 段机制和描述符 2.4 分页机制 2.5 Linux中的分页机制 2.6 Linux中的汇编语言 第三章中断机制 3.1 中断基本知识 3.2中断描述符表的初始化 3.3异常处理 3.4 中断处理 3.5中断的后半部分处理机制 第四章 进程描述 4.1 进程和程序(Process and Program) 4.2 Linux中的进程概述 4.3 task_struct结构描述 4.4 task_struct结构在内存中的存放 4.5 进程组织的方式 4.6 内核线程 4.7 进程的权能 4.8 内核同步 第五章进程调度 5.1 Linux时间系统 5.2 时钟中断 5.3 Linux的调度程序-Schedule( ) 5.4 进程切换 第六章 Linux内存管理 6.1 Linux的内存管理概述 6.2 Linux内存管理的初始化 6.3 内存的分配和回收 6.4 地址映射机制 6.5 请页机制 6.6 交换机制 6.7 缓存和刷新机制 6.8 进程的创建和执行 第七章 进程间通信 7.1 管道 7.2 信号(signal) 7.3 System V 的IPC机制 第八章 虚拟文件系统 8.1 概述 8.2 VFS中的数据结构 8.3 高速缓存 8.4 文件系统的注册、安装与拆卸 8.5 限额机制 8.6 具体文件系统举例 8.7 文件系统的系统调用 8 .8 Linux2.4文件系统的移植问题 第九章 Ext2文件系统 9.1 基本概念 9.2 Ext2的磁盘布局和数据结构 9.3 文件的访问权限和安全 9.4 链接文件 9.5 分配策略 第十章 模块机制 10.1 概述 10.2 实现机制 10.3 模块的装入和卸载 10.4 内核版本 10.5 编写内核模块 第十一章 设备驱动程序 11.1 概述 11.2 设备驱动基础 11.3 块设备驱动程序 11.4 字符设备驱动程序 第十二章 网络 12.1 概述 12.2 网络协议 12.3 套接字(socket) 12.4 套接字缓冲区(sk_buff) 12.5 网络设备接口 第十三章 启动系统 13.1 初始化流程 13.2 初始化的任务 13.3 Linux 的Boot Loarder 13.4 进入操作系统 13.5 main.c中的初始化 13.6 建立init进程 附录: 1 Linux 2.4内核API 2.1 驱动程序的基本函数 2.2 双向循环链表的操作 2.3 基本C库函数 2.4 Linux内存管理中Slab缓冲区 2.5 Linux中的VFS 2.6 Linux的连网 2.7 网络设备支持 2.8 模块支持 2.9 硬件接口 2.10 块设备 2.11 USB 设备

2,861

社区成员

发帖
与我相关
我的任务
社区描述
本论坛以AI、WoS 、XR、IoT、Auto、生成式AI等核心板块组成,为开发者提供便捷及高效的学习和交流平台。 高通开发者专区主页:https://qualcomm.csdn.net/
人工智能物联网机器学习 技术论坛(原bbs) 北京·东城区
社区管理员
  • csdnsqst0050
  • chipseeker
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧