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

来源:互联网 发布:模拟城市mac版 编辑:程序博客网 时间:2024/05/22 17:45
/** * 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
原创粉丝点击