高级字符驱动程序操作之ioctl

ioctl:

用户空间原型:int
ioctl(int fd, unsigned long cmd, …);

“...”并非可变参数,而是可选参数,防止编译器进行类型检查。

驱动原型:int
(*ioctl)(struct inode *inode, struct file *filp, unsigned int cmd,
unsigned long arg);

inode和flip是原来的fd,cmd原封不动,arg是附加参数,被关闭了类型检查。

选择ioctl的命令:

老的约定:
新的约定,应先查看include/asm/ioctl.h和Documentation/ioctl-number.txt这两个文件。

定义号码的新方法使用了4个位字段,下面所介绍的新符号都定义在<linux/ioctl.h>中

type

幻数,选择一个号码(记住先仔细阅读ioctl-number.txt),并在整个驱动程序中使用这个号码,有8位宽(_IOC_TYPEBITS)

number

序数(顺序编号)。8位宽(_IOC_NRBITS)。

direction

定义数据传输方向,_IOC_NONE(没有数据传输)、_IOC_READ、_IOC_WRITE以及_IOC_READ|_IOC_WRITE(双向传输数据)

size

所涉及的用户数据大小。这个字段的宽度与体系结构有关,通常13或14,可通过_IOC_SIZEBITS找到针对特定体系结构的具体数值。内核并不检查这个位字段

<linux/ioctl.h>中包含的<asm/ioctl.h>头文件定义了一些构造命令编号的宏:

_IO(type,nr)用于构造无参数命令

_IOR(type,nr,datatype)

_IOW(type,nr,datatype)

_IOWR(type,nr,datatype)

size字段通过datatype去sizeof得

解开宏:

_IOC_DIR(nr)、_IOC_TYPE(nr)、_IOC_NR(nr)、_IOC_SIZE(nr)

返回值:

不匹配ioctl合法操作时,某些返回-ENVAL(Invalid
argument,非法参数)。POSIX规定应该返回-ENOTTY(Inappropriate
ioctl for device,不适合设备的ioctl)

预定义命令:

有一些命令可由内核识别,这些命令先于我们的操作被调用时解析,所以,如果我们自己的命令选用了与这些命令相同的编号,就永远不会收到该命令的请求,而且命令冲突,应用程序的行为将无法预测。

分三组:

可用于任何文件(普通、设备、FIFO和套接字)的命令

只用于普通文件的命令

特定于文件系统类型的命令

第一组的幻数都是“T”

下列ioctl命令对任何文件(包括设备特定文件)都是预定义的:

FIOCLEX

FIONCLEX

FIOASYNC

FIOQSIZE

FIONBIO

使用ioctl参数:

如果参数是个指针,那么要关心指向的用户空间是否合法的问题。copy_from_user和copy_to_user可以安全地与用户空间交换数据,但ioctl涉及到小的数据项,效率不高。

可以通过函数access_ok验证地址,该函数在<asm/uaccess.h>中声明:

int
access_ok(int type, const void *addr, unsigned long size);

第一个参数VERIFY_READ或VERIFY_WRITE。与其他不同,返回1表示成功,返回0表示失败驱动程序通常要返回-EFAULT给调用者

在调用access_ok后就可以安全的传输数据了。

还可以使用为最常用的数据大小(1,24,8)优化过的函数,这些函数定义在<asm/uaccess.h>中,列在下面:

put_user(datum,
ptr)

__put_user(datum,
ptr)

这些宏定义展开时不进行类型检查,put_user进行检查以确保进程可以写入指定的内存地址,并在成功时返回0,出错时返回-EFAULT。__put_user做的检查少些(它不调用access_ok),但如果地址只想用户不能写入的内存,也会出现操作失败,因此,__put_user应该在已经使用access_ok检验过内存区后再使用。

一般的用法是,实现一个读取方法时,可以调用__put_user来节省几个时钟周期,或者在复制多项数据之前调用一次access_ok。

get_user(local,
ptr)

__get_user(locak,
ptr)

如果试图使用上面列出的函数传递大小不符合任意一个特定值的数值,结果通常是编译器会给出一条奇怪的消息,比如“conversion
to non-scalar type requested(需要转换为非标量类型)”。

权能与受限操作

全部全能操作可以在<linux/capability.h>中找到,其中包含了系统能够理解的所有权能;不修改内核源码,对驱动程序开发者来讲有意义的权能如下所示:

CAP_DAC_OVERRIDE

越过文件或目录的访问权限(数据访问控制或DAC)的能力

CAP_NET_ADMIN

执行网络管理任务的能力,包括那些能影响网络接口的任务

CAP_SYS_MODULE

载入或卸载内核模块的能力

CAP_SYS_RAWIO

执行裸IO的能力,例如访问设备接口或直接与USB设备通讯

CAP_SYS_ADMIN

截获的能力,它提供了访问许多系统管理操作的途径

CAP_SYS_TTY_CONFIG

执行tty配置任务的能力

检查权能的函数定义在<sys/linux.h>

int
capable(int capability);

时间: 2024-10-05 19:31:23

高级字符驱动程序操作之ioctl的相关文章

《Linux Device Drivers》第六章 高级字符驱动程序操作——note

