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

来源:互联网 发布:java 加一个月 编辑:程序博客网 时间:2024/05/18 00:09

2V4L2驱动注册函数的实现

 

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) {

              

              i = base+nr;

              if (NULL != video_device[i]) {

                     mutex_unlock(&videodev_lock);

                     return -ENFILE;

              }

       } else {

              

              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);

 

       

       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);//结合udevmdev可以实现自动在/dev下创建设备节点

       ……

}

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



四、            V4L2 驱动框架

上述流程的各个操作都需要有底层 V4L2 驱动的支持。内核中有一些非常完善的例子。

比如: linux-2.6.26 内核目录 /drivers/media/video//zc301/zc301_core.c 中的 ZC301 视频驱动代码。上面的 V4L2 操作流程涉及的功能在其中都有实现。

1  V4L2 驱动注册、注销函数

       Video 核心层( drivers/media/video/videodev.c )提供了注册函数

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

video_device:  要构建的核心数据结构

Type:  表示设备类型,此设备号的基地址受此变量的影响

Nr:    如果 end-base>nr>0 :次设备号 =base (基准值,受 type 影响) +nr 

否则:系统自动分配合适的次设备号

       具体驱动只需要构建 video_device 结构,然后调用注册函数既可。

如: zc301_core.c 中的

       err = video_register_device(cam->v4ldev, VFL_TYPE_GRABBER,

                          video_nr[dev_nr]);

       Video 核心层( drivers/media/video/videodev.c )提供了注销函数

void video_unregister_device(struct video_device *vfd)

 

2  struct video_device 的构建

              video_device 结构包含了视频设备的属性和操作方法。参见 zc301_core.c

strcpy(cam->v4ldev->name, "ZC0301[P] PC Camera");

       cam->v4ldev->owner = THIS_MODULE;

       cam->v4ldev->type = VID_TYPE_CAPTURE | VID_TYPE_SCALES;

       cam->v4ldev->fops = &zc0301_fops;

       cam->v4ldev->minor = video_nr[dev_nr];

       cam->v4ldev->release = video_device_release;

       video_set_drvdata(cam->v4ldev, cam);

       大家发现在这个 zc301 的驱动中并没有实现 struct video_device 中的很多操作函数    vidioc_querycap  vidioc_g_fmt_cap 等。主要原因是 struct file_operations zc0301_fops 中的 zc0301_ioctl 实现了前面的所有 ioctl 操作。所以就不需要在 struct video_device 再实现 struct video_device 中的那些操作了。

       另一种实现方法如下:

static struct video_device camif_dev =

{

       .name             = "s3c2440 camif",

       .type              = VID_TYPE_CAPTURE|VID_TYPE_SCALES|VID_TYPE_SUBCAPTURE,

       .fops              = &camif_fops,

       .minor            = -1,

       .release    = camif_dev_release,

       .vidioc_querycap      = vidioc_querycap,

       .vidioc_enum_fmt_cap  = vidioc_enum_fmt_cap,

       .vidioc_g_fmt_cap     = vidioc_g_fmt_cap,

       .vidioc_s_fmt_cap     = vidioc_s_fmt_cap,

       .vidioc_queryctrl = vidioc_queryctrl,

       .vidioc_g_ctrl = vidioc_g_ctrl,

       .vidioc_s_ctrl = vidioc_s_ctrl,

};

static struct file_operations camif_fops =

{

       .owner           = THIS_MODULE,

       .open             = camif_open,

       .release    = camif_release,

       .read              = camif_read,

       .poll        = camif_poll,

       .ioctl              = video_ioctl2,

       .mmap           = camif_mmap,

       .llseek            = no_llseek,

};

注意  video_ioctl2  videodev.c 中是实现的。 video_ioctl2 中会根据 ioctl 不同的 cmd 

调用 video_device 中的操作方法。

0 0
原创粉丝点击