Hasen的linux设备驱动开发学习之旅--增加了并发控制的设备驱动程序
2014-11-04 16:49
447 查看
/** * Author:hasen * 参考 :《linux设备驱动开发详解》 * 简介:android小菜鸟的linux * 设备驱动开发学习之旅 * 主题:增加了并发控制的设备驱动程序 * Date:2014-11-04 */ #define GLOBALMEM_SIZE 0x1000 /*全局变量大小:4KB*/ #define MEM_CLEAR 0x1 /*清零全局内存*/ #define GLOBALMEM_MAJOR 250 /*预设的globalmem的主设备号*/ static int globalmem_major =GLOBALMEM_MAJOR ; /*globalmem设备结构体*/ struct globalmem_dev { struct cdev cdev ; /*cdev结构体*/ unsigned char mem[GLOBALMEM_SIZE] ; /*全局内存*/ struct semaphore sem ; /*并发控制用的信号量*/ } ; struct globalmem_dev *globalmem_devp ;/*设备结构体实例*/ /*globalmem设备文件打开函数*/ int globalmem_open(struct inode *inode ,struct file *filp) { /*将设备结构体指针赋值给文件私有数据指针*/ filp->private_data = globalmem_devp ; return 0 ; } /*globalmem驱动设备文件释放函数*/ int globalmem_release(struct inode *inode,struct file *filp) { return 0 ; } /*globalmem设备驱动模块加载函数*/ int globalmem_init(void) { int result ; dev_t devno = MKDEV(globalmem_major ,0) ; /*申请字符设备驱动区域*/ if(globalmem_major) result = register_chrdev_region(devno,1,"globalmem") ; else{ /*动态获得主设备号*/ result = alloc_chrdev_region(&devno,0,1,"globalmem") ; globalmem_major = MAJOR(devno) ; } if(result < 0) return result ; /*动态申请设备结构体的内存*/ globalmem_devp = kmalloc(sizeof(struct globalmem_dev),GFP_KERNEL) ; if(!globalmem_devp){ /*申请失败*/ result = -ENOMEM ; goto fail_malloc ; } memset(globalmem_devp,0,sizeof(struct globalmem_dev)) ; globalmem_setup_cdev(&globalmem_devp,0) ; init_MUTEX(&globalmem_devp->sem) ; /*初始化信号量*/ return 0 ; fail_malloc : unregister_chrdev_region(devno,1) ; return result ; } /*globalmem设备驱动模块卸载函数*/ void globalmem_exit(void) { cdev_del(&globalmem_devp->cdev) ;/*删除cdev结构*/ kfree(globalmem_devp) ; unregister_chrdev_region(MKDEV(globalmem_major,0),1) ;/*注销设备区域*/ } /*初始化并添加cdev结构体*/ static void globalmem_setup_cdev(struct globalmem_dev *dev, int index) { int err , devno = MKDEV(globalmem_major ,index) ; cdev_init(&dev->cdev,&globalmem_fops) ; dev->cdev.owner = THIS_MODULE ; err = cdev_add(&dev->cdev,devno,1) ; if(err) printk(KERN_NOTICE "Error %d adding globalmem %d\n",err,index) ; } /*globalmem设备驱动文件操作结构体*/ const struct file_operations globalmem_fops = { .owner = THIS_MODULE , .llseek = globalmem_llseek , .read = globalmem_read , .write = globalmem_write , .ioctl = globalmem_ioctl , .open = globalmem_open , .release = globalmem_release , } ; /*globalmem设备驱动读函数*/ static ssize_t globalmem_read(struct file *filp,char __user *buf,size_t count,loff_t *ppos ) { unsigned long p = *ppos ; int ret = 0 ; struct globalmem_dev *dev = filp->private_data ;/*获取设备结构体指针*/ /*分析和获取有效的读长度*/ if(p >= GLOBALMEM_SIZE)/*要读的偏移位置越界*/ return 0 ; if(count > GLOBALMEM_SIZE - p)/*要读的字节数太大*/ count = GLOBALMEM_SIZE -P ; if(down_interruptible(&dev->sem)) /*获得信号量*/ return -ERESATRTSYS ; /*内核空间 -> 用户空间*/ if(copy_to_user(buf,(void *)(dev->mem + p),count)) ret = -EFAULT ; else{ *ppos += count ; ret = count ; printk(KERN_INFO "read %d bytes from %d\n",count,p) ; } up(&dev->sem) ; /*释放信号量*/ } /*globalmem设备驱动写函数*/ static ssize_t globalmem_write(struct file *filp,const char __user buf,size_t count,loff_t *ppos) { unsigned long p = *ppos ; int ret = 0 ; struct globalmem_dev *dev = filp->private_data ;/*获取设备结构体指针*/ /*分析和获取有效的写长度*/ if(p >= GLOBALMEM_SIZE) /*要写的偏移位置越界*/ return 0 ; if(count > GLOBALMEM_SIZE - p ) /*要写的字节数太大*/ count = GLOBALMEM_SIZE - p ; if(down_interruptible(&dev->sem)) /*获得信号量*/ return -ERESATRTSYS ; /*用户空间 -> 内核空间*/ if(copy_from_user(dev->mem+p, buf,count)) ret = -EFAULT ; else{ *ppos += count ; ret = count ; printk(KERN_INFO "write %d bytes from %d\n",count,p) ; } up(&dev->sem) ; /*释放信号量*/ return ret ; } /*globalmem设备驱动seek()函数*/ static loff_t globalmem_llseek(struct file *filp,loff_t offset,int orig) { loff_t ret ; switch(orig){ case 0: /*从文件开头开始偏移*/ if(offset <0){ ret = -EINVAL ; break ; } if((unsigned int)offset >GLOBALMEM_SIZE){ ret = -EINVAL ; break ; } flip->f_pos += offset ; ret = flip->f_pos ; break ; case 1: /*从文件当前位置开始偏移*/ if((flip->f_pos + offset) > GLOBALMEM_SIZE ){ ret = -EINVAL ; break ; } if((flip->f_pos + offset < 0)){ ret = -EINVAL ; break ; } flip->f_pos += offset ; ret = flip->f_pos ; break ; default: return -EINVAL ; } return ret ; } /*globalmem设备驱动的ioctl()函数*/ static int globalmem_ioctl(struct inode *inode,struct file *filp,unsigned int cmd,unsigned long arg) { struct globalmem_dev *dev = filp->private_data ;/*获取设备结构体指针*/ switch(cmd){ case CMD_CLEAR : if(down_interruptible(&dev->sem)) /*获得信号量*/ return -ERESATRTSYS ; /*清除全局变量*/ memset(dev->mem,0,GLOBALMEM_SIZE) ; up(&dev->sem) ; /*释放信号量*/ printk(KERN_INFO "globalmem is set to zero\n") ; break ; default: return -EINVAL ;/*其他不支持的命令*/ } return 0 ; } MODULE_AUTHOR("Hasen<hasen.dc@gmail.com>") ; MODULE_LICENSE("Dual BSD/GPL") ; module_param(globalmem_major,int,S_IRUGO) ; module_init(globalmem_init) ; module_exit(globalmem_exit) ;
相关文章推荐
- linux设备驱动开发学习之旅--增加了并发控制的设备驱动程序
- Hasen的linux设备驱动开发学习之旅--支持轮询操作的设备驱动
- Hasen的linux设备驱动开发学习之旅--使用文件私有数据的字符设备驱动
- linux 设备驱动开发学习笔记(一):并发控制
- Hasen的linux设备驱动开发学习之旅--支持阻塞的设备驱动
- Linux设备驱动开发详解-Note(14)--- Linux 设备驱动中的并发控制(1)
- linux设备驱动开发学习之旅--linux设备驱动中的并发与竞态
- Hasen的linux设备驱动开发学习之旅--linux设备驱动中的并发与竞态
- Hasen的linux设备驱动开发学习之旅--支持多设备的字符设备驱动
- Linux设备驱动开发基础---字符设备驱动程序开发之mini2440_ADC驱动
- Linux设备驱动开发基础---字符设备驱动程序开发之基于中断的按键驱动
- 深入浅出Linux设备驱动编程--设备驱动中的并发控制
- Linux设备驱动程序学习(6) -高级字符驱动程序操作[(3)设备文件的访问控制]
- Linux设备驱动开发基础---字符设备驱动程序开发
- Linux设备驱动程序学习(22)-Linux下PCI设备驱动程序开发
- Linux设备驱动程序学习(5)-并发和竞态
- Linux驱动程序开发 - 设备控制接口
- Linux字符设备驱动程序之并发控制
- 应用定时器,通过应用程序控制LED闪灭(linux设备驱动程序学习)
- 驱动程序学习(四)并发控制(2)自旋锁控制