mirror of https://gitee.com/openkylin/linux.git
V4L/DVB (9903): uvcvideo: V4L2 zoom controls support
Add support for absolute and continuous zoom controls (mapped to absolute and relative UVC zoom controls). Signed-off-by: Laurent Pinchart <laurent.pinchart@skynet.be> Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
This commit is contained in:
parent
6df126f834
commit
9768352ac1
|
@ -327,6 +327,31 @@ static struct uvc_menu_info exposure_auto_controls[] = {
|
||||||
{ 8, "Aperture Priority Mode" },
|
{ 8, "Aperture Priority Mode" },
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static __s32 uvc_ctrl_get_zoom(struct uvc_control_mapping *mapping,
|
||||||
|
__u8 query, const __u8 *data)
|
||||||
|
{
|
||||||
|
__s8 zoom = (__s8)data[0];
|
||||||
|
|
||||||
|
switch (query) {
|
||||||
|
case GET_CUR:
|
||||||
|
return (zoom == 0) ? 0 : (zoom > 0 ? data[2] : -data[2]);
|
||||||
|
|
||||||
|
case GET_MIN:
|
||||||
|
case GET_MAX:
|
||||||
|
case GET_RES:
|
||||||
|
case GET_DEF:
|
||||||
|
default:
|
||||||
|
return data[2];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void uvc_ctrl_set_zoom(struct uvc_control_mapping *mapping,
|
||||||
|
__s32 value, __u8 *data)
|
||||||
|
{
|
||||||
|
data[0] = value == 0 ? 0 : (value > 0) ? 1 : 0xff;
|
||||||
|
data[2] = min(abs(value), 0xff);
|
||||||
|
}
|
||||||
|
|
||||||
static struct uvc_control_mapping uvc_ctrl_mappings[] = {
|
static struct uvc_control_mapping uvc_ctrl_mappings[] = {
|
||||||
{
|
{
|
||||||
.id = V4L2_CID_BRIGHTNESS,
|
.id = V4L2_CID_BRIGHTNESS,
|
||||||
|
@ -532,6 +557,28 @@ static struct uvc_control_mapping uvc_ctrl_mappings[] = {
|
||||||
.v4l2_type = V4L2_CTRL_TYPE_BOOLEAN,
|
.v4l2_type = V4L2_CTRL_TYPE_BOOLEAN,
|
||||||
.data_type = UVC_CTRL_DATA_TYPE_BOOLEAN,
|
.data_type = UVC_CTRL_DATA_TYPE_BOOLEAN,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
.id = V4L2_CID_ZOOM_ABSOLUTE,
|
||||||
|
.name = "Zoom, Absolute",
|
||||||
|
.entity = UVC_GUID_UVC_CAMERA,
|
||||||
|
.selector = CT_ZOOM_ABSOLUTE_CONTROL,
|
||||||
|
.size = 16,
|
||||||
|
.offset = 0,
|
||||||
|
.v4l2_type = V4L2_CTRL_TYPE_INTEGER,
|
||||||
|
.data_type = UVC_CTRL_DATA_TYPE_UNSIGNED,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.id = V4L2_CID_ZOOM_CONTINUOUS,
|
||||||
|
.name = "Zoom, Continuous",
|
||||||
|
.entity = UVC_GUID_UVC_CAMERA,
|
||||||
|
.selector = CT_ZOOM_RELATIVE_CONTROL,
|
||||||
|
.size = 0,
|
||||||
|
.offset = 0,
|
||||||
|
.v4l2_type = V4L2_CTRL_TYPE_INTEGER,
|
||||||
|
.data_type = UVC_CTRL_DATA_TYPE_SIGNED,
|
||||||
|
.get = uvc_ctrl_get_zoom,
|
||||||
|
.set = uvc_ctrl_set_zoom,
|
||||||
|
},
|
||||||
{
|
{
|
||||||
.id = V4L2_CID_PRIVACY,
|
.id = V4L2_CID_PRIVACY,
|
||||||
.name = "Privacy",
|
.name = "Privacy",
|
||||||
|
@ -568,8 +615,8 @@ static inline void uvc_clear_bit(__u8 *data, int bit)
|
||||||
* a signed 32bit integer. Sign extension will be performed if the mapping
|
* a signed 32bit integer. Sign extension will be performed if the mapping
|
||||||
* references a signed data type.
|
* references a signed data type.
|
||||||
*/
|
*/
|
||||||
static __s32 uvc_get_le_value(const __u8 *data,
|
static __s32 uvc_get_le_value(struct uvc_control_mapping *mapping,
|
||||||
struct uvc_control_mapping *mapping)
|
__u8 query, const __u8 *data)
|
||||||
{
|
{
|
||||||
int bits = mapping->size;
|
int bits = mapping->size;
|
||||||
int offset = mapping->offset;
|
int offset = mapping->offset;
|
||||||
|
@ -598,8 +645,8 @@ static __s32 uvc_get_le_value(const __u8 *data,
|
||||||
/* Set the bit string specified by mapping->offset and mapping->size
|
/* Set the bit string specified by mapping->offset and mapping->size
|
||||||
* in the little-endian data stored at 'data' to the value 'value'.
|
* in the little-endian data stored at 'data' to the value 'value'.
|
||||||
*/
|
*/
|
||||||
static void uvc_set_le_value(__s32 value, __u8 *data,
|
static void uvc_set_le_value(struct uvc_control_mapping *mapping,
|
||||||
struct uvc_control_mapping *mapping)
|
__s32 value, __u8 *data)
|
||||||
{
|
{
|
||||||
int bits = mapping->size;
|
int bits = mapping->size;
|
||||||
int offset = mapping->offset;
|
int offset = mapping->offset;
|
||||||
|
@ -751,7 +798,7 @@ int uvc_query_v4l2_ctrl(struct uvc_video_device *video,
|
||||||
video->dev->intfnum, ctrl->info->selector,
|
video->dev->intfnum, ctrl->info->selector,
|
||||||
data, ctrl->info->size)) < 0)
|
data, ctrl->info->size)) < 0)
|
||||||
goto out;
|
goto out;
|
||||||
v4l2_ctrl->default_value = uvc_get_le_value(data, mapping);
|
v4l2_ctrl->default_value = mapping->get(mapping, GET_DEF, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (mapping->v4l2_type) {
|
switch (mapping->v4l2_type) {
|
||||||
|
@ -787,21 +834,21 @@ int uvc_query_v4l2_ctrl(struct uvc_video_device *video,
|
||||||
video->dev->intfnum, ctrl->info->selector,
|
video->dev->intfnum, ctrl->info->selector,
|
||||||
data, ctrl->info->size)) < 0)
|
data, ctrl->info->size)) < 0)
|
||||||
goto out;
|
goto out;
|
||||||
v4l2_ctrl->minimum = uvc_get_le_value(data, mapping);
|
v4l2_ctrl->minimum = mapping->get(mapping, GET_MIN, data);
|
||||||
}
|
}
|
||||||
if (ctrl->info->flags & UVC_CONTROL_GET_MAX) {
|
if (ctrl->info->flags & UVC_CONTROL_GET_MAX) {
|
||||||
if ((ret = uvc_query_ctrl(video->dev, GET_MAX, ctrl->entity->id,
|
if ((ret = uvc_query_ctrl(video->dev, GET_MAX, ctrl->entity->id,
|
||||||
video->dev->intfnum, ctrl->info->selector,
|
video->dev->intfnum, ctrl->info->selector,
|
||||||
data, ctrl->info->size)) < 0)
|
data, ctrl->info->size)) < 0)
|
||||||
goto out;
|
goto out;
|
||||||
v4l2_ctrl->maximum = uvc_get_le_value(data, mapping);
|
v4l2_ctrl->maximum = mapping->get(mapping, GET_MAX, data);
|
||||||
}
|
}
|
||||||
if (ctrl->info->flags & UVC_CONTROL_GET_RES) {
|
if (ctrl->info->flags & UVC_CONTROL_GET_RES) {
|
||||||
if ((ret = uvc_query_ctrl(video->dev, GET_RES, ctrl->entity->id,
|
if ((ret = uvc_query_ctrl(video->dev, GET_RES, ctrl->entity->id,
|
||||||
video->dev->intfnum, ctrl->info->selector,
|
video->dev->intfnum, ctrl->info->selector,
|
||||||
data, ctrl->info->size)) < 0)
|
data, ctrl->info->size)) < 0)
|
||||||
goto out;
|
goto out;
|
||||||
v4l2_ctrl->step = uvc_get_le_value(data, mapping);
|
v4l2_ctrl->step = mapping->get(mapping, GET_RES, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = 0;
|
ret = 0;
|
||||||
|
@ -938,8 +985,8 @@ int uvc_ctrl_get(struct uvc_video_device *video,
|
||||||
ctrl->loaded = 1;
|
ctrl->loaded = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
xctrl->value = uvc_get_le_value(
|
xctrl->value = mapping->get(mapping, GET_CUR,
|
||||||
uvc_ctrl_data(ctrl, UVC_CTRL_DATA_CURRENT), mapping);
|
uvc_ctrl_data(ctrl, UVC_CTRL_DATA_CURRENT));
|
||||||
|
|
||||||
if (mapping->v4l2_type == V4L2_CTRL_TYPE_MENU) {
|
if (mapping->v4l2_type == V4L2_CTRL_TYPE_MENU) {
|
||||||
menu = mapping->menu_info;
|
menu = mapping->menu_info;
|
||||||
|
@ -995,8 +1042,8 @@ int uvc_ctrl_set(struct uvc_video_device *video,
|
||||||
ctrl->info->size);
|
ctrl->info->size);
|
||||||
}
|
}
|
||||||
|
|
||||||
uvc_set_le_value(value,
|
mapping->set(mapping, value,
|
||||||
uvc_ctrl_data(ctrl, UVC_CTRL_DATA_CURRENT), mapping);
|
uvc_ctrl_data(ctrl, UVC_CTRL_DATA_CURRENT));
|
||||||
|
|
||||||
ctrl->dirty = 1;
|
ctrl->dirty = 1;
|
||||||
ctrl->modified = 1;
|
ctrl->modified = 1;
|
||||||
|
@ -1272,6 +1319,11 @@ int uvc_ctrl_add_mapping(struct uvc_control_mapping *mapping)
|
||||||
struct uvc_control_mapping *map;
|
struct uvc_control_mapping *map;
|
||||||
int ret = -EINVAL;
|
int ret = -EINVAL;
|
||||||
|
|
||||||
|
if (mapping->get == NULL)
|
||||||
|
mapping->get = uvc_get_le_value;
|
||||||
|
if (mapping->set == NULL)
|
||||||
|
mapping->set = uvc_set_le_value;
|
||||||
|
|
||||||
if (mapping->id & ~V4L2_CTRL_ID_MASK) {
|
if (mapping->id & ~V4L2_CTRL_ID_MASK) {
|
||||||
uvc_trace(UVC_TRACE_CONTROL, "Can't add mapping '%s' with "
|
uvc_trace(UVC_TRACE_CONTROL, "Can't add mapping '%s' with "
|
||||||
"invalid control id 0x%08x\n", mapping->name,
|
"invalid control id 0x%08x\n", mapping->name,
|
||||||
|
|
|
@ -914,7 +914,7 @@ static int uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg)
|
||||||
if (!capable(CAP_SYS_ADMIN))
|
if (!capable(CAP_SYS_ADMIN))
|
||||||
return -EPERM;
|
return -EPERM;
|
||||||
|
|
||||||
info = kmalloc(sizeof *info, GFP_KERNEL);
|
info = kzalloc(sizeof *info, GFP_KERNEL);
|
||||||
if (info == NULL)
|
if (info == NULL)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
|
@ -941,7 +941,7 @@ static int uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg)
|
||||||
if (!capable(CAP_SYS_ADMIN))
|
if (!capable(CAP_SYS_ADMIN))
|
||||||
return -EPERM;
|
return -EPERM;
|
||||||
|
|
||||||
map = kmalloc(sizeof *map, GFP_KERNEL);
|
map = kzalloc(sizeof *map, GFP_KERNEL);
|
||||||
if (map == NULL)
|
if (map == NULL)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
|
|
|
@ -384,6 +384,11 @@ struct uvc_control_mapping {
|
||||||
|
|
||||||
struct uvc_menu_info *menu_info;
|
struct uvc_menu_info *menu_info;
|
||||||
__u32 menu_count;
|
__u32 menu_count;
|
||||||
|
|
||||||
|
__s32 (*get) (struct uvc_control_mapping *mapping, __u8 query,
|
||||||
|
const __u8 *data);
|
||||||
|
void (*set) (struct uvc_control_mapping *mapping, __s32 value,
|
||||||
|
__u8 *data);
|
||||||
};
|
};
|
||||||
|
|
||||||
struct uvc_control {
|
struct uvc_control {
|
||||||
|
|
Loading…
Reference in New Issue