Linux用户空间与内核交互——ioclt
来源:互联网 发布:python 元组长度 编辑:程序博客网 时间:2024/06/08 04:52
设备驱动程序除了读写设备外,大部分驱动还需要一种管理和控制设备的功能,这些操作通常通过ioctl方法支持。
用户空间接口:
#include <sys/ioctl.h> int ioctl(int d, int request, ...);
内核空间接口(2.6.36之后内核修改了接口):
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 36)) int (*ioctl)(stuct file *filp, unsigned int cmd, unsigned long arg);#else int (*ioctl)(struct inode *inode_p, struct file *filp, unsigned int cmd, unsigned long args);#endif
内核空间函数实现
filp对应着文件描述符
cmd由用户空间不经修改的传入内核空间
arg无论用户空间使用的是指针还是整数值,它都以unsigned long的形式传递给驱动程序,如果应用调用程序没有传递第三个参数,驱动程序接收的arg就处于未定义状态
编写ioctl需要预先统一用户空间和内核空间的cmd编号,编号不是随便填写的,需要根据内核约定的方法为驱动程序选择cmd编号。
Documentation/ioctl-number.txt文件中罗列了内核使用的幻数,在选择自己的幻数的时候要避免和内核冲突。
include/asm/ioctl.h中定义了要使用的位字段:
#define _IOC(dir,type,nr,size) \ (((dir) << _IOC_DIRSHIFT) | \ ((type) << _IOC_TYPESHIFT) | \ ((nr) << _IOC_NRSHIFT) | \ ((size) << _IOC_SIZESHIFT))
type
幻数,选择一个号码并在整个驱动中使用这个号码。8bit字宽。
number
序数,8bit字宽。
direction
如果相关的命令涉及到数据传输,则此字段定义了数据的传输方向。可以使用的值:
_IOC_NONE 没有数据传输
_IOC_READ 从设备读数据
_IOC_WRITE 往设备写数据
_IOC_READ | _IOC_WRITE 双向数据传输
size
用户数据大小
在kernel/include/asm-generic/ioctl.h还定义了一些构造命令的宏,可以方便用户使用
/* used to create numbers */#define _IO(type,nr) _IOC(_IOC_NONE,(type),(nr),0)#define _IOR(type,nr,size) _IOC(_IOC_READ,(type),(nr),(_IOC_TYPECHECK(size)))#define _IOW(type,nr,size) _IOC(_IOC_WRITE,(type),(nr),(_IOC_TYPECHECK(size)))#define _IOWR(type,nr,size) _IOC(_IOC_READ|_IOC_WRITE,(type),(nr),(_IOC_TYPECHECK(size)))#define _IOR_BAD(type,nr,size) _IOC(_IOC_READ,(type),(nr),sizeof(size))#define _IOW_BAD(type,nr,size) _IOC(_IOC_WRITE,(type),(nr),sizeof(size))#define _IOWR_BAD(type,nr,size) _IOC(_IOC_READ|_IOC_WRITE,(type),(nr),sizeof(size))/* used to decode ioctl numbers.. */#define _IOC_DIR(nr) (((nr) >> _IOC_DIRSHIFT) & _IOC_DIRMASK)#define _IOC_TYPE(nr) (((nr) >> _IOC_TYPESHIFT) & _IOC_TYPEMASK)#define _IOC_NR(nr) (((nr) >> _IOC_NRSHIFT) & _IOC_NRMASK)#define _IOC_SIZE(nr) (((nr) >> _IOC_SIZESHIFT) & _IOC_SIZEMASK)/* ...and for the drivers/sound files... */#define IOC_IN (_IOC_WRITE << _IOC_DIRSHIFT)#define IOC_OUT (_IOC_READ << _IOC_DIRSHIFT)#define IOC_INOUT ((_IOC_WRITE|_IOC_READ) << _IOC_DIRSHIFT)#define IOCSIZE_MASK (_IOC_SIZEMASK << _IOC_SIZESHIFT)#define IOCSIZE_SHIFT (_IOC_SIZESHIFT)
啰嗦了一大堆,其实写IOCTL关键就是cmd要写对,注意传参数。
写一个简单的上拉下拉GPIO的例子:
kernel部分
#define G_SIZE 32static char G_INFO_BUFFER[G_SIZE];#define GPIO152_MAGIC 'Y'#define GPIO152_MAX_NR 4#define XXX_IO_OFF _IO(GPIO152_MAGIC, 0)#define XXX_IO_ON _IO(GPIO152_MAGIC, 1)#define XXX_IOR _IOR(GPIO152_MAGIC, 2, char[G_SIZE])#define XXX_IOW _IOW(GPIO152_MAGIC, 3, char[G_SIZE])static long xxx_ioctl(struct file *filp, unsigned int cmd, unsigned long arg){char buffer[G_SIZE]; if (_IOC_TYPE(cmd) != GPIO152_MAGIC) { return -ENOTTY; } if (_IOC_NR(cmd) > GPIO152_MAX_NR) { return -ENOTTY; } switch(cmd) { case XXX_IO_ON: gpio_pull_down(GPIO152); break; case XXX_IO_OFF: gpio_pull_up(GPIO152); break; case XXX_IOR: sprintf(G_INFO_BUFFER, "xxx power %s\n", (mt_get_gpio_out(GPIO152)?"disable":"enable")); if(copy_to_user((char *)arg, G_INFO_BUFFER, G_SIZE)) { return -EFAULT; } break;case XXX_IOW:if(copy_from_user(buffer, (char *)arg, G_SIZE)){ return -EFAULT; }break; default: return -ENOTTY; } return 0;}
用户空间部分,跟kernel一样需要相同的命令
#define G_SIZE 32static char G_INFO_BUFFER[G_SIZE];#define GPIO152_MAGIC 'Y'#define GPIO152_MAX_NR 4#define XXX_IO_OFF _IO(GPIO152_MAGIC, 0)#define XXX_IO_ON _IO(GPIO152_MAGIC, 1)#define XXX_IOR _IOR(GPIO152_MAGIC, 2, char[G_SIZE])#define XXX_IOW _IOW(GPIO152_MAGIC, 3, char[G_SIZE])int gpio_pull_downup(int en) { int fd; int ret; memset(G_INFO_BUFFER, 0, G_SIZE); fd = open(XXX_DEV, O_RDONLY); if (fd < 0) printf(" %s: open %s failed", __func__, XXX_DEV); if (en) ret = ioctl(fd, XXX_IO_ON, G_INFO_BUFFER); else ret = ioctl(fd, XXX_IO_OFF, G_INFO_BUFFER); if (ret < 0) printf("%s: ioctl gpio %s failed", __func__, en?"up":"down"); ret = ioctl(fd, XXX_IOR, G_INFO_BUFFER); printf("%s", G_INFO_BUFFER);sprintf(G_INFO_BUFFER, "%s", "test for ioctl")ret = ret = ioctl(fd, XXX_IOW, G_INFO_BUFFER); close(fd); return ret;}
- Linux用户空间与内核交互——ioclt
- linux内核空间 与用户空间交互
- 深入理解Linux网络技术内幕——用户空间与内核空间交互
- linux内核空间与用户空间信息交互方法
- linux内核空间与用户空间信息交互方法
- linux内核空间与用户空间信息交互方法
- linux内核空间与用户空间信息交互方法
- Linux内核空间与用户空间信息交互方法
- linux内核空间与用户空间信息交互方法
- linux内核空间与用户空间信息交互方法
- linux内核空间与用户空间信息交互方法
- linux内核空间与用户空间信息交互方法
- linux内核空间与用户空间信息交互方法
- linux内核空间与用户空间信息交互方法
- linux内核空间与用户空间信息交互方法
- linux内核空间与用户空间信息交互方法
- linux内核空间与用户空间信息交互方法
- linux内核空间与用户空间信息交互方法
- pcap的用法
- 解决了在ScrollPane中加Jtable不能显示的问题
- linux 系统每天自动重启的方法
- 【Lua】模块(module)和包(package)详解
- 闪客工具:flex 组件用法查询
- Linux用户空间与内核交互——ioclt
- 我的新目标
- 设计模式:28 男人和女人_访问者模式
- Jquery Web 前端验证框架插件,jquery-validate资料,validation
- php中fetchall()与fetch()的区别
- C#自动添加using引用命名空间
- 有关hibernate入门小实例--hibernate+mysql
- ajax与异步请求
- 黑马程序员--java技术blog---第八篇:网络编程(1)