第六章:高级字符驱动程序操作

原创 2012年03月30日 10:58:56

ioctl

大多数ioctl的实现中都包括一个switch语句来根据cmd参数选择对应的操作。

用户空间,ioctl原型如下:

int ioctl(int fd, unsigned long cmd, …);

最后省略号一般表示可变参数,但在实际系统中,系统调用不会真正的使用可变数目的参数。它只是为了在编译时防止编译器进行类型检查。因为有时它是一个整形数,有时是一个指针。

驱动程序的ioctl原型:

int (*ioctl)(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg);

inodefilp两个指针的值对应于应用程序传递的文件描述符fdcmd是用户空间传递过来的值。可选的arg,无论用户传递的是整数还是指针,都以unsigned long的形式传给arg

通常ioctl是一个switch语句,根据传递进来的cmd执行相应的操作。

选择ioctl命令

为驱动程序选择一个ioctl编号,应该首先看看include/asm/ioctl.hDocumention/ioctl-number.txt这两个文件。

cmdtypenumberdirectionsize四个部分组成。四部分定义在<linux/ioctl.h>中。

<linux/ioctl.h>包含的<asm/ioctl.h>包含了大量的构造以及解析cmd的宏。如

_IO(type, nr); //构造无参数的命令编号

_IOR(type, nr, datatype); //构造从驱动程序读取数据的命令编号

_IOW(type, nr, datatype); //给驱动程序写数据的命令编号

_IOWR(type, nr, datatype); //双向传输

解析cmd的宏:_IOC_DIR(nr)_IOC_TYPE(nr)_IOC_NR(nr)_IOC_SIZE(nr)

预定义命令

在定义我们用于ioctl的命令时,需要注意避免与内核已有的命令相冲突。内核已有的命令有:FIOCLEXFIONCLEXFIOASYNCFIOQSIZEFIONBIO

使用ioctl参数

在驱动程序中,如果需要与用户空间地址数据做交换,可以首先使用定义在<asm/uaccess.h>中的access_ok来验证地址。

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

第一个参数是VERIFY_READ或者VERIFY_WRITE,取决于是读取还是写入用户空间。如果既要读取又要写入,则应该是VERIFY_WRITE。返回1表示成功,0表示失败。

定义在<asm/uaccess.h>中的函数:put_user(data, ptr)__put_user(data, ptr)get_user(data, ptr)__get_user(data, ptr)。可以用来与用户空间交换1248字节内容。若ptr是一个指向字符的指针,则传递1个字节的内容。

权能和受限操作

对设备的访问由设备文件的权限控制,驱动程序一般不进行检查。

全部的权能操作可以在<linux/capability.h>中找到,对驱动程序开发者有意义的权能有:

CAP_DAC_OVERRIDE, CAP_NET_ADMIN, CAP_SYS_MODULE, CAP_SYS_RAWIO, CAP_SYS_ADMIN, CAP_SYS_TTY_CONFIG

权能的检查通过capable函数实现(定义在<sys/sched.h>中)。

int capable(int capability);

休眠

休眠进程被从调度器的运行队列移走,直到某情况下修改这个状态,进程才会在CPU上调度。

² 永远不要在原子上下文进入休眠。

² 除非我们知道有其他人在其他地方会唤醒我们,否则进程不能进入休眠。

linux中,一个等待队列通过一个“等待队列头(wait queue head)”管理。等待队列头是一个类型为wait_queue_head_t的结构体。定义在<linux/wait.h>中。

静态初始化一个等待队列头:

DECLARE_WAIT_QUEUE_HEAD(name);

动态初始化一个等待队列头:

wait_queue_head_t my_queue;

init_waitqueue_head(&my_queue);

linux内核中最简单的休眠是wait_event宏。如下:

wait_event(queue, condition);

wait_event_interruptible(queue, condition);

wait_event_timeout(queue, condition, timeout);

wait_event_iterruptible_timeout(queue, condition, timeout);

queue是等待队列头,它通过“值”传递。condition是一个布尔表达式,此表达式会被多次求值,因此对该表达式的求值不能带来任何副作用。wait_event_interruptible返回一个整数值,非零值表示休眠被某个信号中断。

唤醒的宏有:

void wake_up(wait_queue_head_t *queue);

void wake_up_interruptible(wait_queue_head_t *queue);

wake_up会唤醒queue上的所有进程,wake_up_interruptible只会唤醒哪些执行可中断休眠的进程。

阻塞和非阻塞型操作

显式的非阻塞IOfilp->f_flags中的O_NONBLOCK标志决定,这个标志定义在<linux/fcntl.h>

在驱动程序中实现输出缓冲区可以提高性能。

只有readwriteopen文件操作受非阻塞标志影响。

