一、驱动整体设计思路
实现一个自定义USB设备驱动(以虚拟的USB数据传输设备为例),核心逻辑:
- 基于
usb_device_id匹配特定VID/PID的USB设备; - 注册字符设备,为用户空间提供读写接口;
- 设备驱动通过URB完成与USB设备的数据交互;
- 实现URB传输完成回调,处理数据收发结果;
- 遵循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_device、usb_interface、字符设备、URB、缓冲区等核心资源;urb:USB传输最小单元,通过usb_alloc_urb申请、usb_fill_control_urb填充、usb_submit_urb提交;cdev:字符设备对象,为用户空间提供读写接口(/dev/usb_custom_device)。
2. 数据传输流程
- 用户空间写数据:调用
write(/dev/usb_custom_device, buf, len); - 驱动层处理:
usb_custom_write拷贝用户数据到内核缓冲区,填充URB并调用usb_submit_urb提交给USB Core; - USB Core处理:验证URB合法性,通过
urb_enqueue将URB加入HCD传输队列; - HCD处理:将URB拆分为TRB,按照USB协议封装后通过PHY发送;
- 传输完成回调:
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;
}
四、总结
- 核心要点:
- Linux USB驱动核心是实现
usb_driver结构体,其中probe(匹配成功)和disconnect(设备断开)是核心入口; - URB是USB数据传输的最小单元,需完成“申请→填充→提交→回调处理→释放”完整生命周期;
- 字符设备接口是用户空间与USB驱动交互的标准方式,需实现
open/write/release等函数。
- Linux USB驱动核心是实现
- 扩展建议:
- 实际使用需替换
USB_VENDOR_ID/USB_PRODUCT_ID为设备真实值; - 若为批量/中断传输,需替换
usb_fill_control_urb为usb_fill_bulk_urb/usb_fill_int_urb; - 可添加
read函数实现数据接收,补充rx_urb的填充与提交逻辑; - 增加并发保护(如
mutex),避免多进程读写冲突。
- 实际使用需替换

4165

被折叠的 条评论
为什么被折叠?



