Linux-USB设备驱动

一、驱动整体设计思路

实现一个自定义USB设备驱动(以虚拟的USB数据传输设备为例),核心逻辑:

  1. 基于usb_device_id匹配特定VID/PID的USB设备;
  2. 注册字符设备,为用户空间提供读写接口;
  3. 设备驱动通过URB完成与USB设备的数据交互;
  4. 实现URB传输完成回调,处理数据收发结果;
  5. 遵循Linux USB驱动框架规范,包含probe/remove、URB管理、资源释放等完整生命周期。

二、完整USB设备驱动代码实现

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/usb.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <linux/uaccess.h>
#include <linux/slab.h>

// 1. 自定义USB设备ID(匹配特定VID/PID,需替换为实际设备值)
#define USB_VENDOR_ID    0x1234  // 厂商ID
#define USB_PRODUCT_ID   0x5678  // 产品ID
#define USB_MINOR_BASE   0       // 次设备号起始值
#define DEVICE_NAME      "usb_custom_device"

// 2. 私有数据结构(整合设备相关资源)
struct usb_custom_dev {
    struct usb_device *udev;          // 指向USB设备抽象对象
    struct usb_interface *interface;  // 指向USB接口抽象对象
    struct cdev cdev;                 // 字符设备对象
    dev_t dev_num;                    // 设备号
    struct urb *tx_urb;               // 发送URB
    struct urb *rx_urb;               // 接收URB
    uint8_t *tx_buffer;               // 发送缓冲区
    uint8_t *rx_buffer;               // 接收缓冲区
    size_t buffer_size;               // 缓冲区大小(默认64字节)
    struct mutex lock;                // 并发保护锁
};

// 全局变量
static struct class *usb_custom_class;
static struct usb_custom_dev *usb_dev_priv;

// 3. USB设备ID表(驱动匹配依据)
static const struct usb_device_id usb_custom_id_table[] = {
    { USB_DEVICE(USB_VENDOR_ID, USB_PRODUCT_ID) },  // 设备级匹配
    // 也可添加接口级匹配:{ USB_INTERFACE_INFO(类, 子类, 协议) }
    { }  // 结束标记
};
MODULE_DEVICE_TABLE(usb, usb_custom_id_table);

// 4. URB传输完成回调函数(处理传输结果)
static void usb_custom_tx_complete(struct urb *urb)
{
    struct usb_custom_dev *dev = urb->context;
    int status = urb->status;

    // 检查传输状态
    switch (status) {
        case 0:  // 传输成功
            dev_info(&dev->interface->dev, "TX URB传输成功,长度:%d\n", urb->actual_length);
            break;
        case -ECONNRESET:
        case -ENOENT:
        case -ESHUTDOWN:
            dev_err(&dev->interface->dev, "TX URB被取消:%d\n", status);
            return;
        default:
            dev_err(&dev->interface->dev, "TX URB传输失败:%d\n", status);
            break;
    }

    // 释放本次传输的URB(若需重复传输可重新提交)
    usb_free_urb(urb);
}

static void usb_custom_rx_complete(struct urb *urb)
{
    struct usb_custom_dev *dev = urb->context;
    int status = urb->status;

    switch (status) {
        case 0:  // 接收成功
            dev_info(&dev->interface->dev, "RX URB接收成功,数据:");
            for (int i = 0; i < urb->actual_length; i++) {
                printk("%02x ", dev->rx_buffer[i]);
            }
            printk("\n");
            break;
        case -ECONNRESET:
        case -ENOENT:
        case -ESHUTDOWN:
            dev_err(&dev->interface->dev, "RX URB被取消:%d\n", status);
            return;
        default:
            dev_err(&dev->interface->dev, "RX URB接收失败:%d\n", status);
            break;
    }

    usb_free_urb(urb);
}

