LINUX设备驱动程序阅读同步代码之二(scull管道)
#include<linux/module.h> #include<linux/init.h> #include<linux/list.h> #include<linux/fs.h> #include<linux/types.h> #include<linux/kdev_t.h> #include<linux/cdev.h> #include<linux/errno.h> #include<linux/slab.h> #include<asm/uaccess.h> #include<asm/ioctl.h> #include<linux/ioctl.h> #include<linux/semaphore.h> #include<linux/sched.h> #include<linux/poll.h> #define NR_DEVS 1 #define BUFFERSIZE 2048 MODULE_LICENSE("Dual BSD/GPL"); //************************************************ //下边这些是该设备模块的全局数据区 int scull_major=0; int scull_minor=0; unsigned int scull_nr_devs=NR_DEVS; int buffersize=BUFFERSIZE; struct scull_pipe { wait_queue_head_t inq,outq; char *buffer,*end; int buffersize; char *rp,*wp; int nreaders,nwriters; struct fasync_struct *async_queue; struct semaphore sem; //在此加入了信号量,互斥锁 struct cdev cdev; } scull_pipe; //************************************************************** // 赋值给struct file_operations结构的函数指针成员的函数 //************************************************************* ssize_t spacefree(struct scull_pipe *pipe) { if( pipe->rp == pipe->wp ) return pipe->buffersize-1; return ((pipe->rp-pipe->wp+pipe->buffersize)%pipe->buffersize)-1; } static int scull_getwritespace(struct scull_pipe *dev,struct file * filp) { while(spacefree(dev)==0) { DEFINE_WAIT(wait); up(&dev->sem); if(filp->f_flags&O_NONBLOCK) return -EAGAIN; printk(KERN_INFO "\"%s\" writing: going to sleep\n",current->comm); prepare_to_wait(&dev->outq,&wait,TASK_INTERRUPTIBLE); if(spacefree(dev)==0) schedule(); finish_wait(&dev->outq,&wait); if(signal_pending(current)) return -ERESTARTSYS; if(down_interruptible(&dev->sem)) return -ERESTARTSYS; } printk(KERN_INFO "here is in scull_getwritespace before return 0"); return 0; } ssize_t scull_p_read(struct file *filp,char __user *buf,size_t count,loff_t *f_pos) { struct scull_pipe *dev = filp->private_data; if( down_interruptible(&dev->sem) ) return -ERESTARTSYS; while(dev->rp == dev->wp ) { up(&dev->sem); if(filp->f_flags & O_NONBLOCK) return -EAGAIN; printk(KERN_INFO "\"%s\" reading: going to sleep\n",current->comm); if(wait_event_interruptible(dev->inq,(dev->rp != dev->wp))) return -ERESTARTSYS; if(down_interruptible(&dev->sem)) return -ERESTARTSYS; } if( dev->wp > dev->rp ) count = min(count,(size_t)(dev->wp-dev->rp)); else count = min(count,(size_t)(dev->end-dev->rp)); if(copy_to_user(buf,dev->rp,count)) { up(&dev->sem); return -EFAULT; } dev->rp += count; if(dev->rp == dev->end) dev->rp = dev->buffer; up(&dev->sem); wake_up_interruptible(&dev->outq); printk("\"%s\" did read %li bytes\n",current->comm,(long)count); return count; } ssize_t scull_p_write(struct file *filp,const char __user *buf,size_t count,loff_t *f_pos) { struct scull_pipe *dev = filp->private_data; int result; printk(KERN_INFO "start scull_p_write\n"); printk(KERN_INFO "1end of scull_p_write\n"); if( down_interruptible(&dev->sem) ) return -ERESTARTSYS; result = scull_getwritespace(dev,filp); printk(KERN_INFO "2end of scull_p_write\n"); if( result ) return result; printk(KERN_INFO "3end of scull_p_write\n"); count = min(count,(size_t)spacefree(dev)); printk(KERN_INFO "4end of scull_p_write\n"); if(dev->wp >= dev->rp ) count = min(count,(size_t)(dev->end-dev->wp)); else count = min(count,(size_t)(dev->rp-dev->wp-1)); printk(KERN_INFO "5end of scull_p_write\n"); if( copy_from_user(dev->wp,buf,count)) { up(&dev->sem); return -EFAULT; } printk(KERN_INFO "6end of scull_p_write\n"); dev->wp += count; if(dev->wp==dev->end) dev->wp=dev->buffer; printk(KERN_INFO "7end of scull_p_write\n"); up(&dev->sem); wake_up_interruptible(&dev->inq); if(dev->async_queue) kill_fasync(&dev->async_queue,SIGIO,POLL_IN); printk(KERN_INFO "8end of scull_p_write\n"); return count; } int scull_p_open(struct inode * inode,struct file *filp) { struct scull_pipe *dev; dev = container_of(inode->i_cdev,struct scull_pipe,cdev); filp->private_data = dev; printk(KERN_INFO "here is end of scull_open\n"); if( filp->f_mode &FMODE_READ ) dev->nreaders++; if( filp->f_mode &FMODE_WRITE ) dev->nwriters++; return 0; } static unsigned int scull_p_poll(struct file *filp,poll_table *wait) { struct scull_pipe *dev = filp->private_data; unsigned int mask=0; down(&dev->sem); printk(KERN_INFO "the scull_p_poll is called by vfs now!!!\n"); poll_wait(filp,&dev->inq,wait); poll_wait(filp,&dev->outq,wait); if(dev->rp!=dev->wp) mask |= POLLIN|POLLRDNORM; if(spacefree(dev)) mask |= POLLOUT |POLLWRNORM; up(&dev->sem); return mask; } struct file_operations scull_fops= { .owner = THIS_MODULE, .read = scull_p_read, .write = scull_p_write, .open = scull_p_open, .poll = scull_p_poll, }; //************************************************************* //以下是模块初始化和模块退出代码 //************************************************************ int get_major(void) { dev_t dev; int result; if( scull_major ) { 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_INFO "scull: can't get major %d\n",scull_major); return result; } return result; } static void scull_setup_cdev(struct scull_pipe *dev,int index) { int err,devno = MKDEV(scull_major,scull_minor+index); cdev_init(&dev->cdev,&scull_fops); dev->cdev.owner = THIS_MODULE; err = cdev_add(&dev->cdev,devno,scull_nr_devs); if( err ) printk(KERN_INFO "error %d adding scull %d",err,index); } static int scull_init(void) { int i=0; printk(KERN_INFO "scull_init \n"); get_major(); scull_setup_cdev(&scull_pipe,i); scull_pipe.buffersize = buffersize; scull_pipe.buffer = kmalloc(scull_pipe.buffersize,GFP_KERNEL); if( !scull_pipe.buffer ) { printk(KERN_INFO "kmalloc for buffer failed now,please rmmod the module\n"); return -1; } scull_pipe.rp = scull_pipe.buffer; scull_pipe.wp = scull_pipe.buffer; scull_pipe.end = scull_pipe.buffer+scull_pipe.buffersize; scull_pipe.nreaders = 0; scull_pipe.nwriters = 0; sema_init(&scull_pipe.sem,1); init_waitqueue_head(&scull_pipe.inq); init_waitqueue_head(&scull_pipe.outq); return 0; } static void scull_exit(void) { printk(KERN_INFO "scull_exit\n"); cdev_del(&scull_pipe.cdev); unregister_chrdev_region(MKDEV(scull_major,scull_minor),scull_nr_devs); kfree(scull_pipe.buffer); } module_init(scull_init); module_exit(scull_exit); //**************************************************************************
上面贴出来的代码就是供阅读《LINUX设备驱动程序》的朋友参考一下,我的系统是UBUNTU12.04的版本,下边的MAKEFILE文件也贴出来了:
obj-m := scull.o kernel_dir = /usr/src/linux-headers-3.2.0-29-generic-pae all: make -C $(kernel_dir) M=`pwd` modules clean: rm -rf *.ko *.mod.c *.o *.order *.symvers