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

原创 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。 2、休眠。 3、poll和select。...

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

一、ioctl        1)概念:#include        2)功 能: 控制I/O设备 ,提供了一种获得设备信息和向设备发送控制参数的手段。用于向设备发控制和配置命令 ,有些命令需要...

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

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

【Linux 驱动】第六章 高级字符驱动程序操作 ----阻塞型I/O

序言:试想如果在驱动方法中的read/write中,当数据不可用时,用户可能调用read,当输出缓冲区满时,设备并未准备好接受数据,这种情况下驱动程序可以阻塞该进程,并且置入休眠状态直到满足条件。 ...

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

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

ldd3学习之十二(2):高级字符驱动程序操作--等待队列,阻塞I/O,休眠

在应用程序调用read,write时,若驱动程序无法立即满足要求,该如何响应?驱动程序应该(默认)阻塞该进程,将其置入休眠状态直到请求可继续。1.休眠进程被置为休眠,意味着它被标识为处于一个特殊的状态...

高级字符驱动程序操作之异步通知IO(实践篇)基于内核2.6.35-30

1. async.c 主要展示异步通知机制在驱动程序中的实现 #include #include #include /* everything... */ #includ...

高级字符驱动程序操作之休眠(理论篇)

1. 休眠的原则   第一条: "永远不要在原子上下文中进入休眠" (LDD3 p149) 第二条: 当线程被唤醒时,应当检查等待的条件是否为真 第三条: 确保即将休眠的线程一定会被唤醒  ...

高级字符驱动程序操作[(2)阻塞型I/O和休眠]

高级字符驱动程序操作[(2)阻塞型I/O和休眠] 这一部分主要讨论:如果驱动程序无法立即满足请求,该如何响应?(65865346)  一、休眠进程被置为休眠,意味着它被标识为处于一个特殊的状态并且从调...

LDD3读书笔记(第11章 高级字符驱动程序操作)

本章的目的是让读者知道: 1.内核与用户空间同步 2.如何使进程休眠(并唤醒) 3.如何实现非阻塞I/O 4.设备可读取或写入时如何通知用户空间 #include     这个头文件声明...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:第六章:高级字符驱动程序操作
举报原因:
原因补充:

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