Linux中ioctl()函数命令字生成

在应用层调用ioctl()函数的时候,该函数第二个参数是cmd,如下调用:

ret = ioctl(ppp_dev_fd, PPPIOCGIDLE, ip) ;

看下cmd的格式:

/* get idle time */
#define PPPIOCGIDLE	_IOR('t', 63, struct ppp_idle) 

然后就有的研究了。

通过ioctl()函数的cmd,下发需要底层响应的命令。cmd命令的大小32位,分成4个部分:

bit31~bit30:“区别读写” 区,作用是区分是读取命令还是写入命令;

bit29~bit16:“数据大小” 区,表示 ioctl() 中的 arg 变量传送的内存大小。

bit15~bit8  :“魔数”(也称为"幻数")区,这个值用以与其它设备驱动程序的 ioctl 命令进行区别。

bit7~bit0    :“区别序号”区,是区分命令的命令顺序序号。

比如,对于以上的PPPIOCGIDLE命令,

#define _IOR(type,nr,size)	_IOC(_IOC_READ,(type),(nr),(_IOC_TYPECHECK(size)))

_IOC_READ:这是读取命令,定义如下:

/*
 * Direction bits.
 */
#define _IOC_NONE	0U
#define _IOC_WRITE	1U
#define _IOC_READ	2U

_IOC_TYPECHECK:/* provoke
compile error for invalid uses of size argument */

/* provoke compile error for invalid uses of size argument */
#define _IOC_SIZEBITS	14
extern unsigned int __invalid_size_argument_for_IOC;
#define _IOC_TYPECHECK(t) 	((sizeof(t) == sizeof(t[1]) && 	  sizeof(t) < (1 << _IOC_SIZEBITS)) ? 	  sizeof(t) : __invalid_size_argument_for_IOC)

_IOC_SIZEBITS之所以被定义为14,因为size字段占了32位中的14位(bit29~bit16)

所以,PPPIOCGIDLE命令等价于:

#define PPPIOCGIDLE <--->
(2 << 30) | ('t' << 8) | (63 << 0) | (size << 16)

参考Linux内核文件:include/asm-generic/ioctl.h

#ifndef _ASM_GENERIC_IOCTL_H
#define _ASM_GENERIC_IOCTL_H

/* ioctl command encoding: 32 bits total, command in lower 16 bits,
 * size of the parameter structure in the lower 14 bits of the
 * upper 16 bits.
 * Encoding the size of the parameter structure in the ioctl request
 * is useful for catching programs compiled with old versions
 * and to avoid overwriting user space outside the user buffer area.
 * The highest 2 bits are reserved for indicating the ``access mode''.
 * NOTE: This limits the max parameter size to 16kB -1 !
 */

/*
 * The following is for compatibility across the various Linux
 * platforms.  The generic ioctl numbering scheme doesn't really enforce
 * a type field.  De facto, however, the top 8 bits of the lower 16
 * bits are indeed used as a type field, so we might just as well make
 * this explicit here.  Please be sure to use the decoding macros
 * below from now on.
 */
#define _IOC_NRBITS	8
#define _IOC_TYPEBITS	8
#define _IOC_SIZEBITS	14
#define _IOC_DIRBITS	2

#define _IOC_NRMASK	((1 << _IOC_NRBITS)-1)
#define _IOC_TYPEMASK	((1 << _IOC_TYPEBITS)-1)
#define _IOC_SIZEMASK	((1 << _IOC_SIZEBITS)-1)
#define _IOC_DIRMASK	((1 << _IOC_DIRBITS)-1)

#define _IOC_NRSHIFT	0
#define _IOC_TYPESHIFT	(_IOC_NRSHIFT+_IOC_NRBITS)
#define _IOC_SIZESHIFT	(_IOC_TYPESHIFT+_IOC_TYPEBITS)
#define _IOC_DIRSHIFT	(_IOC_SIZESHIFT+_IOC_SIZEBITS)

/*
 * Direction bits.
 */
#define _IOC_NONE	0U
#define _IOC_WRITE	1U
#define _IOC_READ	2U

#define _IOC(dir,type,nr,size) 	(((dir)  << _IOC_DIRSHIFT) | 	 ((type) << _IOC_TYPESHIFT) | 	 ((nr)   << _IOC_NRSHIFT) | 	 ((size) << _IOC_SIZESHIFT))

/* provoke compile error for invalid uses of size argument */
extern unsigned int __invalid_size_argument_for_IOC;
#define _IOC_TYPECHECK(t) 	((sizeof(t) == sizeof(t[1]) && 	  sizeof(t) < (1 << _IOC_SIZEBITS)) ? 	  sizeof(t) : __invalid_size_argument_for_IOC)

/* 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)

#endif /* _ASM_GENERIC_IOCTL_H */
时间: 2024-10-09 00:47:37

