ssize_t (*read) (struct file *file, char __user * buf, size_t count, loff_t *pos);
功能:从内核空间读取数据到用户空间
参数:
file: 存放open打开文件时生成的file指针
buf: 从用户空间的read传来,所以buf是用户空间的地址,buf指向的地址用来存放读取的数据
count:从用户空间的read传来,表示要读取的字节数
pos: 文件的偏移位置
返回值:返回值已读取的字节数,出错返回一个负值
long (*unlocked_ioctl) (struct file *, unsigned int cmd, unsigned long arg);
功能:驱动程序一般需要支持通过ioctl实现各种控制与参数设置
参数:
file: 存放open打开文件时生成的file指针
cmd: 存放用户空间传送过来的命令
arg: 存放用户空间传送过来的参数,如为整数,可直接使用。如为指针,驱动首先要检查指针的合法性
使用
access_ok函数检查,检查通过后才可以使用
返回值:与ioctl系统调用一样,成功返回0,失败返回错误码
可通过
capable函数来确定调用进程是否有权执行操作
注:为了创建唯一的
ioctl命令号,每一个命令号被分为了4个字段,下面介绍的新符号都定义在
<linux/ioctl.h>中。
type:
幻数。选择一个号码,并在整个驱动程序中使用这个号码。(记住先阅读ioctl-number.txt)
number:
序列号。
direction :
数据传送的方向,如果这个特殊的命令涉及数据传送。可能的值是
_IOC_NONE(没有数据传输),
_IOC_READ,
_IOC_WRITE, 和
IOC_READ|_IOC_WRITE (双向传输数据)。 数据传送是从应用程序的角度来看的;也就是说,_IOC_READ 意思是从设备中读取设备, 因此设备必须写到用户空间. 注意这个成员是一个位掩码, 因此 _IOC_READ 和 _IOC_WRITE 可使用一个逻辑 AND 操作来抽取.
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) 用于双向传输
type:幻数
nr: 序列号
datatype:数据类型
unsigned int (*poll) (struct file *filp, poll_table *wait);
功能:是poll,epoll,select的后端实现。
参数:
fp: 存放open打开文件时生成的file指针
wait:它由vfs层的
do_select函数传递给
poll。然后向其中加入等待队列,使用
poll_wait向
poll_table结构体中添加一个等待队列 。
void poll_wait (struct file *, wait_queue_head_t *, poll_table *);
返回值:返回一个用来描述操作是否可以立即无阻塞执行的位掩码
这几个标志在
<linux/poll.h>中定义:
POLLIN
如果设备可被不阻塞地读, 这个位必须设置.
POLLRDNORM
如果“通常”的数据已经就绪,可以读取,就设置该位。一个可读设备需返回
( POLLIN | POLLRDNORM ).
POLLRDBAND
这个位指示可以从设备中读取带外(
out-of-band)数据, 当前只可以在 Linux 内核的DECnet 代码中使用,并且通常不用于设备驱动
POLLPRI
可以不阻塞地读取高优先级数据,设置该位会使 select 报告文件发生一个异常,因为 selct 把带外据作为一个异常情况.
POLLHUP
当读这个设备的进程到达文件尾时, 驱动必须设置 POLLUP(挂起)位。依照select的功能描述,调用select的进程会被告知设备时可读的。
POLLERR
一个错误情况已在设备上发生. 当调用 poll, 就会报告设备可读可写, 因为读写都会无阻塞地返回一个错误码
POLLOUT
如果设备可以无阻塞地写入,就在返回值中设置该位
POLLWRNORM
这个位和 POLLOUT 有相同的含义,有时其实就是同一个数字。一个可写的设备需返回
( POLLOUT | POLLWRNORM).
POLLWRBAND
如同 POLLRDBAND , 这个位意思是带有零优先级的数据可写入设备. 只有 poll 的数据报实现使用这个位, 因为一个数据报看传送带外数据.
POLLRDBAND 和 POLLWRBAND 只在与套接字相关的文件描述符中才有意义。设备驱动通常用不到这两个标志
poll的一般模板:
static unsigned int hello_poll(struct file *filp, poll_table *wait)
{
unsigned int mask = 0;
struct hello_device *dev = filp->private_data;
poll_wait(filp, &dev->rq, wait);
poll_wait(filp, &dev->wq, wait);
down(&dev->sem);
if (dev->len > 0)
{
mask |= POLLIN | POLLRDNORM;
}
if (dev->len != 128)
{
mask |= POLLOUT | POLLWRNORM;
}
up(&dev->sem);
return mask;
}
注:对poll机制需要做的一些说明:
- 首先需要明确poll_wait所做的操作就是把等待队列添加到poll_table 中,然后在vfs层的do_select中执行等待队列的操作。此时所有的描述符处在等待队列的状态中,直到其中一个描述符被唤醒。
- 而唤醒等待队列的操作时机是在对select中所包含的任一描述符进行相应地读写操作或其他操作时,在相应操作的驱动中实现调用唤醒队列的内核函数,此时do_select才会被唤醒。如果在驱动函数中没有调用唤醒操作,则do_select不会被唤醒。
- do_select被唤醒后,对所有的文件描述符(注意,这里是对系统调用select中包含的所有文件描述符)执行其相应的驱动函数poll,然后在驱动函数中来判断其对应的设备是否已经就绪。
- 驱动函数判断完后,返回一个用来描述操作是否可以立即无阻塞执行的位掩码,do_select根据各个驱动函数poll返回的掩码,来判断相应的设备是否可被无阻塞操作。如果可以则置位系统调用slect中参数相应的位。
int (*fasync) (int fd, struct file *fp, int mode);