📄 main.c
字号:
case SCULL_IOCRESET: scull_quantum = SCULL_QUANTUM; scull_qset = SCULL_QSET; break; case SCULL_IOCSQUANTUM: /* Set: arg points to the value */ if (! capable (CAP_SYS_ADMIN)) return -EPERM; ret = __get_user(scull_quantum, (int *)arg); break; case SCULL_IOCTQUANTUM: /* Tell: arg is the value */ if (! capable (CAP_SYS_ADMIN)) return -EPERM; scull_quantum = arg; break; case SCULL_IOCGQUANTUM: /* Get: arg is pointer to result */ ret = __put_user(scull_quantum, (int *)arg); break; case SCULL_IOCQQUANTUM: /* Query: return it (it's positive) */ return scull_quantum; case SCULL_IOCXQUANTUM: /* eXchange: use arg as pointer */ if (! capable (CAP_SYS_ADMIN)) return -EPERM; tmp = scull_quantum; ret = __get_user(scull_quantum, (int *)arg); if (ret == 0) ret = __put_user(tmp, (int *)arg); break; case SCULL_IOCHQUANTUM: /* sHift: like Tell + Query */ if (! capable (CAP_SYS_ADMIN)) return -EPERM; tmp = scull_quantum; scull_quantum = arg; return tmp; case SCULL_IOCSQSET: if (! capable (CAP_SYS_ADMIN)) return -EPERM; ret = __get_user(scull_qset, (int *)arg); break; case SCULL_IOCTQSET: if (! capable (CAP_SYS_ADMIN)) return -EPERM; scull_qset = arg; break; case SCULL_IOCGQSET: ret = __put_user(scull_qset, (int *)arg); break; case SCULL_IOCQQSET: return scull_qset; case SCULL_IOCXQSET: if (! capable (CAP_SYS_ADMIN)) return -EPERM; tmp = scull_qset; ret = __get_user(scull_qset, (int *)arg); if (ret == 0) ret = put_user(tmp, (int *)arg); break; case SCULL_IOCHQSET: if (! capable (CAP_SYS_ADMIN)) return -EPERM; tmp = scull_qset; scull_qset = arg; return tmp; /* * The following two change the buffer size for scullpipe. * The scullpipe device uses this same ioctl method, just to * write less code. Actually, it's the same driver, isn't it? */ case SCULL_P_IOCTSIZE: scull_p_buffer = arg; break; case SCULL_P_IOCQSIZE: return scull_p_buffer; default: /* redundant, as cmd was checked against MAXNR */ return -ENOTTY; } return ret;}#else /* LINUX_20 */int scull_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg){ int err = 0, tmp; /* * extract the type and number bitfields, and don't decode * wrong cmds: return ENOTTY before verify_area() */ if (_IOC_TYPE(cmd) != SCULL_IOC_MAGIC) return -ENOTTY; if (_IOC_NR(cmd) > SCULL_IOC_MAXNR) return -ENOTTY; /* * the direction is a bitmask, and VERIFY_WRITE catches R/W * transfers. `Type' is user-oriented, while * verify_area is kernel-oriented, so the concept of "read" and * "write" is reversed */ if (_IOC_DIR(cmd) & _IOC_READ) err = verify_area(VERIFY_WRITE, (void *)arg, _IOC_SIZE(cmd)); else if (_IOC_DIR(cmd) & _IOC_WRITE) err = verify_area(VERIFY_READ, (void *)arg, _IOC_SIZE(cmd)); if (err) return err; switch(cmd) { case SCULL_IOCRESET: scull_quantum = SCULL_QUANTUM; scull_qset = SCULL_QSET; break; case SCULL_IOCSQUANTUM: /* Set: arg points to the value */ scull_quantum = get_user((int *)arg); break; case SCULL_IOCTQUANTUM: /* Tell: arg is the value */ scull_quantum = arg; break; case SCULL_IOCGQUANTUM: /* Get: arg is pointer to result */ put_user(scull_quantum, (int *)arg); break; case SCULL_IOCQQUANTUM: /* Query: return it (it's positive) */ return scull_quantum; case SCULL_IOCXQUANTUM: /* eXchange: use arg as pointer */ tmp = scull_quantum; scull_quantum = get_user((int *)arg); put_user(tmp, (int *)arg); break; case SCULL_IOCHQUANTUM: /* sHift: like Tell + Query */ tmp = scull_quantum; scull_quantum = arg; return tmp; case SCULL_IOCSQSET: scull_qset = get_user((int *)arg); break; case SCULL_IOCTQSET: scull_qset = arg; break; case SCULL_IOCGQSET: put_user(scull_qset, (int *)arg); break; case SCULL_IOCQQSET: return scull_qset; case SCULL_IOCXQSET: tmp = scull_qset; scull_qset = get_user((int *)arg); put_user(tmp, (int *)arg); break; case SCULL_IOCHQSET: tmp = scull_qset; scull_quantum = arg; return tmp; /* * The following two change the buffer size for scullpipe. * The scullpipe device uses this same ioctl method, just to * write less code. Actually, it's the same driver, isn't it? */ case SCULL_P_IOCTSIZE: scull_p_buffer = arg; break; case SCULL_P_IOCQSIZE: return scull_p_buffer; default: /* redundant, as cmd was checked against MAXNR */ return -ENOTTY; } return 0;}#endif /* LINUX_20 *//* * The "extended" operations -- only seek */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 + off; break; default: /* can't happen */ return -EINVAL; } if (newpos<0) return -EINVAL; filp->f_pos = newpos; return newpos;}/* * The following wrappers are meant to make things work with 2.0 kernels */#ifdef LINUX_20int scull_lseek_20(struct inode *ino, struct file *f, off_t offset, int whence){ return (int)scull_llseek(f, offset, whence);}int scull_read_20(struct inode *ino, struct file *f, char *buf, int count){ return (int)scull_read(f, buf, count, &f->f_pos);}int scull_write_20(struct inode *ino, struct file *f, const char *b, int c){ return (int)scull_write(f, b, c, &f->f_pos);}void scull_release_20(struct inode *ino, struct file *f){ scull_release(ino, f);}/* Redefine "real" names to the 2.0 ones */#define scull_llseek scull_lseek_20#define scull_read scull_read_20#define scull_write scull_write_20#define scull_release scull_release_20#define llseek lseek#endif /* LINUX_20 */struct file_operations scull_fops = { llseek: scull_llseek, read: scull_read, write: scull_write, ioctl: scull_ioctl, open: scull_open, release: scull_release,};/* * Finally, the module stuff */#ifdef CONFIG_DEVFS_FSdevfs_handle_t scull_devfs_dir;static char devname[4];#endif/* * The cleanup function is used to handle initialization failures as well. * Thefore, it must be careful to work correctly even if some of the items * have not been initialized */void scull_cleanup_module(void){ int i;#ifndef CONFIG_DEVFS_FS /* cleanup_module is never called if registering failed */ unregister_chrdev(scull_major, "scull");#endif#ifdef SCULL_DEBUG /* use proc only if debugging */ scull_remove_proc();#endif if (scull_devices) { for (i=0; i<scull_nr_devs; i++) { scull_trim(scull_devices+i); /* the following line is only used for devfs */ devfs_unregister(scull_devices[i].handle); } kfree(scull_devices); } /* and call the cleanup functions for friend devices */ scull_p_cleanup(); scull_access_cleanup(); /* once again, only for devfs */ devfs_unregister(scull_devfs_dir);}int scull_init_module(void){ int result, i; SET_MODULE_OWNER(&scull_fops);#ifdef CONFIG_DEVFS_FS /* If we have devfs, create /dev/scull to put files in there */ scull_devfs_dir = devfs_mk_dir(NULL, "scull", NULL); if (!scull_devfs_dir) return -EBUSY; /* problem */#else /* no devfs, do it the "classic" way */ /* * Register your major, and accept a dynamic number. This is the * first thing to do, in order to avoid releasing other module's * fops in scull_cleanup_module() */ 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; /* dynamic */#endif /* CONFIG_DEVFS_FS */ /* * allocate the devices -- we can't have them static, as the number * can be specified at load time */ 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].quantum = scull_quantum; scull_devices[i].qset = scull_qset; sema_init(&scull_devices[i].sem, 1);#ifdef CONFIG_DEVFS_FS sprintf(devname, "%i", i); devfs_register(scull_devfs_dir, devname, DEVFS_FL_AUTO_DEVNUM, 0, 0, S_IFCHR | S_IRUGO | S_IWUGO, &scull_fops, scull_devices+i);#endif } /* At this point call the init function for any friend device */ if ( (result = scull_p_init()) ) goto fail; if ( (result = scull_access_init()) ) goto fail; /* ... */#ifndef SCULL_DEBUG EXPORT_NO_SYMBOLS; /* otherwise, leave global symbols visible */#endif#ifdef SCULL_DEBUG /* only when debugging */ scull_create_proc();#endif return 0; /* succeed */ 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 + -