C #include#include#include#include#include// 设备相关参数,别乱动! #define MAJOR_NUM 100 #define DEVICE_NAME "demo_chrdev" #define CLASS_NAME "demo_class" // 内核和用户交互的缓冲区,相当于“传话筒” static char kernel_buf[64] = "hello from kernel"; static struct cdev chrdev_cdev; static struct class *chrdev_class; static struct device *chrdev_device; // 用户程序调用read时,驱动执行这个函数(给用户传数据) static ssize_t demo_read(struct file *file, char __user *buf, size_t size, loff_t *ppos) { int len = strlen(kernel_buf); int to_copy = (size < len) ? size : len; if (*ppos >= len) return 0; // 把内核的数据拷贝给用户,别搞反了! if (copy_to_user(buf, kernel_buf, to_copy)) return -EFAULT; *ppos = to_copy; return to_copy; } // 用户程序调用write时,驱动执行这个函数(接收用户数据) static ssize_t demo_write(struct file *file, const char __user *buf, size_t size, loff_t *ppos) { int to_copy = (size < 63) ? size : 63; // 把用户的数据拷贝到内核,超了会报错! if (copy_from_user(kernel_buf, buf, to_copy)) return -EFAULT; kernel_buf[to_copy] = '\0'; printk("kernel recv: %s\n", kernel_buf); return to_copy; } // 用户程序打开设备时,驱动喊一句“我准备好了” static int demo_open(struct inode *inode, struct file *file) { printk("device opened\n"); return 0; } // 用户程序关闭设备时,驱动说“下次见” static int demo_release(struct inode *inode, struct file *file) { printk("device closed\n"); return 0; } // 驱动的“功能清单”,告诉内核我能干嘛 static struct file_operations fops = { .owner = THIS_MODULE, .open = demo_open, .release = demo_release, .read = demo_read, .write = demo_write, }; // 驱动初始化(相当于“开机启动”) static int __init demo_init(void) { int ret; dev_t dev = MKDEV(MAJOR_NUM, 0); // 申请设备号,相当于给驱动办“身份证” ret = register_chrdev_region(dev, 1, DEVICE_NAME); if (ret < 0) { printk("Failed to register chrdev region\n"); return ret; } // 初始化驱动核心 cdev_init(&chrdev_cdev, &fops); chrdev_cdev.owner = THIS_MODULE; ret = cdev_add(&chrdev_cdev, dev, 1); if (ret < 0) { printk("Failed to add cdev\n"); unregister_chrdev_region(dev, 1); return ret; } // 创建设备类,让系统认识这个驱动 chrdev_class = class_create(THIS_MODULE, CLASS_NAME); if (IS_ERR(chrdev_class)) { printk("Failed to create class\n"); cdev_del(&chrdev_cdev); unregister_chrdev_region(dev, 1); return PTR_ERR(chrdev_class); } // 创建设备节点,用户程序能找到驱动了 chrdev_device = device_create(chrdev_class, NULL, dev, NULL, DEVICE_NAME); if (IS_ERR(chrdev_device)) { printk("Failed to create device\n"); class_destroy(chrdev_class); cdev_del(&chrdev_cdev); unregister_chrdev_region(dev, 1); return PTR_ERR(chrdev_device); } printk("chrdev init ok\n"); return 0; } // 驱动卸载(相当于“关机清理”) static void __exit demo_exit(void) { dev_t dev = MKDEV(MAJOR_NUM, 0); device_destroy(chrdev_class, dev); class_destroy(chrdev_class); cdev_del(&chrdev_cdev); unregister_chrdev_region(dev, 1); printk("chrdev exit ok\n"); } module_init(demo_init); module_exit(demo_exit); MODULE_LICENSE("GPL"); MODULE_AUTHOR("linuxROS"); MODULE_DESCRIPTION("字符设备驱动实操demo"); |