Hasen的linux设备驱动开发学习之旅--简单字符驱动实例globalmem

/**
 * Author:hasen
 * 参考 :《linux设备驱动开发详解》
 * 简介:android小菜鸟的linux
 * 	         设备驱动开发学习之旅
 * 主题:简单的字符设备驱动globalmem
 * Date:2014-10-30
 */

/**
 * 	[1]分配和释放设备号:
 * 	分配函数:
 * 		(1)int register_chrdev_region(dev_t from,unsigned int count,const char *name) ;
 * 			用于已知起始设备的设备号的情况
 * 		(2)int alloc_chrdev_region(dev_t *dev,unsigned int firstminor,
 * 			unsigned int count,char *name) ;
 * 			用于设备号未知,向系统动态申请未被占用的设备号的情况
 * 	释放函数:
 * 		void unregister_chrdev_region(dev_t from,unsigned int count) ;
 * 			用于释放先前申请的设备号
 * 	[2]内核空间和用户空间内存互访
 * 		由于内核空间和用户空间内存不能直接互访,使用下面的方法实现间接互访,均返回不能被复制
 * 		的字节数,完全复制成功,返回0。
 * 		(1)unsigned long copy_from_user(void *to,const void __user *from,
 * 			unsigned long count);
 * 			(用户空间到内核空间复制数据)
 * 		(2)unsigned long copy_to_user(void __user *to,const void *from,
 * 			unsigned long count);
 * 			(内核空间到用户空间复制数据)
 * 	[3]cdev的操作函数
 * 		(1)void cdev_init(struct cdev *dev,struct file_operations *fops);
 * 			将字符设备驱动程序操作集与相关的cdev绑定
 * 		(2)int cdev_add(struct cdev *dev,dev_t devno,unsigned int count) ;
 * 			将设备号与cdev绑定,通常发生在驱动模块的加载函数中
 * 		(3)void cdev_del(struct cdev *dev) ;
 * 			移除一个cdev,通常发生在驱动模块的卸载函数中
 * 
 */


#include <linux/module.h>
#include <linux/types.h>
#include <linux/fs.h>
#include <linux/error.h>
#include <linux/mm.h>
#include <linux/sched.h>
#include <linux/cdev.h>
#include <linux/init.h>
#include <asm/io.h>
#include <asm/system.h>
#include <asm/uaccess.h>

#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 globalmem_dev dev ;/*设备结构体实例*/

/*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_setup_cdev() ;
	return 0 ;
}

/*globalmem设备驱动模块卸载函数*/
void globalmem_exit(void)
{
	cdev_del(&dev.cdev) ;/*删除cdev结构*/
	unregister_chrdev_region(MKDEV(globalmem_major,0),1) ;/*注销设备区域*/
}

/*初始化并天界cdev结构体*/
static void globalmem_setup_cdev()
{
	int err , devno = MKDEV(globalmem_major ,0) ;
	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\n",err) ;
}

/*globalmem设备驱动文件操作结构体*/
const struct file_operations globalmem_fops = {
	.owner = THIS_MODULE ,
	.llseek = globalmem_llseek ,
	.read = globalmem_read ,
	.write = globalmem_write ,
	.ioctl = globalmem_ioctl ,
} ;

/*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 ;
	
	/*分析和获取有效的读长度*/
	if(p >= GLOBALMEM_SIZE)/*要读的偏移位置越界*/
		return 0 ;
	if(count > GLOBALMEM_SIZE - p)/*要读的字节数太大*/
		count = GLOBALMEM_SIZE -P ;
	
	/*内核空间 -> 用户空间*/
	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) ;	
	}
}

/*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 ;
	
	/*分析和获取有效的写长度*/
	if(p >= GLOBALMEM_SIZE) /*要写的偏移位置越界*/
		return 0 ;
	if(count > GLOBALMEM_SIZE - p ) /*要写的字节数太大*/
		count = GLOBALMEM_SIZE - p ;
	
	/*用户空间 -> 内核空间*/
	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) ;
	}
	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)
{
	switch(cmd){
	case CMD_CLEAR :
		/*清除全局变量*/
		memset(dev->mem,0,GLOBALMEM_SIZE) ;
		printk(KERN_INFO "globalmem is set to zero\n") ;
		break ;
	default:
		return -EINVAL ;/*其他不支持的命令*/
	}
	return 0 ;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值