日期:2014-05-16 浏览次数:20697 次
源代码如下:
#include <linux/config.h> #include <linux/module.h> #include <linux/moduleparam.h> #include <linux/init.h> #include <linux/kernel.h> #include <linux/slab.h> #include <linux/fs.h> #include <linux/cdev.h> #include <asm/uaccess.h> //#include "scull.h" #define SCULL_MAJOR 0 /* dynamic major by default */ #define SCULL_NR_DEVS 4 /* scull0 through scull3 */ #define SCULL_P_NR_DEVS 4 /* scullpipe0 through scullpipe3 */ #define SCULL_QUANTUM 4000 #define SCULL_QSET 1000 struct scull_qset { void **data; struct scull_qset *next; }; struct scull_dev { struct scull_qset *data; /* Pointer to first quantum set */ int quantum; /* the current quantum size */ int qset; /* the current array size */ unsigned long size; /* amount of data stored here */ unsigned int access_key; /* used by sculluid and scullpriv */ struct semaphore sem; /* mutual exclusion semaphore */ struct cdev cdev; /* Char device structure */ }; int scull_major = SCULL_MAJOR; int scull_minor = 0; int scull_nr_devs = SCULL_NR_DEVS; int scull_quantum = SCULL_QUANTUM; int scull_qset = SCULL_QSET; module_param(scull_major, int, S_IRUGO); module_param(scull_minor, int, S_IRUGO); module_param(scull_nr_devs,int, S_IRUGO); module_param(scull_quantum, int, S_IRUGO); module_param(scull_qset,int,S_IRUGO); MODULE_AUTHOR("BG2BKK"); MODULE_LICENSE("Dual BSD/GPL"); struct scull_dev *scull_devices; int scull_trim(struct scull_dev *dev) { struct scull_qset *next,*dptr; int qset = dev->qset; int i; for(dptr = dev->data; dptr;dptr = next) { if(dptr->data){ for (i=0;i<qset;i++) kfree(dptr->data[i]); kfree(dptr->data); dptr->data = NULL; } next = dptr->next; kfree(dptr); } dev->size = 0; dev->quantum = scull_quantum; dev->qset = scull_qset; dev->data = NULL; return 0; } int scull_open(struct inode *inode, struct file *filp) { struct scull_dev *dev; dev = container_of(inode->i_cdev,struct scull_dev, cdev); filp->private_data = dev; if((filp->f_flags & O_ACCMODE) == O_WRONLY){ scull_trim(dev); } return 0; } int scull_release(struct inode *inode,struct file *filp) { printk(KERN_ALERT "scullrelease\n"); return 0; } struct scull_qset *scull_follow(struct scull_dev *dev,int n) { struct scull_qset *qs = dev->data; if(!qs) { qs = dev->data = kmalloc(sizeof(struct scull_qset),GFP_KERNEL); if(qs == NULL) return NULL; memset(qs,0,sizeof(struct scull_qset)); } while(n--) { if( !qs->next ){ qs->next = kmalloc(sizeof(struct scull_qset),GFP_KERNEL); if(qs->next == NULL) return NULL; memset(qs->next, 0 ,sizeof(struct scull_qset)); } qs = qs->next; continue; } return qs; } ssize_t scull_read(struct file *filp, char __user *buf, size_t count, loff_t *f_pos) { struct scull_dev *dev = filp->private_data; struct scull_qset *dptr; int quantum = dev->quantum, qset = dev->qset; int itemsize = quantum*qset; int item,s_pos,q_pos,rest; ssize_t retval = 0; if(down_interruptible(&dev->sem)) return -ERESTARTSYS; // printk("f_pos= %d\n",*f_pos); // printk("count= %d\n",count); if( *f_pos >= dev->size) goto out; if( *f_pos + count > dev->size) count = dev->size - *f_pos; item = (long)*f_pos / itemsize; rest = (long)*f_pos % itemsize; s_pos = rest / quantum; q_pos = rest % quantum; dptr = scull_follow(dev,item); if(dptr == NULL || !dptr->data || !dptr->data[s_pos]) goto out; if(count > quantum - q_pos) count = quantum - q_pos; if(copy_to_user(buf, dptr->data[s_pos] + q_pos, count)){ retval = -EFAULT; goto out; } // printk("read scull: %d\n",count); *f_pos += count; retval = count; out: u