V4L2_CONTROLS

这是一篇关于V4L2 CONTROLS的基本使用方法介绍。

内核中相关的文件是:v4l2-ctrls.h  v4l2-ctrls.c

V4L2 CONTROLS机制主要提供了设置硬件的方法,包含两个主要的对象:

struct v4l2_ctrl

struct v4l2_ctrl_handler

struct v4l2_ctrl代表一个控制变量和它的值,例如:声音。

struct v4l2_ctrl_handler是用来管理v4l2_ctrl的。

使用v4l2 control的步骤:

1.将v4l2_ctrl_handler增加到驱动顶层结构体中:

struct foo_dev {

...

struct v4l2_ctrl_handler ctrl_handler;

...

};

struct foo_dev *foo;

2.初始化v4l2_ctrl_handler:

v4l2_ctrl_handler_init(&foo->ctrl_handler, nr_of_controls);

第二个参数nr_of_controls是你要使用的控制变量的个数。

3.关联v4l2_ctrl_handler和v4l2_device:

struct foo_dev {

...

struct v4l2_device v4l2_dev;

...

struct v4l2_ctrl_handler ctrl_handler;

...

};

foo->v4l2_dev.ctrl_handler = &foo->ctrl_handler;

然后从v4l2_ioctl_ops中移除所有的控制函数:vidioc_queryctrl, vidioc_querymenu, vidioc_g_ctrl, vidioc_s_ctrl,vidioc_g_ext_ctrls, vidioc_try_ext_ctrls and vidioc_s_ext_ctrls。

对于子设备,我们这样做:

struct foo_dev {

...

struct v4l2_subdev sd;

...

struct v4l2_ctrl_handler ctrl_handler;

...

};

foo->sd.ctrl_handler = &foo->ctrl_handler;

然后对v4l2_subdev_core_ops结构增加函数支持:

.queryctrl = v4l2_subdev_queryctrl,

.querymenu = v4l2_subdev_querymenu,

.g_ctrl = v4l2_subdev_g_ctrl,

.s_ctrl = v4l2_subdev_s_ctrl,

.g_ext_ctrls = v4l2_subdev_g_ext_ctrls,

.try_ext_ctrls = v4l2_subdev_try_ext_ctrls,

.s_ext_ctrls = v4l2_subdev_s_ext_ctrls,

4.在驱动退出的时候清除v4l2_ctrl_handler:

v4l2_ctrl_handler_free(&foo->ctrl_handler);

5.增加控制变量:

