ioctl设备控制(笔记)
来源:互联网 发布:java工程师认证 编辑:程序博客网 时间:2024/05/16 01:13
用户层:
原型:int ioctl(int fd, unsigned long cmd, ...)
说明:其中原点表示可选参数,存在与否依赖于控制命令(第二个参数)是否涉及到与设备的数据交互;
驱动层:
原型:int
说明:cmd参数是从用户层传下来,可选参数arg以一个unsigned long 的形式传递(为一个整数或为一
个指针),如果cmd命令不涉及数据传输,则arg无任何意义;
用法步骤:
1、定义命令
ioctl命令编码划分为几个阶段,在include/asm/ioctl.h中定义:类型(幻数)、序号、传递方向、参数
的大小。在documention/ioctl-number.txt中罗列了在内核中已经使用的幻数。
其中:
type:幻数(类型):表明哪个设备的命令,8位宽;
number:序号:表面设备命令中的第几个,8位宽;
direction:数据传递的方向:常见的宏定义有:_IOC_NONE(没有数据传送),_IOC_READ(从设备
读),_IOC_WRITE(从设备写),数据传送是从应用层的观点来看待;
size:用户数据的大小。(13/14位宽,视处理器而定)
_IO(type, nr) //没有参数的命令
_IOR(type, nr, datatype) //从驱动中读数据
_IOW(type, nr, datatype) //写数据到驱动
_IOWR(type, nr, datatype) //双向传输,type和number成员作为参数被传递
定义命令范例:
#define MEM_IOC_MAGIC 'm'
#define MEM_IOCSET _IOW(MEM_IOC_MAGIC, 0, int)
#define MEM_IOCGQSET _IOW(MEM_IOC_MAGIC, 1, int)
2、实现ioctl
包括三个环节:1、返回值 2,参数使用 3命令操作
注:当命令号不能匹配任何一个设备所支持的命令时,通常返回-EINVAL (非法参数)
参数检查:
如果是一个整数,可以直接使用,如果是指针,首先得确保用户地址的有效性;
不需要检测的有:
copy_form_user, copy_to_user, get_user, put_user;
需要检测的有:__get_user, __put_user;
参数检查方法(函数):
原型:int access_ok(int type, const void *addr, unsigned long size)
其中:第一个参数是VERIFY_READ 还是 VERIFY_WRITE, 用来表明是读用户内存还是写用户内存。addr
参数是要操作的用户内存地址,size是操作的长度。如果ioctl需要从用户空间读一个整数,则size参
等于sizeof(int)。
access_ok返回一个布尔值,1 是成功(存取都没问题), 0 是失败(存取有问题), 如果该函数返回失
败,则返回-EFAULT;
参数检查范例:
if(_IOC_DIR(cmd) & _IOC_READ)
err = !access_ok(VERIFY_WRITE, (void __user*)arg, _IOC_SIZE(cmd));
else if(_IOC_DIR(cmd) & _IOC_WRITE)
err = !access_ok(VERIFY_WREAD, (void __user*)arg, _IOC_SIZE(cmd));
if(err)
驱动层:
原型:int ioctl(int fd, unsigned long cmd, ...)
说明:其中原点表示可选参数,存在与否依赖于控制命令(第二个参数)是否涉及到与设备的数据交互;
驱动层:
原型:int
说明:cmd参数是从用户层传下来,可选参数arg以一个unsigned long 的形式传递(为一个整数或为一
个指针),如果cmd命令不涉及数据传输,则arg无任何意义;
用法步骤:
1、定义命令
ioctl命令编码划分为几个阶段,在include/asm/ioctl.h中定义:类型(幻数)、序号、传递方向、参数
的大小。在documention/ioctl-number.txt中罗列了在内核中已经使用的幻数。
其中:
type:幻数(类型):表明哪个设备的命令,8位宽;
number:序号:表面设备命令中的第几个,8位宽;
direction:数据传递的方向:常见的宏定义有:_IOC_NONE(没有数据传送),_IOC_READ(从设备
读),_IOC_WRITE(从设备写),数据传送是从应用层的观点来看待;
size:用户数据的大小。(13/14位宽,视处理器而定)
_IO(type, nr) //没有参数的命令
_IOR(type, nr, datatype) //从驱动中读数据
_IOW(type, nr, datatype) //写数据到驱动
_IOWR(type, nr, datatype) //双向传输,type和number成员作为参数被传递
定义命令范例:
#define MEM_IOC_MAGIC 'm'
#define MEM_IOCSET _IOW(MEM_IOC_MAGIC, 0, int)
#define MEM_IOCGQSET _IOW(MEM_IOC_MAGIC, 1, int)
2、实现ioctl
包括三个环节:1、返回值 2,参数使用 3命令操作
注:当命令号不能匹配任何一个设备所支持的命令时,通常返回-EINVAL (非法参数)
参数检查:
如果是一个整数,可以直接使用,如果是指针,首先得确保用户地址的有效性;
不需要检测的有:
copy_form_user, copy_to_user, get_user, put_user;
需要检测的有:__get_user, __put_user;
参数检查方法(函数):
原型:int access_ok(int type, const void *addr, unsigned long size)
其中:第一个参数是VERIFY_READ 还是 VERIFY_WRITE, 用来表明是读用户内存还是写用户内存。addr
参数是要操作的用户内存地址,size是操作的长度。如果ioctl需要从用户空间读一个整数,则size参
等于sizeof(int)。
access_ok返回一个布尔值,1 是成功(存取都没问题), 0 是失败(存取有问题), 如果该函数返回失
败,则返回-EFAULT;
参数检查范例:
if(_IOC_DIR(cmd) & _IOC_READ)
err = !access_ok(VERIFY_WRITE, (void __user*)arg, _IOC_SIZE(cmd));
else if(_IOC_DIR(cmd) & _IOC_WRITE)
err = !access_ok(VERIFY_WREAD, (void __user*)arg, _IOC_SIZE(cmd));
if(err)
return -EFAULT;
===================================
范例:
用户层:
cmd = MEMDEV_IOCPRINT;if (ioctl(fd, cmd, &arg) < 0) { printf("Call cmd MEMDEV_IOCPRINT fail\n"); return -1;}/* 调用命令MEMDEV_IOCSETDATA */printf("<--- Call MEMDEV_IOCSETDATA --->\n");cmd = MEMDEV_IOCSETDATA;arg = 2007;if (ioctl(fd, cmd, &arg) < 0) { printf("Call cmd MEMDEV_IOCSETDATA fail\n"); return -1;}/* 调用命令MEMDEV_IOCGETDATA */printf("<--- Call MEMDEV_IOCGETDATA --->\n");cmd = MEMDEV_IOCGETDATA;if (ioctl(fd, cmd, &arg) < 0) { printf("Call cmd MEMDEV_IOCGETDATA fail\n"); return -1;}
驱动层:
int memdev_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg){ int err = 0; int ret = 0; int ioarg = 0; /* 检测命令的有效性 */ if (_IOC_TYPE(cmd) != MEMDEV_IOC_MAGIC) return -EINVAL; if (_IOC_NR(cmd) > MEMDEV_IOC_MAXNR) return -EINVAL; /* 根据命令类型,检测参数空间是否可以访问 */ if (_IOC_DIR(cmd) & _IOC_READ) err = !access_ok(VERIFY_WRITE, (void *)arg, _IOC_SIZE(cmd)); else if (_IOC_DIR(cmd) & _IOC_WRITE) err = !access_ok(VERIFY_READ, (void *)arg, _IOC_SIZE(cmd)); if (err) return -EFAULT; /* 根据命令,执行相应的操作 */ switch(cmd) { /* 打印当前设备信息 */ case MEMDEV_IOCPRINT: printk("<--- CMD MEMDEV_IOCPRINT Done--->\n\n"); break; /* 获取参数 */ case MEMDEV_IOCGETDATA: ioarg = 1101; ret = __put_user(ioarg, (int *)arg); break; /* 设置参数 */ case MEMDEV_IOCSETDATA: ret = __get_user(ioarg, (int *)arg); printk("<--- In Kernel MEMDEV_IOCSETDATA ioarg = %d --->\n\n",ioarg); break; default: return -EINVAL; } return ret;}
- ioctl设备控制(笔记)
- 高级字符设备驱动-Ioctl设备控制笔记
- 高级字符设备驱动-Ioctl设备控制笔记
- ioctl设备控制
- 设备Ioctl控制
- ioctl设备控制
- ioctl设备控制及例子
- IO设备控制IOCTL操作
- Linux 设备驱动--- Ioctl 设备控制
- 设备控制接口(ioctl 函数)
- linux设备驱动之Ioctl控制
- Linux设备驱动之Ioctl控制
- Linux设备驱动之Ioctl控制
- 设备控制接口(ioctl 函数)
- Linux设备驱动之ioctl控制
- Linux设备驱动之Ioctl控制
- Linux设备驱动之Ioctl控制
- Linux设备驱动之Ioctl控制
- android socket通信(下)
- NDK的Windows环境搭建
- nginx命令:启动,停止及命令参数详解
- sql数据库备份和恢复
- 数据库 join的解析
- ioctl设备控制(笔记)
- 总线错误&段错误
- 设计模式之07原型模式(笔记)
- 动态代理1 (JDK 需要实现接口)
- 基于Annotation的Struts2.0+Hibernate3.3+Spring2.5整合开发 (1)
- Windows下Nginx+PHP5(FastCgi)安装配置详解
- jdk与jre的区别
- Tomcat
- Hibernate关联映射之一对多单向关联映射