mirror of
https://github.com/FEX-Emu/linux.git
synced 2025-02-14 00:13:53 +00:00
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>
This commit is contained in:
parent
3653639e5d
commit
561474c2d2
@ -1606,6 +1606,28 @@ void uvc_ctrl_cleanup_device(struct uvc_device *dev)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void uvc_ctrl_cleanup(void)
|
||||||
|
{
|
||||||
|
struct uvc_control_info *info;
|
||||||
|
struct uvc_control_info *ni;
|
||||||
|
struct uvc_control_mapping *mapping;
|
||||||
|
struct uvc_control_mapping *nm;
|
||||||
|
|
||||||
|
list_for_each_entry_safe(info, ni, &uvc_driver.controls, list) {
|
||||||
|
if (!(info->flags & UVC_CONTROL_EXTENSION))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
list_for_each_entry_safe(mapping, nm, &info->mappings, list) {
|
||||||
|
list_del(&mapping->list);
|
||||||
|
kfree(mapping->menu_info);
|
||||||
|
kfree(mapping);
|
||||||
|
}
|
||||||
|
|
||||||
|
list_del(&info->list);
|
||||||
|
kfree(info);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void uvc_ctrl_init(void)
|
void uvc_ctrl_init(void)
|
||||||
{
|
{
|
||||||
struct uvc_control_info *ctrl = uvc_ctrls;
|
struct uvc_control_info *ctrl = uvc_ctrls;
|
||||||
|
@ -2260,6 +2260,7 @@ static int __init uvc_init(void)
|
|||||||
static void __exit uvc_cleanup(void)
|
static void __exit uvc_cleanup(void)
|
||||||
{
|
{
|
||||||
usb_deregister(&uvc_driver.driver);
|
usb_deregister(&uvc_driver.driver);
|
||||||
|
uvc_ctrl_cleanup();
|
||||||
}
|
}
|
||||||
|
|
||||||
module_init(uvc_init);
|
module_init(uvc_init);
|
||||||
|
@ -28,6 +28,71 @@
|
|||||||
|
|
||||||
#include "uvcvideo.h"
|
#include "uvcvideo.h"
|
||||||
|
|
||||||
|
/* ------------------------------------------------------------------------
|
||||||
|
* UVC ioctls
|
||||||
|
*/
|
||||||
|
static int uvc_ioctl_ctrl_map(struct uvc_xu_control_mapping *xmap, int old)
|
||||||
|
{
|
||||||
|
struct uvc_control_mapping *map;
|
||||||
|
unsigned int size;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
map = kzalloc(sizeof *map, GFP_KERNEL);
|
||||||
|
if (map == NULL)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
map->id = xmap->id;
|
||||||
|
memcpy(map->name, xmap->name, sizeof map->name);
|
||||||
|
memcpy(map->entity, xmap->entity, sizeof map->entity);
|
||||||
|
map->selector = xmap->selector;
|
||||||
|
map->size = xmap->size;
|
||||||
|
map->offset = xmap->offset;
|
||||||
|
map->v4l2_type = xmap->v4l2_type;
|
||||||
|
map->data_type = xmap->data_type;
|
||||||
|
|
||||||
|
switch (xmap->v4l2_type) {
|
||||||
|
case V4L2_CTRL_TYPE_INTEGER:
|
||||||
|
case V4L2_CTRL_TYPE_BOOLEAN:
|
||||||
|
case V4L2_CTRL_TYPE_BUTTON:
|
||||||
|
break;
|
||||||
|
|
||||||
|
case V4L2_CTRL_TYPE_MENU:
|
||||||
|
if (old) {
|
||||||
|
ret = -EINVAL;
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
|
size = xmap->menu_count * sizeof(*map->menu_info);
|
||||||
|
map->menu_info = kmalloc(size, GFP_KERNEL);
|
||||||
|
if (map->menu_info == NULL) {
|
||||||
|
ret = -ENOMEM;
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (copy_from_user(map->menu_info, xmap->menu_info, size)) {
|
||||||
|
ret = -EFAULT;
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
|
map->menu_count = xmap->menu_count;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
ret = -EINVAL;
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = uvc_ctrl_add_mapping(map);
|
||||||
|
|
||||||
|
done:
|
||||||
|
if (ret < 0) {
|
||||||
|
kfree(map->menu_info);
|
||||||
|
kfree(map);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
/* ------------------------------------------------------------------------
|
/* ------------------------------------------------------------------------
|
||||||
* V4L2 interface
|
* V4L2 interface
|
||||||
*/
|
*/
|
||||||
@ -974,7 +1039,8 @@ static long uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg)
|
|||||||
info->flags = xinfo->flags;
|
info->flags = xinfo->flags;
|
||||||
|
|
||||||
info->flags |= UVC_CONTROL_GET_MIN | UVC_CONTROL_GET_MAX |
|
info->flags |= UVC_CONTROL_GET_MIN | UVC_CONTROL_GET_MAX |
|
||||||
UVC_CONTROL_GET_RES | UVC_CONTROL_GET_DEF;
|
UVC_CONTROL_GET_RES | UVC_CONTROL_GET_DEF |
|
||||||
|
UVC_CONTROL_EXTENSION;
|
||||||
|
|
||||||
ret = uvc_ctrl_add_info(info);
|
ret = uvc_ctrl_add_info(info);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
@ -982,32 +1048,12 @@ static long uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case UVCIOC_CTRL_MAP_OLD:
|
||||||
case UVCIOC_CTRL_MAP:
|
case UVCIOC_CTRL_MAP:
|
||||||
{
|
|
||||||
struct uvc_xu_control_mapping *xmap = arg;
|
|
||||||
struct uvc_control_mapping *map;
|
|
||||||
|
|
||||||
if (!capable(CAP_SYS_ADMIN))
|
if (!capable(CAP_SYS_ADMIN))
|
||||||
return -EPERM;
|
return -EPERM;
|
||||||
|
|
||||||
map = kzalloc(sizeof *map, GFP_KERNEL);
|
return uvc_ioctl_ctrl_map(arg, cmd == UVCIOC_CTRL_MAP_OLD);
|
||||||
if (map == NULL)
|
|
||||||
return -ENOMEM;
|
|
||||||
|
|
||||||
map->id = xmap->id;
|
|
||||||
memcpy(map->name, xmap->name, sizeof map->name);
|
|
||||||
memcpy(map->entity, xmap->entity, sizeof map->entity);
|
|
||||||
map->selector = xmap->selector;
|
|
||||||
map->size = xmap->size;
|
|
||||||
map->offset = xmap->offset;
|
|
||||||
map->v4l2_type = xmap->v4l2_type;
|
|
||||||
map->data_type = xmap->data_type;
|
|
||||||
|
|
||||||
ret = uvc_ctrl_add_mapping(map);
|
|
||||||
if (ret < 0)
|
|
||||||
kfree(map);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
case UVCIOC_CTRL_GET:
|
case UVCIOC_CTRL_GET:
|
||||||
return uvc_xu_ctrl_query(chain, arg, 0);
|
return uvc_xu_ctrl_query(chain, arg, 0);
|
||||||
|
@ -27,6 +27,8 @@
|
|||||||
#define UVC_CONTROL_RESTORE (1 << 6)
|
#define UVC_CONTROL_RESTORE (1 << 6)
|
||||||
/* Control can be updated by the camera. */
|
/* Control can be updated by the camera. */
|
||||||
#define UVC_CONTROL_AUTO_UPDATE (1 << 7)
|
#define UVC_CONTROL_AUTO_UPDATE (1 << 7)
|
||||||
|
/* Control is an extension unit control. */
|
||||||
|
#define UVC_CONTROL_EXTENSION (1 << 8)
|
||||||
|
|
||||||
#define UVC_CONTROL_GET_RANGE (UVC_CONTROL_GET_CUR | UVC_CONTROL_GET_MIN | \
|
#define UVC_CONTROL_GET_RANGE (UVC_CONTROL_GET_CUR | UVC_CONTROL_GET_MIN | \
|
||||||
UVC_CONTROL_GET_MAX | UVC_CONTROL_GET_RES | \
|
UVC_CONTROL_GET_MAX | UVC_CONTROL_GET_RES | \
|
||||||
@ -40,6 +42,15 @@ struct uvc_xu_control_info {
|
|||||||
__u32 flags;
|
__u32 flags;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct uvc_menu_info {
|
||||||
|
__u32 value;
|
||||||
|
__u8 name[32];
|
||||||
|
};
|
||||||
|
|
||||||
|
struct uvc_xu_control_mapping_old {
|
||||||
|
__u8 reserved[64];
|
||||||
|
};
|
||||||
|
|
||||||
struct uvc_xu_control_mapping {
|
struct uvc_xu_control_mapping {
|
||||||
__u32 id;
|
__u32 id;
|
||||||
__u8 name[32];
|
__u8 name[32];
|
||||||
@ -50,6 +61,11 @@ struct uvc_xu_control_mapping {
|
|||||||
__u8 offset;
|
__u8 offset;
|
||||||
enum v4l2_ctrl_type v4l2_type;
|
enum v4l2_ctrl_type v4l2_type;
|
||||||
__u32 data_type;
|
__u32 data_type;
|
||||||
|
|
||||||
|
struct uvc_menu_info __user *menu_info;
|
||||||
|
__u32 menu_count;
|
||||||
|
|
||||||
|
__u32 reserved[4];
|
||||||
};
|
};
|
||||||
|
|
||||||
struct uvc_xu_control {
|
struct uvc_xu_control {
|
||||||
@ -60,6 +76,7 @@ struct uvc_xu_control {
|
|||||||
};
|
};
|
||||||
|
|
||||||
#define UVCIOC_CTRL_ADD _IOW('U', 1, struct uvc_xu_control_info)
|
#define UVCIOC_CTRL_ADD _IOW('U', 1, struct uvc_xu_control_info)
|
||||||
|
#define UVCIOC_CTRL_MAP_OLD _IOWR('U', 2, struct uvc_xu_control_mapping_old)
|
||||||
#define UVCIOC_CTRL_MAP _IOWR('U', 2, struct uvc_xu_control_mapping)
|
#define UVCIOC_CTRL_MAP _IOWR('U', 2, struct uvc_xu_control_mapping)
|
||||||
#define UVCIOC_CTRL_GET _IOWR('U', 3, struct uvc_xu_control)
|
#define UVCIOC_CTRL_GET _IOWR('U', 3, struct uvc_xu_control)
|
||||||
#define UVCIOC_CTRL_SET _IOW('U', 4, struct uvc_xu_control)
|
#define UVCIOC_CTRL_SET _IOW('U', 4, struct uvc_xu_control)
|
||||||
@ -198,11 +215,6 @@ struct uvc_streaming_control {
|
|||||||
__u8 bMaxVersion;
|
__u8 bMaxVersion;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct uvc_menu_info {
|
|
||||||
__u32 value;
|
|
||||||
__u8 name[32];
|
|
||||||
};
|
|
||||||
|
|
||||||
struct uvc_control_info {
|
struct uvc_control_info {
|
||||||
struct list_head list;
|
struct list_head list;
|
||||||
struct list_head mappings;
|
struct list_head mappings;
|
||||||
@ -625,6 +637,7 @@ extern int uvc_ctrl_init_device(struct uvc_device *dev);
|
|||||||
extern void uvc_ctrl_cleanup_device(struct uvc_device *dev);
|
extern void uvc_ctrl_cleanup_device(struct uvc_device *dev);
|
||||||
extern int uvc_ctrl_resume_device(struct uvc_device *dev);
|
extern int uvc_ctrl_resume_device(struct uvc_device *dev);
|
||||||
extern void uvc_ctrl_init(void);
|
extern void uvc_ctrl_init(void);
|
||||||
|
extern void uvc_ctrl_cleanup(void);
|
||||||
|
|
||||||
extern int uvc_ctrl_begin(struct uvc_video_chain *chain);
|
extern int uvc_ctrl_begin(struct uvc_video_chain *chain);
|
||||||
extern int __uvc_ctrl_commit(struct uvc_video_chain *chain, int rollback);
|
extern int __uvc_ctrl_commit(struct uvc_video_chain *chain, int rollback);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user