日期:2014-05-16 浏览次数:20850 次
/* * 说明:用于演示一个驱动如何管理多个设备。 */ #include <linux/init.h> #include <linux/kernel.h> #include <linux/module.h> #include <linux/fs.h> #include <linux/mm.h> #include <linux/cdev.h> #include <linux/slab.h> #include <linux/uaccess.h> #include "ioctl.h" #define FSDEV_MAJOR 250 #define FSDEV_MINOR 0 #define FSDEV_NR 2 #define FSDEV_NAME "fsdev" struct fsdev { struct cdev cdev; unsigned char buf[256]; }; static struct fsdev *fsdev[FSDEV_NR]; static int fschr_open(struct inode *inode, struct file *filp) { struct fsdev *fsdev; /* 根据保存在inode节点中的cdev指针,反向查询到包含该cdev的结构体, * 将该结构体指针保存在打开的文件结构体的私有数据中,可以在之后 * 的read、write以及ioctl当中通过file结构体指针顺利获得反查得到的 * 结构体指针,这是实现一个驱动管理多个设备的关键 */ fsdev = container_of(inode->i_cdev, struct fsdev, cdev); filp->private_data = fsdev; return 0; } static int fschr_close(struct inode *inode, struct file *filp) { return 0; } static ssize_t fschr_read(struct file *filp, char __user *buf, size_t count, loff_t *fops) { int len; int ret; struct fsdev *fsdev = filp->private_data;//通过filp的private_data得到是哪一个设备的操作 len = count > 256 ? 256 : count; ret = copy_to_user(buf, fsdev->buf, len); return len - ret; } static ssize_t fschr_write(struct file *filp, const char __user *buf, size_t count, loff_t *fops) { int len; int ret; struct fsdev *fsdev = filp->private_data; len = count > 256 ? 256 : count; ret = copy_from_user(fsdev->buf, buf, len); return len - ret; } static int fschr_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg) { int ret = 0; struct fsdev *fsdev = filp->private_data; if (_IOC_TYPE(cmd) != FS_IOC_MAGIC) return -ENOTTY; if (_IOC_NR(cmd) > FS_IOC_MAXNR) return -ENOTTY; if (_IOC_DIR(cmd) & _IOC_READ) ret = !access_ok(VERIFY_WRITE, (void __user *)arg, _IOC_SIZE(cmd)); else if (_IOC_DIR(cmd) & _IOC_WRITE) ret = !access_ok(VERIFY_READ, (void __user *)arg, _IOC_SIZE(cmd)); if (ret) return -EFAULT; switch (cmd) { case FS_IOC_SET_BUF: memset(fsdev->buf, *(char *)arg, sizeof(fsdev->buf)); break; } return 0; } static struct file_operations fsfops = { .owner = THIS_MODULE, .open = fschr_open, .release = fschr_close, .read = fschr_read, .write = fschr_write, .ioctl = fschr_ioctl }; static int __init fschr_init(void) { int i; int ret; int alloc_num = 0; int add_num = 0; dev_t devno; devno = MKDEV(FSDEV_MAJOR, FSDEV_MINOR); ret = register_chrdev_region(devno, FSDEV_NR, FSDEV_NAME); if (ret) { printk(KERN_ERR "fschr: register chrdev region failed\n"); goto reg_err; } for (i = 0; i < FSDEV_NR; i++) { fsdev[i] = (struct fsdev *)kzalloc(sizeof(struct fsdev), GFP_KERNEL); if (!fsdev[i]) { printk(KERN_ERR "fschr: kzalloc failure\n"); alloc_num = i; ret = -ENOMEM; goto alloc_err; } } alloc_num = FSDEV_NR; for (i = 0; i < FSDEV_NR; i++) { cdev_init(&fsdev[i]->cdev, &fsfops); fsdev[i]->cdev.owner = THIS_MODULE; ret = cdev_add(&fsdev[i]->cdev, devno + i, 1); if (ret) { printk(KERN_ERR "fschr: add cdev failed"); add_num = i; goto add_err; } } return 0; add_err: for (i = 0; i < add_num; i++) cdev_del(&fsdev[i]->cdev); alloc_err: for (i = 0; i < alloc_num; i++) kfree(fsdev[i]); unregister_chrdev_region(devno, FSDEV_NR); reg_err: return ret; } static void __exit fschr_exit(void) { int i; dev_t devno; devno = MKDEV(FSDEV_MAJOR, FSDEV_MINOR); for