LINUX设备驱动程序阅读同步代码
1 #include<linux/module.h> 2 #include<linux/init.h> 3 #include<linux/list.h> 4 #include<linux/fs.h> 5 #include<linux/types.h> 6 #include<linux/kdev_t.h> 7 #include<linux/cdev.h> 8 #include<linux/errno.h> 9 #include<linux/slab.h> 10 #include<asm/uaccess.h> 11 #include<asm/ioctl.h> 12 #include<linux/ioctl.h> 13 #include<linux/semaphore.h> 14 #include"scull.h" 15 16 #define SCULL_QUANTUM 4000 17 #define SCULL_QSET 1000 18 #define NR_DEVS 1 19 20 21 22 MODULE_LICENSE("Dual BSD/GPL"); 23 24 //************************************************ 25 //下边这些是该设备模块的全局数据区 26 int scull_quantum = SCULL_QUANTUM; 27 int scull_qset = SCULL_QSET; 28 29 int scull_major=0; 30 int scull_minor=0; 31 unsigned int scull_nr_devs=NR_DEVS; 32 33 34 struct scull_qset 35 { 36 void **data; 37 struct scull_qset *next; 38 }; 39 40 struct scull_dev 41 { 42 struct scull_qset *data; 43 int quantum; 44 int qset; 45 unsigned long size; 46 struct semaphore sem; //在此加入了信号量, 47 struct cdev cdev; 48 } scull_dev[NR_DEVS]; 49 50 //************************************************** 51 //供底层调用的内部函数 52 //************************************************** 53 static int scull_trim(struct scull_dev *dev) 54 { 55 struct scull_qset *next,*dptr; 56 57 int i; 58 if( dev->data == NULL ) 59 goto out; 60 for( next=dev->data; next; ) 61 { 62 dptr=next; 63 next=next->next; 64 if( dptr->data ) 65 { 66 for(i=0;i<dev->qset;i++) 67 { 68 kfree(dptr->data[i]); 69 } 70 kfree(dptr->data); 71 } 72 kfree(dptr); 73 } 74 dev->data = NULL; 75 out: 76 77 dev->size =0; 78 dev->quantum = scull_quantum; 79 dev->qset = scull_qset; 80 sema_init(&dev->sem,1); 81 return 0; 82 } 83 84 85 static struct scull_qset *scull_follow(struct scull_dev *dev,int index) 86 { 87 int i; 88 struct scull_qset *dptr=NULL,*next=dev->data; 89 printk(KERN_INFO "dev->data=%p\n",dev->data); 90 for(i=0;i<=index;i++) 91 { 92 dptr = next; 93 if( !dptr ) 94 { 95 dptr=kmalloc(sizeof(struct scull_qset),GFP_KERNEL); 96 if( !dptr ) 97 return NULL; 98 dptr->next=NULL; 99 dptr->data=NULL; 100 if( i==0 ) 101 dev->data = dptr; 102 } 103 104 next = dptr->next; 105 } 106 printk(KERN_INFO "after follow:the dev->data=%p\n",dev->data); 107 return dptr; 108 } 109 //************************************************************** 110 // 赋值给struct file_operations结构的函数指针成员的函数 111 //************************************************************* 112 ssize_t scull_read(struct file *filp,char __user *buf,size_t len,loff_t *f_pos) 113 { 114 struct scull_dev *dev = filp->private_data; 115 int node_index,qset_index,quantum_index; 116 struct scull_qset *dptr; 117 int retval=0; 118 if( down_interruptible(&dev->sem) ) 119 return -ERESTARTSYS; 120 if( dev->size <= *f_pos ) 121 goto out; 122 123 node_index = (long)(*f_pos) /( dev->quantum * dev->qset ); 124 qset_index = ( (long)(*f_pos) / dev->quantum )% dev->qset ; 125 quantum_index = (long)(*f_pos) % dev->quantum; 126 127 if( dev->size < *f_pos+len ) 128 len = dev->size-*f_pos; 129 if( quantum_index + len > dev->quantum ) 130 len = dev->quantum-quantum_index; 131 132 133 dptr = scull_follow(dev,node_index); 134 if( !dptr || !dptr->data || !dptr->data[qset_index] ) 135 goto out; 136 if( copy_to_user(buf,dptr->data[qset_index]+quantum_index,len) ) 137 { 138 retval = -EFAULT; 139 goto out; 140 } 141 retval = len; 142 *f_pos = *f_pos+len; 143 out: 144 up(&dev->sem); 145 return retval; 146 } 147 148 ssize_t scull_write(struct file *filp,const char __user *buf,size_t len,loff_t *f_pos) 149 { 150 struct scull_dev *dev = filp->private_data; 151 int node_index,qset_index,quantum_index; 152 struct scull_qset *dptr=NULL; 153 int retval=0; 154 if( down_interruptible(&dev->sem) ) 155 return -ERESTARTSYS; 156 node_index = (long)(*f_pos) /( dev->quantum * dev->qset ); 157 qset_index = ( (long)(*f_pos) / dev->quantum )% dev->qset ; 158 quantum_index = (long)(*f_pos) % dev->quantum; 159 printk(KERN_INFO "here is in scull_write before scull_follow\n"); 160 dptr = scull_follow(dev,node_index); 161 printk(KERN_INFO "here is in scull_write after scull_follow\n"); 162 if( dptr ) 163 { 164 if( !dptr->data ) 165 { 166 dptr->data = kmalloc(sizeof(void*)*dev->qset,GFP_KERNEL); 167 if( !dptr->data ) 168 goto out; 169 memset(dptr->data,0,dev->qset*sizeof(void*)); 170 } 171 if( !dptr->data[qset_index] ) 172 { 173 dptr->data[qset_index] = kmalloc(dev->quantum,GFP_KERNEL); 174 if( !dptr->data[qset_index] ) 175 goto out; 176 } 177 if( quantum_index + len > dev->quantum ) 178 len = dev->quantum-quantum_index; 179 if( copy_from_user(dptr->data[qset_index]+quantum_index,buf,len) ) 180 { 181 retval = -EFAULT; 182 goto out; 183 } 184 185 retval = len; 186 *f_pos = *f_pos+len; 187 if( dev->size < *f_pos ) 188 dev->size += *f_pos; 189 } 190 printk(KERN_INFO "here is in scull_write before out label\n"); 191 out: 192 up(&dev->sem); 193 return retval; 194 } 195 196 int scull_open(struct inode * inode,struct file *filp) 197 { 198 struct scull_dev *dev; 199 dev = container_of(inode->i_cdev,struct scull_dev,cdev); 200 filp->private_data = dev; 201 if( ( filp->f_flags & O_ACCMODE ) == O_WRONLY ) 202 scull_trim(dev); 203 printk(KERN_INFO "here is end of scull_open\n"); 204 return 0; 205 } 206 207 long scull_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) 208 { 209 long retval=0,tmp; 210 switch(cmd) 211 { 212 case SCULL_IOCRESET : 213 scull_quantum = SCULL_QUANTUM; 214 scull_qset = SCULL_QSET; 215 break; 216 case SCULL_IOCSQUANTUM : 217 if( !capable(CAP_SYS_ADMIN)) 218 return -EPERM; 219 retval = __get_user(scull_quantum,(int __user*)arg); 220 break; 221 222 case SCULL_IOCTQUANTUM : 223 if(!capable(CAP_SYS_ADMIN)) 224 return -EPERM; 225 scull_quantum = arg; 226 break; 227 228 case SCULL_IOCGQUANTUM : 229 retval = __put_user(scull_quantum,(int __user*)arg); 230 break; 231 case SCULL_IOCQQUANTUM : 232 return scull_quantum; 233 234 case SCULL_IOCXQUANTUM : 235 if(!capable(CAP_SYS_ADMIN)) 236 return -EPERM; 237 tmp = scull_quantum; 238 retval = __get_user(scull_quantum,(int __user*)arg); 239 if(retval == 0 ) 240 retval = __put_user(tmp,(int __user*)arg); 241 break; 242 case SCULL_IOCHQUANTUM : 243 if( !capable(CAP_SYS_ADMIN)) 244 return -EPERM; 245 tmp = scull_quantum; 246 scull_quantum=arg; 247 return tmp; 248 default: return -ENOTTY; 249 250 } 251 return retval; 252 } 253 254 255 struct file_operations scull_fops= 256 { 257 .owner = THIS_MODULE, 258 .read = scull_read, 259 .write = scull_write, 260 .open = scull_open, 261 .unlocked_ioctl = scull_ioctl, 262 }; 263 //************************************************************* 264 //以下是模块初始化和模块退出代码 265 //************************************************************ 266 267 268 int get_major(void) 269 { 270 dev_t dev; 271 int result; 272 if( scull_major ) 273 { 274 dev = MKDEV(scull_major,scull_minor); 275 result=register_chrdev_region(dev,scull_nr_devs,"scull"); 276 } 277 else 278 { 279 result=alloc_chrdev_region(&dev,scull_minor,scull_nr_devs,"scull"); 280 scull_major = MAJOR(dev); 281 } 282 if( result<0 ) 283 { 284 printk(KERN_INFO "scull: can't get major %d\n",scull_major); 285 return result; 286 } 287 return result; 288 } 289 290 291 static void scull_setup_cdev(struct scull_dev *dev,int index) 292 { 293 int err,devno = MKDEV(scull_major,scull_minor+index); 294 cdev_init(&dev->cdev,&scull_fops); 295 dev->cdev.owner = THIS_MODULE; 296 err = cdev_add(&dev->cdev,devno,scull_nr_devs); 297 if( err ) 298 printk(KERN_INFO "error %d adding scull %d",err,index); 299 } 300 301 static int scull_init(void) 302 { 303 int i; 304 printk(KERN_INFO "scull_init \n"); 305 get_major(); 306 for(i=0;i<scull_nr_devs;i++) 307 { 308 scull_setup_cdev(scull_dev+i,i); 309 if( scull_trim(scull_dev+i) ) 310 return -1; 311 } 312 return 0; 313 } 314 315 static void scull_exit(void) 316 { 317 int i; 318 printk(KERN_INFO "scull_exit\n"); 319 for(i=0;i<scull_nr_devs;i++) 320 { 321 cdev_del(&((scull_dev+i)->cdev)); 322 } 323 unregister_chrdev_region(MKDEV(scull_major,scull_minor),scull_nr_devs); 324 325 } 326 327 module_init(scull_init); 328 module_exit(scull_exit); 329 330 //**************************************************************************
以上代码是边看书边敲出来的,综合书上的理论和部分示例代码写的整个模块代码,对于在学LINUX设备驱动程序的朋友们如果正在看《LINUX设备驱动程序》这本书的话,可以参考一下这些代码。
以下还有一个“scull.h"头文件的内容:
#ifndef __SCULL_H_ #define __SCULL_H_ #include<linux/errno.h> #include<asm/ioctl.h> #include<linux/ioctl.h> #define SCULL_IOC_MAGIC 'k' #define SCULL_IOCRESET _IO(SCULL_IOC_MAGIC,0) #define SCULL_IOCSQUANTUM _IOW(SCULL_IOC_MAGIC,1,int) #define SCULL_IOCSQSET _IOW(SCULL_IOC_MAGIC,2,int) #define SCULL_IOCTQUANTUM _IO(SCULL_IOC_MAGIC,3) #define SCULL_IOCTQSET _IO(SCULL_IOC_MAGIC,4) #define SCULL_IOCGQUANTUM _IOR(SCULL_IOC_MAGIC,5,int) #define SCULL_IOCGQSET _IOR(SCULL_IOC_MAGIC,6,int) #define SCULL_IOCQQUANTUM _IO(SCULL_IOC_MAGIC,7) #define SCULL_IOCQQSET _IO(SCULL_IOC_MAGIC,8) #define SCULL_IOCXQUANTUM _IOWR(SCULL_IOC_MAGIC,9,int) #define SCULL_IOCXQSET _IOWR(SCULL_IOC_MAGIC,10,int) #define SCULL_IOCHQUANTUM _IO(SCULL_IOC_MAGIC,11) #define SCULL_IOCHQSET _IO(SCULL_IOC_MAGIC,12) #define SCULL_IOC_MAXNR 14 #endif
欢迎朋友指正。