您的位置:首页 > 运维架构 > Linux

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) ;
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