1、什么是globalmem虚拟设备
(1)、globalmem字符设备驱动中,分配一片内存大小为GLOBALMEM_SIZE(4K)的空间
(2)、提供对该片内存的读写、控制和定位函数
(3)、用户进程能够通过linux系统调用访问这篇内存
- #include <linux/module.h>
- #include <linux/init.h>
- #include <linux/types.h>
- #include <linux/fs.h>
- #include <linux/errno.h>
- #include <linux/mm.h>
- #include <linux/sched.h>
- #include <linux/cdev.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 254 /* 预设的globalmem 的主设备号 */
- static globalmem_major = GLOBALMEM_MAJOR;/*预设的globalmem的主设备号*/
- /*globalmem的设备结构体:包含了对应于globalmem字符设备的cdev 和 使用内存mem[GLOBALMEM_SIZE]*/
- struct globalmem_dev
- {
- struct cdev cdev; //cdev结构体
- unsigned char mem[GLOBALMEM_SIZE); //全局内存
- };
- struct globalmem_dev *globalmem_devp; //设备结构体指针
- /*文件打开函数*/
- int globalmem_open(struct inode *inode,struct file *filp)
- {
- filp->private_data = globalmem_devp; //将设备结构体指针赋值给文件私有数据指针
- return 0
- }
- /*文件释放函数*/
- int globalmem_release(struct inode *inode,struct file *filp)
- {
- return 0;
- }
- /*设备控制函数:ioctl()函数接受的MEM_CLEAR命令,这个命令将全局内存的有效数据长度清零,对于设备不支持的命令,ioctl()函数应该返回-EINVAL*/
- static int globalmen_ioctl(struct inode *inodep,struct file *filp,unsigned int cmd,unsigned long arg)
- {
- struct globalmen_dev *dev = filp->private_data; //获得设备结构体指针
- switch(cmd)
- {
- case MEE_CLEAR:
- memset(dev->mem,0,GLOBALMEM_SIZE);
- printk(KERN_INFO"globalmem is set to zero\n);
- break;
- default:
- return -EINVAL;
- }
- return 0;
- }
- /*读函数:读写函数主要是让设备结构体的mem[]数组与用户空间交互数据,并随着访问字节数变更返回用户的文件读写偏移位置*/
- static ssizez_t globalmem_read(struct file *filp,char __user *buf,size_t size,loff_t *opps)
- {
- unsigned long p = *ppos;
- unsigned int count = size;
- int ret = 0;
- struct globalmem_dev *dev = filp->private_data; //获得设备结构体指针
- if(p >= GLOBALMEM_SIZE) //分析和获取有效的写长度
- {
- return count ? -ENXIO:0;
- }
- if(count > GLOBAL_SIZE - P)
- {
- count = GLOBALMEN_SIZE - P;
- }
- if(copy_to_user(buf,(void *)(dev->mem+p),count)) //内核空间->用户空间
- {
- ret = -ENAU;T;
- }
- else
- {
- *oppos += count;
- ret = count;
- printk(KERN_INFO"read %d bytes(s) from %d\n",count,p);
- }
- return ret;
- }
- /*写函数*/
- static ssize_t globalmem_write(struct file *filp,const char __user *buf,size_t size,loff_t *ppos)
- {
- unsigned long *p = *ppos;
- unsigned int count = size;
- int ret;
- struct globalmem_dev *dev = filp->private_data;
- if(p >= CLOBALMEM_SIZE) //分析和获取有效的写长度
- {
- return count? -ENXIO:0;
- }
- if(count > GLOBALMEN_SIZE - P) // 要写的字节数太多
- {
- count = CLOBALMEN_SIZE - P;
- }
- if(copy_from_user(dev->mem + p,buf,count)) // 用户空间->内核空间
- {
- ret = -ENAULT;
- }
- else
- {
- *ppos =+ count;
- ret = count;
- printk(KERN_INFO"written %d bytes(s) from %d\n",count,p);
- }
- return ret;
- }
- /*seek文件定位函数:seek()函数对文件定位的起始地址可以是文件开头(SEEK_SET,0)、当前位置(SEEK_CUR,1)、文件尾(SEEK_END,2)*/
- static loff_t globalmem_llseek(struct file *filp,loff_t offset,int orig)
- {
- loff_t ret = 0;
- switch(orig)
- {
- case 0: //相对文件开始位置偏移
- if(offset <0 )
- {
- ret = -EINVAL;
- break;
- }
- if((unsigned int )offset > GLOBALMEM_SIZE)
- {
- ret = - EINVAL;
- break;
- }
- filp->f_ops = (unsigned int)offset;
- ret = filp->f_pos;
- break;
- case 1: //相对文件当前位置偏移
- if((filp->f_ops + offset) > GLOBALMEMSIZE)
- {
- ret = -EINVAL;
- break;
- }
- if((filp->f_ops + offset)<0)
- {
- ret = -ENVAL;
- break;
- }
- filp->f_ops +=offset;
- ret = filp->f_ops;
- break;
- default:
- ret = -EINVAL;
- break;
- }
- return ret;
- }
- /*文件操作结构体*/
- static 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;
- };
- /*初始化并注册cdev*/
- static void globalmem_setup_cdev(struct globalmem_dev *dev,int index)
- {
- int err,devno = MKDEV(globalmen_major,index);
- cdev_init(&dev->cdev,&globalmem_fops);
- dev->cdev.owner = THIS_MOUDEL;
- dev->cdev.ops = &golbalmem_fops;
- err = cdev_add(&dev->cdev,devno,1);
- if(err)
- {
- printk(KERN_NOTICE"Error %d adding LED%d",err,index);
- }
- }
- /*设备驱动模块加载函数*/
- static int __init 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;
- }
- /*模块卸载函数*/
- void __eixt globalmem_exit(void)
- {
- cdev_del(&globalmem_devp->cdev); //注销cdev
- kfree(globalmem_devp); //释放设备结构体内存
- unregister_chrdev_region(MKDEV(globalmem_major,0),1); //释放设备号
- }
- MODULE_AUTHOR("NOODLE");
- MODULE_LICENSE("GPL");
- mdule_param(globalmem_major,int,S_IRUGO);
- module_init(globalmem_init);
- module_exit(globalmem_exit);