#include <linux/module.h> #include <linux/moduleparam.h> #include <linux/init.h>
#include <linux/kernel.h> /*printk()*/ #include <linux/slab.h> /*kmalloc()*/ #include <linux/fs.h> /*everything...*/ #include <linux/errno.h> /*error codes*/ #include <linux/types.h> /*size_t*/ #include <linux/cdev.h> /*cdev struct*/ #include <asm/system.h> /*cli(),*_flags*/ #include <asm/uaccess.h> /*copy_ ....*/ #include "scull_t1.h" /*attention to the "" and <>*/
/* *Our parameters which can be set at load time. * */ int scull_major = SCULL_MAJOR; int scull_minor = 0; int scull_nr_devs = SCULL_NR_DEVS; /*number of bare scull devs*/ int scull_quantum = SCULL_QUANTUM; /*every one of quantum array has a quantum size*/ int scull_qset = SCULL_QSET; /*the longth of quantum-set*/
module_param(scull_major,int,S_IRUGO); /*knowledge 1*/ module_param(scull_monor,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);
struct scull_dev *scull_devices; /*allocated in scull_init_module*/ /* *Empty out (like "clean up")the scull device */ int scull_trim(struct scull_dev *dev) /*知識點(diǎn)4*/ { struct scull_qset *next,*dptr; int qset = dev->qset; /*amount of quantum*/ int i;
for(dptr = dev->data;dptr;dptr = next) /*循環(huán)scull_qset list 個數(shù)*/ { if(dptr->data) { for(i = 0; i<qset; i++) kfree(dptr->data[i]); /*釋放dptr指向的數(shù)組的每個數(shù)組元素指向的quantum空間*/
kfree(dptr->data);/* 釋放當(dāng)前的scull_set的量子集的空間*/ dptr->data = NULL;/* 釋放一個scull_set中的void **data指針*/ /*其實(shí)就我個人寫的話下面那句指向空會漏掉*/ } next = dptr->next; /*下一個scull_qset list開始*/ kfree(dptr); /*knowledge 2*/ } dev->size =0; /*amount of data store here 為0*/ dev->quantum = scull_quantum; /*set the quantum'size*//*你不是清空不,怎么還來設(shè)置它的大小啊*/ dev->qset = scull_qset; /*set the number of quantum in a array*//*同上的疑問*/ dev->data = NULL; /*釋放當(dāng)前的scull_device的struct scull_qset *data指針*/ return 0; }
/********************************************************************/ /* *Open and close */ int scull_open(struct inode *inode,struct file *filp) { struct scull_dev *dev; /*the information of this dev*/
dev = contairner_of(inode->i_cdev,struct scull_dev, cdev); /*知識點(diǎn)3*/ flip->private_data = dev; /*.將獲得的dev保存到filp->private_data*/ /*如果是以只讀模式打開則調(diào)用scull_trim()截短設(shè)備為0*/ if((filp->f_flags&O_ACCMODE) == O_WRONLY) /*這里注意是檢測打開的方式不是讀寫權(quán)限f_mode*/ { if(down_interruptible(&dev->sem)) /* 對訪問區(qū)域加鎖*/ return -ERESTARTSYS; /*猜想應(yīng)該是信號量不可用的意思吧??*/ scull_trim(dev); up(&dev->sem); /* 解鎖*/ }
}
int scull_release(struct inode *inode, struct file *filp) { return 0; /*由于前面定義了scull是一個全局且持久的內(nèi)存區(qū),所以他的release什么都不做*/ }
/* *Follow the list */ struct scull_qset *scull_follow(struct scull_dev *dev,int n) { struct scull_qset *qs = dev->data;
/*Allocate frist qset explicitly if need be*/ if(! qs) /*當(dāng)list為null時*/ { qs = dev->data = kmalloc(sizeof(struct scull_qset),GFP_KERNEL); if(qs == NULL) return NULL; /*??*/ memset(qs,0,sizeof(struct scull_qset)); } /*follow the list*/ while(n--) { if(!qs->next) { qs->next = kmalloc(sizeof(struct scull_qset), GFP_KERNEL); if (qs->next == NULL) return NULL; /* Never mind */ memset(qs->next, 0, sizeof(struct scull_qset)); } qs = qs->next; continue; /*這下我傻了*/ return qs; } }
/* *read and write */
ssize_t scull_read(struct file *filp, char __user *buf, size_t count, loff_t *f_pos) { struct scull_dev *dev = filp->private_data; /*獲得已經(jīng)保存在其中的設(shè)備結(jié)構(gòu)體入口指針*/ struct scull_qset *dptr; /*the first listitem*/ 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 -ERESTARSYS; if(*f_pos >= dev->size) /*判讀off_t *f_pos參數(shù)是否超越了設(shè)備存儲的范圍*/ goto out; if(*f_pos+count > dev->size) count = dev->size - *f_pos;
/*find listitem,qset index,and offset in the quantum*//* 根據(jù)數(shù)組結(jié)構(gòu)得出相應(yīng)數(shù)據(jù) */ item = (long)*f_pos/ itemsize; /*long???why???*/ rest = (long)*f_pos%itemsize; s_pos = rest/quantum; /*no long ??why??*/ q_pos = rest%quantum;
/*follow the list up to the right position(defined elsewhere)*/ dptr = scull_follow(dev,item); /*判斷各個數(shù)值的合法性并做修正*/ if(dptr == NULL||!dptr->data||!dptr->data||!dptr->data[s_pos]) goto out; /*read only up to the end of this quantum*/ if(count>quantum - q_pos) count = quantum -q_pos; /*將內(nèi)核數(shù)據(jù)復(fù)制到用戶區(qū)域*/ if(copy_to_user(buf, dptr->data[s_pos]+q_pos,count))/*發(fā)現(xiàn)自己對返回值還是不足*/ { retval = -EFUALT; /*上面應(yīng)該是成功返回0非成功返回非0即真*/ goto out; } *f_pos += count; retval = count; out: up(&dev->sem); return retval; }
ssize_t scull_write(struct file *filp, const 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 = -ENOMEM; /*no mem used in "goto out"*/
if(down_interruptible(&dev->sem)) return -ERESTART; /*同read*/ item = (long)*f_pos / itemsize; rest = (long)*f_pos % itemsize;
s_pos = rest / quantum; q_pos = rest % quantum;
/* follow the list up to the right position */ /*同read*/ dptr = scull_follow(dev, item); if (dptr == NULL) goto out; if (!dptr->data) { dptr->data = kmalloc(qset * sizeof(char *), GFP_KERNEL); if (!dptr->data) goto out; memset(dptr->data, 0, qset * sizeof(char *)); } if (!dptr->data[s_pos]) { dptr->data[s_pos] = kmalloc(quantum, GFP_KERNEL); if (!dptr->data[s_pos]) goto out; } if (count > quantum - q_pos) count = quantum - q_pos; /*注意假如內(nèi)核訪問用戶區(qū)域,由于user域存在分頁機(jī)制, 進(jìn)程有可能被休眠以等待不再當(dāng)前頁中的數(shù)據(jù),所以需要 copy_from_user函數(shù)是可重入的.*/
if(copy_from_user(dptr->data[s_pos]+q_pos, buf, count)) { retval = -EFAULT; /*bad address*/ goto out; } *f_pos +=count; retval = count; /*updata the size*/ /*實(shí)際上大多數(shù)情況讀寫函數(shù)是不能完全讀寫完的,所以做更新方便讀寫完的操作*/ if(dev->size< *f_pos) dev->size = *f_pos;
out: up(&dev->sem); return retval; }
/*set file_operations*/ struct file_operations scull_fops = { .owner = THIS_MODULE, .read = scull_read, .write = scull_write, .open = scull_open, .release = scull_release, };
/*init and exit*/ void scull_cleanup_module(void) { int i; dev_t devno = MKDEV(scull_major,scull_minor);/*獲取設(shè)備號*/
/*get rid of dev entries*/ if(scull_devices) { for(i = 0; i<scull_nr_devs; i++ ) { scull_trim(scull_devices +i); cdev_del(&scull_devices[i].cdev); } kfree(scull_devices); } unregister_chrdev_region(devno, scull_nr_devs); }
/* *set up the char_dev structure for this device */ static void scull_setup_cdev(struct scull_dev *dev, int index) { int err,devno = MKDEV(scull_major,scull_minor+index); /*初始化cdev,主要是指定其fops */ cdev_init(&dev->cdev,&scull_fops); /*注冊設(shè)備結(jié)構(gòu)體*//*知識點(diǎn)5*/ dev->cdev.owner = THIS_MODULE; /*注意這里是先注冊再初始化有些元素,原因有待查*/ dev->cdev.ops = &scull_fops; /*cdev->init里面已經(jīng)初始化了 可省略*/ err = cdev_add(&dev->cdev, devno,1) /*告知內(nèi)核該結(jié)構(gòu)體信息,設(shè)備注冊到這里才算真的激活*/ if(err) printk(KERN_NOTICE "Error %d adding scull%d",err,index); /*這個失敗的可能很小書上這么提到why??*/ }
int scull_init_module(void) { int result,i; dev_t dev = 0; if (scull_major) /*選擇是否自動獲取設(shè)備號*/ { dev = MKDEV(scull_major, scull_minor); result = register_chrdev_region(dev, scull_nr_devs, "scull"); } else { result = alloc_chrdev_region(&dev, scull_minor, scull_nr_devs, "scull"); scull_major = MAJOR(dev); } if (result < 0) { printk(KERN_WARNING "scull: can't get major %d\n", scull_major); return result; } /* *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(struct scull_dev), GFP_KERNEL);/*分配nr個scull_dev的內(nèi)存*/ if(!scull_devices) { result = -ENOMEM; /*NO enogh memory */ goto fail; } memset(scull_devices,0,scull_nr_devs*sizeof(struct scull_dev)); /*kmalloc不清空*/
/*init each device*/ for(i = 0; i<scull_nr_devs;i++) { scull_devices[i].quantum = scull_quantum; scull_devices[i].qset = scull_qset; init_MUTEX(&scull_devices[i].sem); /*初始化旗幟變量 用于down_interruptible up(&xxx_dev->sem);*/ scull_setup_cdev(&scull_devices[i],i); /*這個一定記得放于最后*/ } return 0; /*succeed*/ fail: /*知識點(diǎn)6 goto*/ scull_cleanup_module(); return result; }
/*加載 注銷*/ module_init(scull_init_module); module_exit(scull_cleanup_module); /*程序信息*/ MODULE_AUTHOR("小獸"); MODULE_LICENSE("Dual BSD/GPL"); /*聽說不寫這個會有警告,等下編譯的時候試驗(yàn)下*/
|