字符设备之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. 





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

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

linux字符设备驱动helloword

 linux版本 ubuntu12.04LTS //驱动部分 #include #include #include #include #include #incl...
  • onedayalones
  • onedayalones
  • 2014年03月02日 23:32
  • 617

块设备驱动实战基础篇四 (逐渐成型,加入ioctl通信机制)

1.6介绍一种内核与用户空间通信的方法-misc设备ioctl机制 块设备驱动开发中往往需要配合用户态的管理程序工具,管理我们的块设备,此时我们需要涉及用户空间程序与块设备通信的方法,ioctl机制...
  • u012317833
  • u012317833
  • 2014年01月06日 20:40
  • 1324

添加字符设备ioctl

ioctl 中幻数使用 范围文件kernel\linux-3.0.y\Documentation\ioctl\ioctl-number.txt 平台:VMware 7.0 + Linux ...
  • bestboyxie
  • bestboyxie
  • 2015年08月26日 16:05
  • 1143

字符设备(4)ioctl

1.无参数 //ioctl 命令 static int test_ioctl(struct file *filp, unsigned long cmd, unsigned long arg)//2.6...
  • lileidajiangjun
  • lileidajiangjun
  • 2014年03月15日 17:03
  • 383

linux设备驱动之ioctl控制

大部分驱动除了具有读写的能力之外,还需要具有对硬件控制的能力。一。用户空间:ioctl 用户程序使用ioctl系统调用来控制设备。用户程序只是通过命令码告诉驱动程序想做什么,至于怎么解释这些命令和怎...
  • lincuiting06
  • lincuiting06
  • 2015年12月11日 16:43
  • 601

pixhawk px4 字符型设备驱动

分析字符型设备为什么register/open/read/write怎样与底层驱动代码联系在一起的,为什么需要注册,为什么会有路径,为什么open之后read/write就可以读/写了 另:此篇bl...
  • czyv587
  • czyv587
  • 2016年12月21日 12:40
  • 1877

Linux Platform设备驱动学习与小结

Platform 设备先被注册然后platfrom驱动加载时会调用驱动程序中的probe()入口函数,扫描系统中已注册的设备,通过。Name域找到匹配设备后将驱动和设备绑定。一个驱动可以对应多个设备,...
  • u010944778
  • u010944778
  • 2015年04月06日 19:23
  • 884

字符设备驱动第六课---ioctl

ioctl功能
  • u010243305
  • u010243305
  • 2016年12月05日 14:59
  • 175

Android字符设备驱动及应用层从jni控制GPIO实战

本文主要讲述从实际项目中一个GPIO口控制一个加密芯片上下电的功能,提供动态库给客户,并有Android应用层apk调用.so库文件的例子,希望能为大家字符设备驱动以及jni开发入门带来帮助! ...
  • xiaozhude
  • xiaozhude
  • 2017年04月07日 16:54
  • 585
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:字符设备之ioctl
举报原因:
原因补充:

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