(1struct v4l2_ctrl *v4l2_ctrl_new_std(struct v4l2_ctrl_handler *hdl,

const struct v4l2_ctrl_ops *ops,

u32 id, s32 min, s32 max, u32 step, s32 def);

这个函数用来增加非菜单式的控制变量,如声音等。min是最小值,max是最大值,step是步进长度,def是默认值。这个函数适用于在某一范围内均匀变化的控制变量。

例:v4l2_ctrl_new_std(&foo->ctrl_handler, &foo_ctrl_ops,V4L2_CID_VOLUM, 0, 255, 1, 128);

2struct v4l2_ctrl *v4l2_ctrl_new_std_menu(struct v4l2_ctrl_handler *hdl,

const struct v4l2_ctrl_ops *ops,

u32 id, s32 max, s32 skip_mask, s32 def);

这个函数用来增加菜单式的控制变量,max是菜单最大值,skip_mask是屏蔽标志,比如它的值是0x4,就么就屏蔽菜单值为4的菜单选项,def是默认的菜单值。这个函数适用于从0开始,相邻变量值增加1的控制变量。

例:

enum{

BW_6M,

BW_7M,

BW_8M

}BW;

v4l2_ctrl_new_std_menu(&foo->ctrl_handler,&foo_ctrl_ops,V4L2_CID_BW,BW_8M

,0,BW_6M);

3struct v4l2_ctrl *v4l2_ctrl_new_int_menu(struct v4l2_ctrl_handler *hdl,

const struct v4l2_ctrl_ops *ops,

u32 id, s32 max, s32 def, const s64 *qmenu_int);

这个函数用来增加整数型菜单的控制变量,max是最大的菜单索引号,def是默认的菜单索引号,qmenu_int是菜单的数组指针。这个函数适用于变量值是不连续的无规则的整数的控制变量。

例:

static const s64 audio_sample_qmenu[] = {22100,44100,48000,96000};

v4l2_ctrl_new_int_menu(&foo->ctrl_handler,&foo_ctrl_ops,V4L2_CID_AUDIOSAMPLERATE,ARRAY_SIZE(audio_sample_qmenu)-1,1,audio_sample_qmenu);

4struct v4l2_ctrl *v4l2_ctrl_new_std_menu_items(

struct v4l2_ctrl_handler *hdl,

const struct v4l2_ctrl_ops *ops, u32 id, s32 max,

s32 skip_mask, s32 def, const char * const *qmenu);

这个函数用来增加一个驱动指定的菜单数组给控制变量,max是菜单最大索引号,skip_mask是需要跳过的菜单的索引号,def是默认菜单索引号,qmenu是菜单数组。

例:

static const char * const test_pattern[] = {

"Disabled",

"Vertical Bars",

"Solid Black",

"Solid White",

};

v4l2_ctrl_new_std_menu_items(&foo->ctrl_handler, &foo_ctrl_ops,

V4L2_CID_TEST_PATTERN, ARRAY_SIZE(test_pattern) - 1, 0,

0, test_pattern);

设置变量的值一般是在初始化了v4l2_ctrl_handler之后进行,在最后需要检查一下有没有错误 :

if (foo->ctrl_handler.error) {

int err = foo->ctrl_handler.error;

v4l2_ctrl_handler_free(&foo->ctrl_handler);

return err;

}

6.(可选,推荐使用)使用控制变量的默认值初始化所有硬件:

v4l2_ctrl_handler_setup(&foo->ctrl_handler);

这个函数会调用s_ctrl设置每个控制变量到硬件或其他地方。

7.最后,实现v4l2_ctrl_ops结构体:

static const struct v4l2_ctrl_ops foo_ctrl_ops = {

.s_ctrl = foo_s_ctrl,

};

static int foo_s_ctrl(struct v4l2_ctrl *ctrl)

{

struct foo *state = container_of(ctrl->handler, struct foo, ctrl_handler);

switch (ctrl->id) {

case V4L2_CID_BRIGHTNESS:

write_reg(0x123, ctrl->val);

break;

case V4L2_CID_CONTRAST:

write_reg(0x456, ctrl->val);

break;

}

return 0;

}

上面就是V4L2框架提供的基本的控制变量的使用方法,下面是bttv驱动的实例代码:

struct bttv {

......

/* controls */

struct v4l2_ctrl_handler   ctrl_handler;

struct v4l2_ctrl_handler   radio_ctrl_handler;

......

};

static int bttv_probe(struct pci_dev *dev, const struct pci_device_id *pci_id)

{

......

hdl = &btv->ctrl_handler;

v4l2_ctrl_handler_init(hdl, 20);

btv->c.v4l2_dev.ctrl_handler = hdl;

v4l2_ctrl_handler_init(&btv->radio_ctrl_handler, 6);

......

v4l2_ctrl_new_std(hdl, &bttv_ctrl_ops,

V4L2_CID_BRIGHTNESS, 0, 0xff00, 0x100, 32768);

v4l2_ctrl_new_std(hdl, &bttv_ctrl_ops,

V4L2_CID_CONTRAST, 0, 0xff80, 0x80, 0x6c00);

v4l2_ctrl_new_std(hdl, &bttv_ctrl_ops,

V4L2_CID_SATURATION, 0, 0xff80, 0x80, 32768);

......

v4l2_ctrl_handler_setup(hdl);

......

}

static const struct v4l2_ctrl_ops bttv_ctrl_ops = {

.s_ctrl = bttv_s_ctrl,

};

static int bttv_s_ctrl(struct v4l2_ctrl *c)

{

struct bttv *btv = container_of(c->handler, struct bttv, ctrl_handler);

int val;

switch (c->id) {

case V4L2_CID_BRIGHTNESS:

bt848_bright(btv, c->val);

break;

case V4L2_CID_HUE:

bt848_hue(btv, c->val);

break;

......

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值