aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/media/video/uvc
diff options
context:
space:
mode:
authorLaurent Pinchart <laurent.pinchart@ideasonboard.com>2010-02-18 14:38:52 -0500
committerMauro Carvalho Chehab <mchehab@redhat.com>2010-08-02 14:33:39 -0400
commit561474c2d2a1e212ea186e0b65cc69fb330e7bd5 (patch)
treeff01d7c41345625982ec594fe80b85dfb73b0942 /drivers/media/video/uvc
parent3653639e5daf2ac5f4763e4f1b6cb57538184be9 (diff)
V4L/DVB: uvcvideo: Support menu controls in the control mapping API
The UVCIOC_CTRL_MAP ioctl doesn't support menu entries for menu controls. As the uvc_xu_control_mapping structure has no reserved fields, this can't be fixed while keeping ABI compatibility. Modify the UVCIOC_CTRL_MAP ioctl to add menu entries support, and define UVCIOC_CTRL_MAP_OLD that supports the old ABI without any ability to add menu controls. Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com> Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
Diffstat (limited to 'drivers/media/video/uvc')
-rw-r--r--drivers/media/video/uvc/uvc_ctrl.c22
-rw-r--r--drivers/media/video/uvc/uvc_driver.c1
-rw-r--r--drivers/media/video/uvc/uvc_v4l2.c92
-rw-r--r--drivers/media/video/uvc/uvcvideo.h23
4 files changed, 110 insertions, 28 deletions
diff --git a/drivers/media/video/uvc/uvc_ctrl.c b/drivers/media/video/uvc/uvc_ctrl.c
index 4e6d484911fe..bd72100a21dd 100644
--- a/drivers/media/video/uvc/uvc_ctrl.c
+++ b/drivers/media/video/uvc/uvc_ctrl.c
@@ -1606,6 +1606,28 @@ void uvc_ctrl_cleanup_device(struct uvc_device *dev)
1606 } 1606 }
1607} 1607}
1608 1608
1609void uvc_ctrl_cleanup(void)
1610{
1611 struct uvc_control_info *info;
1612 struct uvc_control_info *ni;
1613 struct uvc_control_mapping *mapping;
1614 struct uvc_control_mapping *nm;
1615
1616 list_for_each_entry_safe(info, ni, &uvc_driver.controls, list) {
1617 if (!(info->flags & UVC_CONTROL_EXTENSION))
1618 continue;
1619
1620 list_for_each_entry_safe(mapping, nm, &info->mappings, list) {
1621 list_del(&mapping->list);
1622 kfree(mapping->menu_info);
1623 kfree(mapping);
1624 }
1625
1626 list_del(&info->list);
1627 kfree(info);
1628 }
1629}
1630
1609void uvc_ctrl_init(void) 1631void uvc_ctrl_init(void)
1610{ 1632{
1611 struct uvc_control_info *ctrl = uvc_ctrls; 1633 struct uvc_control_info *ctrl = uvc_ctrls;
diff --git a/drivers/media/video/uvc/uvc_driver.c b/drivers/media/video/uvc/uvc_driver.c
index 45aac1041862..c5258b30777f 100644
--- a/drivers/media/video/uvc/uvc_driver.c
+++ b/drivers/media/video/uvc/uvc_driver.c
@@ -2260,6 +2260,7 @@ static int __init uvc_init(void)
2260static void __exit uvc_cleanup(void) 2260static void __exit uvc_cleanup(void)
2261{ 2261{
2262 usb_deregister(&uvc_driver.driver); 2262 usb_deregister(&uvc_driver.driver);
2263 uvc_ctrl_cleanup();
2263} 2264}
2264 2265
2265module_init(uvc_init); 2266module_init(uvc_init);
diff --git a/drivers/media/video/uvc/uvc_v4l2.c b/drivers/media/video/uvc/uvc_v4l2.c
index 7c9ab2933496..485a89912cef 100644
--- a/drivers/media/video/uvc/uvc_v4l2.c
+++ b/drivers/media/video/uvc/uvc_v4l2.c
@@ -29,6 +29,71 @@
29#include "uvcvideo.h" 29#include "uvcvideo.h"
30 30
31/* ------------------------------------------------------------------------ 31/* ------------------------------------------------------------------------
32 * UVC ioctls
33 */
34static int uvc_ioctl_ctrl_map(struct uvc_xu_control_mapping *xmap, int old)
35{
36 struct uvc_control_mapping *map;
37 unsigned int size;
38 int ret;
39
40 map = kzalloc(sizeof *map, GFP_KERNEL);
41 if (map == NULL)
42 return -ENOMEM;
43
44 map->id = xmap->id;
45 memcpy(map->name, xmap->name, sizeof map->name);
46 memcpy(map->entity, xmap->entity, sizeof map->entity);
47 map->selector = xmap->selector;
48 map->size = xmap->size;
49 map->offset = xmap->offset;
50 map->v4l2_type = xmap->v4l2_type;
51 map->data_type = xmap->data_type;
52
53 switch (xmap->v4l2_type) {
54 case V4L2_CTRL_TYPE_INTEGER:
55 case V4L2_CTRL_TYPE_BOOLEAN:
56 case V4L2_CTRL_TYPE_BUTTON:
57 break;
58
59 case V4L2_CTRL_TYPE_MENU:
60 if (old) {
61 ret = -EINVAL;
62 goto done;
63 }
64
65 size = xmap->menu_count * sizeof(*map->menu_info);
66 map->menu_info = kmalloc(size, GFP_KERNEL);
67 if (map->menu_info == NULL) {
68 ret = -ENOMEM;
69 goto done;
70 }
71
72 if (copy_from_user(map->menu_info, xmap->menu_info, size)) {
73 ret = -EFAULT;
74 goto done;
75 }
76
77 map->menu_count = xmap->menu_count;
78 break;
79
80 default:
81 ret = -EINVAL;
82 goto done;
83 }
84
85 ret = uvc_ctrl_add_mapping(map);
86
87done:
88 if (ret < 0) {
89 kfree(map->menu_info);
90 kfree(map);
91 }
92
93 return ret;
94}
95
96/* ------------------------------------------------------------------------
32 * V4L2 interface 97 * V4L2 interface
33 */ 98 */
34 99
@@ -974,7 +1039,8 @@ static long uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg)
974 info->flags = xinfo->flags; 1039 info->flags = xinfo->flags;
975 1040
976 info->flags |= UVC_CONTROL_GET_MIN | UVC_CONTROL_GET_MAX | 1041 info->flags |= UVC_CONTROL_GET_MIN | UVC_CONTROL_GET_MAX |
977 UVC_CONTROL_GET_RES | UVC_CONTROL_GET_DEF; 1042 UVC_CONTROL_GET_RES | UVC_CONTROL_GET_DEF |
1043 UVC_CONTROL_EXTENSION;
978 1044
979 ret = uvc_ctrl_add_info(info); 1045 ret = uvc_ctrl_add_info(info);
980 if (ret < 0) 1046 if (ret < 0)
@@ -982,32 +1048,12 @@ static long uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg)
982 break; 1048 break;
983 } 1049 }
984 1050
1051 case UVCIOC_CTRL_MAP_OLD:
985 case UVCIOC_CTRL_MAP: 1052 case UVCIOC_CTRL_MAP:
986 {
987 struct uvc_xu_control_mapping *xmap = arg;
988 struct uvc_control_mapping *map;
989
990 if (!capable(CAP_SYS_ADMIN)) 1053 if (!capable(CAP_SYS_ADMIN))
991 return -EPERM; 1054 return -EPERM;
992 1055
993 map = kzalloc(sizeof *map, GFP_KERNEL); 1056 return uvc_ioctl_ctrl_map(arg, cmd == UVCIOC_CTRL_MAP_OLD);
994 if (map == NULL)
995 return -ENOMEM;
996
997 map->id = xmap->id;
998 memcpy(map->name, xmap->name, sizeof map->name);
999 memcpy(map->entity, xmap->entity, sizeof map->entity);
1000 map->selector = xmap->selector;
1001 map->size = xmap->size;
1002 map->offset = xmap->offset;
1003 map->v4l2_type = xmap->v4l2_type;
1004 map->data_type = xmap->data_type;
1005
1006 ret = uvc_ctrl_add_mapping(map);
1007 if (ret < 0)
1008 kfree(map);
1009 break;
1010 }
1011 1057
1012 case UVCIOC_CTRL_GET: 1058 case UVCIOC_CTRL_GET:
1013 return uvc_xu_ctrl_query(chain, arg, 0); 1059 return uvc_xu_ctrl_query(chain, arg, 0);
diff --git a/drivers/media/video/uvc/uvcvideo.h b/drivers/media/video/uvc/uvcvideo.h
index d1f88406a5e7..14f77e42fd45 100644
--- a/drivers/media/video/uvc/uvcvideo.h
+++ b/drivers/media/video/uvc/uvcvideo.h
@@ -27,6 +27,8 @@
27#define UVC_CONTROL_RESTORE (1 << 6) 27#define UVC_CONTROL_RESTORE (1 << 6)
28/* Control can be updated by the camera. */ 28/* Control can be updated by the camera. */
29#define UVC_CONTROL_AUTO_UPDATE (1 << 7) 29#define UVC_CONTROL_AUTO_UPDATE (1 << 7)
30/* Control is an extension unit control. */
31#define UVC_CONTROL_EXTENSION (1 << 8)
30 32
31#define UVC_CONTROL_GET_RANGE (UVC_CONTROL_GET_CUR | UVC_CONTROL_GET_MIN | \ 33#define UVC_CONTROL_GET_RANGE (UVC_CONTROL_GET_CUR | UVC_CONTROL_GET_MIN | \
32 UVC_CONTROL_GET_MAX | UVC_CONTROL_GET_RES | \ 34 UVC_CONTROL_GET_MAX | UVC_CONTROL_GET_RES | \
@@ -40,6 +42,15 @@ struct uvc_xu_control_info {
40 __u32 flags; 42 __u32 flags;
41}; 43};
42 44
45struct uvc_menu_info {
46 __u32 value;
47 __u8 name[32];
48};
49
50struct uvc_xu_control_mapping_old {
51 __u8 reserved[64];
52};
53
43struct uvc_xu_control_mapping { 54struct uvc_xu_control_mapping {
44 __u32 id; 55 __u32 id;
45 __u8 name[32]; 56 __u8 name[32];
@@ -50,6 +61,11 @@ struct uvc_xu_control_mapping {
50 __u8 offset; 61 __u8 offset;
51 enum v4l2_ctrl_type v4l2_type; 62 enum v4l2_ctrl_type v4l2_type;
52 __u32 data_type; 63 __u32 data_type;
64
65 struct uvc_menu_info __user *menu_info;
66 __u32 menu_count;
67
68 __u32 reserved[4];
53}; 69};
54 70
55struct uvc_xu_control { 71struct uvc_xu_control {
@@ -60,6 +76,7 @@ struct uvc_xu_control {
60}; 76};
61 77
62#define UVCIOC_CTRL_ADD _IOW('U', 1, struct uvc_xu_control_info) 78#define UVCIOC_CTRL_ADD _IOW('U', 1, struct uvc_xu_control_info)
79#define UVCIOC_CTRL_MAP_OLD _IOWR('U', 2, struct uvc_xu_control_mapping_old)
63#define UVCIOC_CTRL_MAP _IOWR('U', 2, struct uvc_xu_control_mapping) 80#define UVCIOC_CTRL_MAP _IOWR('U', 2, struct uvc_xu_control_mapping)
64#define UVCIOC_CTRL_GET _IOWR('U', 3, struct uvc_xu_control) 81#define UVCIOC_CTRL_GET _IOWR('U', 3, struct uvc_xu_control)
65#define UVCIOC_CTRL_SET _IOW('U', 4, struct uvc_xu_control) 82#define UVCIOC_CTRL_SET _IOW('U', 4, struct uvc_xu_control)
@@ -198,11 +215,6 @@ struct uvc_streaming_control {
198 __u8 bMaxVersion; 215 __u8 bMaxVersion;
199}; 216};
200 217
201struct uvc_menu_info {
202 __u32 value;
203 __u8 name[32];
204};
205
206struct uvc_control_info { 218struct uvc_control_info {
207 struct list_head list; 219 struct list_head list;
208 struct list_head mappings; 220 struct list_head mappings;
@@ -625,6 +637,7 @@ extern int uvc_ctrl_init_device(struct uvc_device *dev);
625extern void uvc_ctrl_cleanup_device(struct uvc_device *dev); 637extern void uvc_ctrl_cleanup_device(struct uvc_device *dev);
626extern int uvc_ctrl_resume_device(struct uvc_device *dev); 638extern int uvc_ctrl_resume_device(struct uvc_device *dev);
627extern void uvc_ctrl_init(void); 639extern void uvc_ctrl_init(void);
640extern void uvc_ctrl_cleanup(void);
628 641
629extern int uvc_ctrl_begin(struct uvc_video_chain *chain); 642extern int uvc_ctrl_begin(struct uvc_video_chain *chain);
630extern int __uvc_ctrl_commit(struct uvc_video_chain *chain, int rollback); 643extern int __uvc_ctrl_commit(struct uvc_video_chain *chain, int rollback);