📄 scull.c
字号:
#ifndef __KERNEL__# define __KERNEL__#endif#ifndef MODULE# define MODULE#endif#include <linux/config.h>#include <linux/module.h>#include <linux/kernel.h> #include <linux/init.h> #include <linux/slab.h> #include <linux/fs.h> #include <linux/errno.h> #include <linux/types.h> #include <linux/proc_fs.h>#include <asm/system.h> #include <asm/uaccess.h> /*使用copy_to_user,copy_from_user必须要包含该文件*/#include "scull.h"MODULE_LICENSE("GPL");Scull_Dev *scull_devices; int scull_major = SCULL_MAJOR;/*设备打开*/int scull_open(struct inode *inode, struct file *filp){ Scull_Dev *dev; /*获取次设备号*/ int num = MINOR(inode->i_rdev); dev = (Scull_Dev *)filp->private_data; if (!dev) { if (num >= SCULL_NR_DEVS) return -ENODEV; dev = &scull_devices[num]; filp->private_data = dev; } /*增加模块引用计数*/ MOD_INC_USE_COUNT; return 0; }/*设备关闭*/int scull_release(struct inode *inode, struct file *filp){ MOD_DEC_USE_COUNT; return 0;}/*设备读操作*/ssize_t scull_read(struct file *filp, char *buf, size_t count, loff_t *f_pos){ Scull_Dev *dev = filp->private_data; int pos = *f_pos; ssize_t ret = 0; /*不允许重入*/ if (down_interruptible(&dev->sem)) return -ERESTARTSYS; /*判断读位置是否有效*/ if (pos >= dev->size) goto out; if (pos + count > dev->size) count = dev->size - pos; if (!dev->data) goto out; /*读数据到用户空间*/ if (copy_to_user(buf, &(dev->data[pos]), count)) { ret = -EFAULT; goto out; } *f_pos += count; ret = count; out: up(&dev->sem); return ret;}/*文件写操作*/ssize_t scull_write(struct file *filp, const char *buf, size_t count, loff_t *f_pos){ Scull_Dev *dev = filp->private_data; int pos = *f_pos; ssize_t ret = -ENOMEM; /*不允许重入*/ if (down_interruptible(&dev->sem)) return -ERESTARTSYS; /*判断写位置是否有效*/ if (pos >= dev->size) goto out; if (pos + count > dev->size) count = dev->size - pos; /*从用户空间写入数据*/ if (copy_from_user(&(dev->data[pos]), buf, count)) { ret = -EFAULT; goto out; } *f_pos += count; ret = count; out: up(&dev->sem); return ret;}/*文件定位*/loff_t scull_llseek(struct file *filp, loff_t off, int whence){ Scull_Dev *dev = filp->private_data; loff_t newpos; switch(whence) { case 0: /* SEEK_SET */ newpos = off; break; case 1: /* SEEK_CUR */ newpos = filp->f_pos + off; break; case 2: /* SEEK_END */ newpos = dev->size - 1; break; default: /* can't happen */ return -EINVAL; } if (newpos<0) return -EINVAL; filp->f_pos = newpos; return newpos;}/*IO操作*/int scull_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg){ int err = 0; int ret = 0; int ioarg = 0; /* 检测命令的有效性 */ if (_IOC_TYPE(cmd) != SCULL_IOC_MAGIC) return -ENOTTY; if (_IOC_NR(cmd) > SCULL_IOC_MAXNR) return -ENOTTY; /* 根据命令类型,检测参数空间是否可以访问 */ if (_IOC_DIR(cmd) & _IOC_READ) err = !access_ok(VERIFY_WRITE, (void *)arg, _IOC_SIZE(cmd)); else if (_IOC_DIR(cmd) & _IOC_WRITE) err = !access_ok(VERIFY_READ, (void *)arg, _IOC_SIZE(cmd)); if (err) return -EFAULT; /* 根据命令,执行相应的操作 */ switch(cmd) { /* 打印当前设备信息 */ case SCULL_IOCPRINT: printk("<--- CMD SCULL_IOCPRINT Done--->\n\n"); break; /* 获取参数 */ case SCULL_IOCGETDATA: ioarg = 1101; ret = __put_user(ioarg, (int *)arg); break; /* 设置参数 */ case SCULL_IOCSETDATA: ret = __get_user(ioarg, (int *)arg); printk("<--- In Kernel SCULL_IOCSETDATA ioarg = %d --->\n\n",ioarg); break; default: return -ENOTTY; } return ret;}/* * The following wrappers are meant to make things work with 2.0 kernels */struct file_operations scull_fops = { llseek: scull_llseek, read: scull_read, write: scull_write, ioctl: scull_ioctl, open: scull_open, release: scull_release,};/*卸载函数*/void scull_cleanup_module(void){ int i; /*注销字符设备*/ unregister_chrdev(scull_major, "scull"); /*释放内存*/ if (scull_devices) { for (i=0; i<SCULL_NR_DEVS; i++) kfree(scull_devices[i].data); kfree(scull_devices); }}/*加载函数*/int scull_init_module(void){ int result, i; /*设置模块owner*/ SET_MODULE_OWNER(&scull_fops); /*注册字符设备*/ result = register_chrdev(scull_major, "scull", &scull_fops); if (result < 0) { printk(KERN_WARNING "scull: can't get major %d\n",scull_major); return result; } if (scull_major == 0) scull_major = result; /*为设备描述结构分配内存*/ scull_devices = kmalloc(SCULL_NR_DEVS * sizeof(Scull_Dev), GFP_KERNEL); if (!scull_devices) { result = -ENOMEM; goto fail; } memset(scull_devices, 0, SCULL_NR_DEVS * sizeof(Scull_Dev)); /*为设备分配内存*/ for (i=0; i < SCULL_NR_DEVS; i++) { scull_devices[i].size = SCULL_SIZE; scull_devices[i].data = kmalloc(SCULL_SIZE, GFP_KERNEL); memset(scull_devices[i].data, 0, SCULL_SIZE); sema_init(&scull_devices[i].sem, 1); } return 0; fail: scull_cleanup_module(); return result;}module_init(scull_init_module);module_exit(scull_cleanup_module);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -