博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
字符设备驱动的组成
阅读量:4654 次
发布时间:2019-06-09

本文共 6540 字,大约阅读时间需要 21 分钟。

1.在字符设备驱动模块加载函数中应该实现设备号的申请和cdev 的注册,而在卸载函数中应实现设备号的释放和cdev 的注销。

1//设备结构体2 struct xxx_dev_t3 {4 struct cdev cdev;5 ...6 } xxx_dev;7 //设备驱动模块加载函数8 static int _ _init xxx_init(void)9 {10 ...11 cdev_init(&xxx_dev.cdev, &xxx_fops); //初始化cdev12 xxx_dev.cdev.owner = THIS_MODULE;13 //获取字符设备号14 if (xxx_major)15 {16 register_chrdev_region(xxx_dev_no, 1, DEV_NAME);17 }18 else19 {20 alloc_chrdev_region(&xxx_dev_no, 0, 1, DEV_NAME);21 }2223 ret = cdev_add(&xxx_dev.cdev, xxx_dev_no, 1); //注册设备24 ...25 }26 /*设备驱动模块卸载函数*/27 static void _ _exit xxx_exit(void)28 {29 unregister_chrdev_region(xxx_dev_no, 1); //释放占用的设备号30 cdev_del(&xxx_dev.cdev); //注销设备31 ...32 }

2.file_operations 结构体中成员函数是字符设备驱动与内核的接口,是用户空间对Linux 进行系统调用最终的落实者。大多数字符设备驱动会实现read()、write()和ioctl()函数。

1 struct file_operations xxx_fops =2 {3 .owner = THIS_MODULE,4 .read = xxx_read,5 .write = xxx_write,6 .ioctl = xxx_ioctl,7 ...8 };

 

下面将基于虚拟的 globalmem 设备进行字符设备驱动。globalmem 意味着“全局内存”,在globalmem 字符设备驱动中会分配一片大小为GLOBALMEM_ SIZE的内存空

间,并在驱动中提供针对该片内存的读写、控制和定位函数,以供用户空间的进程能通过Linux 系统调用访问这片内存。

