요약·해설과 원문, 전문 번역을 서로 분리했습니다. API 이름, symbol, source path는 원문 표기를 사용합니다.
1. 요약·해설
원문의 핵심 논리와 kernel programming 관점의 보충 설명입니다. 아래의 전문 번역과는 별도로 작성했습니다.
2. 영어 원문 전체
번역 기준이 된 Linux v6.18.37 원문입니다. 줄 번호는 이 버전의 파일 좌표입니다.
원문 전체 펼치기
.. SPDX-License-Identifier: GPL-2.0
V4L2 Controls
=============
Introduction
------------
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
is actually not driver specific and can be moved to the V4L core framework.
After all, the only part that a driver developer is interested in is:
1) How do I add a control?
2) How do I set the control's value? (i.e. s_ctrl)
And occasionally:
3) How do I get the control's value? (i.e. g_volatile_ctrl)
4) How do I validate the user's proposed control value? (i.e. try_ctrl)
All the rest is something that can be done centrally.
The control framework was created in order to implement all the rules of the
V4L2 specification with respect to controls in a central place. And to make
life as easy as possible for the driver developer.
Note that the control framework relies on the presence of a struct
:c:type:`v4l2_device` for V4L2 drivers and struct v4l2_subdev for
sub-device drivers.
Objects in the framework
------------------------
There are two main objects:
The :c:type:`v4l2_ctrl` object describes the control properties and keeps
track of the control's value (both the current value and the proposed new
value).
:c:type:`v4l2_ctrl_handler` is the object that keeps track of controls. It
maintains a list of v4l2_ctrl objects that it owns and another list of
references to controls, possibly to controls owned by other handlers.
Basic usage for V4L2 and sub-device drivers
-------------------------------------------
1) Prepare the driver:
.. code-block:: c
#include <media/v4l2-ctrls.h>
1.1) Add the handler to your driver's top-level struct:
For V4L2 drivers:
.. code-block:: c
struct foo_dev {
...
struct v4l2_device v4l2_dev;
...
struct v4l2_ctrl_handler ctrl_handler;
...
};
For sub-device drivers:
.. code-block:: c
struct foo_dev {
...
struct v4l2_subdev sd;
...
struct v4l2_ctrl_handler ctrl_handler;
...
};
1.2) Initialize the handler:
.. code-block:: c
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.
1.3) Hook the control handler into the driver:
For V4L2 drivers:
.. code-block:: c
foo->v4l2_dev.ctrl_handler = &foo->ctrl_handler;
For sub-device drivers:
.. code-block:: c
foo->sd.ctrl_handler = &foo->ctrl_handler;
1.4) Clean up the handler at the end:
.. code-block:: c
v4l2_ctrl_handler_free(&foo->ctrl_handler);
:c:func:`v4l2_ctrl_handler_free` does not touch the handler's ``error`` field.
2) Add controls:
You add non-menu controls by calling :c:func:`v4l2_ctrl_new_std`:
.. code-block:: c
struct 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);
Menu and integer menu controls are added by calling
:c:func:`v4l2_ctrl_new_std_menu`:
.. code-block:: c
struct 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);
Menu controls with a driver specific menu are added by calling
:c:func:`v4l2_ctrl_new_std_menu_items`:
.. code-block:: c
struct 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);
Standard compound controls can be added by calling
:c:func:`v4l2_ctrl_new_std_compound`:
.. code-block:: c
struct v4l2_ctrl *v4l2_ctrl_new_std_compound(struct v4l2_ctrl_handler *hdl,
const struct v4l2_ctrl_ops *ops, u32 id,
const union v4l2_ctrl_ptr p_def);
Integer menu controls with a driver specific menu can be added by calling
:c:func:`v4l2_ctrl_new_int_menu`:
.. code-block:: c
struct 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);
These functions are typically called right after the
:c:func:`v4l2_ctrl_handler_init`:
.. code-block:: c
static const s64 exp_bias_qmenu[] = {
-2, -1, 0, 1, 2
};
static const char * const test_pattern[] = {
"Disabled",
"Vertical Bars",
"Solid Black",
"Solid White",
};
v4l2_ctrl_handler_init(&foo->ctrl_handler, nr_of_controls);
v4l2_ctrl_new_std(&foo->ctrl_handler, &foo_ctrl_ops,
V4L2_CID_BRIGHTNESS, 0, 255, 1, 128);
v4l2_ctrl_new_std(&foo->ctrl_handler, &foo_ctrl_ops,
V4L2_CID_CONTRAST, 0, 255, 1, 128);
v4l2_ctrl_new_std_menu(&foo->ctrl_handler, &foo_ctrl_ops,
V4L2_CID_POWER_LINE_FREQUENCY,
V4L2_CID_POWER_LINE_FREQUENCY_60HZ, 0,
V4L2_CID_POWER_LINE_FREQUENCY_DISABLED);
v4l2_ctrl_new_int_menu(&foo->ctrl_handler, &foo_ctrl_ops,
V4L2_CID_EXPOSURE_BIAS,
ARRAY_SIZE(exp_bias_qmenu) - 1,
ARRAY_SIZE(exp_bias_qmenu) / 2 - 1,
exp_bias_qmenu);
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);
...
if (foo->ctrl_handler.error)
return v4l2_ctrl_handler_free(&foo->ctrl_handler);
The :c:func:`v4l2_ctrl_new_std` function returns the v4l2_ctrl pointer to
the new control, but if you do not need to access the pointer outside the
control ops, then there is no need to store it.
The :c:func:`v4l2_ctrl_new_std` function will fill in most fields based on
the control ID except for the min, max, step and default values. These are
passed in the last four arguments. These values are driver specific while
control attributes like type, name, flags are all global. The control's
current value will be set to the default value.
The :c:func:`v4l2_ctrl_new_std_menu` function is very similar but it is
used for menu controls. There is no min argument since that is always 0 for
menu controls, and instead of a step there is a skip_mask argument: if bit
X is 1, then menu item X is skipped.
The :c:func:`v4l2_ctrl_new_int_menu` function creates a new standard
integer menu control with driver-specific items in the menu. It differs
from v4l2_ctrl_new_std_menu in that it doesn't have the mask argument and
takes as the last argument an array of signed 64-bit integers that form an
exact menu item list.
The :c:func:`v4l2_ctrl_new_std_menu_items` function is very similar to
v4l2_ctrl_new_std_menu but takes an extra parameter qmenu, which is the
driver specific menu for an otherwise standard menu control. A good example
for this control is the test pattern control for capture/display/sensors
devices that have the capability to generate test patterns. These test
patterns are hardware specific, so the contents of the menu will vary from
device to device.
Note that if something fails, the function will return NULL or an error and
set ctrl_handler->error to the error code. If ctrl_handler->error was already
set, then it will just return and do nothing. This is also true for
v4l2_ctrl_handler_init if it cannot allocate the internal data structure.
This makes it easy to init the handler and just add all controls and only check
the error code at the end. Saves a lot of repetitive error checking.
It is recommended to add controls in ascending control ID order: it will be
a bit faster that way.
3) Optionally force initial control setup:
.. code-block:: c
v4l2_ctrl_handler_setup(&foo->ctrl_handler);
This will call s_ctrl for all controls unconditionally. Effectively this
initializes the hardware to the default control values. It is recommended
that you do this as this ensures that both the internal data structures and
the hardware are in sync.
4) Finally: implement the :c:type:`v4l2_ctrl_ops`
.. code-block:: c
static const struct v4l2_ctrl_ops foo_ctrl_ops = {
.s_ctrl = foo_s_ctrl,
};
Usually all you need is s_ctrl:
.. code-block:: c
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;
}
The control ops are called with the v4l2_ctrl pointer as argument.
The new control value has already been validated, so all you need to do is
to actually update the hardware registers.
You're done! And this is sufficient for most of the drivers we have. No need
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.
.. 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 Sub-device Controls
------------------------------
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
and v4l2_device are set, then the controls of the subdev will become
automatically available in the V4L2 driver as well. If the subdev driver
contains controls that already exist in the V4L2 driver, then those will be
skipped (so a V4L2 driver can always override a subdev control).
What happens here is that v4l2_device_register_subdev() calls
v4l2_ctrl_add_handler() adding the controls of the subdev to the controls
of v4l2_device.
Accessing Control Values
------------------------
The following union is used inside the control framework to access control
values:
.. code-block:: c
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
current and new values:
.. code-block:: c
s32 val;
struct {
s32 val;
} cur;
union v4l2_ctrl_ptr p_new;
union v4l2_ctrl_ptr p_cur;
If the control has a simple s32 type, then:
.. code-block:: c
&ctrl->val == ctrl->p_new.p_s32
&ctrl->cur.val == ctrl->p_cur.p_s32
For all other types use ctrl->p_cur.p<something>. Basically the val
and cur.val fields can be considered an alias since these are used so often.
Within the control ops you can freely use these. The val and cur.val speak for
themselves. The p_char pointers point to character buffers of length
ctrl->maximum + 1, and are always 0-terminated.
Unless the control is marked volatile the p_cur field points to the
current cached control value. When you create a new control this value is made
identical to the default value. After calling v4l2_ctrl_handler_setup() this
value is passed to the hardware. It is generally a good idea to call this
function.
Whenever a new value is set that new value is automatically cached. This means
that most drivers do not need to implement the g_volatile_ctrl() op. The
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
implement g_volatile_ctrl like this:
.. code-block:: c
static int foo_g_volatile_ctrl(struct v4l2_ctrl *ctrl)
{
switch (ctrl->id) {
case V4L2_CID_BRIGHTNESS:
ctrl->val = read_reg(0x123);
break;
}
}
Note that you use the 'new value' union as well in g_volatile_ctrl. In general
controls that need to implement g_volatile_ctrl are read-only controls. If they
are not, a V4L2_EVENT_CTRL_CH_VALUE will not be generated when the control
changes.
To mark a control as volatile you have to set V4L2_CTRL_FLAG_VOLATILE:
.. code-block:: c
ctrl = v4l2_ctrl_new_std(&sd->ctrl_handler, ...);
if (ctrl)
ctrl->flags |= V4L2_CTRL_FLAG_VOLATILE;
For try/s_ctrl the new values (i.e. as passed by the user) are filled in and
you can modify them in try_ctrl or set them in s_ctrl. The 'cur' union
contains the current value, which you can use (but not change!) as well.
If s_ctrl returns 0 (OK), then the control framework will copy the new final
values to the 'cur' union.
While in g_volatile/s/try_ctrl you can access the value of all controls owned
by the same handler since the handler's lock is held. If you need to access
the value of controls owned by other handlers, then you have to be very careful
not to introduce deadlocks.
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:
.. code-block:: c
s32 v4l2_ctrl_g_ctrl(struct v4l2_ctrl *ctrl);
int v4l2_ctrl_s_ctrl(struct v4l2_ctrl *ctrl, s32 val);
These functions go through the control framework just as VIDIOC_G/S_CTRL ioctls
do. Don't use these inside the control ops g_volatile/s/try_ctrl, though, that
will result in a deadlock since these helpers lock the handler as well.
You can also take the handler lock yourself:
.. code-block:: c
mutex_lock(&state->ctrl_handler.lock);
pr_info("String value is '%s'\n", ctrl1->p_cur.p_char);
pr_info("Integer value is '%s'\n", ctrl2->cur.val);
mutex_unlock(&state->ctrl_handler.lock);
Menu Controls
-------------
The v4l2_ctrl struct contains this union:
.. code-block:: c
union {
u32 step;
u32 menu_skip_mask;
};
For menu controls menu_skip_mask is used. What it does is that it allows you
to easily exclude certain menu items. This is used in the VIDIOC_QUERYMENU
implementation where you can return -EINVAL if a certain menu item is not
present. Note that VIDIOC_QUERYCTRL always returns a step value of 1 for
menu controls.
A good example is the MPEG Audio Layer II Bitrate menu control where the
menu is a list of standardized possible bitrates. But in practice hardware
implementations will only support a subset of those. By setting the skip
mask you can tell the framework which menu items should be skipped. Setting
it to 0 means that all menu items are supported.
You set this mask either through the v4l2_ctrl_config struct for a custom
control, or by calling v4l2_ctrl_new_std_menu().
Custom Controls
---------------
Driver specific controls can be created using v4l2_ctrl_new_custom():
.. code-block:: c
static const struct v4l2_ctrl_config ctrl_filter = {
.ops = &ctrl_custom_ops,
.id = V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER,
.name = "Spatial Filter",
.type = V4L2_CTRL_TYPE_INTEGER,
.flags = V4L2_CTRL_FLAG_SLIDER,
.max = 15,
.step = 1,
};
ctrl = v4l2_ctrl_new_custom(&foo->ctrl_handler, &ctrl_filter, NULL);
The last argument is the priv pointer which can be set to driver-specific
private data.
The v4l2_ctrl_config struct also has a field to set the is_private flag.
If the name field is not set, then the framework will assume this is a standard
control and will fill in the name, type and flags fields accordingly.
Active and Grabbed Controls
---------------------------
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
on, then the Chroma Gain control is inactive. That is, you may set it, but
the value will not be used by the hardware as long as the automatic gain
control is on. Typically user interfaces can disable such input fields.
You can set the 'active' status using v4l2_ctrl_activate(). By default all
controls are active. Note that the framework does not check for this flag.
It is meant purely for GUIs. The function is typically called from within
s_ctrl.
The other flag is the 'grabbed' flag. A grabbed control means that you cannot
change it because it is in use by some resource. Typical examples are MPEG
bitrate controls that cannot be changed while capturing is in progress.
If a control is set to 'grabbed' using v4l2_ctrl_grab(), then the framework
will return -EBUSY if an attempt is made to set this control. The
v4l2_ctrl_grab() function is typically called from the driver when it
starts or stops streaming.
Control Clusters
----------------
By default all controls are independent from the others. But in more
complex scenarios you can get dependencies from one control to another.
In that case you need to 'cluster' them:
.. code-block:: c
struct foo {
struct v4l2_ctrl_handler ctrl_handler;
#define AUDIO_CL_VOLUME (0)
#define AUDIO_CL_MUTE (1)
struct v4l2_ctrl *audio_cluster[2];
...
};
state->audio_cluster[AUDIO_CL_VOLUME] =
v4l2_ctrl_new_std(&state->ctrl_handler, ...);
state->audio_cluster[AUDIO_CL_MUTE] =
v4l2_ctrl_new_std(&state->ctrl_handler, ...);
v4l2_ctrl_cluster(ARRAY_SIZE(state->audio_cluster), state->audio_cluster);
From now on whenever one or more of the controls belonging to the same
cluster is set (or 'gotten', or 'tried'), only the control ops of the first
control ('volume' in this example) is called. You effectively create a new
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
all two controls belonging to the audio_cluster:
.. code-block:: c
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_AUDIO_VOLUME: {
struct v4l2_ctrl *mute = ctrl->cluster[AUDIO_CL_MUTE];
write_reg(0x123, mute->val ? 0 : ctrl->val);
break;
}
case V4L2_CID_CONTRAST:
write_reg(0x456, ctrl->val);
break;
}
return 0;
}
In the example above the following are equivalent for the VOLUME case:
.. code-block:: c
ctrl == ctrl->cluster[AUDIO_CL_VOLUME] == state->audio_cluster[AUDIO_CL_VOLUME]
ctrl->cluster[AUDIO_CL_MUTE] == state->audio_cluster[AUDIO_CL_MUTE]
In practice using cluster arrays like this becomes very tiresome. So instead
the following equivalent method is used:
.. code-block:: c
struct {
/* audio cluster */
struct v4l2_ctrl *volume;
struct v4l2_ctrl *mute;
};
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
array with two control pointers. So you can just do:
.. code-block:: c
state->volume = v4l2_ctrl_new_std(&state->ctrl_handler, ...);
state->mute = v4l2_ctrl_new_std(&state->ctrl_handler, ...);
v4l2_ctrl_cluster(2, &state->volume);
And in foo_s_ctrl you can use these pointers directly: state->mute->val.
Note that controls in a cluster may be NULL. For example, if for some
reason mute was never added (because the hardware doesn't support that
particular feature), then mute will be NULL. So in that case we have a
cluster of 2 controls, of which only 1 is actually instantiated. The
only restriction is that the first control of the cluster must always be
present, since that is the 'master' control of the cluster. The master
control is the one that identifies the cluster and that provides the
pointer to the v4l2_ctrl_ops struct that is used for that cluster.
Obviously, all controls in the cluster array must be initialized to either
a valid control or to NULL.
In rare cases you might want to know which controls of a cluster actually
were set explicitly by the user. For this you can check the 'is_new' flag of
each control. For example, in the case of a volume/mute cluster the 'is_new'
flag of the mute control would be set if the user called VIDIOC_S_CTRL for
mute only. If the user would call VIDIOC_S_EXT_CTRLS for both mute and volume
controls, then the 'is_new' flag would be 1 for both controls.
The 'is_new' flag is always 1 when called from v4l2_ctrl_handler_setup().
Handling autogain/gain-type Controls with Auto Clusters
-------------------------------------------------------
A common type of control cluster is one that handles 'auto-foo/foo'-type
controls. Typical examples are autogain/gain, autoexposure/exposure,
autowhitebalance/red balance/blue balance. In all cases you have one control
that determines whether another control is handled automatically by the hardware,
or whether it is under manual control from the user.
If the cluster is in automatic mode, then the manual controls should be
marked inactive and volatile. When the volatile controls are read the
g_volatile_ctrl operation should return the value that the hardware's automatic
mode set up automatically.
If the cluster is put in manual mode, then the manual controls should become
active again and the volatile flag is cleared (so g_volatile_ctrl is no longer
called while in manual mode). In addition just before switching to manual mode
the current values as determined by the auto mode are copied as the new manual
values.
Finally the V4L2_CTRL_FLAG_UPDATE should be set for the auto control since
changing that control affects the control flags of the manual controls.
In order to simplify this a special variation of v4l2_ctrl_cluster was
introduced:
.. code-block:: c
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
tells the framework which value switches the cluster into manual mode. The
last argument will optionally set V4L2_CTRL_FLAG_VOLATILE for the non-auto controls.
If it is false, then the manual controls are never volatile. You would typically
use that if the hardware does not give you the option to read back to values as
determined by the auto mode (e.g. if autogain is on, the hardware doesn't allow
you to obtain the current gain value).
The first control of the cluster is assumed to be the 'auto' control.
Using this function will ensure that you don't need to handle all the complex
flag and volatile handling.
VIDIOC_LOG_STATUS Support
-------------------------
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
value of the controls owned by the given handler to the log. You can supply a
prefix as well. If the prefix didn't end with a space, then ': ' will be added
for you.
Different Handlers for Different Video Nodes
--------------------------------------------
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
different video nodes. You can do that by manually setting the ctrl_handler
field of struct video_device.
That is no problem if there are no subdevs involved but if there are, then
you need to block the automatic merging of subdev controls to the global
control handler. You do that by simply setting the ctrl_handler field in
struct v4l2_device to NULL. Now v4l2_device_register_subdev() will no longer
merge subdev controls.
After each subdev was added, you will then have to call v4l2_ctrl_add_handler
manually to add the subdev's control handler (sd->ctrl_handler) to the desired
control handler. This control handler may be specific to the video_device or
for a subset of video_device's. For example: the radio device nodes only have
audio controls, while the video and vbi device nodes share the same control
handler for the audio and video controls.
If you want to have one handler (e.g. for a radio device node) have a subset
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
handler and finally add the first handler to the second. For example:
.. code-block:: c
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(&video_ctrl_handler, &video_ops, V4L2_CID_BRIGHTNESS, ...);
v4l2_ctrl_new_std(&video_ctrl_handler, &video_ops, V4L2_CID_CONTRAST, ...);
v4l2_ctrl_add_handler(&video_ctrl_handler, &radio_ctrl_handler, NULL);
The last argument to v4l2_ctrl_add_handler() is a filter function that allows
you to filter which controls will be added. Set it to NULL if you want to add
all controls.
Or you can add specific controls to a handler:
.. code-block:: c
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_CONTRAST, ...);
What you should not do is make two identical controls for two handlers.
For example:
.. code-block:: c
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, ...);
This would be bad since muting the radio would not change the video mute
control. The rule is to have one control for each hardware 'knob' that you
can twiddle.
Finding Controls
----------------
Normally you have created the controls yourself and you can store the struct
v4l2_ctrl pointer into your own struct.
But sometimes you need to find a control from another handler that you do
not own. For example, if you have to find a volume control from a subdev.
You can do that by calling v4l2_ctrl_find:
.. code-block:: c
struct v4l2_ctrl *volume;
volume = v4l2_ctrl_find(sd->ctrl_handler, V4L2_CID_AUDIO_VOLUME);
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:
.. code-block:: c
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_CONTRAST, ...);
...and in video_ops.s_ctrl:
.. code-block:: c
case V4L2_CID_BRIGHTNESS:
contrast = v4l2_find_ctrl(&ctrl_handler, V4L2_CID_CONTRAST);
...
When s_ctrl is called by the framework the ctrl_handler.lock is already taken, so
attempting to find another control from the same handler will deadlock.
It is recommended not to use this function from inside the control ops.
Preventing Controls inheritance
-------------------------------
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
have low-level controls that make sense for some advanced embedded system, but
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
setting the 'is_private' flag of the control to 1:
.. code-block:: c
static const struct v4l2_ctrl_config ctrl_private = {
.ops = &ctrl_custom_ops,
.id = V4L2_CID_...,
.name = "Some Private Control",
.type = V4L2_CTRL_TYPE_INTEGER,
.max = 15,
.step = 1,
.is_private = 1,
};
ctrl = v4l2_ctrl_new_custom(&foo->ctrl_handler, &ctrl_private, NULL);
These controls will now be skipped when v4l2_ctrl_add_handler is called.
V4L2_CTRL_TYPE_CTRL_CLASS Controls
----------------------------------
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
containing the controls belonging to a particular control class. The name of
each tab can be found by querying a special control with ID <control class | 1>.
Drivers do not have to care about this. The framework will automatically add
a control of this type whenever the first control belonging to a new control
class is added.
Adding Notify Callbacks
-----------------------
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
this function:
.. code-block:: c
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
with a pointer to the control and the priv pointer that was passed with
v4l2_ctrl_notify. Note that the control's handler lock is held when the
notify function is called.
There can be only one notify function per control handler. Any attempt
to set another notify function will cause a WARN_ON.
v4l2_ctrl functions and data structures
---------------------------------------
.. kernel-doc:: include/media/v4l2-ctrls.h
3. 한국어 전문 번역
영어 원문의 문단 순서와 의미를 유지한 전체 번역입니다. 코드, 함수명, symbol과 URL은 원문 표기를 유지합니다.
V4L2 control framework의 목적
1-33V4L2 control API는 단순해 보이지만 driver에서 올바르게 구현하기가 금세 어려워집니다. Control 처리 코드의 상당 부분은 driver 전용이 아니므로 V4L core framework로 옮길 수 있습니다.
Driver 개발자가 주로 신경 쓸 일은 control을 추가하는 방법과 `s_ctrl`로 값을 설정하는 방법입니다. 때로는 `g_volatile_ctrl`로 값을 읽는 방법과 `try_ctrl`로 사용자가 제안한 값을 검증하는 방법도 필요합니다. 나머지 동작은 중앙에서 처리할 수 있습니다.
Control framework는 V4L2 specification의 control 관련 규칙을 한 곳에서 구현하고 driver 개발을 단순하게 만들기 위해 만들어졌습니다.
Framework는 V4L2 driver에 `struct v4l2_device`가 있고 sub-device driver에 `struct v4l2_subdev`가 있다고 가정합니다.
.. SPDX-License-Identifier: GPL-2.0
V4L2 Controls
=============
Introduction
------------
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
is actually not driver specific and can be moved to the V4L core framework.
After all, the only part that a driver developer is interested in is:
1) How do I add a control?
2) How do I set the control's value? (i.e. s_ctrl)
And occasionally:
3) How do I get the control's value? (i.e. g_volatile_ctrl)
4) How do I validate the user's proposed control value? (i.e. try_ctrl)
All the rest is something that can be done centrally.
The control framework was created in order to implement all the rules of the
V4L2 specification with respect to controls in a central place. And to make
life as easy as possible for the driver developer.
Note that the control framework relies on the presence of a struct
:c:type:`v4l2_device` for V4L2 drivers and struct v4l2_subdev for
sub-device drivers.
Framework의 두 핵심 object
34-47`v4l2_ctrl` object는 control 속성을 설명하고 현재 값과 사용자가 제안한 새 값을 모두 추적합니다.
`v4l2_ctrl_handler`는 control을 추적하는 object입니다. 자신이 소유한 `v4l2_ctrl` 목록과 다른 handler가 소유할 수도 있는 control reference 목록을 각각 관리합니다.
Objects in the framework
------------------------
There are two main objects:
The :c:type:`v4l2_ctrl` object describes the control properties and keeps
track of the control's value (both the current value and the proposed new
value).
:c:type:`v4l2_ctrl_handler` is the object that keeps track of controls. It
maintains a list of v4l2_ctrl objects that it owns and another list of
references to controls, possibly to controls owned by other handlers.
Handler 준비·연결·해제
48-114Driver는 먼저 `<media/v4l2-ctrls.h>`를 include하고 최상위 driver 구조체에 `struct v4l2_ctrl_handler`를 추가합니다. V4L2 driver에서는 `struct v4l2_device`와 함께, sub-device driver에서는 `struct v4l2_subdev`와 함께 embed합니다.
`v4l2_ctrl_handler_init(&foo->ctrl_handler, nr_of_controls)`로 handler를 초기화합니다. 두 번째 인자는 예상 control 수를 알려 주는 hint이며 framework는 이를 바탕으로 hashtable을 할당하지만 정확할 필요는 없습니다.
V4L2 driver는 `foo->v4l2_dev.ctrl_handler`에, sub-device driver는 `foo->sd.ctrl_handler`에 handler pointer를 연결합니다.
마지막에는 `v4l2_ctrl_handler_free()`로 handler를 정리합니다. 이 함수는 handler의 `error` 필드를 변경하지 않습니다.
Top-level object에 handler를 embed하고 해당 V4L2 object에 pointer를 연결합니다.
Basic usage for V4L2 and sub-device drivers
-------------------------------------------
1) Prepare the driver:
.. code-block:: c
#include <media/v4l2-ctrls.h>
1.1) Add the handler to your driver's top-level struct:
For V4L2 drivers:
.. code-block:: c
struct foo_dev {
...
struct v4l2_device v4l2_dev;
...
struct v4l2_ctrl_handler ctrl_handler;
...
};
For sub-device drivers:
.. code-block:: c
struct foo_dev {
...
struct v4l2_subdev sd;
...
struct v4l2_ctrl_handler ctrl_handler;
...
};
1.2) Initialize the handler:
.. code-block:: c
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.
1.3) Hook the control handler into the driver:
For V4L2 drivers:
.. code-block:: c
foo->v4l2_dev.ctrl_handler = &foo->ctrl_handler;
For sub-device drivers:
.. code-block:: c
foo->sd.ctrl_handler = &foo->ctrl_handler;
1.4) Clean up the handler at the end:
.. code-block:: c
v4l2_ctrl_handler_free(&foo->ctrl_handler);
:c:func:`v4l2_ctrl_handler_free` does not touch the handler's ``error`` field.
Control 생성 API
115-161일반적인 non-menu control은 `v4l2_ctrl_new_std()`로 추가하며 handler, ops, ID, min, max, step, default 값을 전달합니다.
표준 menu control은 `v4l2_ctrl_new_std_menu()`로 만들고 min 대신 0부터 시작하며 `skip_mask`로 사용할 수 없는 항목을 지정합니다.
표준 menu이지만 driver 전용 문자열 항목이 필요하면 `v4l2_ctrl_new_std_menu_items()`에 `qmenu`를 전달합니다. 표준 compound control은 `v4l2_ctrl_new_std_compound()`에 기본값 pointer union을 전달합니다.
Driver 전용 signed 64-bit integer menu는 `v4l2_ctrl_new_int_menu()`에 정확한 menu item 배열 `qmenu_int`를 전달하여 생성합니다.
2) Add controls:
You add non-menu controls by calling :c:func:`v4l2_ctrl_new_std`:
.. code-block:: c
struct 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);
Menu and integer menu controls are added by calling
:c:func:`v4l2_ctrl_new_std_menu`:
.. code-block:: c
struct 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);
Menu controls with a driver specific menu are added by calling
:c:func:`v4l2_ctrl_new_std_menu_items`:
.. code-block:: c
struct 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);
Standard compound controls can be added by calling
:c:func:`v4l2_ctrl_new_std_compound`:
.. code-block:: c
struct v4l2_ctrl *v4l2_ctrl_new_std_compound(struct v4l2_ctrl_handler *hdl,
const struct v4l2_ctrl_ops *ops, u32 id,
const union v4l2_ctrl_ptr p_def);
Integer menu controls with a driver specific menu can be added by calling
:c:func:`v4l2_ctrl_new_int_menu`:
.. code-block:: c
struct 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);
Control 생성 예제와 error 누적
162-237Control 생성 함수는 보통 `v4l2_ctrl_handler_init()` 직후 호출합니다. 예제는 brightness·contrast, power-line frequency menu, exposure bias integer menu, hardware별 test-pattern 문자열 menu를 추가합니다. 마지막에 `ctrl_handler.error`를 한 번 확인하고 오류면 handler를 정리합니다.
`v4l2_ctrl_new_std()`는 새 `v4l2_ctrl` pointer를 반환하지만 control ops 밖에서 접근할 필요가 없다면 저장하지 않아도 됩니다.
이 함수는 control ID를 바탕으로 type·name·flag 같은 전역 속성을 채우고 driver별 min·max·step·default는 마지막 네 인자에서 받습니다. 현재 값은 default로 초기화됩니다.
Menu control의 min은 항상 0입니다. `skip_mask`의 bit X가 1이면 menu item X를 건너뜁니다. Integer menu는 mask가 없고 signed 64-bit 배열이 정확한 항목 목록입니다. `v4l2_ctrl_new_std_menu_items()`의 `qmenu`는 test pattern처럼 표준 control이지만 hardware마다 문자열 항목이 다른 경우에 사용합니다.
생성 중 실패하면 함수는 `NULL` 또는 오류를 반환하고 `ctrl_handler->error`에 오류 code를 기록합니다. Error가 이미 설정되어 있으면 이후 호출은 아무 작업도 하지 않습니다. 내부 구조 할당에 실패한 `v4l2_ctrl_handler_init()`도 같은 규칙을 따르므로 모든 control을 추가한 뒤 error를 한 번만 검사할 수 있습니다.
Control은 ID 오름차순으로 추가하는 것이 조금 더 빠르므로 권장됩니다.
Handler가 첫 오류를 보존하므로 반복적인 개별 검사를 생략할 수 있습니다.
These functions are typically called right after the
:c:func:`v4l2_ctrl_handler_init`:
.. code-block:: c
static const s64 exp_bias_qmenu[] = {
-2, -1, 0, 1, 2
};
static const char * const test_pattern[] = {
"Disabled",
"Vertical Bars",
"Solid Black",
"Solid White",
};
v4l2_ctrl_handler_init(&foo->ctrl_handler, nr_of_controls);
v4l2_ctrl_new_std(&foo->ctrl_handler, &foo_ctrl_ops,
V4L2_CID_BRIGHTNESS, 0, 255, 1, 128);
v4l2_ctrl_new_std(&foo->ctrl_handler, &foo_ctrl_ops,
V4L2_CID_CONTRAST, 0, 255, 1, 128);
v4l2_ctrl_new_std_menu(&foo->ctrl_handler, &foo_ctrl_ops,
V4L2_CID_POWER_LINE_FREQUENCY,
V4L2_CID_POWER_LINE_FREQUENCY_60HZ, 0,
V4L2_CID_POWER_LINE_FREQUENCY_DISABLED);
v4l2_ctrl_new_int_menu(&foo->ctrl_handler, &foo_ctrl_ops,
V4L2_CID_EXPOSURE_BIAS,
ARRAY_SIZE(exp_bias_qmenu) - 1,
ARRAY_SIZE(exp_bias_qmenu) / 2 - 1,
exp_bias_qmenu);
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);
...
if (foo->ctrl_handler.error)
return v4l2_ctrl_handler_free(&foo->ctrl_handler);
The :c:func:`v4l2_ctrl_new_std` function returns the v4l2_ctrl pointer to
the new control, but if you do not need to access the pointer outside the
control ops, then there is no need to store it.
The :c:func:`v4l2_ctrl_new_std` function will fill in most fields based on
the control ID except for the min, max, step and default values. These are
passed in the last four arguments. These values are driver specific while
control attributes like type, name, flags are all global. The control's
current value will be set to the default value.
The :c:func:`v4l2_ctrl_new_std_menu` function is very similar but it is
used for menu controls. There is no min argument since that is always 0 for
menu controls, and instead of a step there is a skip_mask argument: if bit
X is 1, then menu item X is skipped.
The :c:func:`v4l2_ctrl_new_int_menu` function creates a new standard
integer menu control with driver-specific items in the menu. It differs
from v4l2_ctrl_new_std_menu in that it doesn't have the mask argument and
takes as the last argument an array of signed 64-bit integers that form an
exact menu item list.
The :c:func:`v4l2_ctrl_new_std_menu_items` function is very similar to
v4l2_ctrl_new_std_menu but takes an extra parameter qmenu, which is the
driver specific menu for an otherwise standard menu control. A good example
for this control is the test pattern control for capture/display/sensors
devices that have the capability to generate test patterns. These test
patterns are hardware specific, so the contents of the menu will vary from
device to device.
Note that if something fails, the function will return NULL or an error and
set ctrl_handler->error to the error code. If ctrl_handler->error was already
set, then it will just return and do nothing. This is also true for
v4l2_ctrl_handler_init if it cannot allocate the internal data structure.
This makes it easy to init the handler and just add all controls and only check
the error code at the end. Saves a lot of repetitive error checking.
It is recommended to add controls in ascending control ID order: it will be
a bit faster that way.
초기 setup과 s_ctrl 구현
238-290선택적으로 `v4l2_ctrl_handler_setup()`을 호출하면 모든 control의 `s_ctrl`을 조건 없이 호출하여 hardware를 default control 값으로 초기화합니다. 내부 자료 구조와 hardware 상태를 동기화하므로 이 호출을 권장합니다.
마지막으로 `v4l2_ctrl_ops`를 구현합니다. 대부분의 driver에는 `.s_ctrl = foo_s_ctrl`만 있으면 충분합니다.
`s_ctrl`은 `v4l2_ctrl` pointer를 받고 `ctrl->handler`에서 driver state를 얻은 뒤 control ID에 따라 이미 검증된 `ctrl->val`을 hardware register에 씁니다. 새 값은 framework가 검증했으므로 driver는 실제 register만 갱신하면 됩니다.
이 기본 구현만으로 control 값 검증이나 `QUERYCTRL`, `QUERY_EXT_CTRL`, `QUERYMENU`를 직접 구현할 필요가 없습니다. `G/S_CTRL`과 `G/TRY/S_EXT_CTRLS`도 자동으로 지원됩니다.
뒤의 절은 고급 control 주제와 시나리오를 다룹니다. 실제로는 여기까지의 기본 사용법으로 대부분의 driver에 충분합니다.
Framework가 검증과 ioctl을 맡고 driver의 s_ctrl은 hardware만 갱신합니다.
3) Optionally force initial control setup:
.. code-block:: c
v4l2_ctrl_handler_setup(&foo->ctrl_handler);
This will call s_ctrl for all controls unconditionally. Effectively this
initializes the hardware to the default control values. It is recommended
that you do this as this ensures that both the internal data structures and
the hardware are in sync.
4) Finally: implement the :c:type:`v4l2_ctrl_ops`
.. code-block:: c
static const struct v4l2_ctrl_ops foo_ctrl_ops = {
.s_ctrl = foo_s_ctrl,
};
Usually all you need is s_ctrl:
.. code-block:: c
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;
}
The control ops are called with the v4l2_ctrl pointer as argument.
The new control value has already been validated, so all you need to do is
to actually update the hardware registers.
You're done! And this is sufficient for most of the drivers we have. No need
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.
.. 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.
Sub-device control 상속
291-305`v4l2_device_register_subdev()`로 sub-device를 V4L2 driver에 등록할 때 `v4l2_subdev`와 `v4l2_device` 양쪽의 `ctrl_handler` 필드가 설정되어 있으면 sub-device control도 V4L2 driver에서 자동으로 사용할 수 있습니다.
Sub-device에 V4L2 driver가 이미 가진 control이 있으면 건너뛰므로 V4L2 driver가 sub-device control을 항상 override할 수 있습니다.
내부적으로 `v4l2_device_register_subdev()`가 `v4l2_ctrl_add_handler()`를 호출해 sub-device control을 `v4l2_device` control에 추가합니다.
양쪽 handler가 연결된 경우 등록 시 중복을 제외하고 control reference를 합칩니다.
Inheriting Sub-device Controls
------------------------------
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
and v4l2_device are set, then the controls of the subdev will become
automatically available in the V4L2 driver as well. If the subdev driver
contains controls that already exist in the V4L2 driver, then those will be
skipped (so a V4L2 driver can always override a subdev control).
What happens here is that v4l2_device_register_subdev() calls
v4l2_ctrl_add_handler() adding the controls of the subdev to the controls
of v4l2_device.
Current·new control value 표현
306-354Control framework는 `union v4l2_ctrl_ptr`의 `p_s32`, `p_s64`, `p_char`, 일반 `p` pointer로 control 값에 접근합니다.
`v4l2_ctrl`에는 새 값용 `val`과 `p_new`, 현재 값용 `cur.val`과 `p_cur`가 있습니다. 단순 `s32` control에서는 `&ctrl->val`이 `ctrl->p_new.p_s32`와 같고 `&ctrl->cur.val`이 `ctrl->p_cur.p_s32`와 같습니다.
다른 type은 `p_cur`·`p_new`의 해당 member를 사용합니다. 자주 쓰이는 `val`과 `cur.val`은 pointer union의 alias로 볼 수 있습니다.
Control ops 안에서는 이 필드에 자유롭게 접근할 수 있습니다. `p_char`는 길이가 `ctrl->maximum + 1`인 character buffer를 가리키며 항상 NUL로 끝납니다.
Volatile 표시가 없는 control에서 `p_cur`은 cache된 현재 값을 가리킵니다. 새 control의 현재 값은 default와 같고 `v4l2_ctrl_handler_setup()`을 호출하면 이 값이 hardware에 전달됩니다.
Accessing Control Values
------------------------
The following union is used inside the control framework to access control
values:
.. code-block:: c
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
current and new values:
.. code-block:: c
s32 val;
struct {
s32 val;
} cur;
union v4l2_ctrl_ptr p_new;
union v4l2_ctrl_ptr p_cur;
If the control has a simple s32 type, then:
.. code-block:: c
&ctrl->val == ctrl->p_new.p_s32
&ctrl->cur.val == ctrl->p_cur.p_s32
For all other types use ctrl->p_cur.p<something>. Basically the val
and cur.val fields can be considered an alias since these are used so often.
Within the control ops you can freely use these. The val and cur.val speak for
themselves. The p_char pointers point to character buffers of length
ctrl->maximum + 1, and are always 0-terminated.
Unless the control is marked volatile the p_cur field points to the
current cached control value. When you create a new control this value is made
identical to the default value. After calling v4l2_ctrl_handler_setup() this
value is passed to the hardware. It is generally a good idea to call this
function.
Volatile control과 값 commit
355-391새 값을 설정하면 framework가 자동으로 cache하므로 대부분의 driver는 `g_volatile_ctrl()`을 구현할 필요가 없습니다. 계속 변하는 signal strength register처럼 volatile 값을 반환하는 control만 예외입니다.
예제 `foo_g_volatile_ctrl()`은 brightness register를 읽어 `ctrl->val`에 넣습니다. `g_volatile_ctrl`에서도 new-value union을 사용합니다.
일반적으로 `g_volatile_ctrl`이 필요한 control은 read-only입니다. Read-only가 아니라면 control 값이 바뀔 때 `V4L2_EVENT_CTRL_CH_VALUE`가 생성되지 않습니다.
Control을 volatile로 표시하려면 생성한 pointer의 `flags`에 `V4L2_CTRL_FLAG_VOLATILE`을 설정합니다.
`try_ctrl`과 `s_ctrl`에는 사용자가 전달한 새 값이 채워집니다. `try_ctrl`에서 이를 수정하거나 `s_ctrl`에서 설정할 수 있습니다. `cur` union의 현재 값은 읽을 수 있지만 바꾸면 안 됩니다.
`s_ctrl`이 0을 반환하면 framework가 최종 new value를 `cur` union으로 복사합니다.
Volatile 여부와 s_ctrl 성공에 따라 cache 갱신 경로가 달라집니다.
Whenever a new value is set that new value is automatically cached. This means
that most drivers do not need to implement the g_volatile_ctrl() op. The
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
implement g_volatile_ctrl like this:
.. code-block:: c
static int foo_g_volatile_ctrl(struct v4l2_ctrl *ctrl)
{
switch (ctrl->id) {
case V4L2_CID_BRIGHTNESS:
ctrl->val = read_reg(0x123);
break;
}
}
Note that you use the 'new value' union as well in g_volatile_ctrl. In general
controls that need to implement g_volatile_ctrl are read-only controls. If they
are not, a V4L2_EVENT_CTRL_CH_VALUE will not be generated when the control
changes.
To mark a control as volatile you have to set V4L2_CTRL_FLAG_VOLATILE:
.. code-block:: c
ctrl = v4l2_ctrl_new_std(&sd->ctrl_handler, ...);
if (ctrl)
ctrl->flags |= V4L2_CTRL_FLAG_VOLATILE;
For try/s_ctrl the new values (i.e. as passed by the user) are filled in and
you can modify them in try_ctrl or set them in s_ctrl. The 'cur' union
contains the current value, which you can use (but not change!) as well.
If s_ctrl returns 0 (OK), then the control framework will copy the new final
values to the 'cur' union.
Control 값 접근과 handler lock
392-418`g_volatile_ctrl`, `s_ctrl`, `try_ctrl` 안에서는 handler lock이 잡혀 있으므로 같은 handler가 소유한 모든 control 값에 접근할 수 있습니다. 다른 handler 소유 control에 접근하면 deadlock을 만들지 않도록 매우 주의해야 합니다.
Control ops 밖에서 단일 control 값을 안전하게 읽고 쓰려면 `v4l2_ctrl_g_ctrl()`과 `v4l2_ctrl_s_ctrl()` helper를 사용합니다. 이 함수는 `VIDIOC_G/S_CTRL` ioctl과 똑같이 framework를 거칩니다.
이 helper들은 handler를 다시 lock하므로 `g_volatile_ctrl`, `s_ctrl`, `try_ctrl` 안에서 호출하면 deadlock이 발생합니다.
Ops 밖에서는 handler mutex를 직접 잡아 `p_cur`나 `cur.val`을 읽고 해제할 수도 있습니다.
While in g_volatile/s/try_ctrl you can access the value of all controls owned
by the same handler since the handler's lock is held. If you need to access
the value of controls owned by other handlers, then you have to be very careful
not to introduce deadlocks.
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:
.. code-block:: c
s32 v4l2_ctrl_g_ctrl(struct v4l2_ctrl *ctrl);
int v4l2_ctrl_s_ctrl(struct v4l2_ctrl *ctrl, s32 val);
These functions go through the control framework just as VIDIOC_G/S_CTRL ioctls
do. Don't use these inside the control ops g_volatile/s/try_ctrl, though, that
will result in a deadlock since these helpers lock the handler as well.
You can also take the handler lock yourself:
.. code-block:: c
mutex_lock(&state->ctrl_handler.lock);
pr_info("String value is '%s'\n", ctrl1->p_cur.p_char);
pr_info("Integer value is '%s'\n", ctrl2->cur.val);
mutex_unlock(&state->ctrl_handler.lock);
Driver 전용 custom control
447-474Driver 전용 control은 `v4l2_ctrl_config`를 정의하고 `v4l2_ctrl_new_custom()`으로 생성합니다. Config에는 ops, ID, name, type, flag, 범위와 step 등을 지정할 수 있습니다.
마지막 `priv` 인자에는 driver 전용 private data pointer를 전달할 수 있습니다. `v4l2_ctrl_config`에는 `is_private` flag를 설정하는 필드도 있습니다.
`name`을 설정하지 않으면 framework는 표준 control로 간주하고 name, type, flag를 자동으로 채웁니다.
Custom Controls
---------------
Driver specific controls can be created using v4l2_ctrl_new_custom():
.. code-block:: c
static const struct v4l2_ctrl_config ctrl_filter = {
.ops = &ctrl_custom_ops,
.id = V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER,
.name = "Spatial Filter",
.type = V4L2_CTRL_TYPE_INTEGER,
.flags = V4L2_CTRL_FLAG_SLIDER,
.max = 15,
.step = 1,
};
ctrl = v4l2_ctrl_new_custom(&foo->ctrl_handler, &ctrl_filter, NULL);
The last argument is the priv pointer which can be set to driver-specific
private data.
The v4l2_ctrl_config struct also has a field to set the is_private flag.
If the name field is not set, then the framework will assume this is a standard
control and will fill in the name, type and flags fields accordingly.
Active와 grabbed control
475-498Control 관계가 복잡하면 control을 activate하거나 deactivate해야 할 수 있습니다. 예를 들어 Chroma AGC가 켜져 있으면 Chroma Gain은 inactive입니다. 값을 설정할 수는 있지만 자동 gain이 켜진 동안 hardware가 사용하지 않으므로 GUI가 해당 입력을 비활성화할 수 있습니다.
`v4l2_ctrl_activate()`로 active 상태를 바꿉니다. 기본적으로 모든 control은 active입니다. Framework는 이 flag를 강제 검사하지 않으며 GUI를 위한 표시입니다. 보통 `s_ctrl` 안에서 호출합니다.
Grabbed control은 어떤 resource에서 사용 중이라 값을 바꿀 수 없는 control입니다. Capture 중 변경할 수 없는 MPEG bitrate control이 대표적입니다.
`v4l2_ctrl_grab()`으로 grabbed 상태를 설정하면 값을 바꾸려는 시도에 framework가 `-EBUSY`를 반환합니다. Driver가 streaming을 시작하거나 멈출 때 보통 호출합니다.
Active and Grabbed Controls
---------------------------
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
on, then the Chroma Gain control is inactive. That is, you may set it, but
the value will not be used by the hardware as long as the automatic gain
control is on. Typically user interfaces can disable such input fields.
You can set the 'active' status using v4l2_ctrl_activate(). By default all
controls are active. Note that the framework does not check for this flag.
It is meant purely for GUIs. The function is typically called from within
s_ctrl.
The other flag is the 'grabbed' flag. A grabbed control means that you cannot
change it because it is in use by some resource. Typical examples are MPEG
bitrate controls that cannot be changed while capturing is in progress.
If a control is set to 'grabbed' using v4l2_ctrl_grab(), then the framework
will return -EBUSY if an attempt is made to set this control. The
v4l2_ctrl_grab() function is typically called from the driver when it
starts or stops streaming.
Control cluster와 master
499-601기본적으로 control은 서로 독립적이지만 dependency가 있으면 `v4l2_ctrl_cluster()`로 묶습니다. Volume과 mute를 두 control 배열로 만들고 cluster하면 복합 control처럼 동작합니다.
같은 cluster의 control 하나 이상을 set, get, try할 때 첫 control인 master의 control ops만 호출됩니다. 예제에서는 volume이 master이므로 `s_ctrl`이 volume ID로 호출되고 cluster의 mute 값까지 함께 적용합니다.
`ctrl`은 volume cluster pointer와 같고 `ctrl->cluster`로 다른 member에 접근합니다. 배열 대신 anonymous struct에 연속된 `volume`, `mute` pointer를 두고 `v4l2_ctrl_cluster(2, &state->volume)`을 호출하는 방식이 더 편리하며 효과는 같습니다.
Cluster member는 hardware가 기능을 지원하지 않는 경우 `NULL`일 수 있습니다. 다만 첫 control인 master는 항상 존재해야 합니다. Master가 cluster를 식별하고 cluster가 사용할 `v4l2_ctrl_ops` pointer를 제공합니다. 모든 member slot은 유효한 control 또는 `NULL`로 초기화해야 합니다.
사용자가 cluster의 어떤 control을 명시적으로 설정했는지 드물게 알아야 할 때 각 control의 `is_new`를 확인합니다. `VIDIOC_S_CTRL`로 mute만 설정하면 mute만 1이고 `VIDIOC_S_EXT_CTRLS`로 mute와 volume을 함께 설정하면 둘 다 1입니다.
`v4l2_ctrl_handler_setup()`에서 호출될 때는 `is_new`가 항상 1입니다.
첫 member가 master로서 cluster 전체의 ops를 대표합니다.
Control Clusters
----------------
By default all controls are independent from the others. But in more
complex scenarios you can get dependencies from one control to another.
In that case you need to 'cluster' them:
.. code-block:: c
struct foo {
struct v4l2_ctrl_handler ctrl_handler;
#define AUDIO_CL_VOLUME (0)
#define AUDIO_CL_MUTE (1)
struct v4l2_ctrl *audio_cluster[2];
...
};
state->audio_cluster[AUDIO_CL_VOLUME] =
v4l2_ctrl_new_std(&state->ctrl_handler, ...);
state->audio_cluster[AUDIO_CL_MUTE] =
v4l2_ctrl_new_std(&state->ctrl_handler, ...);
v4l2_ctrl_cluster(ARRAY_SIZE(state->audio_cluster), state->audio_cluster);
From now on whenever one or more of the controls belonging to the same
cluster is set (or 'gotten', or 'tried'), only the control ops of the first
control ('volume' in this example) is called. You effectively create a new
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
all two controls belonging to the audio_cluster:
.. code-block:: c
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_AUDIO_VOLUME: {
struct v4l2_ctrl *mute = ctrl->cluster[AUDIO_CL_MUTE];
write_reg(0x123, mute->val ? 0 : ctrl->val);
break;
}
case V4L2_CID_CONTRAST:
write_reg(0x456, ctrl->val);
break;
}
return 0;
}
In the example above the following are equivalent for the VOLUME case:
.. code-block:: c
ctrl == ctrl->cluster[AUDIO_CL_VOLUME] == state->audio_cluster[AUDIO_CL_VOLUME]
ctrl->cluster[AUDIO_CL_MUTE] == state->audio_cluster[AUDIO_CL_MUTE]
In practice using cluster arrays like this becomes very tiresome. So instead
the following equivalent method is used:
.. code-block:: c
struct {
/* audio cluster */
struct v4l2_ctrl *volume;
struct v4l2_ctrl *mute;
};
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
array with two control pointers. So you can just do:
.. code-block:: c
state->volume = v4l2_ctrl_new_std(&state->ctrl_handler, ...);
state->mute = v4l2_ctrl_new_std(&state->ctrl_handler, ...);
v4l2_ctrl_cluster(2, &state->volume);
And in foo_s_ctrl you can use these pointers directly: state->mute->val.
Note that controls in a cluster may be NULL. For example, if for some
reason mute was never added (because the hardware doesn't support that
particular feature), then mute will be NULL. So in that case we have a
cluster of 2 controls, of which only 1 is actually instantiated. The
only restriction is that the first control of the cluster must always be
present, since that is the 'master' control of the cluster. The master
control is the one that identifies the cluster and that provides the
pointer to the v4l2_ctrl_ops struct that is used for that cluster.
Obviously, all controls in the cluster array must be initialized to either
a valid control or to NULL.
In rare cases you might want to know which controls of a cluster actually
were set explicitly by the user. For this you can check the 'is_new' flag of
each control. For example, in the case of a volume/mute cluster the 'is_new'
flag of the mute control would be set if the user called VIDIOC_S_CTRL for
mute only. If the user would call VIDIOC_S_EXT_CTRLS for both mute and volume
controls, then the 'is_new' flag would be 1 for both controls.
The 'is_new' flag is always 1 when called from v4l2_ctrl_handler_setup().
Auto cluster
602-646일반적인 cluster는 autogain/gain, autoexposure/exposure, autowhitebalance/red balance/blue balance처럼 auto control이 manual control의 hardware 자동 처리 여부를 결정하는 형태입니다.
Automatic mode에서는 manual control을 inactive·volatile로 표시해야 합니다. Volatile control을 읽을 때 `g_volatile_ctrl`은 hardware auto mode가 정한 값을 반환해야 합니다.
Manual mode로 바꾸면 manual control을 다시 active로 만들고 volatile flag를 지워 `g_volatile_ctrl` 호출을 중지합니다. 전환 직전 auto mode의 현재 값을 새 manual 값으로 복사합니다.
Auto control 변경은 manual control flag에 영향을 주므로 auto control에는 `V4L2_CTRL_FLAG_UPDATE`를 설정해야 합니다.
`v4l2_ctrl_auto_cluster(ncontrols, controls, manual_val, set_volatile)`가 이 동작을 단순화합니다. 앞의 두 인자는 일반 cluster와 같고 `manual_val`은 manual mode로 전환하는 auto-control 값입니다.
`set_volatile`이 true이면 non-auto control에 `V4L2_CTRL_FLAG_VOLATILE`을 선택적으로 설정합니다. False이면 manual control은 어느 때도 volatile이 아닙니다. Hardware가 auto mode에서 정한 현재 값을 읽을 수 없는 경우 false를 사용합니다.
첫 control은 auto control로 간주됩니다. 이 helper를 사용하면 복잡한 flag와 volatile 전환을 driver가 직접 처리하지 않아도 됩니다.
Auto control 값이 manual mode 여부와 manual member flag를 함께 바꿉니다.
Handling autogain/gain-type Controls with Auto Clusters
-------------------------------------------------------
A common type of control cluster is one that handles 'auto-foo/foo'-type
controls. Typical examples are autogain/gain, autoexposure/exposure,
autowhitebalance/red balance/blue balance. In all cases you have one control
that determines whether another control is handled automatically by the hardware,
or whether it is under manual control from the user.
If the cluster is in automatic mode, then the manual controls should be
marked inactive and volatile. When the volatile controls are read the
g_volatile_ctrl operation should return the value that the hardware's automatic
mode set up automatically.
If the cluster is put in manual mode, then the manual controls should become
active again and the volatile flag is cleared (so g_volatile_ctrl is no longer
called while in manual mode). In addition just before switching to manual mode
the current values as determined by the auto mode are copied as the new manual
values.
Finally the V4L2_CTRL_FLAG_UPDATE should be set for the auto control since
changing that control affects the control flags of the manual controls.
In order to simplify this a special variation of v4l2_ctrl_cluster was
introduced:
.. code-block:: c
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
tells the framework which value switches the cluster into manual mode. The
last argument will optionally set V4L2_CTRL_FLAG_VOLATILE for the non-auto controls.
If it is false, then the manual controls are never volatile. You would typically
use that if the hardware does not give you the option to read back to values as
determined by the auto mode (e.g. if autogain is on, the hardware doesn't allow
you to obtain the current gain value).
The first control of the cluster is assumed to be the 'auto' control.
Using this function will ensure that you don't need to handle all the complex
flag and volatile handling.
VIDIOC_LOG_STATUS 지원
647-656`VIDIOC_LOG_STATUS` ioctl은 driver의 현재 상태를 kernel log에 출력합니다.
`v4l2_ctrl_handler_log_status(ctrl_handler, prefix)`는 지정한 handler가 소유한 control 값을 log에 출력합니다. Prefix를 전달할 수 있으며 공백으로 끝나지 않으면 framework가 `: `를 덧붙입니다.
VIDIOC_LOG_STATUS Support
-------------------------
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
value of the controls owned by the given handler to the log. You can supply a
prefix as well. If the prefix didn't end with a space, then ': ' will be added
for you.
Video node별 다른 handler
657-715보통 V4L2 driver는 모든 video node가 공유하는 전역 control handler 하나를 사용하지만 `struct video_device.ctrl_handler`를 직접 설정해 node마다 다른 handler를 둘 수도 있습니다.
Sub-device가 있으면 `struct v4l2_device.ctrl_handler`를 `NULL`로 설정해 sub-device control이 전역 handler에 자동 merge되는 것을 막아야 합니다. 그러면 `v4l2_device_register_subdev()`가 더 이상 merge하지 않습니다.
각 sub-device를 추가한 뒤 `v4l2_ctrl_add_handler()`를 직접 호출하여 `sd->ctrl_handler`를 원하는 video-device 전용 또는 일부 node 공유 handler에 추가합니다. 예를 들어 radio node에는 audio control만 두고 video와 VBI node는 audio·video control handler를 공유할 수 있습니다.
한 handler가 다른 handler의 subset이어야 하면 먼저 첫 handler에 공통 control을 추가하고, 두 번째 handler에 나머지 control을 추가한 뒤 첫 handler를 두 번째에 추가합니다. `v4l2_ctrl_add_handler()`의 마지막 filter 함수는 추가할 control을 거르며 `NULL`이면 모두 추가합니다.
특정 control만 handler에 직접 추가할 수도 있습니다. 하지만 하나의 hardware knob에 대해 서로 다른 handler에 동일 control 두 개를 만들면 안 됩니다. Radio mute를 바꿔도 video mute가 바뀌지 않는 불일치가 생기기 때문입니다.
원칙은 조작 가능한 hardware knob 하나마다 control object 하나만 두는 것입니다.
공통 hardware control object를 handler reference로 공유합니다.
Different Handlers for Different Video Nodes
--------------------------------------------
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
different video nodes. You can do that by manually setting the ctrl_handler
field of struct video_device.
That is no problem if there are no subdevs involved but if there are, then
you need to block the automatic merging of subdev controls to the global
control handler. You do that by simply setting the ctrl_handler field in
struct v4l2_device to NULL. Now v4l2_device_register_subdev() will no longer
merge subdev controls.
After each subdev was added, you will then have to call v4l2_ctrl_add_handler
manually to add the subdev's control handler (sd->ctrl_handler) to the desired
control handler. This control handler may be specific to the video_device or
for a subset of video_device's. For example: the radio device nodes only have
audio controls, while the video and vbi device nodes share the same control
handler for the audio and video controls.
If you want to have one handler (e.g. for a radio device node) have a subset
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
handler and finally add the first handler to the second. For example:
.. code-block:: c
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(&video_ctrl_handler, &video_ops, V4L2_CID_BRIGHTNESS, ...);
v4l2_ctrl_new_std(&video_ctrl_handler, &video_ops, V4L2_CID_CONTRAST, ...);
v4l2_ctrl_add_handler(&video_ctrl_handler, &radio_ctrl_handler, NULL);
The last argument to v4l2_ctrl_add_handler() is a filter function that allows
you to filter which controls will be added. Set it to NULL if you want to add
all controls.
Or you can add specific controls to a handler:
.. code-block:: c
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_CONTRAST, ...);
What you should not do is make two identical controls for two handlers.
For example:
.. code-block:: c
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, ...);
This would be bad since muting the radio would not change the video mute
control. The rule is to have one control for each hardware 'knob' that you
can twiddle.
다른 handler의 control 찾기
716-756직접 만든 control은 `struct v4l2_ctrl` pointer를 driver 구조체에 저장할 수 있지만, sub-device volume처럼 소유하지 않은 다른 handler의 control을 찾아야 할 때가 있습니다.
이때 `v4l2_ctrl_find(sd->ctrl_handler, V4L2_CID_AUDIO_VOLUME)`를 호출합니다.
`v4l2_ctrl_find()`는 handler를 lock하므로 호출 위치에 주의해야 합니다. Framework가 `s_ctrl`을 호출할 때는 이미 `ctrl_handler.lock`을 잡고 있으므로 같은 handler에서 다른 control을 찾으려 하면 deadlock이 발생합니다.
따라서 control ops 안에서는 이 함수를 사용하지 않는 것이 권장됩니다.
Handler lock을 이미 가진 control ops에서는 find helper를 호출하지 않습니다.
Finding Controls
----------------
Normally you have created the controls yourself and you can store the struct
v4l2_ctrl pointer into your own struct.
But sometimes you need to find a control from another handler that you do
not own. For example, if you have to find a volume control from a subdev.
You can do that by calling v4l2_ctrl_find:
.. code-block:: c
struct v4l2_ctrl *volume;
volume = v4l2_ctrl_find(sd->ctrl_handler, V4L2_CID_AUDIO_VOLUME);
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:
.. code-block:: c
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_CONTRAST, ...);
...and in video_ops.s_ctrl:
.. code-block:: c
case V4L2_CID_BRIGHTNESS:
contrast = v4l2_find_ctrl(&ctrl_handler, V4L2_CID_CONTRAST);
...
When s_ctrl is called by the framework the ctrl_handler.lock is already taken, so
attempting to find another control from the same handler will deadlock.
It is recommended not to use this function from inside the control ops.
Control 상속 방지
757-783`v4l2_ctrl_add_handler()`로 한 handler를 다른 handler에 추가하면 기본적으로 모든 control을 merge합니다. 그러나 advanced embedded system에는 의미가 있지만 consumer hardware에서는 노출하면 안 되는 sub-device 저수준 control이 있을 수 있습니다.
이런 control을 sub-device 안에 유지하려면 `v4l2_ctrl_config.is_private`를 1로 설정하고 `v4l2_ctrl_new_custom()`으로 생성합니다.
Private control은 이후 `v4l2_ctrl_add_handler()`가 호출될 때 건너뜁니다.
Preventing Controls inheritance
-------------------------------
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
have low-level controls that make sense for some advanced embedded system, but
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
setting the 'is_private' flag of the control to 1:
.. code-block:: c
static const struct v4l2_ctrl_config ctrl_private = {
.ops = &ctrl_custom_ops,
.id = V4L2_CID_...,
.name = "Some Private Control",
.type = V4L2_CTRL_TYPE_INTEGER,
.max = 15,
.step = 1,
.is_private = 1,
};
ctrl = v4l2_ctrl_new_custom(&foo->ctrl_handler, &ctrl_private, NULL);
These controls will now be skipped when v4l2_ctrl_add_handler is called.
V4L2_CTRL_TYPE_CTRL_CLASS
784-796`V4L2_CTRL_TYPE_CTRL_CLASS` control은 GUI가 control class 이름을 얻을 때 사용합니다. 완전한 GUI는 class별 tab을 만들고 각 tab에 해당 class의 control을 배치할 수 있습니다.
각 tab 이름은 ID가 `<control class | 1>`인 특수 control을 query하여 얻습니다.
Driver는 이를 직접 처리할 필요가 없습니다. 새 control class에 속하는 첫 control을 추가하면 framework가 이 type의 control을 자동으로 추가합니다.
Framework가 class-name control을 자동 생성합니다.
V4L2_CTRL_TYPE_CTRL_CLASS Controls
----------------------------------
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
containing the controls belonging to a particular control class. The name of
each tab can be found by querying a special control with ID <control class | 1>.
Drivers do not have to care about this. The framework will automatically add
a control of this type whenever the first control belonging to a new control
class is added.
Control notify callback
797-816Platform 또는 bridge driver가 sub-device control 변경을 알아야 할 때 `v4l2_ctrl_notify()`로 notify callback과 private pointer를 설정합니다.
지정한 control 값이 바뀔 때마다 callback은 control pointer와 등록 시 전달한 `priv` pointer를 받습니다. Notify 함수가 호출되는 동안 control handler lock이 잡혀 있습니다.
Control handler마다 notify 함수는 하나만 둘 수 있습니다. 다른 notify 함수를 설정하려 하면 `WARN_ON`이 발생합니다.
Handler당 하나의 callback이 lock을 보유한 상태에서 호출됩니다.
Adding Notify Callbacks
-----------------------
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
this function:
.. code-block:: c
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
with a pointer to the control and the priv pointer that was passed with
v4l2_ctrl_notify. Note that the control's handler lock is held when the
notify function is called.
There can be only one notify function per control handler. Any attempt
to set another notify function will cause a WARN_ON.
v4l2_ctrl 함수와 자료 구조
817-820V4L2 control 함수와 자료 구조의 상세 정의는 `include/media/v4l2-ctrls.h`의 kernel-doc에서 가져옵니다.
v4l2_ctrl functions and data structures
---------------------------------------
.. kernel-doc:: include/media/v4l2-ctrls.h
요약과 해설
v4l2-controls.rst:1-820V4L2 control framework는 specification의 공통 규칙·검증·ioctl·cache를 맡아 driver가 control 생성과 hardware 적용에 집중하게 합니다. 기본 driver는 handler를 초기화하고 control을 추가한 뒤 `s_ctrl`을 구현하는 것만으로 충분합니다.
고급 사용에서는 current/new pointer alias, volatile value와 handler lock, menu·custom control, active·grabbed state, cluster·auto cluster, node별 handler와 private 상속, class·notify callback 규칙을 지켜야 합니다.