ioctl 支持的操作,例如 简单数据传输 控制动作,例如用户空间发起弹出介质动作 反馈硬件的状态,例如报告错误信息 参数配置,例如改变波特率 执行自破坏 用户空间的ioctl方法原型:int ioctl(int fd, unsigned long cmd, -);每个ioctl命令就是一个独立的系统调用,而且是非公开的 驱动程序的ioctl方法原型:int (*ioctl) (struct inode *inode, struct file *filp, unsigned int cmd, u

Linux设备驱动程序学习 高级字符驱动程序操作[阻塞型I/O和非阻塞I/O]【转】

转自:http://blog.csdn.net/jacobywu/article/details/7475432 阻塞型I/O和非阻塞I/O 阻塞:休眠 非阻塞:异步通知 一 休眠 安全地进入休眠的两条规则: (1) 永远不要在原子上下文中进入休眠,即当驱动在持有一个自旋锁.seqlock或者 RCU锁时不能睡眠:关闭中断也不能睡眠.持有一个信号量时休眠是合法的,但你应当仔细查看代码:如果代码在持有一个信号量时睡眠,任何其他的等待这个信号量的线程也会休眠.因此发生在持有信号量时的休眠必须短暂,而

Linux设备驱动第七篇:高级字符驱动操作之阻塞IO

我们之前介绍过简单的read,write操作,那么会有一个问题:当驱动无法立即响应请求该怎么办?比如一个进程调用read读取数据,当没有数据可读时该怎么办,是立即返回还是等到有数据的时候:另一种情况是进程调用write向设备写数据,如果缓冲区满了或者设备正忙的时候怎么办,是立即返回还是继续等待直到设备可写?这种情况下,一般的缺省做法是使进程睡眠直到请求可以满足为止.本篇就介绍遇到这类问题驱动的处理方法. 睡眠 什么是睡眠?一个进程睡眠意味着它暂时放弃了CPU的运行权,直到某个条件发生后才可再次被

Linux设备驱动第六篇:高级字符驱动操作之iotcl

在之前我们介绍了怎样实现一个简单的字符设备驱动.并介绍了简单的open,close,read,write等驱动提供的基本功能.可是一个真正的设备驱动往往提供了比简单读写更高级的功能. 这一篇我们就来介绍一些驱动动中使用的一些高级的操作的实现. 大部分驱动除了提供对设备的读写操作外,还须要提供对硬件控制的接口,比方查询一个framebuffer设备能提供多大的分辨率,读取一个RTC设备的时间,设置一个gpio的高低电平等等.而这些对硬件操作能力的实现一般都是通过ioctl方法来实现的 1. 原型介

树莓派上的GPIO字符驱动程序

前言 主要是在嵌入式Linux(树莓派)中如何使用已有的函数库编写应用程序操纵GPIO,如何编写字符设备驱动程序在内核程序中使用GPIO 硬件连接图 虚拟文件系统操作GPIO Linux可以通过访问sys/class/gpio下的一些文件,通过对这些文件的读写来实现对于GPIO的访问. 树莓派下面的可用的GPIO如下图所示,需要注意树莓派一代和二代的区别 首先用一个小灯来测试下操作.首先向export中写入18,表示启用18号gpio端口,执行之后,可以看到该目录下多出了一个gpio18的目录.

小白的linux字符驱动程序

关于如何编译一个测试型的字符驱动程序,网上一搜还是很多的在此给出一个不错的教程http://blog.chinaunix.net/uid-11829250-id-337300.html 我主要是在搜索ioctl的时候才有自己编写一个字符驱动的想法,因为刚工作的时候就看到有同事在用ioctl,当时在网上搜了下ioctl也没怎么明白.现在才发现原来ioctl就是对应的设备驱动程序里的ioctl函数.好了,废话就不多说了.写这篇文档的主要意义在于给后来编写驱动程序的新手们提示几个可能会遇到的问题,希望

Linux C高级编程——文件操作之系统调用

Linux C高级编程文件操作之系统调用 宗旨:技术的学习是有限的,分享的精神的无限的! 库函数是一些完成特定功能的函数,一般由某个标准组织制作发布,并形成一定的标准.使用库函数编写的函数一般可以应用于不同的平台而不需要做任何修改,具有很好的可移植性. 系统调用函数与操作系统直接相关,不同的操作系统所使用的系统调用可能不太一样,因此,如果两个操作系统差异很大,系统调用函数的可移植性就不高.例如windows采用的系统调用的应用程序不能直接在Linux下编译运行. 之所以使用系统调用是因为系统资源

Linux 字符驱动程序(一)

Linux 字符驱动程序(一) 在linux内核中设备主要有三种: 1 字符设备: ?字符设备的读写以字节为单位,存取时没有缓存. ?对字符设备发出读写请求时,实际的硬件I/O紧接着就发生了.一般来说,字符设备不支持随机访问. ?典型的字符设备包括鼠标.键盘及串行口等. 2 块设备: ?块设备读写以块为单位,典型的块大小为512或1024字节. ?利用一块系统内存作为缓冲区,当用户进程对设备发出读写请求时,驱动程序先察看缓冲区中的内容,若缓冲区中的数据能满足用户的要求就返回相应的数据,否则就调用

java的IO操作:字节流与字符流操作

流的概念 程序中的输入输出都是以流形式,流中保存的实际上都是字节文件. 字节流与字符流 字节流的操作: 1)输入:inputStream, 2)输出:outPutStream; 字符流的操作: 1)输入主要使用:write类. 2)输出主要使用:reader类. 内容操作就四个类. 操作流程: 使用File类操作一定有路径问题,注意分隔符: 实际上四个操作类都是抽象类(区别接口,抽象类的成员都是抽象,并且只能单继承,接口可以有全局变量,但是接口可以多继承) IO操作属于资源操作,对于资源操作,操