1 #include
2 #include
3 #include
4 #include
5 #include
6 #include
7 #include
8 #include
9 #include
10 #include
11 #include
12 #include
13 #include
14 #include
15 16 #define GLOBALMEM_SIZE 0x1000 17 #define MEM_CLEAR 0x1 18 #define GLOBALMEM_MAJOR 254 /*预设的globalmem 的主设备号*/ 19 20 static int globalmem_major = GLOBALMEM_MAJOR; 21 /*globalmem 设备结构体*/ 22 struct globalmem_dev 23 { 24 struct cdev cdev; 25 unsigned char mem[GLOBALMEM_SIZE]; 26 }; 27 struct globalmem_dev *globalmem_devp; /*设备结构体指针*/ 28 /*文件打开函数*/ 29 int globalmem_open(struct inode *inode, struct file *filp) 30 { 31 filp->private_data = globalmem_devp;/*将设备结构体指针赋值给文件私有数据指针*/ 32 return 0; 33 } 34 /*文件释放函数*/ 35 int globalmem_release(struct inode *inode, struct file *filp) 36 { 37 return 0; 38 } 39 /* ioctl 设备控制函数 */ 40 static int globalmem_ioctl(struct inode *inodep, struct file *filp, unsigned int cmd, unsigned long arg) 41 { 42 struct globalmem_dev *dev = filp->private_data;/*获得设备结构体指针*/ 43 switch (cmd) 44 { 45 case MEM_CLEAR: 46 memset(dev->mem, 0, GLOBALMEM_SIZE); 47 printk(KERN_INFO "globalmem is set to zero\n"); 48 break; 49 default:return - EINVAL; 50 } 51 return 0; 52 } 53 /*读函数*/ 54 static ssize_t globalmem_read(struct file *filp, char __user *buf, size_t size, loff_t *ppos) 55 { 56 unsigned long p = *ppos; 57 unsigned int count = size; 58 int ret = 0; 59 struct globalmem_dev *dev = filp->private_data; 60 if (p >= GLOBALMEM_SIZE) 61 return count ? - ENXIO: 0; 62 if (count > GLOBALMEM_SIZE - p) 63 count = GLOBALMEM_SIZE - p; 64 /*内核空间→用户空间*/ 65 if (copy_to_user(buf, (void*)(dev->mem + p), count)) 66 { 67 ret = - EFAULT; 68 } 69 else 70 { 71 *ppos += count; 72 ret = count; 73 printk(KERN_INFO "read %d bytes(s) from %d\n",count,p); 74 } 75 return ret; 76 } 77 /*写函数*/ 78 static ssize_t globalmem_write(struct file *filp, const char __user *buf,size_t size, loff_t *ppos) 79 { 80 unsigned long p = *ppos; 81 unsigned int count = size; 82 int ret = 0; 83 struct globalmem_dev *dev = filp->private_data; 84 if (p >= GLOBALMEM_SIZE) 85 return count ? - ENXIO: 0; 86 if (count > GLOBALMEM_SIZE - p) 87 count = GLOBALMEM_SIZE - p; 88 /*用户空间→内核空间*/ 89 if (copy_from_user(dev->mem + p, buf, count)) 90 { 91 ret = - EFAULT; 92 } 93 else 94 { 95 *ppos += count; 96 ret = count; 97 printk(KERN_INFO "written %d bytes(s) from %d\n", count, p); 98 } 99 return ret;100 }101 /* seek 文件定位函数 */102 static loff_t globalmem_llseek(struct file *filp,loff_t offset,int orig)103 {104 loff_t ret = 0;105 switch(orig)106 {107 case 0: /*相对文件开始位置偏移*/108 if(offset < 0)109 {110 ret = -EINVAL;//111 break;112 }113 if((unsigned int)offset > GLOBALMEM_SIZE)114 {115 ret = -EINVAL;116 break;117 }118 filp->f_pos = (unsigned int)offset;119 ret = filp->f_pos;120 break;121 case 1: /*相对文件当前位置偏移*/122 if((filp->f_pos + offset) > GLOBALMEM_SIZE)123 {124 ret = -EINVAL;125 break;126 }127 if((filp->f_pos + offset) < 0)128 {129 ret = -EINVAL;130 break;131 }132 filp->f_pos +=offset;133 ret = filp->f_pos;134 break;135 default:136 ret = -EINVAL;137 break;138 }139 return ret;140 }141 /*文件操作结构体*/142 static const struct file_operations globalmem_fops=143 {144 .owner = THIS_MODULE,145 .llseek = globalmem_llseek,146 .read = globalmem_read,147 .write = globalmem_write,148 .ioctl = globalmem_ioctl,149 .open = globalmem_open,150 .release = globalmem_release,151 };152 /*初始化并注册cdev*/153 static void globalmem_setup_cdev(struct globalmem_dev *dev,int index)154 {155 int err,devno = MKDEV(globalmem_major,index);156 cdev_init(&dev->cdev,&globalmem_fops);157 dev->cdev.owner = THIS_MODULE;158 err = cdev_add(&dev->cdev,devno,1);159 if(err)160 printk(KERN_INFO"error %d ading globalmem %d",err,index);161 }162 /*设备驱动模块加载函数*/163 int globalmem_init(void)164 {165 int result;166 dev_t devno = MKDEV(globalmem_major,0);167 if(globalmem_major) /* 申请设备号*/168 {169 result = register_chrdev_region(devno,1,"globalmem");170 printk("register_chrdev_region\n");171 }172 else /* 动态申请设备号 */173 {174 result = alloc_chrdev_region(&devno,0,1,"globalmem");175 globalmem_major = MAJOR(devno);176 printk("alloc_chrdev_region\n");177 }178 if(result < 0)179 return result;180 /* 动态申请设备结构体的内存*/181 globalmem_devp = kmalloc(sizeof(struct globalmem_dev),GFP_KERNEL);182 if(!globalmem_devp)183 {184 result = -ENOMEM;//no memory185 goto fail_malloc;186 }187 memset(globalmem_devp,0,sizeof(struct globalmem_dev));188 globalmem_setup_cdev(globalmem_devp,0);189 printk("init ok..\n");190 return 0;191 fail_malloc:192 unregister_chrdev_region(devno,1);193 return result;194 }195 /*模块卸载函数*/196 void globalmem_exit(void)197 {198 cdev_del(&globalmem_devp->cdev); /*注销cdev*/199 kfree(globalmem_devp);200 unregister_chrdev_region(MKDEV(globalmem_major,0),1); /*释放设备号*/201 printk("exit..\n");202 }203 MODULE_AUTHOR("Huang");204 MODULE_LICENSE("Dual BSD/GPL");205 206 module_param(globalmem_major, int, S_IRUGO);/*内核模块通过module_param()来传递参数*/207 module_init(globalmem_init);208 module_exit(globalmem_exit);

Makefile:

1 ifneq ($(KERNELRELEASE),) 2     obj-m:= globalmem.o 3 else 4     PWD:=$(shell pwd) 5     KVER?=$(shell uname -r) 6     KERNELDIR:= /usr/src/linux-2.6.32.2     //编译好的内核 7 default: 8     make -C $(KERNELDIR) M=$(PWD) modules 9 endif10 clean:11     rm-f *.ko *.mod.c *.mod.o *.o

运行 insmod globalmem.ko 命令加载模块,通过 lsmod 命令,发现globalmem 模块已被加载。再通过 cat /proc/devices 命令查看,发现多出了主设备号为254的globalmem字符设备驱动。

转载于:https://www.cnblogs.com/ht-beyond/p/4313927.html

你可能感兴趣的文章
内置函数filter
查看>>
FIREDAC TFDCONNECTION连接ORACLE
查看>>
【LeetCode从零单排】No 114 Flatten Binary Tree to Linked List
查看>>
Effective Go(官方文档)笔记
查看>>
Spring表达式语言SpEL简单介绍
查看>>
NancyFX 第八章 内容协商
查看>>
操蛋的一天
查看>>
20172324 2017-2018-2 《程序设计与数据结构》第八周学习总结
查看>>
Dao层设计
查看>>
css各种姿势的水平居中
查看>>
MYSQL 测试常用语句使用技巧
查看>>
基础细节知识
查看>>
树状数组求区间最大值
查看>>
从面试官角度来告诉大家,哪些人能面试成功
查看>>
以我的亲身经历为例,告诉大家写简历和面试的技巧(面向高级开发和架构师)...
查看>>
一个简单的PHP网站结构
查看>>
Redis 学习之简介及安装
查看>>
jsp简单的学习
查看>>
[LeetCode][JavaScript]Number of 1 Bits
查看>>
[LeetCode][JavaScript]Plus One
查看>>