|
@@ -1,5 +1,8 @@
|
|
|
|
+V4L2 Controls
|
|
|
|
+=============
|
|
|
|
+
|
|
Introduction
|
|
Introduction
|
|
-============
|
|
|
|
|
|
+------------
|
|
|
|
|
|
The V4L2 control API seems simple enough, but quickly becomes very hard to
|
|
The V4L2 control API seems simple enough, but quickly becomes very hard to
|
|
implement correctly in drivers. But much of the code needed to handle controls
|
|
implement correctly in drivers. But much of the code needed to handle controls
|
|
@@ -26,7 +29,7 @@ for V4L2 drivers and struct v4l2_subdev for sub-device drivers.
|
|
|
|
|
|
|
|
|
|
Objects in the framework
|
|
Objects in the framework
|
|
-========================
|
|
|
|
|
|
+------------------------
|
|
|
|
|
|
There are two main objects:
|
|
There are two main objects:
|
|
|
|
|
|
@@ -39,12 +42,14 @@ controls, possibly to controls owned by other handlers.
|
|
|
|
|
|
|
|
|
|
Basic usage for V4L2 and sub-device drivers
|
|
Basic usage for V4L2 and sub-device drivers
|
|
-===========================================
|
|
|
|
|
|
+-------------------------------------------
|
|
|
|
|
|
1) Prepare the driver:
|
|
1) Prepare the driver:
|
|
|
|
|
|
1.1) Add the handler to your driver's top-level struct:
|
|
1.1) Add the handler to your driver's top-level struct:
|
|
|
|
|
|
|
|
+.. code-block:: none
|
|
|
|
+
|
|
struct foo_dev {
|
|
struct foo_dev {
|
|
...
|
|
...
|
|
struct v4l2_ctrl_handler ctrl_handler;
|
|
struct v4l2_ctrl_handler ctrl_handler;
|
|
@@ -55,16 +60,20 @@ Basic usage for V4L2 and sub-device drivers
|
|
|
|
|
|
1.2) Initialize the handler:
|
|
1.2) Initialize the handler:
|
|
|
|
|
|
|
|
+.. code-block:: none
|
|
|
|
+
|
|
v4l2_ctrl_handler_init(&foo->ctrl_handler, nr_of_controls);
|
|
v4l2_ctrl_handler_init(&foo->ctrl_handler, nr_of_controls);
|
|
|
|
|
|
- The second argument is a hint telling the function how many controls this
|
|
|
|
- handler is expected to handle. It will allocate a hashtable based on this
|
|
|
|
- information. It is a hint only.
|
|
|
|
|
|
+The second argument is a hint telling the function how many controls this
|
|
|
|
+handler is expected to handle. It will allocate a hashtable based on this
|
|
|
|
+information. It is a hint only.
|
|
|
|
|
|
1.3) Hook the control handler into the driver:
|
|
1.3) Hook the control handler into the driver:
|
|
|
|
|
|
1.3.1) For V4L2 drivers do this:
|
|
1.3.1) For V4L2 drivers do this:
|
|
|
|
|
|
|
|
+.. code-block:: none
|
|
|
|
+
|
|
struct foo_dev {
|
|
struct foo_dev {
|
|
...
|
|
...
|
|
struct v4l2_device v4l2_dev;
|
|
struct v4l2_device v4l2_dev;
|
|
@@ -75,15 +84,17 @@ Basic usage for V4L2 and sub-device drivers
|
|
|
|
|
|
foo->v4l2_dev.ctrl_handler = &foo->ctrl_handler;
|
|
foo->v4l2_dev.ctrl_handler = &foo->ctrl_handler;
|
|
|
|
|
|
- Where foo->v4l2_dev is of type struct v4l2_device.
|
|
|
|
|
|
+Where foo->v4l2_dev is of type struct v4l2_device.
|
|
|
|
|
|
- Finally, remove all control functions from your v4l2_ioctl_ops (if any):
|
|
|
|
- vidioc_queryctrl, vidioc_query_ext_ctrl, vidioc_querymenu, vidioc_g_ctrl,
|
|
|
|
- vidioc_s_ctrl, vidioc_g_ext_ctrls, vidioc_try_ext_ctrls and vidioc_s_ext_ctrls.
|
|
|
|
- Those are now no longer needed.
|
|
|
|
|
|
+Finally, remove all control functions from your v4l2_ioctl_ops (if any):
|
|
|
|
+vidioc_queryctrl, vidioc_query_ext_ctrl, vidioc_querymenu, vidioc_g_ctrl,
|
|
|
|
+vidioc_s_ctrl, vidioc_g_ext_ctrls, vidioc_try_ext_ctrls and vidioc_s_ext_ctrls.
|
|
|
|
+Those are now no longer needed.
|
|
|
|
|
|
1.3.2) For sub-device drivers do this:
|
|
1.3.2) For sub-device drivers do this:
|
|
|
|
|
|
|
|
+.. code-block:: none
|
|
|
|
+
|
|
struct foo_dev {
|
|
struct foo_dev {
|
|
...
|
|
...
|
|
struct v4l2_subdev sd;
|
|
struct v4l2_subdev sd;
|
|
@@ -94,10 +105,12 @@ Basic usage for V4L2 and sub-device drivers
|
|
|
|
|
|
foo->sd.ctrl_handler = &foo->ctrl_handler;
|
|
foo->sd.ctrl_handler = &foo->ctrl_handler;
|
|
|
|
|
|
- Where foo->sd is of type struct v4l2_subdev.
|
|
|
|
|
|
+Where foo->sd is of type struct v4l2_subdev.
|
|
|
|
|
|
1.4) Clean up the handler at the end:
|
|
1.4) Clean up the handler at the end:
|
|
|
|
|
|
|
|
+.. code-block:: none
|
|
|
|
+
|
|
v4l2_ctrl_handler_free(&foo->ctrl_handler);
|
|
v4l2_ctrl_handler_free(&foo->ctrl_handler);
|
|
|
|
|
|
|
|
|
|
@@ -105,12 +118,16 @@ Basic usage for V4L2 and sub-device drivers
|
|
|
|
|
|
You add non-menu controls by calling v4l2_ctrl_new_std:
|
|
You add non-menu controls by calling v4l2_ctrl_new_std:
|
|
|
|
|
|
|
|
+.. code-block:: none
|
|
|
|
+
|
|
struct v4l2_ctrl *v4l2_ctrl_new_std(struct v4l2_ctrl_handler *hdl,
|
|
struct v4l2_ctrl *v4l2_ctrl_new_std(struct v4l2_ctrl_handler *hdl,
|
|
const struct v4l2_ctrl_ops *ops,
|
|
const struct v4l2_ctrl_ops *ops,
|
|
u32 id, s32 min, s32 max, u32 step, s32 def);
|
|
u32 id, s32 min, s32 max, u32 step, s32 def);
|
|
|
|
|
|
Menu and integer menu controls are added by calling v4l2_ctrl_new_std_menu:
|
|
Menu and integer menu controls are added by calling v4l2_ctrl_new_std_menu:
|
|
|
|
|
|
|
|
+.. code-block:: none
|
|
|
|
+
|
|
struct v4l2_ctrl *v4l2_ctrl_new_std_menu(struct v4l2_ctrl_handler *hdl,
|
|
struct v4l2_ctrl *v4l2_ctrl_new_std_menu(struct v4l2_ctrl_handler *hdl,
|
|
const struct v4l2_ctrl_ops *ops,
|
|
const struct v4l2_ctrl_ops *ops,
|
|
u32 id, s32 max, s32 skip_mask, s32 def);
|
|
u32 id, s32 max, s32 skip_mask, s32 def);
|
|
@@ -118,6 +135,8 @@ Menu and integer menu controls are added by calling v4l2_ctrl_new_std_menu:
|
|
Menu controls with a driver specific menu are added by calling
|
|
Menu controls with a driver specific menu are added by calling
|
|
v4l2_ctrl_new_std_menu_items:
|
|
v4l2_ctrl_new_std_menu_items:
|
|
|
|
|
|
|
|
+.. code-block:: none
|
|
|
|
+
|
|
struct v4l2_ctrl *v4l2_ctrl_new_std_menu_items(
|
|
struct v4l2_ctrl *v4l2_ctrl_new_std_menu_items(
|
|
struct v4l2_ctrl_handler *hdl,
|
|
struct v4l2_ctrl_handler *hdl,
|
|
const struct v4l2_ctrl_ops *ops, u32 id, s32 max,
|
|
const struct v4l2_ctrl_ops *ops, u32 id, s32 max,
|
|
@@ -126,12 +145,16 @@ v4l2_ctrl_new_std_menu_items:
|
|
Integer menu controls with a driver specific menu can be added by calling
|
|
Integer menu controls with a driver specific menu can be added by calling
|
|
v4l2_ctrl_new_int_menu:
|
|
v4l2_ctrl_new_int_menu:
|
|
|
|
|
|
|
|
+.. code-block:: none
|
|
|
|
+
|
|
struct v4l2_ctrl *v4l2_ctrl_new_int_menu(struct v4l2_ctrl_handler *hdl,
|
|
struct v4l2_ctrl *v4l2_ctrl_new_int_menu(struct v4l2_ctrl_handler *hdl,
|
|
const struct v4l2_ctrl_ops *ops,
|
|
const struct v4l2_ctrl_ops *ops,
|
|
u32 id, s32 max, s32 def, const s64 *qmenu_int);
|
|
u32 id, s32 max, s32 def, const s64 *qmenu_int);
|
|
|
|
|
|
These functions are typically called right after the v4l2_ctrl_handler_init:
|
|
These functions are typically called right after the v4l2_ctrl_handler_init:
|
|
|
|
|
|
|
|
+.. code-block:: none
|
|
|
|
+
|
|
static const s64 exp_bias_qmenu[] = {
|
|
static const s64 exp_bias_qmenu[] = {
|
|
-2, -1, 0, 1, 2
|
|
-2, -1, 0, 1, 2
|
|
};
|
|
};
|
|
@@ -208,6 +231,8 @@ a bit faster that way.
|
|
|
|
|
|
3) Optionally force initial control setup:
|
|
3) Optionally force initial control setup:
|
|
|
|
|
|
|
|
+.. code-block:: none
|
|
|
|
+
|
|
v4l2_ctrl_handler_setup(&foo->ctrl_handler);
|
|
v4l2_ctrl_handler_setup(&foo->ctrl_handler);
|
|
|
|
|
|
This will call s_ctrl for all controls unconditionally. Effectively this
|
|
This will call s_ctrl for all controls unconditionally. Effectively this
|
|
@@ -217,12 +242,16 @@ the hardware are in sync.
|
|
|
|
|
|
4) Finally: implement the v4l2_ctrl_ops
|
|
4) Finally: implement the v4l2_ctrl_ops
|
|
|
|
|
|
|
|
+.. code-block:: none
|
|
|
|
+
|
|
static const struct v4l2_ctrl_ops foo_ctrl_ops = {
|
|
static const struct v4l2_ctrl_ops foo_ctrl_ops = {
|
|
.s_ctrl = foo_s_ctrl,
|
|
.s_ctrl = foo_s_ctrl,
|
|
};
|
|
};
|
|
|
|
|
|
Usually all you need is s_ctrl:
|
|
Usually all you need is s_ctrl:
|
|
|
|
|
|
|
|
+.. code-block:: none
|
|
|
|
+
|
|
static int foo_s_ctrl(struct v4l2_ctrl *ctrl)
|
|
static int foo_s_ctrl(struct v4l2_ctrl *ctrl)
|
|
{
|
|
{
|
|
struct foo *state = container_of(ctrl->handler, struct foo, ctrl_handler);
|
|
struct foo *state = container_of(ctrl->handler, struct foo, ctrl_handler);
|
|
@@ -247,16 +276,14 @@ to do any validation of control values, or implement QUERYCTRL, QUERY_EXT_CTRL
|
|
and QUERYMENU. And G/S_CTRL as well as G/TRY/S_EXT_CTRLS are automatically supported.
|
|
and QUERYMENU. And G/S_CTRL as well as G/TRY/S_EXT_CTRLS are automatically supported.
|
|
|
|
|
|
|
|
|
|
-==============================================================================
|
|
|
|
-
|
|
|
|
-The remainder of this document deals with more advanced topics and scenarios.
|
|
|
|
-In practice the basic usage as described above is sufficient for most drivers.
|
|
|
|
|
|
+.. note::
|
|
|
|
|
|
-===============================================================================
|
|
|
|
|
|
+ The remainder sections deal with more advanced controls topics and scenarios.
|
|
|
|
+ In practice the basic usage as described above is sufficient for most drivers.
|
|
|
|
|
|
|
|
|
|
Inheriting Controls
|
|
Inheriting Controls
|
|
-===================
|
|
|
|
|
|
+-------------------
|
|
|
|
|
|
When a sub-device is registered with a V4L2 driver by calling
|
|
When a sub-device is registered with a V4L2 driver by calling
|
|
v4l2_device_register_subdev() and the ctrl_handler fields of both v4l2_subdev
|
|
v4l2_device_register_subdev() and the ctrl_handler fields of both v4l2_subdev
|
|
@@ -271,21 +298,25 @@ of v4l2_device.
|
|
|
|
|
|
|
|
|
|
Accessing Control Values
|
|
Accessing Control Values
|
|
-========================
|
|
|
|
|
|
+------------------------
|
|
|
|
|
|
The following union is used inside the control framework to access control
|
|
The following union is used inside the control framework to access control
|
|
values:
|
|
values:
|
|
|
|
|
|
-union v4l2_ctrl_ptr {
|
|
|
|
- s32 *p_s32;
|
|
|
|
- s64 *p_s64;
|
|
|
|
- char *p_char;
|
|
|
|
- void *p;
|
|
|
|
-};
|
|
|
|
|
|
+.. code-block:: none
|
|
|
|
+
|
|
|
|
+ union v4l2_ctrl_ptr {
|
|
|
|
+ s32 *p_s32;
|
|
|
|
+ s64 *p_s64;
|
|
|
|
+ char *p_char;
|
|
|
|
+ void *p;
|
|
|
|
+ };
|
|
|
|
|
|
The v4l2_ctrl struct contains these fields that can be used to access both
|
|
The v4l2_ctrl struct contains these fields that can be used to access both
|
|
current and new values:
|
|
current and new values:
|
|
|
|
|
|
|
|
+.. code-block:: none
|
|
|
|
+
|
|
s32 val;
|
|
s32 val;
|
|
struct {
|
|
struct {
|
|
s32 val;
|
|
s32 val;
|
|
@@ -297,6 +328,8 @@ current and new values:
|
|
|
|
|
|
If the control has a simple s32 type type, then:
|
|
If the control has a simple s32 type type, then:
|
|
|
|
|
|
|
|
+.. code-block:: none
|
|
|
|
+
|
|
&ctrl->val == ctrl->p_new.p_s32
|
|
&ctrl->val == ctrl->p_new.p_s32
|
|
&ctrl->cur.val == ctrl->p_cur.p_s32
|
|
&ctrl->cur.val == ctrl->p_cur.p_s32
|
|
|
|
|
|
@@ -319,6 +352,8 @@ exception is for controls that return a volatile register such as a signal
|
|
strength read-out that changes continuously. In that case you will need to
|
|
strength read-out that changes continuously. In that case you will need to
|
|
implement g_volatile_ctrl like this:
|
|
implement g_volatile_ctrl like this:
|
|
|
|
|
|
|
|
+.. code-block:: none
|
|
|
|
+
|
|
static int foo_g_volatile_ctrl(struct v4l2_ctrl *ctrl)
|
|
static int foo_g_volatile_ctrl(struct v4l2_ctrl *ctrl)
|
|
{
|
|
{
|
|
switch (ctrl->id) {
|
|
switch (ctrl->id) {
|
|
@@ -335,6 +370,8 @@ changes.
|
|
|
|
|
|
To mark a control as volatile you have to set V4L2_CTRL_FLAG_VOLATILE:
|
|
To mark a control as volatile you have to set V4L2_CTRL_FLAG_VOLATILE:
|
|
|
|
|
|
|
|
+.. code-block:: none
|
|
|
|
+
|
|
ctrl = v4l2_ctrl_new_std(&sd->ctrl_handler, ...);
|
|
ctrl = v4l2_ctrl_new_std(&sd->ctrl_handler, ...);
|
|
if (ctrl)
|
|
if (ctrl)
|
|
ctrl->flags |= V4L2_CTRL_FLAG_VOLATILE;
|
|
ctrl->flags |= V4L2_CTRL_FLAG_VOLATILE;
|
|
@@ -354,6 +391,8 @@ not to introduce deadlocks.
|
|
Outside of the control ops you have to go through to helper functions to get
|
|
Outside of the control ops you have to go through to helper functions to get
|
|
or set a single control value safely in your driver:
|
|
or set a single control value safely in your driver:
|
|
|
|
|
|
|
|
+.. code-block:: none
|
|
|
|
+
|
|
s32 v4l2_ctrl_g_ctrl(struct v4l2_ctrl *ctrl);
|
|
s32 v4l2_ctrl_g_ctrl(struct v4l2_ctrl *ctrl);
|
|
int v4l2_ctrl_s_ctrl(struct v4l2_ctrl *ctrl, s32 val);
|
|
int v4l2_ctrl_s_ctrl(struct v4l2_ctrl *ctrl, s32 val);
|
|
|
|
|
|
@@ -363,6 +402,8 @@ will result in a deadlock since these helpers lock the handler as well.
|
|
|
|
|
|
You can also take the handler lock yourself:
|
|
You can also take the handler lock yourself:
|
|
|
|
|
|
|
|
+.. code-block:: none
|
|
|
|
+
|
|
mutex_lock(&state->ctrl_handler.lock);
|
|
mutex_lock(&state->ctrl_handler.lock);
|
|
pr_info("String value is '%s'\n", ctrl1->p_cur.p_char);
|
|
pr_info("String value is '%s'\n", ctrl1->p_cur.p_char);
|
|
pr_info("Integer value is '%s'\n", ctrl2->cur.val);
|
|
pr_info("Integer value is '%s'\n", ctrl2->cur.val);
|
|
@@ -370,10 +411,12 @@ You can also take the handler lock yourself:
|
|
|
|
|
|
|
|
|
|
Menu Controls
|
|
Menu Controls
|
|
-=============
|
|
|
|
|
|
+-------------
|
|
|
|
|
|
The v4l2_ctrl struct contains this union:
|
|
The v4l2_ctrl struct contains this union:
|
|
|
|
|
|
|
|
+.. code-block:: none
|
|
|
|
+
|
|
union {
|
|
union {
|
|
u32 step;
|
|
u32 step;
|
|
u32 menu_skip_mask;
|
|
u32 menu_skip_mask;
|
|
@@ -396,10 +439,12 @@ control, or by calling v4l2_ctrl_new_std_menu().
|
|
|
|
|
|
|
|
|
|
Custom Controls
|
|
Custom Controls
|
|
-===============
|
|
|
|
|
|
+---------------
|
|
|
|
|
|
Driver specific controls can be created using v4l2_ctrl_new_custom():
|
|
Driver specific controls can be created using v4l2_ctrl_new_custom():
|
|
|
|
|
|
|
|
+.. code-block:: none
|
|
|
|
+
|
|
static const struct v4l2_ctrl_config ctrl_filter = {
|
|
static const struct v4l2_ctrl_config ctrl_filter = {
|
|
.ops = &ctrl_custom_ops,
|
|
.ops = &ctrl_custom_ops,
|
|
.id = V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER,
|
|
.id = V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER,
|
|
@@ -422,7 +467,7 @@ control and will fill in the name, type and flags fields accordingly.
|
|
|
|
|
|
|
|
|
|
Active and Grabbed Controls
|
|
Active and Grabbed Controls
|
|
-===========================
|
|
|
|
|
|
+---------------------------
|
|
|
|
|
|
If you get more complex relationships between controls, then you may have to
|
|
If you get more complex relationships between controls, then you may have to
|
|
activate and deactivate controls. For example, if the Chroma AGC control is
|
|
activate and deactivate controls. For example, if the Chroma AGC control is
|
|
@@ -446,16 +491,18 @@ starts or stops streaming.
|
|
|
|
|
|
|
|
|
|
Control Clusters
|
|
Control Clusters
|
|
-================
|
|
|
|
|
|
+----------------
|
|
|
|
|
|
By default all controls are independent from the others. But in more
|
|
By default all controls are independent from the others. But in more
|
|
complex scenarios you can get dependencies from one control to another.
|
|
complex scenarios you can get dependencies from one control to another.
|
|
In that case you need to 'cluster' them:
|
|
In that case you need to 'cluster' them:
|
|
|
|
|
|
|
|
+.. code-block:: none
|
|
|
|
+
|
|
struct foo {
|
|
struct foo {
|
|
struct v4l2_ctrl_handler ctrl_handler;
|
|
struct v4l2_ctrl_handler ctrl_handler;
|
|
-#define AUDIO_CL_VOLUME (0)
|
|
|
|
-#define AUDIO_CL_MUTE (1)
|
|
|
|
|
|
+ #define AUDIO_CL_VOLUME (0)
|
|
|
|
+ #define AUDIO_CL_MUTE (1)
|
|
struct v4l2_ctrl *audio_cluster[2];
|
|
struct v4l2_ctrl *audio_cluster[2];
|
|
...
|
|
...
|
|
};
|
|
};
|
|
@@ -474,6 +521,8 @@ composite control. Similar to how a 'struct' works in C.
|
|
So when s_ctrl is called with V4L2_CID_AUDIO_VOLUME as argument, you should set
|
|
So when s_ctrl is called with V4L2_CID_AUDIO_VOLUME as argument, you should set
|
|
all two controls belonging to the audio_cluster:
|
|
all two controls belonging to the audio_cluster:
|
|
|
|
|
|
|
|
+.. code-block:: none
|
|
|
|
+
|
|
static int foo_s_ctrl(struct v4l2_ctrl *ctrl)
|
|
static int foo_s_ctrl(struct v4l2_ctrl *ctrl)
|
|
{
|
|
{
|
|
struct foo *state = container_of(ctrl->handler, struct foo, ctrl_handler);
|
|
struct foo *state = container_of(ctrl->handler, struct foo, ctrl_handler);
|
|
@@ -494,12 +543,16 @@ all two controls belonging to the audio_cluster:
|
|
|
|
|
|
In the example above the following are equivalent for the VOLUME case:
|
|
In the example above the following are equivalent for the VOLUME case:
|
|
|
|
|
|
|
|
+.. code-block:: none
|
|
|
|
+
|
|
ctrl == ctrl->cluster[AUDIO_CL_VOLUME] == state->audio_cluster[AUDIO_CL_VOLUME]
|
|
ctrl == ctrl->cluster[AUDIO_CL_VOLUME] == state->audio_cluster[AUDIO_CL_VOLUME]
|
|
ctrl->cluster[AUDIO_CL_MUTE] == state->audio_cluster[AUDIO_CL_MUTE]
|
|
ctrl->cluster[AUDIO_CL_MUTE] == state->audio_cluster[AUDIO_CL_MUTE]
|
|
|
|
|
|
In practice using cluster arrays like this becomes very tiresome. So instead
|
|
In practice using cluster arrays like this becomes very tiresome. So instead
|
|
the following equivalent method is used:
|
|
the following equivalent method is used:
|
|
|
|
|
|
|
|
+.. code-block:: none
|
|
|
|
+
|
|
struct {
|
|
struct {
|
|
/* audio cluster */
|
|
/* audio cluster */
|
|
struct v4l2_ctrl *volume;
|
|
struct v4l2_ctrl *volume;
|
|
@@ -510,6 +563,8 @@ The anonymous struct is used to clearly 'cluster' these two control pointers,
|
|
but it serves no other purpose. The effect is the same as creating an
|
|
but it serves no other purpose. The effect is the same as creating an
|
|
array with two control pointers. So you can just do:
|
|
array with two control pointers. So you can just do:
|
|
|
|
|
|
|
|
+.. code-block:: none
|
|
|
|
+
|
|
state->volume = v4l2_ctrl_new_std(&state->ctrl_handler, ...);
|
|
state->volume = v4l2_ctrl_new_std(&state->ctrl_handler, ...);
|
|
state->mute = v4l2_ctrl_new_std(&state->ctrl_handler, ...);
|
|
state->mute = v4l2_ctrl_new_std(&state->ctrl_handler, ...);
|
|
v4l2_ctrl_cluster(2, &state->volume);
|
|
v4l2_ctrl_cluster(2, &state->volume);
|
|
@@ -539,7 +594,7 @@ The 'is_new' flag is always 1 when called from v4l2_ctrl_handler_setup().
|
|
|
|
|
|
|
|
|
|
Handling autogain/gain-type Controls with Auto Clusters
|
|
Handling autogain/gain-type Controls with Auto Clusters
|
|
-=======================================================
|
|
|
|
|
|
+-------------------------------------------------------
|
|
|
|
|
|
A common type of control cluster is one that handles 'auto-foo/foo'-type
|
|
A common type of control cluster is one that handles 'auto-foo/foo'-type
|
|
controls. Typical examples are autogain/gain, autoexposure/exposure,
|
|
controls. Typical examples are autogain/gain, autoexposure/exposure,
|
|
@@ -564,8 +619,10 @@ changing that control affects the control flags of the manual controls.
|
|
In order to simplify this a special variation of v4l2_ctrl_cluster was
|
|
In order to simplify this a special variation of v4l2_ctrl_cluster was
|
|
introduced:
|
|
introduced:
|
|
|
|
|
|
-void v4l2_ctrl_auto_cluster(unsigned ncontrols, struct v4l2_ctrl **controls,
|
|
|
|
- u8 manual_val, bool set_volatile);
|
|
|
|
|
|
+.. code-block:: none
|
|
|
|
+
|
|
|
|
+ void v4l2_ctrl_auto_cluster(unsigned ncontrols, struct v4l2_ctrl **controls,
|
|
|
|
+ u8 manual_val, bool set_volatile);
|
|
|
|
|
|
The first two arguments are identical to v4l2_ctrl_cluster. The third argument
|
|
The first two arguments are identical to v4l2_ctrl_cluster. The third argument
|
|
tells the framework which value switches the cluster into manual mode. The
|
|
tells the framework which value switches the cluster into manual mode. The
|
|
@@ -582,7 +639,7 @@ flag and volatile handling.
|
|
|
|
|
|
|
|
|
|
VIDIOC_LOG_STATUS Support
|
|
VIDIOC_LOG_STATUS Support
|
|
-=========================
|
|
|
|
|
|
+-------------------------
|
|
|
|
|
|
This ioctl allow you to dump the current status of a driver to the kernel log.
|
|
This ioctl allow you to dump the current status of a driver to the kernel log.
|
|
The v4l2_ctrl_handler_log_status(ctrl_handler, prefix) can be used to dump the
|
|
The v4l2_ctrl_handler_log_status(ctrl_handler, prefix) can be used to dump the
|
|
@@ -592,7 +649,7 @@ for you.
|
|
|
|
|
|
|
|
|
|
Different Handlers for Different Video Nodes
|
|
Different Handlers for Different Video Nodes
|
|
-============================================
|
|
|
|
|
|
+--------------------------------------------
|
|
|
|
|
|
Usually the V4L2 driver has just one control handler that is global for
|
|
Usually the V4L2 driver has just one control handler that is global for
|
|
all video nodes. But you can also specify different control handlers for
|
|
all video nodes. But you can also specify different control handlers for
|
|
@@ -617,6 +674,8 @@ of another handler (e.g. for a video device node), then you should first add
|
|
the controls to the first handler, add the other controls to the second
|
|
the controls to the first handler, add the other controls to the second
|
|
handler and finally add the first handler to the second. For example:
|
|
handler and finally add the first handler to the second. For example:
|
|
|
|
|
|
|
|
+.. code-block:: none
|
|
|
|
+
|
|
v4l2_ctrl_new_std(&radio_ctrl_handler, &radio_ops, V4L2_CID_AUDIO_VOLUME, ...);
|
|
v4l2_ctrl_new_std(&radio_ctrl_handler, &radio_ops, V4L2_CID_AUDIO_VOLUME, ...);
|
|
v4l2_ctrl_new_std(&radio_ctrl_handler, &radio_ops, V4L2_CID_AUDIO_MUTE, ...);
|
|
v4l2_ctrl_new_std(&radio_ctrl_handler, &radio_ops, V4L2_CID_AUDIO_MUTE, ...);
|
|
v4l2_ctrl_new_std(&video_ctrl_handler, &video_ops, V4L2_CID_BRIGHTNESS, ...);
|
|
v4l2_ctrl_new_std(&video_ctrl_handler, &video_ops, V4L2_CID_BRIGHTNESS, ...);
|
|
@@ -629,6 +688,8 @@ all controls.
|
|
|
|
|
|
Or you can add specific controls to a handler:
|
|
Or you can add specific controls to a handler:
|
|
|
|
|
|
|
|
+.. code-block:: none
|
|
|
|
+
|
|
volume = v4l2_ctrl_new_std(&video_ctrl_handler, &ops, V4L2_CID_AUDIO_VOLUME, ...);
|
|
volume = v4l2_ctrl_new_std(&video_ctrl_handler, &ops, V4L2_CID_AUDIO_VOLUME, ...);
|
|
v4l2_ctrl_new_std(&video_ctrl_handler, &ops, V4L2_CID_BRIGHTNESS, ...);
|
|
v4l2_ctrl_new_std(&video_ctrl_handler, &ops, V4L2_CID_BRIGHTNESS, ...);
|
|
v4l2_ctrl_new_std(&video_ctrl_handler, &ops, V4L2_CID_CONTRAST, ...);
|
|
v4l2_ctrl_new_std(&video_ctrl_handler, &ops, V4L2_CID_CONTRAST, ...);
|
|
@@ -636,6 +697,8 @@ Or you can add specific controls to a handler:
|
|
What you should not do is make two identical controls for two handlers.
|
|
What you should not do is make two identical controls for two handlers.
|
|
For example:
|
|
For example:
|
|
|
|
|
|
|
|
+.. code-block:: none
|
|
|
|
+
|
|
v4l2_ctrl_new_std(&radio_ctrl_handler, &radio_ops, V4L2_CID_AUDIO_MUTE, ...);
|
|
v4l2_ctrl_new_std(&radio_ctrl_handler, &radio_ops, V4L2_CID_AUDIO_MUTE, ...);
|
|
v4l2_ctrl_new_std(&video_ctrl_handler, &video_ops, V4L2_CID_AUDIO_MUTE, ...);
|
|
v4l2_ctrl_new_std(&video_ctrl_handler, &video_ops, V4L2_CID_AUDIO_MUTE, ...);
|
|
|
|
|
|
@@ -645,7 +708,7 @@ can twiddle.
|
|
|
|
|
|
|
|
|
|
Finding Controls
|
|
Finding Controls
|
|
-================
|
|
|
|
|
|
+----------------
|
|
|
|
|
|
Normally you have created the controls yourself and you can store the struct
|
|
Normally you have created the controls yourself and you can store the struct
|
|
v4l2_ctrl pointer into your own struct.
|
|
v4l2_ctrl pointer into your own struct.
|
|
@@ -655,6 +718,8 @@ not own. For example, if you have to find a volume control from a subdev.
|
|
|
|
|
|
You can do that by calling v4l2_ctrl_find:
|
|
You can do that by calling v4l2_ctrl_find:
|
|
|
|
|
|
|
|
+.. code-block:: none
|
|
|
|
+
|
|
struct v4l2_ctrl *volume;
|
|
struct v4l2_ctrl *volume;
|
|
|
|
|
|
volume = v4l2_ctrl_find(sd->ctrl_handler, V4L2_CID_AUDIO_VOLUME);
|
|
volume = v4l2_ctrl_find(sd->ctrl_handler, V4L2_CID_AUDIO_VOLUME);
|
|
@@ -662,6 +727,8 @@ You can do that by calling v4l2_ctrl_find:
|
|
Since v4l2_ctrl_find will lock the handler you have to be careful where you
|
|
Since v4l2_ctrl_find will lock the handler you have to be careful where you
|
|
use it. For example, this is not a good idea:
|
|
use it. For example, this is not a good idea:
|
|
|
|
|
|
|
|
+.. code-block:: none
|
|
|
|
+
|
|
struct v4l2_ctrl_handler ctrl_handler;
|
|
struct v4l2_ctrl_handler ctrl_handler;
|
|
|
|
|
|
v4l2_ctrl_new_std(&ctrl_handler, &video_ops, V4L2_CID_BRIGHTNESS, ...);
|
|
v4l2_ctrl_new_std(&ctrl_handler, &video_ops, V4L2_CID_BRIGHTNESS, ...);
|
|
@@ -669,6 +736,8 @@ use it. For example, this is not a good idea:
|
|
|
|
|
|
...and in video_ops.s_ctrl:
|
|
...and in video_ops.s_ctrl:
|
|
|
|
|
|
|
|
+.. code-block:: none
|
|
|
|
+
|
|
case V4L2_CID_BRIGHTNESS:
|
|
case V4L2_CID_BRIGHTNESS:
|
|
contrast = v4l2_find_ctrl(&ctrl_handler, V4L2_CID_CONTRAST);
|
|
contrast = v4l2_find_ctrl(&ctrl_handler, V4L2_CID_CONTRAST);
|
|
...
|
|
...
|
|
@@ -680,7 +749,7 @@ It is recommended not to use this function from inside the control ops.
|
|
|
|
|
|
|
|
|
|
Inheriting Controls
|
|
Inheriting Controls
|
|
-===================
|
|
|
|
|
|
+-------------------
|
|
|
|
|
|
When one control handler is added to another using v4l2_ctrl_add_handler, then
|
|
When one control handler is added to another using v4l2_ctrl_add_handler, then
|
|
by default all controls from one are merged to the other. But a subdev might
|
|
by default all controls from one are merged to the other. But a subdev might
|
|
@@ -689,6 +758,8 @@ not when it is used in consumer-level hardware. In that case you want to keep
|
|
those low-level controls local to the subdev. You can do this by simply
|
|
those low-level controls local to the subdev. You can do this by simply
|
|
setting the 'is_private' flag of the control to 1:
|
|
setting the 'is_private' flag of the control to 1:
|
|
|
|
|
|
|
|
+.. code-block:: none
|
|
|
|
+
|
|
static const struct v4l2_ctrl_config ctrl_private = {
|
|
static const struct v4l2_ctrl_config ctrl_private = {
|
|
.ops = &ctrl_custom_ops,
|
|
.ops = &ctrl_custom_ops,
|
|
.id = V4L2_CID_...,
|
|
.id = V4L2_CID_...,
|
|
@@ -705,7 +776,7 @@ These controls will now be skipped when v4l2_ctrl_add_handler is called.
|
|
|
|
|
|
|
|
|
|
V4L2_CTRL_TYPE_CTRL_CLASS Controls
|
|
V4L2_CTRL_TYPE_CTRL_CLASS Controls
|
|
-==================================
|
|
|
|
|
|
+----------------------------------
|
|
|
|
|
|
Controls of this type can be used by GUIs to get the name of the control class.
|
|
Controls of this type can be used by GUIs to get the name of the control class.
|
|
A fully featured GUI can make a dialog with multiple tabs with each tab
|
|
A fully featured GUI can make a dialog with multiple tabs with each tab
|
|
@@ -718,14 +789,16 @@ class is added.
|
|
|
|
|
|
|
|
|
|
Adding Notify Callbacks
|
|
Adding Notify Callbacks
|
|
-=======================
|
|
|
|
|
|
+-----------------------
|
|
|
|
|
|
Sometimes the platform or bridge driver needs to be notified when a control
|
|
Sometimes the platform or bridge driver needs to be notified when a control
|
|
from a sub-device driver changes. You can set a notify callback by calling
|
|
from a sub-device driver changes. You can set a notify callback by calling
|
|
this function:
|
|
this function:
|
|
|
|
|
|
-void v4l2_ctrl_notify(struct v4l2_ctrl *ctrl,
|
|
|
|
- void (*notify)(struct v4l2_ctrl *ctrl, void *priv), void *priv);
|
|
|
|
|
|
+.. code-block:: none
|
|
|
|
+
|
|
|
|
+ void v4l2_ctrl_notify(struct v4l2_ctrl *ctrl,
|
|
|
|
+ void (*notify)(struct v4l2_ctrl *ctrl, void *priv), void *priv);
|
|
|
|
|
|
Whenever the give control changes value the notify callback will be called
|
|
Whenever the give control changes value the notify callback will be called
|
|
with a pointer to the control and the priv pointer that was passed with
|
|
with a pointer to the control and the priv pointer that was passed with
|
|
@@ -734,3 +807,8 @@ notify function is called.
|
|
|
|
|
|
There can be only one notify function per control handler. Any attempt
|
|
There can be only one notify function per control handler. Any attempt
|
|
to set another notify function will cause a WARN_ON.
|
|
to set another notify function will cause a WARN_ON.
|
|
|
|
+
|
|
|
|
+v4l2_ctrl functions and data structures
|
|
|
|
+---------------------------------------
|
|
|
|
+
|
|
|
|
+.. kernel-doc:: include/media/v4l2-ctrls.h
|