Linux中ioctl()函数命令字生成的相关文章

Linux中select函数

转载自:http://blog.163.com/henry_hlh/blog/static/17039507420124211841298/ Unix中的函数select和poll用来,支持Unix中I/O复用的功能,在Unix中I/O模型可以分为以一几种: (1)阻塞I/O (2)非阻塞I/O (3)I/O复用(select和poll) (4)信号驱动I/O(SIGIO) (5)异步I/O 其中,现在比较流行的I/O模型是阻塞I/O模型.阻塞I/O是当应用程序和内核交换数据时,由于内核还没有准

linux中fork()函数详解[zz]

转载自:http://www.cnblogs.com/york-hust/archive/2012/11/23/2784534.html 一.fork入门知识 一个进程,包括代码.数据和分配给进程的资源.fork()函数通过系统调用创建一个与原来进程几乎完全相同的进程,也就是两个进程可以做完全相同的事,但如果初始参数或者传入的变量不同,两个进程也可以做不同的事. 一个进程调用fork()函数后,系统先给新的进程分配资源,例如存储数据和代码的空间.然后把原来的进程的所有值都复制到新的新进程中,只有

linux中时间函数

linux下常用时间类型有四种: time_t . struct   tm. struct  timeval .    struct   timespec 1.time_t   时间函数 time_t  类型在time.h中定义: #ifndef   __TIME__T #define  __TIME_T typedef    long  time_t #endif 可见, time_t 实际上是一个长整型,其值表示从1970年1月1日00时00分00秒(linux系统的Epoch时间)到当前时

open()函数 linux中open函数使用

来源:http://www.cnblogs.com/songfeixiang/p/3733855.html linux中open函数使用 open函数用来打开一个设备,他返回的是一个整型变量,如果这个值等于-1,说明打开文件出现错误,如果为大于0的值 参考格式 if(fd=open("/dev/ttys0",O_RDWR | O_NOCTTY | O_NDELAY))<0 {printf("cannot open"}; int open(const char

Linux下ioctl函数理解

一. 什么是ioctl ioctl是设备驱动程序中对设备的I/O通道进行管理的函数.所谓对I/O通道进行管理,就是对设备的一些特性进行控制,例如串口的传输波特率.马达的转速等等.它的调用个数如下: int ioctl(int fd, ind cmd, -): 其中fd就是用户程序打开设备时使用open函数返回的文件标示符,cmd就是用户程序对设备的控制命令,至于后面的省略号,那是一些补充参数,一般最多一个,有或没有是和cmd的意义相关的,如果有的话,第三个参数总是一个指针,但指针的类型依赖于re

Linux中open函数以及退出进程的函数

open函数的flag详解1 读写权限:O_RDONLY O_WRONLY O_RDWR (1)linux中文件有读写权限,我们在open打开文件时也可以附带一定的权限说明 (譬如O_RDONLY就表示以只读方式打开,O_WRONLY表示以只写方式打开, O_RDWR表示以可读可写方式打开) (2)当我们附带了权限后,打开的文件就只能按照这种权限来操作. 打开存在并有内容的文件时:O_APPEND.O_TRUNC (1)思考一个问题:当我们打开一个已经存在并且内部有内容的文件时会怎么样? 可能结

Linux中Main函数的执行过程

1. 问题:Linux如何执行main函数. 本文使用一个简单的C程序(simple.c)作为例子讲解.代码如下, int main() { return(0); } 2.  编译 -#gcc -o simple simple.c 3. 查看可执行文件的基本信息 -#objdump -f simple simple: file format elf32-i386 architecture: i386, flags 0x00000112: EXEC_P, HAS_SYMS, D_PAGED sta

linux中fork函数的一个小思考

1.fork函数 头文件: #include<unistd.h> 函数原型: pid_t fork( void);(pid_t 是一个宏定义,其实质是int 被定义在#include<sys/types.h>中) 返回值: 若成功调用一次则返回两个值,子进程返回0,父进程返回子进程ID:否则,出错返回-1 函数说明: 一个现有进程可以调用fork函数创建一个新进程.由fork创建的新进程被称为子进程(child process).fork函数被调用一次但返回两次.两次返回的唯一区别

Linux 中 fork() 函数详解

需要的头文件: #include <sys/types.h> #include <unistd.h> pid_t fork(void) 功能: 用于从一个已存在的进程中创建一个新进程,新进程称为子进程,原进程称为父进程. 参数: 无 返回值: 成功:子进程中返回 0,父进程中返回子进程 ID.pid_t,为无符号整型. 失败:返回 -1. 失败的两个主要原因是: 1)当前的进程数已经达到了系统规定的上限,这时 errno 的值被设置为 EAGAIN. 2)系统内存不足,这时 err