您的位置:首页 > 其它

基于V4L2的视频驱动开发(4)

2012-01-05 17:21 351 查看
3 、 Video 核心层的实现

参见内核 /drivers/media/videodev.c

( 1 )注册 256 个视频设备

static int __init videodev_init(void)

{

int ret;

if (register_chrdev (VIDEO_MAJOR, VIDEO_NAME, &video_fops)) {

return -EIO;

}

ret = class_register(&video_class);

……

}

上面的代码注册了 256 个视频设备,并注册了 video_class 类。 video_fops 为这 256 个设备共同的操作方法。

( 2 ) V4L2 驱动注册函数的实现

int video_register_device(struct video_device *vfd, int type, int nr)

{

int i=0;

int base;

int end;

int ret;

char *name_base;

switch(type) // 根据不同的 type 确定设备名称、次设备号

{

case VFL_TYPE_GRABBER:

base=MINOR_VFL_TYPE_GRABBER_MIN;

end=MINOR_VFL_TYPE_GRABBER_MAX+1;

name_base = "video";

break;

case VFL_TYPE_VTX:

base=MINOR_VFL_TYPE_VTX_MIN;

end=MINOR_VFL_TYPE_VTX_MAX+1;

name_base = "vtx";

break;

case VFL_TYPE_VBI:

base=MINOR_VFL_TYPE_VBI_MIN;

end=MINOR_VFL_TYPE_VBI_MAX+1;

name_base = "vbi";

break;

case VFL_TYPE_RADIO:

base=MINOR_VFL_TYPE_RADIO_MIN;

end=MINOR_VFL_TYPE_RADIO_MAX+1;

name_base = "radio";

break;

default:

printk(KERN_ERR "%s called with unknown type: %d/n",

__func__, type);

return -1;

}

/* 计算出次设备号 */

mutex_lock(&videodev_lock);

if (nr >= 0 && nr < end-base) {

/* use the one the driver asked for */

i = base+nr;

if (NULL != video_device[i]) {

mutex_unlock(&videodev_lock);

return -ENFILE;

}

} else {

/* use first free */

for(i=base;i<end;i++)

if (NULL == video_device[i])

break;

if (i == end) {

mutex_unlock(&videodev_lock);

return -ENFILE;

}

}

video_device[i]=vfd; // 保存 video_device 结构指针到系统的结构数组中,最终的次设备号和 i 相关。

vfd->minor=i;

mutex_unlock(&videodev_lock);

mutex_init(&vfd->lock);

/* sysfs class */

memset(&vfd->class_dev, 0x00, sizeof(vfd->class_dev));

if (vfd->dev)

vfd->class_dev.parent = vfd->dev;

vfd->class_dev.class = &video_class;

vfd->class_dev.devt = MKDEV(VIDEO_MAJOR, vfd->minor);

sprintf(vfd->class_dev.bus_id, "%s%d", name_base, i - base);// 最后在 /dev 目录下的名称

ret = device_register(&vfd->class_dev);// 结合 udev 或 mdev 可以实现自动在 /dev 下创建设备节点

……

}

从上面的注册函数中可以看出 V4L2 驱动的注册事实上只是完成了设备节点的创建,如: /dev/video0 。和video_device 结构指针的保存。

( 3 )视频驱动的打开过程

当用户空间调用 open 打开对应的视频文件时,如:

int fd = open(/dev/video0, O_RDWR );

对应 /dev/video0 的文件操作结构是 /drivers/media/videodev.c 中定义的 video_fops 。

static const struct file_operations video_fops=

{

.owner = THIS_MODULE,

.llseek = no_llseek,

.open = video_open,

};

奇怪吧,这里只实现了 open 操作。那么后面的其它操作呢?还是先看看 video_open 吧。

static int video_open(struct inode *inode, struct file *file)

{

unsigned int minor = iminor(inode);

int err = 0;

struct video_device *vfl;

const struct file_operations *old_fops;

if(minor>=VIDEO_NUM_DEVICES)

return -ENODEV;

mutex_lock(&videodev_lock);

vfl=video_device[minor];

if(vfl==NULL) {

mutex_unlock(&videodev_lock);

request_module("char-major-%d-%d", VIDEO_MAJOR, minor);

mutex_lock(&videodev_lock);

vfl=video_device[minor]; // 根据次设备号取出 video_device 结构

if (vfl==NULL) {

mutex_unlock(&videodev_lock);

return -ENODEV;

}

}

old_fops = file->f_op;

file->f_op = fops_get(vfl->fops);// 替换此打开文件的 file_operation 结构。后面的其它针对此文件的操作都由新的结构来负责了。也就是由每个具体的 video_device 的 fops 负责。

if(file->f_op->open)

err = file->f_op->open(inode,file);

if (err) {

fops_put(file->f_op);

file->f_op = fops_get(old_fops);

}

……

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: