如果一类设备有多个个体,比如系统上有两个串口,那么我们就应该写一个驱动来支持多个设备,而不是每一个设备都写一个驱动
上一节我们有说了单字符设备的驱动,这次我们来说下多字符设备驱动。
相比于单设备操作,多设备操作首先在init上要注册多个设备,然后添加多个设备,exit的时候要del多个设备。比较麻烦的是读写,因为不同的设备他们的fifo设备就需要各自独立,那么如何读写的时候去判断读写哪个设备呢?我们观察到open的函数有个inode的参数,节点信息里面包含了设备号以及对应的cdev对象的地址。因此我们可以在open接口函数中取出这些信息,并存在file结构对象的某个成员中(读写函数的参数有file),从而在读写过程中判断是哪类设备。
#include#include #include #include #include #include #define CHRDEV_MAJOR 256 #define CHRDEV_MINOR 0 #define CHRDEV_CNT 2 #define CHRDEV_NAME "chrdev" DEFINE_KFIFO(vsfifo0, char, 32); DEFINE_KFIFO(vsfifo1, char, 32); struct vser_dev { struct cdev cdev; struct kfifo *fifo; }; static struct vser_dev vsdev[2];//定义两个设备 static int chrdev_open(struct inode *inode, struct file *filp) { filp->private_data = container_of(inode->i_cdev, struct vser_dev, cdev);//ptr, type, member return 0; } static int chrdev_release(struct inode *inode, struct file *filp) { return 0; } static ssize_t chrdev_read(struct file *filp, char __user *buf, size_t count, loff_t *pos) { unsigned int copied = 0; struct vser_dev *dev = filp->private_data; kfifo_to_user(dev->fifo, buf, count, &copied); return copied; } static ssize_t chrdev_write(struct file *filp, const char __user *buf, size_t count, loff_t *pos) { unsigned int copied = 0; struct vser_dev *dev = filp->private_data; kfifo_from_user(dev->fifo, buf, count, &copied); return copied; } static struct file_operations chrdev_ops = { .owner = THIS_MODULE, .open = chrdev_open, .release = chrdev_release, .read = chrdev_read, .write = chrdev_write, }; static int __init chrdev_init(void) { int i; int ret; dev_t dev; //在内核中dev_t是一个无符号的32位整数,主设备号占12位,次设备号占20位 dev = MKDEV(CHRDEV_MAJOR, CHRDEV_MINOR); //对一个设备分配设备号 ret = register_chrdev_region(dev, CHRDEV_CNT, CHRDEV_NAME); if (ret) goto reg_err; for (i=0; i 0; --i) { cdev_del(&vsdev[i].cdev); } unregister_chrdev_region(dev, CHRDEV_CNT);//需要把设备注销掉,否则下次在注册会失败 reg_err: return ret; } static void __exit chrdev_exit(void) { dev_t dev; int i; dev = MKDEV(CHRDEV_MAJOR, CHRDEV_MINOR); for (i=0; i "); MODULE_DEscriptION("A simple module"); MODULE_ALIAS("virtual-serial");
代码中我已经加了详细的解释,这里就不再多说了,主要是多多习惯内核的编程思想,比如面向对象的思想等