// 5. 字符设备write函数(用户空间写数据到USB设备)
static ssize_t usb_custom_write(struct file *file, const char __user *buf,
                               size_t count, loff_t *ppos)
{
    struct usb_custom_dev *dev = file->private_data;
    int ret;

    if (!dev || count > dev->buffer_size) {
        return -EINVAL;
    }

    mutex_lock(&dev->lock);

    // 拷贝用户空间数据到内核缓冲区
    if (copy_from_user(dev->tx_buffer, buf, count)) {
        mutex_unlock(&dev->lock);
        return -EFAULT;
    }

    // 分配并初始化发送URB(端点0为控制端点,实际需替换为批量/中断端点)
    dev->tx_urb = usb_alloc_urb(0, GFP_KERNEL);
    if (!dev->tx_urb) {
        mutex_unlock(&dev->lock);
        return -ENOMEM;
    }

    // 填充URB(以控制传输为例,bRequest=0x01,wValue=0x0000)
    usb_fill_control_urb(dev->tx_urb, dev->udev,
                         usb_sndctrlpipe(dev->udev, 0),  // 发送控制端点
                         (unsigned char *)dev->tx_buffer,
                         dev->tx_buffer, count,
                         usb_custom_tx_complete, dev);

    // 提交URB到USB Core
    ret = usb_submit_urb(dev->tx_urb, GFP_KERNEL);
    if (ret) {
        dev_err(&dev->interface->dev, "提交TX URB失败:%d\n", ret);
        usb_free_urb(dev->tx_urb);
        dev->tx_urb = NULL;
        mutex_unlock(&dev->lock);
        return ret;
    }

    mutex_unlock(&dev->lock);
    return count;
}

// 6. 字符设备open函数
static int usb_custom_open(struct inode *inode, struct file *file)
{
    struct usb_custom_dev *dev = container_of(inode->i_cdev,
                                             struct usb_custom_dev, cdev);
    file->private_data = dev;
    return 0;
}

// 7. 字符设备release函数
static int usb_custom_release(struct inode *inode, struct file *file)
{
    file->private_data = NULL;
    return 0;
}

// 8. 字符设备操作集合
static const struct file_operations usb_custom_fops = {
    .owner = THIS_MODULE,
    .open = usb_custom_open,
    .write = usb_custom_write,
    .release = usb_custom_release,
};

// 9. USB驱动probe函数(设备匹配成功后执行)
static int usb_custom_probe(struct usb_interface *interface,
                           const struct usb_device_id *id)
{
    struct usb_device *udev = interface_to_usbdev(interface);
    struct usb_custom_dev *dev;
    int ret;

    // 分配私有数据结构内存
    dev = kzalloc(sizeof(struct usb_custom_dev), GFP_KERNEL);
    if (!dev) {
        return -ENOMEM;
    }

    // 初始化私有数据
    dev->udev = udev;
    dev->interface = interface;
    dev->buffer_size = 64;  // 定义缓冲区大小
    mutex_init(&dev->lock);

    // 分配收发缓冲区
    dev->tx_buffer = kmalloc(dev->buffer_size, GFP_KERNEL);
    dev->rx_buffer = kmalloc(dev->buffer_size, GFP_KERNEL);
    if (!dev->tx_buffer || !dev->rx_buffer) {
        ret = -ENOMEM;
        goto err_free_buffer;
    }

    // 注册字符设备
    ret = alloc_chrdev_region(&dev->dev_num, USB_MINOR_BASE, 1, DEVICE_NAME);
    if (ret) {
        goto err_free_buffer;
    }

    cdev_init(&dev->cdev, &usb_custom_fops);
    dev->cdev.owner = THIS_MODULE;
    ret = cdev_add(&dev->cdev, dev->dev_num, 1);
    if (ret) {
        goto err_unregister_chrdev;
    }

    // 创建设备节点(/dev/usb_custom_device)
    usb_custom_class = class_create(THIS_MODULE, DEVICE_NAME);
    device_create(usb_custom_class, NULL, dev->dev_num, NULL, DEVICE_NAME);

    // 将私有数据关联到USB接口
    usb_set_intfdata(interface, dev);
    usb_dev_priv = dev;

    dev_info(&interface->dev, "USB设备匹配成功(VID:0x%04x, PID:0x%04x)\n",
             le16_to_cpu(udev->descriptor.idVendor),
             le16_to_cpu(udev->descriptor.idProduct));

    return 0;

err_unregister_chrdev:
    unregister_chrdev_region(dev->dev_num, 1);
err_free_buffer:
    kfree(dev->tx_buffer);
    kfree(dev->rx_buffer);
    kfree(dev);
    return ret;
}

