Linux高级字符设备驱动开发
封面图
•
2025-12-24
•
嵌入式
277
0
0
0
Linux高级字符设备驱动开发是一个涉及内核模块编程、设备文件操作、内存管理、并发控制、中断处理等多方面的复杂主题。下面我将为你提供一个**Linux高级字符设备驱动开发的全面指南**,涵盖核心概念、代码示例和最佳实践。 --- ## 一、Linux字符设备驱动简介 ### 1.1 字符设备概述 字符设备(Character Device)是按字节流进行读写操作的设备,如串口、键盘、鼠标、LCD、ADC 等。与块设备不同,字符设备没有缓冲区,数据直接传输。 ### 1.2 字符设备驱动的核心结构 - `struct cdev`:用于注册字符设备。 - `file_operations`:定义设备操作函数(open, read, write, ioctl, etc.)。 - 设备号(major + minor):用于在 `/dev/` 目录中创建设备节点。 --- ## 二、高级字符设备驱动开发要点 ### 2.1 动态分配主设备号(推荐) ```c #include <linux/fs.h> #include <linux/cdev.h> static int major = 0; static struct cdev *my_cdev; static int __init my_init(void) { dev_t dev; alloc_chrdev_region(&dev, 0, 1, "mydevice"); major = MAJOR(dev); my_cdev = cdev_alloc(); cdev_init(my_cdev, &fops); cdev_add(my_cdev, dev, 1); return 0; } ``` ### 2.2 使用 `class_create` 和 `device_create` 创建设备节点 ```c #include <linux/device.h> static struct class *my_class; static struct device *my_device; static int __init my_init(void) { my_class = class_create(THIS_MODULE, "myclass"); my_device = device_create(my_class, NULL, MKDEV(major, 0), NULL, "mydevice"); return 0; } ``` ### 2.3 实现 `file_operations` 结构体 ```c static const struct file_operations fops = { .owner = THIS_MODULE, .open = my_open, .release = my_close, .read = my_read, .write = my_write, .unlocked_ioctl = my_ioctl, }; ``` --- ## 三、高级功能实现 ### 3.1 内存映射(mmap) 允许用户空间程序直接访问内核空间的内存。 ```c static int my_mmap(struct file *filp, struct vm_area_struct *vma) { vma->vm_flags |= VM_IO | VM_DONTEXPAND | VM_RESERVED; vma->vm_ops = &my_vm_ops; // 自定义的 vm_ops return 0; } static struct vm_operations_struct my_vm_ops = { .fault = my_fault, }; ``` ### 3.2 中断处理(Interrupt Handling) ```c #include <linux/interrupt.h> static irqreturn_t my_irq_handler(int irq, void *dev_id) { // 处理中断逻辑 return IRQ_HANDLED; } static int __init my_init(void) { request_irq(IRQ_NUMBER, my_irq_handler, IRQF_SHARED, "mydriver", dev_id); } ``` ### 3.3 并发控制(Mutex, Spinlock) ```c #include <linux/mutex.h> static DEFINE_MUTEX(my_mutex); static ssize_t my_read(struct file *filp, char *buf, size_t count, loff_t *f_pos) { mutex_lock(&my_mutex); // 读取操作 mutex_unlock(&my_mutex); return 0; } ``` ### 3.4 IOCTL 操作(自定义命令) ```c #define MY_IOCTL_CMD _IOW('k', 0, int) static long my_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) { int value; if (cmd == MY_IOCTL_CMD) { if (copy_from_user(&value, (void __user *)arg, sizeof(int))) return -EFAULT; // 处理命令 } return 0; } ``` --- ## 四、高级驱动设计模式 ### 4.1 异步通知(poll / select) ```c static unsigned int my_poll(struct file *filp, poll_table *wait) { poll_wait(filp, &wait_queue, wait); if (data_available) return POLLIN | POLLRDNORM; return 0; } ``` ### 4.2 高性能驱动(DMA、零拷贝) - 使用 `dma_map_single` / `dma_unmap_single` - 使用 `copy_from_user` / `copy_to_user` 的替代方案(如 `ioremap`) ### 4.3 内核线程(kthread) ```c #include <linux/kthread.h> static struct task_struct *my_task; static int my_thread_func(void *data) { while (!kthread_should_stop()) { // 执行任务 schedule_timeout_interruptible(HZ); } return 0; } static int __init my_init(void) { my_task = kthread_run(my_thread_func, NULL, "my_kthread"); } ``` --- ## 五、调试与测试 ### 5.1 内核日志 使用 `printk()` 或 `pr_info()` 输出调试信息。 ```c pr_info("My driver loaded\n"); ``` ### 5.2 使用 `strace` / `gdb` - 用户空间调试:`strace`, `gdb` - 内核调试:`kgdb`, `kprobe`, `ftrace` ### 5.3 测试工具 - `dd`, `cat`, `echo`, `ioctl`, `mmap`, `perf` --- ## 六、完整示例代码(简化版) ```c #include <linux/module.h> #include <linux/fs.h> #include <linux/cdev.h> #include <linux/device.h> #include <linux/uaccess.h> #define DEVICE_NAME "mychardev" #define CLASS_NAME "myclass" static int major; static struct cdev cdev; static struct class *cl; static struct device *dev; static int my_open(struct inode *inode, struct file *filp) { pr_info("Device opened\n"); return 0; } static int my_close(struct inode *inode, struct file *filp) { pr_info("Device closed\n"); return 0; } static ssize_t my_read(struct file *filp, char __user *buf, size_t len, loff_t *off) { char data[] = "Hello from kernel"; if (copy_to_user(buf, data, sizeof(data))) return -EFAULT; return sizeof(data); } static struct file_operations fops = { .owner = THIS_MODULE, .open = my_open, .release = my_close, .read = my_read, }; static int __init my_init(void) { dev_t dev_num; alloc_chrdev_region(&dev_num, 0, 1, DEVICE_NAME); major = MAJOR(dev_num); cdev_init(&cdev, &fops); cdev_add(&cdev, dev_num, 1); cl = class_create(THIS_MODULE, CLASS_NAME); dev = device_create(cl, NULL, dev_num, NULL, DEVICE_NAME); pr_info("Driver loaded, major: %d\n", major); return 0; } static void __exit my_exit(void) { cdev_del(&cdev); unregister_chrdev_region(MKDEV(major, 0), 1); device_destroy(cl, MKDEV(major, 0)); class_destroy(cl); pr_info("Driver unloaded\n"); } module_init(my_init); module_exit(my_exit); MODULE_LICENSE("GPL"); ``` --- ## 七、参考资料 - **《Linux设备驱动程序》**(Linux Device Drivers) by Jonathan Corbet, Alessandro Rubini, and Greg Kroah-Hartman - **Linux 内核源码** - **LDD3(Linux Device Drivers 3rd Edition)** - **官方文档:Documentation/driver-api/目录** --- 如果你有具体的设备或功能需求(如 SPI、I2C、USB、DMA、GPIO 控制等),我可以进一步提供针对性的驱动开发指导。欢迎继续提问!
上一篇:
nand flash控制器
下一篇:
电路基础
标题录入,一次不能超过6条
留言
评论