| From: Martin Rubli <martin_rubli@logitech.com> |
| Date: Wed, 19 May 2010 22:51:56 +0000 (+0200) |
| Subject: uvcvideo: Add support for absolute pan/tilt controls |
| X-Git-Url: http://git.linuxtv.org/pinchartl/uvcvideo.git?a=commitdiff_plain;h=d3c2f664ec76aff14c3841c99e84cd78d7227f79 |
| |
| uvcvideo: Add support for absolute pan/tilt controls |
| |
| Signed-off-by: Martin Rubli <martin_rubli@logitech.com> |
| |
| |
| diff --git a/drivers/media/video/uvc/uvc_ctrl.c b/drivers/media/video/uvc/uvc_ctrl.c |
| index aa0720a..5ec2f4a 100644 |
| |
| |
| @@ -606,6 +606,26 @@ static struct uvc_control_mapping uvc_ctrl_mappings[] = { |
| .set = uvc_ctrl_set_zoom, |
| }, |
| { |
| + .id = V4L2_CID_PAN_ABSOLUTE, |
| + .name = "Pan (Absolute)", |
| + .entity = UVC_GUID_UVC_CAMERA, |
| + .selector = UVC_CT_PANTILT_ABSOLUTE_CONTROL, |
| + .size = 32, |
| + .offset = 0, |
| + .v4l2_type = V4L2_CTRL_TYPE_INTEGER, |
| + .data_type = UVC_CTRL_DATA_TYPE_UNSIGNED, |
| + }, |
| + { |
| + .id = V4L2_CID_TILT_ABSOLUTE, |
| + .name = "Tilt (Absolute)", |
| + .entity = UVC_GUID_UVC_CAMERA, |
| + .selector = UVC_CT_PANTILT_ABSOLUTE_CONTROL, |
| + .size = 32, |
| + .offset = 32, |
| + .v4l2_type = V4L2_CTRL_TYPE_INTEGER, |
| + .data_type = UVC_CTRL_DATA_TYPE_UNSIGNED, |
| + }, |
| + { |
| .id = V4L2_CID_PRIVACY, |
| .name = "Privacy", |
| .entity = UVC_GUID_UVC_CAMERA, |
| From: Hans de Goede <hdegoede@redhat.com> |
| Date: Wed, 19 May 2010 23:15:00 +0000 (+0200) |
| Subject: uvcvideo: Make button controls work properly |
| X-Git-Url: http://git.linuxtv.org/pinchartl/uvcvideo.git?a=commitdiff_plain;h=2bd47ad4894bfaf1a97660b821cbc46439a614d6 |
| |
| uvcvideo: Make button controls work properly |
| |
| According to the v4l2 spec, writing any value to a button control should |
| result in the action belonging to the button control being triggered. |
| UVC cams however want to see a 1 written, this patch fixes this by |
| overriding whatever value user space passed in with -1 (0xffffffff) when |
| the control is a button control. |
| |
| Signed-off-by: Hans de Goede <hdegoede@redhat.com> |
| |
| |
| diff --git a/drivers/media/video/uvc/uvc_ctrl.c b/drivers/media/video/uvc/uvc_ctrl.c |
| index 5ec2f4a..8bb825d 100644 |
| |
| |
| @@ -698,6 +698,14 @@ static void uvc_set_le_value(struct uvc_control_mapping *mapping, |
| int offset = mapping->offset; |
| __u8 mask; |
| |
| + /* According to the v4l2 spec, writing any value to a button control |
| + * should result in the action belonging to the button control being |
| + * triggered. UVC devices however want to see a 1 written -> override |
| + * value. |
| + */ |
| + if (mapping->v4l2_type == V4L2_CTRL_TYPE_BUTTON) |
| + value = -1; |
| + |
| data += offset / 8; |
| offset &= 7; |
| |
| From: Laurent Pinchart <laurent.pinchart@ideasonboard.com> |
| Date: Thu, 18 Feb 2010 19:38:52 +0000 (+0100) |
| Subject: uvcvideo: Support menu controls in the control mapping API |
| X-Git-Url: http://git.linuxtv.org/pinchartl/uvcvideo.git?a=commitdiff_plain;h=4930f2662e47d33e5baedac620da401a225bc3a8 |
| |
| 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> |
| |
| |
| diff --git a/drivers/media/video/uvc/uvc_ctrl.c b/drivers/media/video/uvc/uvc_ctrl.c |
| index 8bb825d..c88d72e 100644 |
| |
| |
| @@ -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) |
| { |
| 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 838b56f..34818c1 100644 |
| |
| |
| @@ -2261,6 +2261,7 @@ static int __init uvc_init(void) |
| static void __exit uvc_cleanup(void) |
| { |
| usb_deregister(&uvc_driver.driver); |
| + uvc_ctrl_cleanup(); |
| } |
| |
| module_init(uvc_init); |
| diff --git a/drivers/media/video/uvc/uvc_v4l2.c b/drivers/media/video/uvc/uvc_v4l2.c |
| index 7c9ab29..485a899 100644 |
| |
| |
| @@ -29,6 +29,71 @@ |
| #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 |
| */ |
| |
| @@ -974,7 +1039,8 @@ static long uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg) |
| info->flags = xinfo->flags; |
| |
| 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); |
| if (ret < 0) |
| @@ -982,32 +1048,12 @@ static long uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg) |
| break; |
| } |
| |
| + case UVCIOC_CTRL_MAP_OLD: |
| case UVCIOC_CTRL_MAP: |
| - { |
| - struct uvc_xu_control_mapping *xmap = arg; |
| - struct uvc_control_mapping *map; |
| - |
| if (!capable(CAP_SYS_ADMIN)) |
| return -EPERM; |
| |
| - 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; |
| - |
| - ret = uvc_ctrl_add_mapping(map); |
| - if (ret < 0) |
| - kfree(map); |
| - break; |
| - } |
| + return uvc_ioctl_ctrl_map(arg, cmd == UVCIOC_CTRL_MAP_OLD); |
| |
| case UVCIOC_CTRL_GET: |
| 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 d1f8840..14f77e4 100644 |
| |
| |
| @@ -27,6 +27,8 @@ |
| #define UVC_CONTROL_RESTORE (1 << 6) |
| /* Control can be updated by the camera. */ |
| #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 | \ |
| UVC_CONTROL_GET_MAX | UVC_CONTROL_GET_RES | \ |
| @@ -40,6 +42,15 @@ struct uvc_xu_control_info { |
| __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 { |
| __u32 id; |
| __u8 name[32]; |
| @@ -50,6 +61,11 @@ struct uvc_xu_control_mapping { |
| __u8 offset; |
| enum v4l2_ctrl_type v4l2_type; |
| __u32 data_type; |
| + |
| + struct uvc_menu_info __user *menu_info; |
| + __u32 menu_count; |
| + |
| + __u32 reserved[4]; |
| }; |
| |
| 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_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_GET _IOWR('U', 3, 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; |
| }; |
| |
| -struct uvc_menu_info { |
| - __u32 value; |
| - __u8 name[32]; |
| -}; |
| - |
| struct uvc_control_info { |
| struct list_head list; |
| 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 int uvc_ctrl_resume_device(struct uvc_device *dev); |
| 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_commit(struct uvc_video_chain *chain, int rollback); |
| From: Laurent Pinchart <laurent.pinchart@ideasonboard.com> |
| Date: Fri, 25 Jun 2010 07:58:43 +0000 (+0200) |
| Subject: uvcvideo: Add support for Manta MM-353 Plako |
| X-Git-Url: http://git.linuxtv.org/pinchartl/uvcvideo.git?a=commitdiff_plain;h=352e661e1f347390a86cf34bc5e41adbdd1caa41 |
| |
| uvcvideo: Add support for Manta MM-353 Plako |
| |
| The camera requires the PROBE_MINMAX quirk. Add a corresponding entry |
| in the device IDs list |
| |
| Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com> |
| |
| |
| diff --git a/drivers/media/video/uvc/uvc_driver.c b/drivers/media/video/uvc/uvc_driver.c |
| index 34818c1..1a89384 100644 |
| |
| |
| @@ -2174,6 +2174,15 @@ static struct usb_device_id uvc_ids[] = { |
| .bInterfaceSubClass = 1, |
| .bInterfaceProtocol = 0, |
| .driver_info = UVC_QUIRK_PROBE_EXTRAFIELDS }, |
| + /* Manta MM-353 Plako */ |
| + { .match_flags = USB_DEVICE_ID_MATCH_DEVICE |
| + | USB_DEVICE_ID_MATCH_INT_INFO, |
| + .idVendor = 0x18ec, |
| + .idProduct = 0x3188, |
| + .bInterfaceClass = USB_CLASS_VIDEO, |
| + .bInterfaceSubClass = 1, |
| + .bInterfaceProtocol = 0, |
| + .driver_info = UVC_QUIRK_PROBE_MINMAX }, |
| /* FSC WebCam V30S */ |
| { .match_flags = USB_DEVICE_ID_MATCH_DEVICE |
| | USB_DEVICE_ID_MATCH_INT_INFO, |