- /**
- * Author:hasen
- * 参考 :《linux设备驱动开发详解》
- * 简介:android小菜鸟的linux
- * 设备驱动开发学习之旅
- * 主题:使用文件私有数据的字符设备驱动
- * Date:2014-10-31
- */
- #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 *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) ;
- 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(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 ;
- struct globalmem_dev *dev = filp->private_data ;/*获取设备结构体指针*/
- /*分析和获取有效的写长度*/
- 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)
- {
- struct globalmem_dev *dev = filp->private_data ;/*获取设备结构体指针*/
- 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 ;
- }
- 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设备驱动开发学习之旅--使用文件私有数据的字符设备驱动
最新推荐文章于 2024-03-05 16:56:35 发布