分类: LINUX
2011-08-18 14:48:40
inode和flip大家应该都比较熟悉了吧,cmd就是对应系统调用ioctl中的第二个参数,而arg对应第三个参数,驱动程序中统一将arg类型转换成unsigned long。
1.1 选择ioctl命令
命令号即是我们传递给驱动程序的一个标号来表明我对应的命令应该做什么操作,所以很简单的话,这个命令可以依次定义为0,1,2,3,....,但是想想这样定义有什么坏处呢?坏处就是我们大部分设备的命令号都是相同的,这样的话不免我们可能将命令发送给了错误的设备,这样的话有可能导致出错,很好的是内核提供了方便我们构造命令号的API以及一系列方法,下面就介绍给大家:
在
type:幻数,8位宽,现有的kernel中使用了的幻数在Documentation/ioctl/ioctl-number.txt中定义。
nr:编号,8位宽,驱动程序设计者自行定义,无限制。一般定义为顺序编号1,2,3,4,5...
direction:涉及到数据传输的ioctl命令,指定传输的方向,可使用的包括:_IOC_NONE,_IOC_READ,_IOC_WRITE,以及_IOC_READ | _IOC_WRITE,注意该数据传输方向是从应用程序角度,如果是_IOC_READ意味着驱动程序要写数据到用户空间;而_IOC_WRITE意味着要向读取用户空间的数据写到设备。
size:所涉及的用户数据大小,这个字段宽度和体系结构相关,一般是13或14位,可以通过宏_IOC_SIZEBITS找到针对特定体系结构的具体数值,一般少用到该字段。
在
_IO(type,nr) 无参数的编号;
_IOR(type,nr,datatype) 从驱动程序读取数据的命令编号
_IOW(type,nr,datatype) 写入数据的命令
_IOWR(type,nr,datatype) 双向传输
———————————————————————————————————————————————
1.2 返回值
ioctl的实现通常就是一个基于命令号的switch语句,如果命令号不能匹配合法的操作时,默认的选择一般是返回-EINVAl或者-ENOTTY,返回-ENOTTY似乎更为合理,但是普遍做法是返回-EINVAL。
1.3 预定义命令
在linux系统中有一些自定义的命令号,为了不与ioctl的冲突,这里把常用的列出来:
FIOCLEX:当调用进程指向一个新程序时,文件描述符将被关闭。
FIONCLEX:恢复通常的文件行为,撤销上诉命令的工作。
FIOASYNC:设置/复位文件异步通知,后面会有讨论。
FIOQSIZE:返回文件或者目录的大小,用于设备文件,返回-ENOTTY的错误。
FIONBIO:修改filp->f_flags中的O_NOBLOCK标记,第三个参数表明是设置还是清楚该标志,通过fcntl系统调用完成。
1.4 使用ioctl参数
如果ioctl的第三个参数是一个指针的话,在内核中使用必须要小心验证,需要用到函数:
因为ioctl一般数据量较小,没必要用到copy_from_user或者copy_to_user这种安全的API,所以需要进行检查用户空间指针,我猜的话copy_from_user或者copy_to_user内部也应该用到了该函数检查指针吧.
经过验证后的地址可以使用的话,内核提供了为最为常用的数据大小传输提供了一组优化后的宏,在
put_user(datum,ptr)
__put_user(datum,ptr)
把datum写到ptr指向的用户空间,速度较快,传送单个数据时使用。含下划线的宏必须用access_ok函数验证。