diff options
author | Laurent Pinchart <laurent.pinchart@skynet.be> | 2008-12-16 04:46:32 -0500 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab@redhat.com> | 2008-12-30 06:39:11 -0500 |
commit | 9768352ac1f9cc3aae675adb299452bd28a54734 (patch) | |
tree | eac3d5caefbcccae4b6cdb877aa86b581ea1e7ba /drivers/media/video/uvc/uvc_ctrl.c | |
parent | 6df126f834c7f6972528cba43604ce0c97329886 (diff) |
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>
Diffstat (limited to 'drivers/media/video/uvc/uvc_ctrl.c')
-rw-r--r-- | drivers/media/video/uvc/uvc_ctrl.c | 76 |
1 files changed, 64 insertions, 12 deletions
diff --git a/drivers/media/video/uvc/uvc_ctrl.c b/drivers/media/video/uvc/uvc_ctrl.c index 335cb00e595b..2208165aa6f0 100644 --- a/drivers/media/video/uvc/uvc_ctrl.c +++ b/drivers/media/video/uvc/uvc_ctrl.c | |||
@@ -327,6 +327,31 @@ static struct uvc_menu_info exposure_auto_controls[] = { | |||
327 | { 8, "Aperture Priority Mode" }, | 327 | { 8, "Aperture Priority Mode" }, |
328 | }; | 328 | }; |
329 | 329 | ||
330 | static __s32 uvc_ctrl_get_zoom(struct uvc_control_mapping *mapping, | ||
331 | __u8 query, const __u8 *data) | ||
332 | { | ||
333 | __s8 zoom = (__s8)data[0]; | ||
334 | |||
335 | switch (query) { | ||
336 | case GET_CUR: | ||
337 | return (zoom == 0) ? 0 : (zoom > 0 ? data[2] : -data[2]); | ||
338 | |||
339 | case GET_MIN: | ||
340 | case GET_MAX: | ||
341 | case GET_RES: | ||
342 | case GET_DEF: | ||
343 | default: | ||
344 | return data[2]; | ||
345 | } | ||
346 | } | ||
347 | |||
348 | static void uvc_ctrl_set_zoom(struct uvc_control_mapping *mapping, | ||
349 | __s32 value, __u8 *data) | ||
350 | { | ||
351 | data[0] = value == 0 ? 0 : (value > 0) ? 1 : 0xff; | ||
352 | data[2] = min(abs(value), 0xff); | ||
353 | } | ||
354 | |||
330 | static struct uvc_control_mapping uvc_ctrl_mappings[] = { | 355 | static struct uvc_control_mapping uvc_ctrl_mappings[] = { |
331 | { | 356 | { |
332 | .id = V4L2_CID_BRIGHTNESS, | 357 | .id = V4L2_CID_BRIGHTNESS, |
@@ -533,6 +558,28 @@ static struct uvc_control_mapping uvc_ctrl_mappings[] = { | |||
533 | .data_type = UVC_CTRL_DATA_TYPE_BOOLEAN, | 558 | .data_type = UVC_CTRL_DATA_TYPE_BOOLEAN, |
534 | }, | 559 | }, |
535 | { | 560 | { |
561 | .id = V4L2_CID_ZOOM_ABSOLUTE, | ||
562 | .name = "Zoom, Absolute", | ||
563 | .entity = UVC_GUID_UVC_CAMERA, | ||
564 | .selector = CT_ZOOM_ABSOLUTE_CONTROL, | ||
565 | .size = 16, | ||
566 | .offset = 0, | ||
567 | .v4l2_type = V4L2_CTRL_TYPE_INTEGER, | ||
568 | .data_type = UVC_CTRL_DATA_TYPE_UNSIGNED, | ||
569 | }, | ||
570 | { | ||
571 | .id = V4L2_CID_ZOOM_CONTINUOUS, | ||
572 | .name = "Zoom, Continuous", | ||
573 | .entity = UVC_GUID_UVC_CAMERA, | ||
574 | .selector = CT_ZOOM_RELATIVE_CONTROL, | ||
575 | .size = 0, | ||
576 | .offset = 0, | ||
577 | .v4l2_type = V4L2_CTRL_TYPE_INTEGER, | ||
578 | .data_type = UVC_CTRL_DATA_TYPE_SIGNED, | ||
579 | .get = uvc_ctrl_get_zoom, | ||
580 | .set = uvc_ctrl_set_zoom, | ||
581 | }, | ||
582 | { | ||
536 | .id = V4L2_CID_PRIVACY, | 583 | .id = V4L2_CID_PRIVACY, |
537 | .name = "Privacy", | 584 | .name = "Privacy", |
538 | .entity = UVC_GUID_UVC_CAMERA, | 585 | .entity = UVC_GUID_UVC_CAMERA, |
@@ -568,8 +615,8 @@ static inline void uvc_clear_bit(__u8 *data, int bit) | |||
568 | * a signed 32bit integer. Sign extension will be performed if the mapping | 615 | * a signed 32bit integer. Sign extension will be performed if the mapping |
569 | * references a signed data type. | 616 | * references a signed data type. |
570 | */ | 617 | */ |
571 | static __s32 uvc_get_le_value(const __u8 *data, | 618 | static __s32 uvc_get_le_value(struct uvc_control_mapping *mapping, |
572 | struct uvc_control_mapping *mapping) | 619 | __u8 query, const __u8 *data) |
573 | { | 620 | { |
574 | int bits = mapping->size; | 621 | int bits = mapping->size; |
575 | int offset = mapping->offset; | 622 | int offset = mapping->offset; |
@@ -598,8 +645,8 @@ static __s32 uvc_get_le_value(const __u8 *data, | |||
598 | /* Set the bit string specified by mapping->offset and mapping->size | 645 | /* Set the bit string specified by mapping->offset and mapping->size |
599 | * in the little-endian data stored at 'data' to the value 'value'. | 646 | * in the little-endian data stored at 'data' to the value 'value'. |
600 | */ | 647 | */ |
601 | static void uvc_set_le_value(__s32 value, __u8 *data, | 648 | static void uvc_set_le_value(struct uvc_control_mapping *mapping, |
602 | struct uvc_control_mapping *mapping) | 649 | __s32 value, __u8 *data) |
603 | { | 650 | { |
604 | int bits = mapping->size; | 651 | int bits = mapping->size; |
605 | int offset = mapping->offset; | 652 | int offset = mapping->offset; |
@@ -751,7 +798,7 @@ int uvc_query_v4l2_ctrl(struct uvc_video_device *video, | |||
751 | video->dev->intfnum, ctrl->info->selector, | 798 | video->dev->intfnum, ctrl->info->selector, |
752 | data, ctrl->info->size)) < 0) | 799 | data, ctrl->info->size)) < 0) |
753 | goto out; | 800 | goto out; |
754 | v4l2_ctrl->default_value = uvc_get_le_value(data, mapping); | 801 | v4l2_ctrl->default_value = mapping->get(mapping, GET_DEF, data); |
755 | } | 802 | } |
756 | 803 | ||
757 | switch (mapping->v4l2_type) { | 804 | switch (mapping->v4l2_type) { |
@@ -787,21 +834,21 @@ int uvc_query_v4l2_ctrl(struct uvc_video_device *video, | |||
787 | video->dev->intfnum, ctrl->info->selector, | 834 | video->dev->intfnum, ctrl->info->selector, |
788 | data, ctrl->info->size)) < 0) | 835 | data, ctrl->info->size)) < 0) |
789 | goto out; | 836 | goto out; |
790 | v4l2_ctrl->minimum = uvc_get_le_value(data, mapping); | 837 | v4l2_ctrl->minimum = mapping->get(mapping, GET_MIN, data); |
791 | } | 838 | } |
792 | if (ctrl->info->flags & UVC_CONTROL_GET_MAX) { | 839 | if (ctrl->info->flags & UVC_CONTROL_GET_MAX) { |
793 | if ((ret = uvc_query_ctrl(video->dev, GET_MAX, ctrl->entity->id, | 840 | if ((ret = uvc_query_ctrl(video->dev, GET_MAX, ctrl->entity->id, |
794 | video->dev->intfnum, ctrl->info->selector, | 841 | video->dev->intfnum, ctrl->info->selector, |
795 | data, ctrl->info->size)) < 0) | 842 | data, ctrl->info->size)) < 0) |
796 | goto out; | 843 | goto out; |
797 | v4l2_ctrl->maximum = uvc_get_le_value(data, mapping); | 844 | v4l2_ctrl->maximum = mapping->get(mapping, GET_MAX, data); |
798 | } | 845 | } |
799 | if (ctrl->info->flags & UVC_CONTROL_GET_RES) { | 846 | if (ctrl->info->flags & UVC_CONTROL_GET_RES) { |
800 | if ((ret = uvc_query_ctrl(video->dev, GET_RES, ctrl->entity->id, | 847 | if ((ret = uvc_query_ctrl(video->dev, GET_RES, ctrl->entity->id, |
801 | video->dev->intfnum, ctrl->info->selector, | 848 | video->dev->intfnum, ctrl->info->selector, |
802 | data, ctrl->info->size)) < 0) | 849 | data, ctrl->info->size)) < 0) |
803 | goto out; | 850 | goto out; |
804 | v4l2_ctrl->step = uvc_get_le_value(data, mapping); | 851 | v4l2_ctrl->step = mapping->get(mapping, GET_RES, data); |
805 | } | 852 | } |
806 | 853 | ||
807 | ret = 0; | 854 | ret = 0; |
@@ -938,8 +985,8 @@ int uvc_ctrl_get(struct uvc_video_device *video, | |||
938 | ctrl->loaded = 1; | 985 | ctrl->loaded = 1; |
939 | } | 986 | } |
940 | 987 | ||
941 | xctrl->value = uvc_get_le_value( | 988 | xctrl->value = mapping->get(mapping, GET_CUR, |
942 | uvc_ctrl_data(ctrl, UVC_CTRL_DATA_CURRENT), mapping); | 989 | uvc_ctrl_data(ctrl, UVC_CTRL_DATA_CURRENT)); |
943 | 990 | ||
944 | if (mapping->v4l2_type == V4L2_CTRL_TYPE_MENU) { | 991 | if (mapping->v4l2_type == V4L2_CTRL_TYPE_MENU) { |
945 | menu = mapping->menu_info; | 992 | menu = mapping->menu_info; |
@@ -995,8 +1042,8 @@ int uvc_ctrl_set(struct uvc_video_device *video, | |||
995 | ctrl->info->size); | 1042 | ctrl->info->size); |
996 | } | 1043 | } |
997 | 1044 | ||
998 | uvc_set_le_value(value, | 1045 | mapping->set(mapping, value, |
999 | uvc_ctrl_data(ctrl, UVC_CTRL_DATA_CURRENT), mapping); | 1046 | uvc_ctrl_data(ctrl, UVC_CTRL_DATA_CURRENT)); |
1000 | 1047 | ||
1001 | ctrl->dirty = 1; | 1048 | ctrl->dirty = 1; |
1002 | ctrl->modified = 1; | 1049 | ctrl->modified = 1; |
@@ -1272,6 +1319,11 @@ int uvc_ctrl_add_mapping(struct uvc_control_mapping *mapping) | |||
1272 | struct uvc_control_mapping *map; | 1319 | struct uvc_control_mapping *map; |
1273 | int ret = -EINVAL; | 1320 | int ret = -EINVAL; |
1274 | 1321 | ||
1322 | if (mapping->get == NULL) | ||
1323 | mapping->get = uvc_get_le_value; | ||
1324 | if (mapping->set == NULL) | ||
1325 | mapping->set = uvc_set_le_value; | ||
1326 | |||
1275 | if (mapping->id & ~V4L2_CTRL_ID_MASK) { | 1327 | if (mapping->id & ~V4L2_CTRL_ID_MASK) { |
1276 | uvc_trace(UVC_TRACE_CONTROL, "Can't add mapping '%s' with " | 1328 | uvc_trace(UVC_TRACE_CONTROL, "Can't add mapping '%s' with " |
1277 | "invalid control id 0x%08x\n", mapping->name, | 1329 | "invalid control id 0x%08x\n", mapping->name, |