模块-模块开发(用户态和内核态通信-通过参数传递数据)
来源:互联网 发布:边锋游戏大厅mac 编辑:程序博客网 时间:2024/06/18 08:02
static struct file_operations cmd_fop = {
ioctl: cmd_ioctl,
};
static int cmd_ioctl (struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg)
{struct ar_req req;
if (copy_from_user(&req, (void *)arg, sizeof(struct ar_req)))
return -EFAULT;
switch (cmd) {
case c01:
return c01fun(&req);
case c02:
return c02(&req);
default:
return -EINVAL;
}
return -ENOTSUPP;
}
一、在用户空间,使用ioctl系统调用来控制设备,原型如下:
int ioctl(int fd,unsigned long cmd,...);/*fd:文件描述符cmd:控制命令...:可选参数:插入*argp,具体内容依赖于cmd*/
用户程序所作的只是通过命令码告诉驱动程序它想做什么,至于怎么解释这些命令和怎么实现这些命令,这都是驱动程序要做的事情。
二、驱动ioctl方法:
int (*ioctl) (struct inode *inode,struct file *filp,unsigned int cmd,unsigned long arg);/*inode与filp两个指针对应于应用程序传递的文件描述符fd,这和传递open方法的参数一样。cmd 由用户空间直接不经修改的传递给驱动程序arg 可选。*/
在驱动程序中实现的ioctl函数体内,实际上是有一个switch {case}结构,每一个case对应一个命令码,做出一些相应的操作。怎么实现这些操作,这是每一个程序员自己的事情,因为设备都是特定的。关键在于怎么样组织命令码,因为在ioctl中命令码是唯一联系用户程序命令和驱动程序支持的途径。
在Linux核心中是这样定义一个命令码的:
____________________________________
| 设备类型 | 序列号 | 方向 | 数据尺寸 |
|----------|--------|------|-------- |
| 8 bit | 8 bit | 2 bit |8~14 bit|
|----------|--------|------|-------- |
这样一来,一个命令就变成了一个整数形式的命令码。但是命令码非常的不直观,所以Linux Kernel中提供了一些宏,这些宏可根据便于理解的字符串生成命令码,或者是从命令码得到一些用户可以理解的字符串以标明这个命令对应的设备类型、设备序列号、数据传送方向和数据传输尺寸。
1、定义命令:
内核提供了一些宏来帮助定义命令:
//nr为序号,datatype为数据类型,如int_IO(type, nr ) //没有参数的命令_IOR(type, nr, datatype) //从驱动中读数据_IOW(type, nr, datatype) //写数据到驱动_IOWR(type,nr, datatype) //双向传送
定义命令例子:
#define MEM_IOC_MAGIC 'm' //定义类型#define MEM_IOCSET _IOW(MEM_IOC_MAGIC,0,int)#define MEM_IOCGQSET _IOR(MEM_IOC_MAGIC, 1, int)
2、实现命令:
定义好了命令,下一步就是要实现ioctl函数了,ioctl的实现包括三个技术环节:
1)返回值;
ioctl函数的实现是根据命令执行的一个switch语句,但是,当命令不能匹配任何一个设备所支持的命令时,通常返回-EINVAL(非法参数);
2)参数使用;
用户使用 int ioctl(int fd,unsinged long cmd,...) 时,...就是要传递的参数;
再通过 int (*ioctl)(struct inode *inode, struct file *filp, unsigned int cmd, unsigned longarg) 中的arg传递;
如果arg是一个整数,可以直接使用;
如果是指针,我们必须确保这个用户地址是有效的,因此,使用之前需要进行正确检查。
内部有检查的,不需要检测的:
copy_from_usercopy_to_userget_userput_user
需要检测的:
__get_user__put_user
检测函数access_ok():
static inline int access_ok(int type, const void *addr, unsigned long size)/*type :是VERIFY_READ 或者VERIFY_WRITE用来表明是读用户内存还是写用户内存;addr:是要操作的用户内存地址;size:是操作的长度。如果ioctl需要从用户空间读一个整数,那么size参数就等于sizeof(int);返回值:Access_ok返回一个布尔值:1,是成功(存取没问题);0,是失败,ioctl返回-EFAULT;*/
3)命令操作;
switch(cmd){ case: ... ...}
- 模块-模块开发(用户态和内核态通信-通过参数传递数据)
- 用户向内核模块传递参数例子
- Linux内核模块传递参数
- linux 内核模块参数传递
- module_param内核模块参数传递
- 内核模块 module_param()传递参数
- insmod 内核模块参数传递
- 内核模块用户和内核态通讯函数
- 通过netlink实现内核模块和应用层通信
- 通过netlink实现内核模块和应用层通信
- 从命令行传递参数给内核模块
- linux 给内核模块传递参数
- Linux 内核 给模块传递参数
- Linux内核模块编程入门-5(传递命令行参数到模块)
- Linux内核参数和模块参数
- 在 Linux 下用户空间与内核空间数据交换的方式,第 1 部分: 内核启动参数、模块参数与sysfs、sysctl、系统调用和netlink
- 在 Linux 下用户空间与内核空间数据交换的方式,第 1 部分: 内核启动参数、模块参数与sysfs、sysctl、系统调用和netlink
- 在 Linux 下用户空间与内核空间数据交换的方式,第 1 部分: 内核启动参数、模块参数与sysfs、sysctl、系统调用和netlink
- springmvc使用SQL的统计功能
- openCv学习笔记(四)-数学形态学1(二值图像的膨胀、腐蚀、开运算和闭运算)
- ACM Steps_Chapter Five_Section1
- FFMpeg中apiexample.c例子分析——解码分析(转)
- iPhone开发关于UDID和UUID的一些理解
- 模块-模块开发(用户态和内核态通信-通过参数传递数据)
- HDU2560:Buildings
- 嵌入式经典面试题
- Magento如何调用子分类
- linux下安装Oracle10g RAC操作--根据[三思笔记]操作
- ubuntu下jthread 和jrtplib的安装
- 举例分析Linux动态库和静态库
- 关于jsp页面对url特殊字符的处理(加码/解码)2013-5-2
- Prism