总有人间一两风,填我十万八千梦

Linux IOCTL动态命令、动态|自定义缓冲区大小、IOCTL使用大缓冲区的问题

Linux C/C++ Zero、J 3940℃ 0评论

深夜睡不着,点根烟起来写点儿东西吧。

ioctlLinux

一个驱动程序除了具备读写设备的能力之外,其也应当具有对硬件控制的能力。在Windows下用户层代码使用API函数DeviceIoControl,通过传入驱动句柄,驱动控制码,以及相应的输入输出缓冲区等参数即可完成对驱动程序的控制,并且Windows中这些参数都是相对独立的,换句话说你可以完全自定义缓冲区的大小等信息,其缓冲区大小是一个DWORD类型的数据,所表示的大小也是一个可观的数值。而在Linux下,驱动的控制通过ioctl来完成,而ioctl种的缓冲区信息却不是独立的。

应用程序使用ioctl

/*
fd:文件描述符
cmd:控制命令
...:可选参数:插入*argp,具体内容依赖于cmd
*/
int ioctl(int fd,unsigned long cmd,...);

ioctl中,缓冲区的信息不是独立的,其大小被整合到了相应的cmd中。在Linux中一个是这样子定义一个cmd命令的:

设备类型 序列号 数据方向 数据尺寸
8 bit 8 bit 2 bit 8~14 bit

可以看出,数据尺寸只占用了8~14Bit,其最大表示的范围为2^14Byte,这个数值似乎有点儿小了。

Linux中提供了一些宏定义来协助定义命令:

//nr为序号,datatype为数据类型,如int
_IO(type, nr ) //没有参数的命令
_IOR(type, nr, datatype) //从驱动中读数据
_IOW(type, nr, datatype) //写数据到驱动
_IOWR(type,nr, datatype) //双向传送

跟进这些宏定义:

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

不难看出,这些宏定义都是基于_IOC这个宏定义,其中_IOC_TYPECHECK也就是 sizeof操作,也就是说如果我们使用了_IO、_IOR、_IOW、_IOWR这些宏去定义一个命令的时候,我们必须要要知道缓冲区的数据类型!然而情况下,应用程序并不能事先知道缓冲区的实际大小,而这个时候只需要使用_IOC这个宏定义去创建我们的命令,并且动态指定相关的大小即可。

自定义|动态指定缓冲区的大小

根据上面的分析可以知道,只需要使用_IOC宏定义即可事先动态缓冲区。

IOCTL使用大缓冲区的问题

上面的cmd组成表已经很清晰的告诉我们,cmd中使用8~14Bit表示的缓冲区的大小,然而在某些情况下2^14Byte的缓冲区是不够的,例如你读取进程链表的数据,这时候缓冲区就不够用了。

一般情况下,例如我们指定缓冲区大小为10,那么一般而言我们认为缓冲区大小为10Byte,然而我们可不可以把10看做是10个int吗?这当然是可以的!这个时候我们只需要把10看做是一个数据类型的计数,这时候10就不在是10个Byte了,她的尺寸就变成与只想对应的数据类型有关了,例如看作是10个自定义的struct,那么这个10能够表示的数据大小就很可观了。

 

转载请注明:悠然品鉴 » Linux IOCTL动态命令、动态|自定义缓冲区大小、IOCTL使用大缓冲区的问题

喜欢 (0)or分享 (0)
发表我的评论
取消评论

Hi,您需要填写昵称和邮箱!

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址