模块-模块开发(用户态和内核态通信-通过参数传递数据)
2013-05-02 16:23
218 查看
1、代码示例
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系统调用来控制设备,原型如下:
用户程序所作的只是通过命令码告诉驱动程序它想做什么,至于怎么解释这些命令和怎么实现这些命令,这都是驱动程序要做的事情。
二、驱动ioctl方法:
在驱动程序中实现的ioctl函数体内,实际上是有一个switch {case}结构,每一个case对应一个命令码,做出一些相应的操作。怎么实现这些操作,这是每一个程序员自己的事情,因为设备都是特定的。关键在于怎么样组织命令码,因为在ioctl中命令码是唯一联系用户程序命令和驱动程序支持的途径。
在Linux核心中是这样定义一个命令码的:
____________________________________
| 设备类型 | 序列号 | 方向 | 数据尺寸 |
|----------|--------|------|-------- |
| 8 bit | 8 bit | 2 bit |8~14 bit|
|----------|--------|------|-------- |
这样一来,一个命令就变成了一个整数形式的命令码。但是命令码非常的不直观,所以Linux Kernel中提供了一些宏,这些宏可根据便于理解的字符串生成命令码,或者是从命令码得到一些用户可以理解的字符串以标明这个命令对应的设备类型、设备序列号、数据传送方向和数据传输尺寸。
1、定义命令:
内核提供了一些宏来帮助定义命令:
定义命令例子:
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是一个整数,可以直接使用;
如果是指针,我们必须确保这个用户地址是有效的,因此,使用之前需要进行正确检查。
内部有检查的,不需要检测的:
需要检测的:
检测函数access_ok():
3)命令操作;
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_user copy_to_user get_user put_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: ... ... }
相关文章推荐
- 通过singleton模式和global static variable变量做C++程序各个模块之间的数据通信
- 例说linux内核与应用数据通信(四):映射设备内核空间到用户态
- 通过netlink实现内核模块和应用层通信
- iOS开发之音频口通信-通过方波来收发数据
- 例说linux内核与应用数据通信(四):映射设备内核空间到用户态
- react项目实战(权限模块开发七)通过ajax技术获取数据
- Linux 驱动开发之内核模块开发 (二)—— 内核模块编译 Makefile 入门
- Android开发:客户端与服务器通过传递和接收json数据进行交互
- netlink--内核态与用户态通信
- 跟我一起学extjs5(31--加入模块和菜单定义[4前台通过ajax来调用数据与展示])
- iOS开发之Socket通信实战--Request请求数据包编码模块
- mini6410基于linux2.6.36内核通过NFS启动根文件系统总结(一搭建开发环境——安装交叉工具连)
- 网络数据通过内核图1
- 在ubuntu上开发编译内核模块,并查看printk打印的消息
- winfrom如何通过http来进行通信,并且通过传递json格式的数据可接受json格式的数据
- Android入门:通过XML数据与服务器进行通信
- Linux用户态与内核态交互数据---socket函数
- socket通信——通过Udp传输方式,将一段文字数据发送出去
- 获得内核模块 通过DriverSection
- 稳扎稳打Silverlight(57) - 4.0通信之WCF RIA Services: 概述, 通过 DomainDataSource 实现数据的添加、查询、更新和删除操作