字符设备之ioctl

原创 2013年12月04日 00:03:43

1.ioctl()函数的存在意义:

    除了简单的数据传输之外,大部分设备还可以执行一些其他的动作,比如用户空间请求设备锁门、弹出介质、改变波特率等.这些动作可以通过ioctl来实现.


2.ioctl()函数的参数说明:

    ioctl()函数原型如下:

int (*ioctl)(struct inode *inode,struct file *filp,unsigned int cmd,unsigned long arg);
    各参数的意义说明如下:

inode:对应于应用程序传递的设备文件节点,和open相同;
filp:对就于应用程序传递的设备文件描述符,和open相同;
    第三个参数比较特别,它虽然是一个无符号整形,在标准的做法里面,它是一个"位数据".每个位都是有规定的意义的.如下:

bit[31]~bit[24]:一共8位.所谓的"幻数",表征此ioctl命令的隶属设备,一般是某个字符.后续所有的ioctl命令对应的都有这个公共部分.
    如:

#define SCULL_IOC_MAGIC  'k'
    SCULL_IOC_MAGIC将作为公共部分来参与到后续的ioctl命令中.因为它是表征后续的ioctl命令隶属于哪个驱动而不是具体的某个命令.内核将此位段标识为"type".

bit[23]~bit[17]:一共8位,表示ioctl的序号.比如一个驱动里面支持16个ioctl命令,则可以排序为1~16.
    如:

#define SCULL_IOCSQUANTUM _IOW(SCULL_IOC_MAGIC,  1, int)
#define SCULL_IOCSQSET    _IOW(SCULL_IOC_MAGIC,  2, int)
#define SCULL_IOCTQUANTUM _IO(SCULL_IOC_MAGIC,   3)
#define SCULL_IOCTQSET    _IO(SCULL_IOC_MAGIC,   4)
#define SCULL_IOCGQUANTUM _IOR(SCULL_IOC_MAGIC,  5, int)
#define SCULL_IOCGQSET    _IOR(SCULL_IOC_MAGIC,  6, int)
#define SCULL_IOCQQUANTUM _IO(SCULL_IOC_MAGIC,   7)
#define SCULL_IOCQQSET    _IO(SCULL_IOC_MAGIC,   8)
#define SCULL_IOCXQUANTUM _IOWR(SCULL_IOC_MAGIC, 9, int)
#define SCULL_IOCXQSET    _IOWR(SCULL_IOC_MAGIC,10, int)
#define SCULL_IOCHQUANTUM _IO(SCULL_IOC_MAGIC,  11)
#define SCULL_IOCHQSET    _IO(SCULL_IOC_MAGIC,  12)
    上述的1~12便是对应bit[23]~bit[17]的设置.内核将此位段标识为"number".

bit[16]~bit[15]:一共两位,标识数据的传输方向.此时的方向是在用户空间的角度看的.比如标识此命令是用户读还是写还是可读可写.
    这两个bit的设备可以通过内核提供的宏_IOW、_IOR和_IOWR来设置.如下:

#define SCULL_IOCSQUANTUM _IOW(SCULL_IOC_MAGIC,  1, int)
#define SCULL_IOCSQSET    _IOW(SCULL_IOC_MAGIC,  2, int)
#define SCULL_IOCGQUANTUM _IOR(SCULL_IOC_MAGIC,  5, int)
#define SCULL_IOCGQSET    _IOR(SCULL_IOC_MAGIC,  6, int)
#define SCULL_IOCXQUANTUM _IOWR(SCULL_IOC_MAGIC, 9, int)
#define SCULL_IOCXQSET    _IOWR(SCULL_IOC_MAGIC,10, int)
    其中"W"表征"写","R"表征"读".内核将此位段标识为"direction".

bit[13]~bit[0]:所涉及的用户数据的大小,以字节为单位,是对宏_IOWR、_IOW、_IOR的第三个参数用sizeof取得.
    比如下面命令:

#define SCULL_IOCXQUANTUM _IOWR(SCULL_IOC_MAGIC, 9, int)
    则此位段值为sizeof(int) = 4.内核将此位段标识为size.


    第四个参数也是比较特别,特别在两点:

   

1).它的存在与否与第二个参数息息相关,如果参数cmd涉及到参数的传递,则需要它来承载参数的传递桥梁,否则其存在与否就一点意义都没有了;
2).它恒为unsigned long类型,无论用户空间在arg上传递的是一个整形数据还是指针,它都以unsigned long的形式传递给内核.因此,当用户空间传递的是一个指针的时候,必须对其进行检查.
    如果传递过来是一个常规数据,直接使用即可.

    针对第2)点,我们需要对用户传递过来的参数指针的合法性进行检查,以确保其对内核空间是有效的.如果用copy_to_user()和copy_from_user()两个函数来保证指针的有效性,未免有点"牛刀杀鸡"的嫌疑.这里推荐使用access_ok()函数.原型如下:

