aboutsummaryrefslogtreecommitdiff
path: root/drivers/media/video/uvc
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2010-02-26 17:16:20 -0800
committerLinus Torvalds <torvalds@linux-foundation.org>2010-02-26 17:16:20 -0800
commit2b8c70b2174402ca3dec13310ce56597233392d7 (patch)
tree0aed464521a2a671cbb7b4302b55fe72abc95d3d /drivers/media/video/uvc
parent29e1fa3565a7951cc415c634eb2b78dbdbee151d (diff)
parent3621263a4d9679726b7bc1e2546c1c03941a59b4 (diff)
Merge branch 'v4l_for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-2.6
* 'v4l_for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-2.6: (362 commits) V4L-DVB: cx88-dvb: remove extra attribution for core V4L/DVB: v4l: soc_camera: fix bound checking of mbus_fmt[] index V4L/DVB: Add support for SMT7020 to cx88 V4L/DVB: radio-si470x: Use UTF-8 encoding on a comment V4L/DVB: MAINTAINERS: Telegent tlg2300 section fix V4L/DVB: gspca_stv06xx: Add support for camera button V4L/DVB: gspca_ov519: add support for the button on ov511 based cams V4L/DVB: gspca_ov519: Add support for the button on ov518 based cams V4L/DVB: gspca_ov519: add support for the button on ov519 based cams V4L/DVB: gspca_main: Fix a compile error when CONFIG_INPUT is not set V4L/DVB: gspca_main: some input error handling fixes V4L/DVB: gspca_main: Allow use of input device creation code for non int. inputs V4L/DVB: gspca_pac7302: much improved exposure control V4L/DVB: gspca_sonixb: Make sonixb driver handle pas106 and pas202 cameras V4L/DVB: gspca_sonixb: pas106: fixup bright ctrl and add gain and exposure ctrls V4L/DVB: Documentation: gspca.txt: update known mr97310a cams V4L/DVB: gspca_mr97310a: add support for the Sakar 1638x CyberPix V4L/DVB: gscpa_sonixb: limit ov7630 max framerate at 640x480 V4L/DVB: gspca_sonixb: pas202: fixup brightness ctrl and add gain and exposure ctrls V4L/DVB: gscpa_sonixb: Differentiate between sensors with a coarse and fine expo ctrl ...
Diffstat (limited to 'drivers/media/video/uvc')
-rw-r--r--drivers/media/video/uvc/uvc_ctrl.c242
-rw-r--r--drivers/media/video/uvc/uvc_driver.c74
-rw-r--r--drivers/media/video/uvc/uvc_queue.c1
-rw-r--r--drivers/media/video/uvc/uvc_v4l2.c4
-rw-r--r--drivers/media/video/uvc/uvc_video.c10
-rw-r--r--drivers/media/video/uvc/uvcvideo.h19
6 files changed, 224 insertions, 126 deletions
diff --git a/drivers/media/video/uvc/uvc_ctrl.c b/drivers/media/video/uvc/uvc_ctrl.c
index ec8ef8c5560..3b2e7800d56 100644
--- a/drivers/media/video/uvc/uvc_ctrl.c
+++ b/drivers/media/video/uvc/uvc_ctrl.c
@@ -23,9 +23,13 @@
#include "uvcvideo.h"
-#define UVC_CTRL_NDATA 2
#define UVC_CTRL_DATA_CURRENT 0
#define UVC_CTRL_DATA_BACKUP 1
+#define UVC_CTRL_DATA_MIN 2
+#define UVC_CTRL_DATA_MAX 3
+#define UVC_CTRL_DATA_RES 4
+#define UVC_CTRL_DATA_DEF 5
+#define UVC_CTRL_DATA_LAST 6
/* ------------------------------------------------------------------------
* Controls
@@ -755,6 +759,49 @@ struct uvc_control *uvc_find_control(struct uvc_video_chain *chain,
return ctrl;
}
+static int uvc_ctrl_populate_cache(struct uvc_video_chain *chain,
+ struct uvc_control *ctrl)
+{
+ int ret;
+
+ if (ctrl->info->flags & UVC_CONTROL_GET_DEF) {
+ ret = uvc_query_ctrl(chain->dev, UVC_GET_DEF, ctrl->entity->id,
+ chain->dev->intfnum, ctrl->info->selector,
+ uvc_ctrl_data(ctrl, UVC_CTRL_DATA_DEF),
+ ctrl->info->size);
+ if (ret < 0)
+ return ret;
+ }
+
+ if (ctrl->info->flags & UVC_CONTROL_GET_MIN) {
+ ret = uvc_query_ctrl(chain->dev, UVC_GET_MIN, ctrl->entity->id,
+ chain->dev->intfnum, ctrl->info->selector,
+ uvc_ctrl_data(ctrl, UVC_CTRL_DATA_MIN),
+ ctrl->info->size);
+ if (ret < 0)
+ return ret;
+ }
+ if (ctrl->info->flags & UVC_CONTROL_GET_MAX) {
+ ret = uvc_query_ctrl(chain->dev, UVC_GET_MAX, ctrl->entity->id,
+ chain->dev->intfnum, ctrl->info->selector,
+ uvc_ctrl_data(ctrl, UVC_CTRL_DATA_MAX),
+ ctrl->info->size);
+ if (ret < 0)
+ return ret;
+ }
+ if (ctrl->info->flags & UVC_CONTROL_GET_RES) {
+ ret = uvc_query_ctrl(chain->dev, UVC_GET_RES, ctrl->entity->id,
+ chain->dev->intfnum, ctrl->info->selector,
+ uvc_ctrl_data(ctrl, UVC_CTRL_DATA_RES),
+ ctrl->info->size);
+ if (ret < 0)
+ return ret;
+ }
+
+ ctrl->cached = 1;
+ return 0;
+}
+
int uvc_query_v4l2_ctrl(struct uvc_video_chain *chain,
struct v4l2_queryctrl *v4l2_ctrl)
{
@@ -762,17 +809,12 @@ int uvc_query_v4l2_ctrl(struct uvc_video_chain *chain,
struct uvc_control_mapping *mapping;
struct uvc_menu_info *menu;
unsigned int i;
- __u8 *data;
int ret;
ctrl = uvc_find_control(chain, v4l2_ctrl->id, &mapping);
if (ctrl == NULL)
return -EINVAL;
- data = kmalloc(ctrl->info->size, GFP_KERNEL);
- if (data == NULL)
- return -ENOMEM;
-
memset(v4l2_ctrl, 0, sizeof *v4l2_ctrl);
v4l2_ctrl->id = mapping->id;
v4l2_ctrl->type = mapping->v4l2_type;
@@ -782,14 +824,15 @@ int uvc_query_v4l2_ctrl(struct uvc_video_chain *chain,
if (!(ctrl->info->flags & UVC_CONTROL_SET_CUR))
v4l2_ctrl->flags |= V4L2_CTRL_FLAG_READ_ONLY;
- if (ctrl->info->flags & UVC_CONTROL_GET_DEF) {
- ret = uvc_query_ctrl(chain->dev, UVC_GET_DEF, ctrl->entity->id,
- chain->dev->intfnum, ctrl->info->selector,
- data, ctrl->info->size);
+ if (!ctrl->cached) {
+ ret = uvc_ctrl_populate_cache(chain, ctrl);
if (ret < 0)
- goto out;
- v4l2_ctrl->default_value =
- mapping->get(mapping, UVC_GET_DEF, data);
+ return ret;
+ }
+
+ if (ctrl->info->flags & UVC_CONTROL_GET_DEF) {
+ v4l2_ctrl->default_value = mapping->get(mapping, UVC_GET_DEF,
+ uvc_ctrl_data(ctrl, UVC_CTRL_DATA_DEF));
}
switch (mapping->v4l2_type) {
@@ -806,56 +849,37 @@ int uvc_query_v4l2_ctrl(struct uvc_video_chain *chain,
}
}
- ret = 0;
- goto out;
+ return 0;
case V4L2_CTRL_TYPE_BOOLEAN:
v4l2_ctrl->minimum = 0;
v4l2_ctrl->maximum = 1;
v4l2_ctrl->step = 1;
- ret = 0;
- goto out;
+ return 0;
case V4L2_CTRL_TYPE_BUTTON:
v4l2_ctrl->minimum = 0;
v4l2_ctrl->maximum = 0;
v4l2_ctrl->step = 0;
- ret = 0;
- goto out;
+ return 0;
default:
break;
}
- if (ctrl->info->flags & UVC_CONTROL_GET_MIN) {
- ret = uvc_query_ctrl(chain->dev, UVC_GET_MIN, ctrl->entity->id,
- chain->dev->intfnum, ctrl->info->selector,
- data, ctrl->info->size);
- if (ret < 0)
- goto out;
- v4l2_ctrl->minimum = mapping->get(mapping, UVC_GET_MIN, data);
- }
- if (ctrl->info->flags & UVC_CONTROL_GET_MAX) {
- ret = uvc_query_ctrl(chain->dev, UVC_GET_MAX, ctrl->entity->id,
- chain->dev->intfnum, ctrl->info->selector,
- data, ctrl->info->size);
- if (ret < 0)
- goto out;
- v4l2_ctrl->maximum = mapping->get(mapping, UVC_GET_MAX, data);
- }
- if (ctrl->info->flags & UVC_CONTROL_GET_RES) {
- ret = uvc_query_ctrl(chain->dev, UVC_GET_RES, ctrl->entity->id,
- chain->dev->intfnum, ctrl->info->selector,
- data, ctrl->info->size);
- if (ret < 0)
- goto out;
- v4l2_ctrl->step = mapping->get(mapping, UVC_GET_RES, data);
- }
+ if (ctrl->info->flags & UVC_CONTROL_GET_MIN)
+ v4l2_ctrl->minimum = mapping->get(mapping, UVC_GET_MIN,
+ uvc_ctrl_data(ctrl, UVC_CTRL_DATA_MIN));
- ret = 0;
-out:
- kfree(data);
- return ret;
+ if (ctrl->info->flags & UVC_CONTROL_GET_MAX)
+ v4l2_ctrl->maximum = mapping->get(mapping, UVC_GET_MAX,
+ uvc_ctrl_data(ctrl, UVC_CTRL_DATA_MAX));
+
+ if (ctrl->info->flags & UVC_CONTROL_GET_RES)
+ v4l2_ctrl->step = mapping->get(mapping, UVC_GET_RES,
+ uvc_ctrl_data(ctrl, UVC_CTRL_DATA_RES));
+
+ return 0;
}
@@ -997,19 +1021,57 @@ int uvc_ctrl_set(struct uvc_video_chain *chain,
{
struct uvc_control *ctrl;
struct uvc_control_mapping *mapping;
- s32 value = xctrl->value;
+ s32 value;
+ u32 step;
+ s32 min;
+ s32 max;
int ret;
ctrl = uvc_find_control(chain, xctrl->id, &mapping);
if (ctrl == NULL || (ctrl->info->flags & UVC_CONTROL_SET_CUR) == 0)
return -EINVAL;
- if (mapping->v4l2_type == V4L2_CTRL_TYPE_MENU) {
- if (value < 0 || value >= mapping->menu_count)
- return -EINVAL;
- value = mapping->menu_info[value].value;
+ /* Clamp out of range values. */
+ switch (mapping->v4l2_type) {
+ case V4L2_CTRL_TYPE_INTEGER:
+ if (!ctrl->cached) {
+ ret = uvc_ctrl_populate_cache(chain, ctrl);
+ if (ret < 0)
+ return ret;
+ }
+
+ min = mapping->get(mapping, UVC_GET_MIN,
+ uvc_ctrl_data(ctrl, UVC_CTRL_DATA_MIN));
+ max = mapping->get(mapping, UVC_GET_MAX,
+ uvc_ctrl_data(ctrl, UVC_CTRL_DATA_MAX));
+ step = mapping->get(mapping, UVC_GET_RES,
+ uvc_ctrl_data(ctrl, UVC_CTRL_DATA_RES));
+
+ xctrl->value = min + (xctrl->value - min + step/2) / step * step;
+ xctrl->value = clamp(xctrl->value, min, max);
+ value = xctrl->value;
+ break;
+
+ case V4L2_CTRL_TYPE_BOOLEAN:
+ xctrl->value = clamp(xctrl->value, 0, 1);
+ value = xctrl->value;
+ break;
+
+ case V4L2_CTRL_TYPE_MENU:
+ if (xctrl->value < 0 || xctrl->value >= mapping->menu_count)
+ return -ERANGE;
+ value = mapping->menu_info[xctrl->value].value;
+ break;
+
+ default:
+ value = xctrl->value;
+ break;
}
+ /* If the mapping doesn't span the whole UVC control, the current value
+ * needs to be loaded from the device to perform the read-modify-write
+ * operation.
+ */
if (!ctrl->loaded && (ctrl->info->size * 8) != mapping->size) {
if ((ctrl->info->flags & UVC_CONTROL_GET_CUR) == 0) {
memset(uvc_ctrl_data(ctrl, UVC_CTRL_DATA_CURRENT),
@@ -1027,6 +1089,7 @@ int uvc_ctrl_set(struct uvc_video_chain *chain,
ctrl->loaded = 1;
}
+ /* Backup the current value in case we need to rollback later. */
if (!ctrl->dirty) {
memcpy(uvc_ctrl_data(ctrl, UVC_CTRL_DATA_BACKUP),
uvc_ctrl_data(ctrl, UVC_CTRL_DATA_CURRENT),
@@ -1080,10 +1143,8 @@ int uvc_xu_ctrl_query(struct uvc_video_chain *chain,
}
if (!found) {
- uvc_trace(UVC_TRACE_CONTROL,
- "Control " UVC_GUID_FORMAT "/%u not found.\n",
- UVC_GUID_ARGS(entity->extension.guidExtensionCode),
- xctrl->selector);
+ uvc_trace(UVC_TRACE_CONTROL, "Control %pUl/%u not found.\n",
+ entity->extension.guidExtensionCode, xctrl->selector);
return -EINVAL;
}
@@ -1159,9 +1220,9 @@ int uvc_ctrl_resume_device(struct uvc_device *dev)
(ctrl->info->flags & UVC_CONTROL_RESTORE) == 0)
continue;
- printk(KERN_INFO "restoring control " UVC_GUID_FORMAT
- "/%u/%u\n", UVC_GUID_ARGS(ctrl->info->entity),
- ctrl->info->index, ctrl->info->selector);
+ printk(KERN_INFO "restoring control %pUl/%u/%u\n",
+ ctrl->info->entity, ctrl->info->index,
+ ctrl->info->selector);
ctrl->dirty = 1;
}
@@ -1215,47 +1276,43 @@ static void uvc_ctrl_add_ctrl(struct uvc_device *dev,
ret = uvc_query_ctrl(dev, UVC_GET_LEN, ctrl->entity->id,
dev->intfnum, info->selector, (__u8 *)&size, 2);
if (ret < 0) {
- uvc_trace(UVC_TRACE_CONTROL, "GET_LEN failed on "
- "control " UVC_GUID_FORMAT "/%u (%d).\n",
- UVC_GUID_ARGS(info->entity), info->selector,
- ret);
+ uvc_trace(UVC_TRACE_CONTROL,
+ "GET_LEN failed on control %pUl/%u (%d).\n",
+ info->entity, info->selector, ret);
return;
}
if (info->size != le16_to_cpu(size)) {
- uvc_trace(UVC_TRACE_CONTROL, "Control " UVC_GUID_FORMAT
- "/%u size doesn't match user supplied "
- "value.\n", UVC_GUID_ARGS(info->entity),
- info->selector);
+ uvc_trace(UVC_TRACE_CONTROL, "Control %pUl/%u size "
+ "doesn't match user supplied value.\n",
+ info->entity, info->selector);
return;
}
ret = uvc_query_ctrl(dev, UVC_GET_INFO, ctrl->entity->id,
dev->intfnum, info->selector, &inf, 1);
if (ret < 0) {
- uvc_trace(UVC_TRACE_CONTROL, "GET_INFO failed on "
- "control " UVC_GUID_FORMAT "/%u (%d).\n",
- UVC_GUID_ARGS(info->entity), info->selector,
- ret);
+ uvc_trace(UVC_TRACE_CONTROL,
+ "GET_INFO failed on control %pUl/%u (%d).\n",
+ info->entity, info->selector, ret);
return;
}
flags = info->flags;
if (((flags & UVC_CONTROL_GET_CUR) && !(inf & (1 << 0))) ||
((flags & UVC_CONTROL_SET_CUR) && !(inf & (1 << 1)))) {
- uvc_trace(UVC_TRACE_CONTROL, "Control "
- UVC_GUID_FORMAT "/%u flags don't match "
- "supported operations.\n",
- UVC_GUID_ARGS(info->entity), info->selector);
+ uvc_trace(UVC_TRACE_CONTROL, "Control %pUl/%u flags "
+ "don't match supported operations.\n",
+ info->entity, info->selector);
return;
}
}
ctrl->info = info;
- ctrl->data = kmalloc(ctrl->info->size * UVC_CTRL_NDATA, GFP_KERNEL);
- uvc_trace(UVC_TRACE_CONTROL, "Added control " UVC_GUID_FORMAT "/%u "
- "to device %s entity %u\n", UVC_GUID_ARGS(ctrl->info->entity),
- ctrl->info->selector, dev->udev->devpath, entity->id);
+ ctrl->data = kmalloc(ctrl->info->size * UVC_CTRL_DATA_LAST, GFP_KERNEL);
+ uvc_trace(UVC_TRACE_CONTROL, "Added control %pUl/%u to device %s "
+ "entity %u\n", ctrl->info->entity, ctrl->info->selector,
+ dev->udev->devpath, entity->id);
}
/*
@@ -1281,17 +1338,16 @@ int uvc_ctrl_add_info(struct uvc_control_info *info)
continue;
if (ctrl->selector == info->selector) {
- uvc_trace(UVC_TRACE_CONTROL, "Control "
- UVC_GUID_FORMAT "/%u is already defined.\n",
- UVC_GUID_ARGS(info->entity), info->selector);
+ uvc_trace(UVC_TRACE_CONTROL,
+ "Control %pUl/%u is already defined.\n",
+ info->entity, info->selector);
ret = -EEXIST;
goto end;
}
if (ctrl->index == info->index) {
- uvc_trace(UVC_TRACE_CONTROL, "Control "
- UVC_GUID_FORMAT "/%u would overwrite index "
- "%d.\n", UVC_GUID_ARGS(info->entity),
- info->selector, info->index);
+ uvc_trace(UVC_TRACE_CONTROL,
+ "Control %pUl/%u would overwrite index %d.\n",
+ info->entity, info->selector, info->index);
ret = -EEXIST;
goto end;
}
@@ -1332,10 +1388,9 @@ int uvc_ctrl_add_mapping(struct uvc_control_mapping *mapping)
continue;
if (info->size * 8 < mapping->size + mapping->offset) {
- uvc_trace(UVC_TRACE_CONTROL, "Mapping '%s' would "
- "overflow control " UVC_GUID_FORMAT "/%u\n",
- mapping->name, UVC_GUID_ARGS(info->entity),
- info->selector);
+ uvc_trace(UVC_TRACE_CONTROL,
+ "Mapping '%s' would overflow control %pUl/%u\n",
+ mapping->name, info->entity, info->selector);
ret = -EOVERFLOW;
goto end;
}
@@ -1354,9 +1409,9 @@ int uvc_ctrl_add_mapping(struct uvc_control_mapping *mapping)
mapping->ctrl = info;
list_add_tail(&mapping->list, &info->mappings);
- uvc_trace(UVC_TRACE_CONTROL, "Adding mapping %s to control "
- UVC_GUID_FORMAT "/%u.\n", mapping->name,
- UVC_GUID_ARGS(info->entity), info->selector);
+ uvc_trace(UVC_TRACE_CONTROL,
+ "Adding mapping %s to control %pUl/%u.\n",
+ mapping->name, info->entity, info->selector);
ret = 0;
break;
@@ -1378,6 +1433,7 @@ uvc_ctrl_prune_entity(struct uvc_device *dev, struct uvc_entity *entity)
struct usb_device_id id;
u8 index;
} blacklist[] = {
+ { { USB_DEVICE(0x13d3, 0x509b) }, 9 }, /* Gain */
{ { USB_DEVICE(0x1c4f, 0x3000) }, 6 }, /* WB Temperature */
{ { USB_DEVICE(0x5986, 0x0241) }, 2 }, /* Hue */
};
diff --git a/drivers/media/video/uvc/uvc_driver.c b/drivers/media/video/uvc/uvc_driver.c
index 391cccca7ff..a814820a3f6 100644
--- a/drivers/media/video/uvc/uvc_driver.c
+++ b/drivers/media/video/uvc/uvc_driver.c
@@ -43,8 +43,9 @@
#define DRIVER_VERSION "v0.1.0"
#endif
+unsigned int uvc_clock_param = CLOCK_MONOTONIC;
unsigned int uvc_no_drop_param;
-static unsigned int uvc_quirks_param;
+static unsigned int uvc_quirks_param = -1;
unsigned int uvc_trace_param;
unsigned int uvc_timeout_param = UVC_CTRL_STREAMING_TIMEOUT;
@@ -59,6 +60,11 @@ static struct uvc_format_desc uvc_fmts[] = {
.fcc = V4L2_PIX_FMT_YUYV,
},
{
+ .name = "YUV 4:2:2 (YUYV)",
+ .guid = UVC_GUID_FORMAT_YUY2_ISIGHT,
+ .fcc = V4L2_PIX_FMT_YUYV,
+ },
+ {
.name = "YUV 4:2:0 (NV12)",
.guid = UVC_GUID_FORMAT_NV12,
.fcc = V4L2_PIX_FMT_NV12,
@@ -309,11 +315,10 @@ static int uvc_parse_format(struct uvc_device *dev,
sizeof format->name);
format->fcc = fmtdesc->fcc;
} else {
- uvc_printk(KERN_INFO, "Unknown video format "
- UVC_GUID_FORMAT "\n",
- UVC_GUID_ARGS(&buffer[5]));
- snprintf(format->name, sizeof format->name,
- UVC_GUID_FORMAT, UVC_GUID_ARGS(&buffer[5]));
+ uvc_printk(KERN_INFO, "Unknown video format %pUl\n",
+ &buffer[5]);
+ snprintf(format->name, sizeof(format->name), "%pUl\n",
+ &buffer[5]);
format->fcc = 0;
}
@@ -1750,7 +1755,8 @@ static int uvc_probe(struct usb_interface *intf,
dev->udev = usb_get_dev(udev);
dev->intf = usb_get_intf(intf);
dev->intfnum = intf->cur_altsetting->desc.bInterfaceNumber;
- dev->quirks = id->driver_info | uvc_quirks_param;
+ dev->quirks = (uvc_quirks_param == -1)
+ ? id->driver_info : uvc_quirks_param;
if (udev->product != NULL)
strlcpy(dev->name, udev->product, sizeof dev->name);
@@ -1773,9 +1779,9 @@ static int uvc_probe(struct usb_interface *intf,
le16_to_cpu(udev->descriptor.idVendor),
le16_to_cpu(udev->descriptor.idProduct));
- if (uvc_quirks_param != 0) {
- uvc_printk(KERN_INFO, "Forcing device quirks 0x%x by module "
- "parameter for testing purpose.\n", uvc_quirks_param);
+ if (dev->quirks != id->driver_info) {
+ uvc_printk(KERN_INFO, "Forcing device quirks to 0x%x by module "
+ "parameter for testing purpose.\n", dev->quirks);
uvc_printk(KERN_INFO, "Please report required quirks to the "
"linux-uvc-devel mailing list.\n");
}
@@ -1892,6 +1898,45 @@ static int uvc_reset_resume(struct usb_interface *intf)
}
/* ------------------------------------------------------------------------
+ * Module parameters
+ */
+
+static int uvc_clock_param_get(char *buffer, struct kernel_param *kp)
+{
+ if (uvc_clock_param == CLOCK_MONOTONIC)
+ return sprintf(buffer, "CLOCK_MONOTONIC");
+ else
+ return sprintf(buffer, "CLOCK_REALTIME");
+}
+
+static int uvc_clock_param_set(const char *val, struct kernel_param *kp)
+{
+ if (strncasecmp(val, "clock_", strlen("clock_")) == 0)
+ val += strlen("clock_");
+
+ if (strcasecmp(val, "monotonic") == 0)
+ uvc_clock_param = CLOCK_MONOTONIC;
+ else if (strcasecmp(val, "realtime") == 0)
+ uvc_clock_param = CLOCK_REALTIME;
+ else
+ return -EINVAL;
+
+ return 0;
+}
+
+module_param_call(clock, uvc_clock_param_set, uvc_clock_param_get,
+ &uvc_clock_param, S_IRUGO|S_IWUSR);
+MODULE_PARM_DESC(clock, "Video buffers timestamp clock");
+module_param_named(nodrop, uvc_no_drop_param, uint, S_IRUGO|S_IWUSR);
+MODULE_PARM_DESC(nodrop, "Don't drop incomplete frames");
+module_param_named(quirks, uvc_quirks_param, uint, S_IRUGO|S_IWUSR);
+MODULE_PARM_DESC(quirks, "Forced device quirks");
+module_param_named(trace, uvc_trace_param, uint, S_IRUGO|S_IWUSR);
+MODULE_PARM_DESC(trace, "Trace level bitmask");
+module_param_named(timeout, uvc_timeout_param, uint, S_IRUGO|S_IWUSR);
+MODULE_PARM_DESC(timeout, "Streaming control requests timeout");
+
+/* ------------------------------------------------------------------------
* Driver initialization and cleanup
*/
@@ -2197,15 +2242,6 @@ static void __exit uvc_cleanup(void)
module_init(uvc_init);
module_exit(uvc_cleanup);
-module_param_named(nodrop, uvc_no_drop_param, uint, S_IRUGO|S_IWUSR);
-MODULE_PARM_DESC(nodrop, "Don't drop incomplete frames");
-module_param_named(quirks, uvc_quirks_param, uint, S_IRUGO|S_IWUSR);
-MODULE_PARM_DESC(quirks, "Forced device quirks");
-module_param_named(trace, uvc_trace_param, uint, S_IRUGO|S_IWUSR);
-MODULE_PARM_DESC(trace, "Trace level bitmask");
-module_param_named(timeout, uvc_timeout_param, uint, S_IRUGO|S_IWUSR);
-MODULE_PARM_DESC(timeout, "Streaming control requests timeout");
-
MODULE_AUTHOR(DRIVER_AUTHOR);
MODULE_DESCRIPTION(DRIVER_DESC);
MODULE_LICENSE("GPL");
diff --git a/drivers/media/video/uvc/uvc_queue.c b/drivers/media/video/uvc/uvc_queue.c
index ea11839cba4..4a925a31b0e 100644
--- a/drivers/media/video/uvc/uvc_queue.c
+++ b/drivers/media/video/uvc/uvc_queue.c
@@ -502,7 +502,6 @@ struct uvc_buffer *uvc_queue_next_buffer(struct uvc_video_queue *queue,
spin_unlock_irqrestore(&queue->irqlock, flags);
buf->buf.sequence = queue->sequence++;
- do_gettimeofday(&buf->buf.timestamp);
wake_up(&buf->wait);
return nextbuf;
diff --git a/drivers/media/video/uvc/uvc_v4l2.c b/drivers/media/video/uvc/uvc_v4l2.c
index 23239a4adef..43152aa5222 100644
--- a/drivers/media/video/uvc/uvc_v4l2.c
+++ b/drivers/media/video/uvc/uvc_v4l2.c
@@ -539,7 +539,7 @@ static long uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg)
xctrl.id = ctrl->id;
xctrl.value = ctrl->value;
- uvc_ctrl_begin(chain);
+ ret = uvc_ctrl_begin(chain);
if (ret < 0)
return ret;
@@ -549,6 +549,8 @@ static long uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg)
return ret;
}
ret = uvc_ctrl_commit(chain);
+ if (ret == 0)
+ ctrl->value = xctrl.value;
break;
}
diff --git a/drivers/media/video/uvc/uvc_video.c b/drivers/media/video/uvc/uvc_video.c
index 7dcf534a0cf..6b0666be370 100644
--- a/drivers/media/video/uvc/uvc_video.c
+++ b/drivers/media/video/uvc/uvc_video.c
@@ -410,6 +410,8 @@ static int uvc_video_decode_start(struct uvc_streaming *stream,
* when the EOF bit is set to force synchronisation on the next packet.
*/
if (buf->state != UVC_BUF_STATE_ACTIVE) {
+ struct timespec ts;
+
if (fid == stream->last_fid) {
uvc_trace(UVC_TRACE_FRAME, "Dropping payload (out of "
"sync).\n");
@@ -419,6 +421,14 @@ static int uvc_video_decode_start(struct uvc_streaming *stream,
return -ENODATA;
}
+ if (uvc_clock_param == CLOCK_MONOTONIC)
+ ktime_get_ts(&ts);
+ else
+ ktime_get_real_ts(&ts);
+
+ buf->buf.timestamp.tv_sec = ts.tv_sec;
+ buf->buf.timestamp.tv_usec = ts.tv_nsec / NSEC_PER_USEC;
+
/* TODO: Handle PTS and SCR. */
buf->state = UVC_BUF_STATE_ACTIVE;
}
diff --git a/drivers/media/video/uvc/uvcvideo.h b/drivers/media/video/uvc/uvcvideo.h
index 2337585001e..2bba059259e 100644
--- a/drivers/media/video/uvc/uvcvideo.h
+++ b/drivers/media/video/uvc/uvcvideo.h
@@ -113,6 +113,9 @@ struct uvc_xu_control {
#define UVC_GUID_FORMAT_YUY2 \
{ 'Y', 'U', 'Y', '2', 0x00, 0x00, 0x10, 0x00, \
0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}
+#define UVC_GUID_FORMAT_YUY2_ISIGHT \
+ { 'Y', 'U', 'Y', '2', 0x00, 0x00, 0x10, 0x00, \
+ 0x80, 0x00, 0x00, 0x00, 0x00, 0x38, 0x9b, 0x71}
#define UVC_GUID_FORMAT_NV12 \
{ 'N', 'V', '1', '2', 0x00, 0x00, 0x10, 0x00, \
0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}
@@ -149,7 +152,7 @@ struct uvc_xu_control {
#define UVC_MAX_STATUS_SIZE 16
#define UVC_CTRL_CONTROL_TIMEOUT 300
-#define UVC_CTRL_STREAMING_TIMEOUT 3000
+#define UVC_CTRL_STREAMING_TIMEOUT 5000
/* Devices quirks */
#define UVC_QUIRK_STATUS_INTERVAL 0x00000001
@@ -242,7 +245,8 @@ struct uvc_control {
uvc_control_info. */
__u8 dirty : 1,
loaded : 1,
- modified : 1;
+ modified : 1,
+ cached : 1;
__u8 *data;
};
@@ -533,6 +537,7 @@ struct uvc_driver {
#define UVC_WARN_MINMAX 0
#define UVC_WARN_PROBE_DEF 1
+extern unsigned int uvc_clock_param;
extern unsigned int uvc_no_drop_param;
extern unsigned int uvc_trace_param;
extern unsigned int uvc_timeout_param;
@@ -552,16 +557,6 @@ extern unsigned int uvc_timeout_param;
#define uvc_printk(level, msg...) \
printk(level "uvcvideo: " msg)
-#define UVC_GUID_FORMAT "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-" \
- "%02x%02x%02x%02x%02x%02x"
-#define UVC_GUID_ARGS(guid) \
- (guid)[3], (guid)[2], (guid)[1], (guid)[0], \
- (guid)[5], (guid)[4], \
- (guid)[7], (guid)[6], \
- (guid)[8], (guid)[9], \
- (guid)[10], (guid)[11], (guid)[12], \
- (guid)[13], (guid)[14], (guid)[15]
-
/* --------------------------------------------------------------------------
* Internal functions.
*/