// 10. USB驱动remove函数(设备拔出/驱动卸载时执行)
static void usb_custom_disconnect(struct usb_interface *interface)
{
    struct usb_custom_dev *dev = usb_get_intfdata(interface);

    if (!dev) {
        return;
    }

    // 终止未完成的URB传输
    if (dev->tx_urb) {
        usb_kill_urb(dev->tx_urb);
    }
    if (dev->rx_urb) {
        usb_kill_urb(dev->rx_urb);
    }

    // 销毁字符设备
    device_destroy(usb_custom_class, dev->dev_num);
    class_destroy(usb_custom_class);
    cdev_del(&dev->cdev);
    unregister_chrdev_region(dev->dev_num, 1);

    // 释放缓冲区和私有数据
    kfree(dev->tx_buffer);
    kfree(dev->rx_buffer);
    kfree(dev);

    usb_set_intfdata(interface, NULL);
    dev_info(&interface->dev, "USB设备已断开连接\n");
}

// 11. USB驱动结构体(核心入口)
static struct usb_driver usb_custom_driver = {
    .name = DEVICE_NAME,
    .probe = usb_custom_probe,
    .disconnect = usb_custom_disconnect,
    .id_table = usb_custom_id_table,
};

// 12. 模块加载/卸载函数
module_usb_driver(usb_custom_driver);

// 模块信息
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("Custom USB Device Driver");
MODULE_AUTHOR("Developer");
MODULE_VERSION("1.0");

三、代码关键说明

1. 核心结构体使用
  • usb_device_id:定义驱动匹配规则,支持设备级(VID/PID)和接口级(类/子类/协议)匹配;
  • usb_custom_dev:私有结构体整合usb_deviceusb_interface、字符设备、URB、缓冲区等核心资源;
  • urb:USB传输最小单元,通过usb_alloc_urb申请、usb_fill_control_urb填充、usb_submit_urb提交;
  • cdev:字符设备对象,为用户空间提供读写接口(/dev/usb_custom_device)。
2. 数据传输流程
  1. 用户空间写数据:调用write(/dev/usb_custom_device, buf, len)
  2. 驱动层处理usb_custom_write拷贝用户数据到内核缓冲区,填充URB并调用usb_submit_urb提交给USB Core;
  3. USB Core处理:验证URB合法性,通过urb_enqueue将URB加入HCD传输队列;
  4. HCD处理:将URB拆分为TRB,按照USB协议封装后通过PHY发送;
  5. 传输完成回调usb_custom_tx_complete处理传输结果(成功/失败)。
3. 编译与测试说明
(1)Makefile编写
obj-m += usb_custom_driver.o
KERNELDIR ?= /lib/modules/$(shell uname -r)/build
PWD := $(shell pwd)

all:
    make -C $(KERNELDIR) M=$(PWD) modules

clean:
    make -C $(KERNELDIR) M=$(PWD) clean
(2)编译与加载
# 编译驱动
make

# 加载驱动
insmod usb_custom_driver.ko

# 查看驱动加载状态
lsmod | grep usb_custom_driver
dmesg | grep USB

# 查看设备节点
ls /dev/usb_custom_device
(3)用户空间测试(示例)
// test_usb.c
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>

int main() {
    int fd = open("/dev/usb_custom_device", O_WRONLY);
    if (fd < 0) {
        perror("open device failed");
        return -1;
    }

    char buf[] = "Hello USB Device!";
    write(fd, buf, sizeof(buf));
    close(fd);
    return 0;
}

四、总结

  1. 核心要点
    • Linux USB驱动核心是实现usb_driver结构体,其中probe(匹配成功)和disconnect(设备断开)是核心入口;
    • URB是USB数据传输的最小单元,需完成“申请→填充→提交→回调处理→释放”完整生命周期;
    • 字符设备接口是用户空间与USB驱动交互的标准方式,需实现open/write/release等函数。
  2. 扩展建议
    • 实际使用需替换USB_VENDOR_ID/USB_PRODUCT_ID为设备真实值;
    • 若为批量/中断传输,需替换usb_fill_control_urbusb_fill_bulk_urb/usb_fill_int_urb
    • 可添加read函数实现数据接收,补充rx_urb的填充与提交逻辑;
    • 增加并发保护(如mutex),避免多进程读写冲突。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值