int access_ok(int type,const void *addr,unsigned long size);
    各参数意义如下:

type:应该为VERIFY_READ或VERIFY_WRITE,标识读或写入用户空间,其中VERIFY_WRITE是VERIFY_READ的超集,当读写动作都需要时,则需要用VERIFY_WRITE标识;
addr:用户空间的指针;
size:字节数,如果ioctl从用户空间读取一个整数,size就是sizeof(int).
    access_ok()函数的返回值:1表示成功;0表示失败.

    针对传递过来的参数是指针,可以通过下面的形式来引用其指向内容:

retval = __get_user(scull_quantum,(int __user *)arg);
    这里需要注意的是把unsigned long arg强制类型转化为(int __user *)指针.


3.ioctl()的返回值:

    当出错时,驱动中一般返回-ENVAL或-ENOTTY.


4.ioctl()所涉及到的数据交互:

    ioctl()涉及到的数据量交互都比较小,如果用copy_to_user()和copy_from_user()显得"牛刀杀鸡"而且浪费一定的系统资源.如果只涉及到一个简单的变量传递,可以调用下面两个函数:

    get_user(x,ptr):

get_user
Name
get_user -- Get a simple variable from user space.
Synopsis
get_user ( x, ptr);

Arguments
x
Variable to store result.

ptr
Source address, in user space.

Context
User context only. This function may sleep.

Description
This macro copies a single simple variable from user space to kernel space. It supports simple types like char and int, but not larger data types like structures or arrays.

ptr must have pointer-to-simple-variable type, and the result of dereferencing ptr must be assignable to x without a cast.

Returns zero on success, or -EFAULT on error. On error, the variable x is set to zero.

    put_user(x,ptr):

put_user
Name
put_user -- Write a simple value into user space.
Synopsis
put_user ( x, ptr);

Arguments
x
Value to copy to user space.

ptr
Destination address, in user space.

Context
User context only. This function may sleep.

Description
This macro copies a single simple value from kernel space to user space. It supports simple types like char and int, but not larger data types like structures or arrays.

ptr must have pointer-to-simple-variable type, and x must be assignable to the result of dereferencing ptr.

Returns zero on success, or -EFAULT on error. 





版权声明:本文为博主原创文章,未经博主允许不得转载。

相关文章推荐

Linux字符设备驱动入门(二)——加入ioctl功能

平台:VMware 7.0 + Linux ubuntu 3.0.0-12-generic 编译器:gcc 参考资料:LDD 3 功能:实现ioctl功能           在Linux...

linux驱动:[3]高级字符设备驱动之ioctl

linux驱动:[3]高级字符设备驱动之ioctllinux驱动:[3]高级字符设备驱动之ioctl测试平台: x86 PC linux-4.4.01.实验目的: 学习并编写ioctl linux高级...

使用ioctl方法创建字符设备驱动

1  ioctl介绍: 用户空间ioctl :int ioctl(int fd,unsinged long cmd,...) fd-文件描述符 cmd-对设备的发出的控制命令 ...表示这是一...

linux驱动开发之字符设备--内核和用户空间数据的交换(ioctl)

在驱动中,除了需要具备读写能力外,还需要对硬件设备进行控制。ioctl就常用户底层的一些操作。

Linux 字符设备驱动开发基础(四)—— ioctl() 函数解析

解析完 open、close、read、write 四个函数后,终于到我们的 ioctl() 函数了 一、 什么是ioctl          ioctl是设备驱动程序中对设备的I/O通道进行管理的函...

LDD3中scull字符设备源代码完全解析(三) ioctl方法

以下是scull源代码中ioctl方法的部分,先整体浏览一下,接着慢慢分析。 int scull_ioctl(struct inode *inode, struct file *filp,unsig...

ioctl---字符设备的控制技术

字符设备的控制 1. 字符设备控制理论     1.1 作用           大部分驱动程序除了需要提供读写设备的能力外,还需要具备控制设备的能力。比如:改变波特率     1.2 应用程...

linux高级字符设备驱动(一 设备Ioctl控制)

1. Ioctl 用来做什么?           大部分驱动除了需要具备读写设备的能力外,还需要具备对硬件控制的能力。例如,要求设备报告错误信息,改变波特率,这些操作常常通过ioctl方法来实现。...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:深度学习:神经网络中的前向传播和反向传播算法推导
举报原因:
原因补充:

(最多只允许输入30个字)