schedule函数:告诉内核重新选择其他进程运行。

高级休眠----手工休眠

1. 建立并初始化一个等待队列入口:

DEFINE_WAIT(my_wait);

也可以通过下步骤建立:

wait_queue_t my_wait;

init_wait(&my_wait);

2. 将我们的等待队列入口加到队列中。

void prepare_to_wait( wait_queue_head_t  *queue,

wait_queue_t *wait,

int state);

3. 在prepare_to_wait之后,进程即可调用schedule,当然在这之前,应确保仍有必要等待。

4. 最后清理。

void finish_wait(wait_queue_t *queue, wait_queue_t *wait);

独占等待

void prepare_to_wait_exclusive( wait_queue_head_t  *queue,

wait_queue_t *wait,

int state);

设置等待队列入口的“独占”标志,并将进程添加到等待队列的尾部。

查漏补缺

 _sync版本函数一般在函数返回前不会重新调度CPU

#include  <linux/poll.h>

void poll_wait(struct file *filp, wait_queue_head_t *q, poll_table *p);

将当前进程置于某个等待队列但不立即调度,该函数主要用于设备驱动程序的poll方法。

 

第六章:高级字符驱动程序操作

1、ioctl ​除了读取和写入设备之外,大部分驱动程序还需要另外一种能力,即通过设备驱动程序执行各种类型的硬件控制。 在用户空间,ioctl系统调用有如下原型: int ioctl(in...
  • u013684730
  • u013684730
  • 2017年07月05日 09:43
  • 85

第六章--高级字符驱动程序操作

本文作为第六章--高级字符驱动程序操作,主要讲述: 1、ioctl。 2、休眠。 3、poll和select。...
  • apple_guet
  • apple_guet
  • 2014年03月11日 11:54
  • 626

高级字符驱动程序操作

通过读/写来实现数据传输,但除了数据传输之外,还有请求设备锁门、弹出介质、报告错误信息等。 休眠:当一个进程所需要的资源得不到满足时,会标记为一种特殊状态,该状态就可以理解为休眠,休眠中的进程会被搁...
  • good123_2014
  • good123_2014
  • 2016年08月05日 20:04
  • 458

并发控制的字符设备驱动程序

http://blog.chinaunix.net/space.php?uid=24219701&do=blog&id=91468
  • juneman
  • juneman
  • 2011年01月18日 19:01
  • 435

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

ioctl 除了读取和写入设备之外,大部分驱动程序还需要另外一种能力,即通过设备驱动程序执行各种类型的硬件控制。如:用户空间经常会请求设备锁门,弹出介质,改变波特率或者执行自破坏等。这些操作通常...
  • masm_2009
  • masm_2009
  • 2013年01月15日 09:39
  • 1146

其它高级字符驱动程序操作

异步通知 尽管大多数时候阻塞和非阻塞型操作的组合及select方法可以有效地查询设备,但某些时候用这种技术处理效率就不高了。为了启用异步通知,用户程序必须执行两个步骤。首先,它们必须为文件指定一...
  • masm_2009
  • masm_2009
  • 2013年01月18日 18:38
  • 580

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

ioctl 支持的操作,例如 简单数据传输控制动作,例如用户空间发起弹出介质动作反馈硬件的状态,例如报告错误信息参数配置,例如改变波特率执行自破坏 用户空间的ioctl方法原型:int ioctl...
  • luopingfeng
  • luopingfeng
  • 2014年09月27日 22:04
  • 389570

【Linux 驱动】第六章 高级字符驱动程序操作----poll,select,epoll

一,poll         允许进程决定是否可以对一个或者多个打开的文件做非阻塞的读取或者写入(但是请注意select自身会阻塞进程知道某个描述符满足条件或者超时),常常用于那些要使用多个输入或者...
  • tianshuai11
  • tianshuai11
  • 2012年04月13日 16:20
  • 1389

【Linux 驱动】第六章 高级字符驱动程序操作----异步通知

一,概念          异步通知:一旦设备就绪,则主动通知应用程序,应用程序根本就不需要查询设备状态。(类似于中断)信号是异步的,一个进程不必通过任何操作来等待信号的到达       ...
  • tianshuai11
  • tianshuai11
  • 2012年04月13日 17:04
  • 1385

【Linux 驱动】第六章 高级字符驱动程序操作 ----ioctl

一、ioctl        1)概念:#include        2)功 能: 控制I/O设备 ,提供了一种获得设备信息和向设备发送控制参数的手段。用于向设备发控制和配置命令 ,有些命令需要...
  • tianshuai11
  • tianshuai11
  • 2012年04月13日 11:43
  • 1615
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:第六章:高级字符驱动程序操作
举报原因:
原因补充:

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