V4L2视频驱动程序开发之驱动方法poll 和 应用程序select

来源:互联网 发布:淘宝炉石卡包为何便宜 编辑:程序博客网 时间:2024/05/17 01:33
V4L2视频驱动程序开发已经进入尾声,本次视频支持多个通道的stream同时传输,即有多个设备文件关联到驱动。最高支持48个stream同时输入。
应用程序在获取stream的时候,需要用到select,而驱动程序中的poll方法将被调用。以下对驱动poll作一下简单分析。


非阻塞 I/O 的应用程序常常使用 select,  允许一个进程来决定它是否可读或者写一个或多个文件而不阻塞. select调用也可阻塞进程直到任何一个给定集合的文件描述符可用来读或写. 它常常用在必须使用多输入输出流的应用程序. 


支持select调用都需要来自设备驱动的支持. 这个支持由驱动的 poll 方法调用. 这个方法有下列的原型:


unsigned int (*poll) (struct file *filp, struct poll_table_struct *wait);


这个设备方法poll负责这两步:


(一). 在一个或多个可指示查询状态变化的等待队列上调用 poll_wait. 如果没有文件描述符可用作 I/O, 内核使这个进程在所有传递给系统调用的文件描述符对应的等待队列上等待.


(二). 返回一个用来描述操作是否可以立即无阻塞执行的位掩码.


这两个操作很明了, 各个驱动实现起来也比较类似. 但是依赖只能由驱动提供的信息, 因此, 必须由每个驱动单独实现.


struct poll_table_struct 结构, 给 poll 方法的第 2 个参数, 在内核中用来实现select调用; 它在 <linux/poll.h>中声明, 这个文件必须被驱动源码包含. 驱动编写者不必要知道所有它的内容,只需要作为一个不透明的对象使用它; 它被传递给驱动poll方法,以便每个能唤醒进程和修改poll状态的等待队列可以被驱动程序装载, 驱动增加一个等待队列到 struct poll_table_struct 结构通过调用函数 poll_wait:


static inline void poll_wait(struct file * filp, wait_queue_head_t * wait_address, poll_table *p); 


poll 方法的第 2 个任务是返回哪个操作可马上被执行的位掩码. 例如, 如果设备有数据可读, 一个读操作可以立刻执行而不必休眠; 那么poll 方法应当指示几个掩码. (定义在 <linux/poll.h>)


如下掩码用来指示可能的操作:


POLLIN
如果设备可以无阻塞地读, 


POLLRDNORM
如果"通常"数据可用来读,设置这个位. 一个可读的设备返回( POLLIN|POLLRDNORM ).


POLLPRI
高优先级数据(带外)可不阻塞地读取. 这个位使 select 报告在文件上遇到一个异常情况, 因为 selct 报告带外数据作为一个异常情况.


POLLHUP
当读这个设备的进程见到文件尾, 驱动必须设置 POLLUP(hang-up). 一个调用 select 的进程被告知设备是可读的, 如同 selcet 功能所规定的.


POLLERR
一个错误情况已在设备上发生.


POLLOUT
 如果设备可被写入而不阻塞,设置这个位.


POLLWRNORM
这个位和 POLLOUT 有相同的含义. 一个可写的设备返回( POLLOUT|POLLWRNORM).


以下是我的代码的简单实现
static unsigned int vi_v4l2_poll(struct file *file, struct poll_table_struct *wait)
{
unsigned long flags = 0;
unsigned int framenum = 0, mask = 0;
struct vi_dev *pdev_info = video_drvdata(file);


VI_PRINT("%s in...\n", __FUNCTION__);


poll_wait(file, &(pdev_info->wait_rippirq), wait);


spin_lock_irqsave(&pdev_info->slock, flags);
ripp_get_scaler_frame_num(pdev_info->scaler_id, &framenum);


if (framenum > 0) {
mask |= POLLIN | POLLRDNORM;
}


spin_unlock_irqrestore(&pdev_info->slock, flags);


return mask;
}


在驱动初始化代码中
init_waitqueue_head(&pdev_info->wait_rippirq);


这个代码简单地增加了1个等待队列到 poll_table, 根据当前缓存中是否有帧流,而返回可读掩码.
当驱动中有数据可读,本代码中是收到一帧流数据的时候去唤醒等待对列。
wake_up_interruptible(pwait);
0 0
原创粉丝点击