aboutsummaryrefslogtreecommitdiff
path: root/drivers/media/video/uvc
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/media/video/uvc')
-rw-r--r--drivers/media/video/uvc/uvc_ctrl.c150
-rw-r--r--drivers/media/video/uvc/uvc_driver.c379
-rw-r--r--drivers/media/video/uvc/uvc_isight.c2
-rw-r--r--drivers/media/video/uvc/uvc_queue.c54
-rw-r--r--drivers/media/video/uvc/uvc_status.c3
-rw-r--r--drivers/media/video/uvc/uvc_v4l2.c137
-rw-r--r--drivers/media/video/uvc/uvc_video.c243
-rw-r--r--drivers/media/video/uvc/uvcvideo.h268
8 files changed, 738 insertions, 498 deletions
diff --git a/drivers/media/video/uvc/uvc_ctrl.c b/drivers/media/video/uvc/uvc_ctrl.c
index f16aafe9cf1..d2576f6391c 100644
--- a/drivers/media/video/uvc/uvc_ctrl.c
+++ b/drivers/media/video/uvc/uvc_ctrl.c
@@ -1,7 +1,7 @@
/*
* uvc_ctrl.c -- USB Video Class driver - Controls
*
- * Copyright (C) 2005-2008
+ * Copyright (C) 2005-2009
* Laurent Pinchart (laurent.pinchart@skynet.be)
*
* This program is free software; you can redistribute it and/or modify
@@ -12,7 +12,6 @@
*/
#include <linux/kernel.h>
-#include <linux/version.h>
#include <linux/list.h>
#include <linux/module.h>
#include <linux/uaccess.h>
@@ -29,7 +28,7 @@
#define UVC_CTRL_DATA_BACKUP 1
/* ------------------------------------------------------------------------
- * Control, formats, ...
+ * Controls
*/
static struct uvc_control_info uvc_ctrls[] = {
@@ -327,6 +326,31 @@ static struct uvc_menu_info exposure_auto_controls[] = {
{ 8, "Aperture Priority Mode" },
};
+static __s32 uvc_ctrl_get_zoom(struct uvc_control_mapping *mapping,
+ __u8 query, const __u8 *data)
+{
+ __s8 zoom = (__s8)data[0];
+
+ switch (query) {
+ case GET_CUR:
+ return (zoom == 0) ? 0 : (zoom > 0 ? data[2] : -data[2]);
+
+ case GET_MIN:
+ case GET_MAX:
+ case GET_RES:
+ case GET_DEF:
+ default:
+ return data[2];
+ }
+}
+
+static void uvc_ctrl_set_zoom(struct uvc_control_mapping *mapping,
+ __s32 value, __u8 *data)
+{
+ data[0] = value == 0 ? 0 : (value > 0) ? 1 : 0xff;
+ data[2] = min(abs(value), 0xff);
+}
+
static struct uvc_control_mapping uvc_ctrl_mappings[] = {
{
.id = V4L2_CID_BRIGHTNESS,
@@ -532,6 +556,38 @@ static struct uvc_control_mapping uvc_ctrl_mappings[] = {
.v4l2_type = V4L2_CTRL_TYPE_BOOLEAN,
.data_type = UVC_CTRL_DATA_TYPE_BOOLEAN,
},
+ {
+ .id = V4L2_CID_ZOOM_ABSOLUTE,
+ .name = "Zoom, Absolute",
+ .entity = UVC_GUID_UVC_CAMERA,
+ .selector = CT_ZOOM_ABSOLUTE_CONTROL,
+ .size = 16,
+ .offset = 0,
+ .v4l2_type = V4L2_CTRL_TYPE_INTEGER,
+ .data_type = UVC_CTRL_DATA_TYPE_UNSIGNED,
+ },
+ {
+ .id = V4L2_CID_ZOOM_CONTINUOUS,
+ .name = "Zoom, Continuous",
+ .entity = UVC_GUID_UVC_CAMERA,
+ .selector = CT_ZOOM_RELATIVE_CONTROL,
+ .size = 0,
+ .offset = 0,
+ .v4l2_type = V4L2_CTRL_TYPE_INTEGER,
+ .data_type = UVC_CTRL_DATA_TYPE_SIGNED,
+ .get = uvc_ctrl_get_zoom,
+ .set = uvc_ctrl_set_zoom,
+ },
+ {
+ .id = V4L2_CID_PRIVACY,
+ .name = "Privacy",
+ .entity = UVC_GUID_UVC_CAMERA,
+ .selector = CT_PRIVACY_CONTROL,
+ .size = 1,
+ .offset = 0,
+ .v4l2_type = V4L2_CTRL_TYPE_BOOLEAN,
+ .data_type = UVC_CTRL_DATA_TYPE_BOOLEAN,
+ },
};
/* ------------------------------------------------------------------------
@@ -543,18 +599,23 @@ static inline __u8 *uvc_ctrl_data(struct uvc_control *ctrl, int id)
return ctrl->data + id * ctrl->info->size;
}
-static inline int uvc_get_bit(const __u8 *data, int bit)
+static inline int uvc_test_bit(const __u8 *data, int bit)
{
return (data[bit >> 3] >> (bit & 7)) & 1;
}
+static inline void uvc_clear_bit(__u8 *data, int bit)
+{
+ data[bit >> 3] &= ~(1 << (bit & 7));
+}
+
/* Extract the bit string specified by mapping->offset and mapping->size
* from the little-endian data stored at 'data' and return the result as
* a signed 32bit integer. Sign extension will be performed if the mapping
* references a signed data type.
*/
-static __s32 uvc_get_le_value(const __u8 *data,
- struct uvc_control_mapping *mapping)
+static __s32 uvc_get_le_value(struct uvc_control_mapping *mapping,
+ __u8 query, const __u8 *data)
{
int bits = mapping->size;
int offset = mapping->offset;
@@ -573,7 +634,7 @@ static __s32 uvc_get_le_value(const __u8 *data,
mask = (1 << bits) - 1;
}
- /* Sign-extend the value if needed */
+ /* Sign-extend the value if needed. */
if (mapping->data_type == UVC_CTRL_DATA_TYPE_SIGNED)
value |= -(value & (1 << (mapping->size - 1)));
@@ -583,8 +644,8 @@ static __s32 uvc_get_le_value(const __u8 *data,
/* Set the bit string specified by mapping->offset and mapping->size
* in the little-endian data stored at 'data' to the value 'value'.
*/
-static void uvc_set_le_value(__s32 value, __u8 *data,
- struct uvc_control_mapping *mapping)
+static void uvc_set_le_value(struct uvc_control_mapping *mapping,
+ __s32 value, __u8 *data)
{
int bits = mapping->size;
int offset = mapping->offset;
@@ -736,7 +797,7 @@ int uvc_query_v4l2_ctrl(struct uvc_video_device *video,
video->dev->intfnum, ctrl->info->selector,
data, ctrl->info->size)) < 0)
goto out;
- v4l2_ctrl->default_value = uvc_get_le_value(data, mapping);
+ v4l2_ctrl->default_value = mapping->get(mapping, GET_DEF, data);
}
switch (mapping->v4l2_type) {
@@ -772,21 +833,21 @@ int uvc_query_v4l2_ctrl(struct uvc_video_device *video,
video->dev->intfnum, ctrl->info->selector,
data, ctrl->info->size)) < 0)
goto out;
- v4l2_ctrl->minimum = uvc_get_le_value(data, mapping);
+ v4l2_ctrl->minimum = mapping->get(mapping, GET_MIN, data);
}
if (ctrl->info->flags & UVC_CONTROL_GET_MAX) {
if ((ret = uvc_query_ctrl(video->dev, GET_MAX, ctrl->entity->id,
video->dev->intfnum, ctrl->info->selector,
data, ctrl->info->size)) < 0)
goto out;
- v4l2_ctrl->maximum = uvc_get_le_value(data, mapping);
+ v4l2_ctrl->maximum = mapping->get(mapping, GET_MAX, data);
}
if (ctrl->info->flags & UVC_CONTROL_GET_RES) {
if ((ret = uvc_query_ctrl(video->dev, GET_RES, ctrl->entity->id,
video->dev->intfnum, ctrl->info->selector,
data, ctrl->info->size)) < 0)
goto out;
- v4l2_ctrl->step = uvc_get_le_value(data, mapping);
+ v4l2_ctrl->step = mapping->get(mapping, GET_RES, data);
}
ret = 0;
@@ -923,8 +984,8 @@ int uvc_ctrl_get(struct uvc_video_device *video,
ctrl->loaded = 1;
}
- xctrl->value = uvc_get_le_value(
- uvc_ctrl_data(ctrl, UVC_CTRL_DATA_CURRENT), mapping);
+ xctrl->value = mapping->get(mapping, GET_CUR,
+ uvc_ctrl_data(ctrl, UVC_CTRL_DATA_CURRENT));
if (mapping->v4l2_type == V4L2_CTRL_TYPE_MENU) {
menu = mapping->menu_info;
@@ -980,8 +1041,8 @@ int uvc_ctrl_set(struct uvc_video_device *video,
ctrl->info->size);
}
- uvc_set_le_value(value,
- uvc_ctrl_data(ctrl, UVC_CTRL_DATA_CURRENT), mapping);
+ mapping->set(mapping, value,
+ uvc_ctrl_data(ctrl, UVC_CTRL_DATA_CURRENT));
ctrl->dirty = 1;
ctrl->modified = 1;
@@ -1257,6 +1318,11 @@ int uvc_ctrl_add_mapping(struct uvc_control_mapping *mapping)
struct uvc_control_mapping *map;
int ret = -EINVAL;
+ if (mapping->get == NULL)
+ mapping->get = uvc_get_le_value;
+ if (mapping->set == NULL)
+ mapping->set = uvc_set_le_value;
+
if (mapping->id & ~V4L2_CTRL_ID_MASK) {
uvc_trace(UVC_TRACE_CONTROL, "Can't add mapping '%s' with "
"invalid control id 0x%08x\n", mapping->name,
@@ -1306,6 +1372,51 @@ end:
}
/*
+ * Prune an entity of its bogus controls. This currently includes processing
+ * unit auto controls for which no corresponding manual control is available.
+ * Such auto controls make little sense if any, and are known to crash at
+ * least the SiGma Micro webcam.
+ */
+static void
+uvc_ctrl_prune_entity(struct uvc_entity *entity)
+{
+ static const struct {
+ u8 idx_manual;
+ u8 idx_auto;
+ } blacklist[] = {
+ { 2, 11 }, /* Hue */
+ { 6, 12 }, /* White Balance Temperature */
+ { 7, 13 }, /* White Balance Component */
+ };
+
+ u8 *controls;
+ unsigned int size;
+ unsigned int i;
+
+ if (UVC_ENTITY_TYPE(entity) != VC_PROCESSING_UNIT)
+ return;
+
+ controls = entity->processing.bmControls;
+ size = entity->processing.bControlSize;
+
+ for (i = 0; i < ARRAY_SIZE(blacklist); ++i) {
+ if (blacklist[i].idx_auto >= 8 * size ||
+ blacklist[i].idx_manual >= 8 * size)
+ continue;
+
+ if (!uvc_test_bit(controls, blacklist[i].idx_auto) ||
+ uvc_test_bit(controls, blacklist[i].idx_manual))
+ continue;
+
+ uvc_trace(UVC_TRACE_CONTROL, "Auto control %u/%u has no "
+ "matching manual control, removing it.\n", entity->id,
+ blacklist[i].idx_auto);
+
+ uvc_clear_bit(controls, blacklist[i].idx_auto);
+ }
+}
+
+/*
* Initialize device controls.
*/
int uvc_ctrl_init_device(struct uvc_device *dev)
@@ -1331,6 +1442,9 @@ int uvc_ctrl_init_device(struct uvc_device *dev)
bControlSize = entity->camera.bControlSize;
}
+ if (dev->quirks & UVC_QUIRK_PRUNE_CONTROLS)
+ uvc_ctrl_prune_entity(entity);
+
for (i = 0; i < bControlSize; ++i)
ncontrols += hweight8(bmControls[i]);
@@ -1345,7 +1459,7 @@ int uvc_ctrl_init_device(struct uvc_device *dev)
ctrl = entity->controls;
for (i = 0; i < bControlSize * 8; ++i) {
- if (uvc_get_bit(bmControls, i) == 0)
+ if (uvc_test_bit(bmControls, i) == 0)
continue;
ctrl->entity = entity;
diff --git a/drivers/media/video/uvc/uvc_driver.c b/drivers/media/video/uvc/uvc_driver.c
index d7ad060640b..b12873265cc 100644
--- a/drivers/media/video/uvc/uvc_driver.c
+++ b/drivers/media/video/uvc/uvc_driver.c
@@ -1,7 +1,7 @@
/*
* uvc_driver.c -- USB Video Class driver
*
- * Copyright (C) 2005-2008
+ * Copyright (C) 2005-2009
* Laurent Pinchart (laurent.pinchart@skynet.be)
*
* This program is free software; you can redistribute it and/or modify
@@ -12,8 +12,8 @@
*/
/*
- * This driver aims to support video input devices compliant with the 'USB
- * Video Class' specification.
+ * This driver aims to support video input and ouput devices compliant with the
+ * 'USB Video Class' specification.
*
* The driver doesn't support the deprecated v4l1 interface. It implements the
* mmap capture method only, and doesn't do any image format conversion in
@@ -24,7 +24,6 @@
*/
#include <linux/kernel.h>
-#include <linux/version.h>
#include <linux/list.h>
#include <linux/module.h>
#include <linux/usb.h>
@@ -32,6 +31,7 @@
#include <linux/vmalloc.h>
#include <linux/wait.h>
#include <asm/atomic.h>
+#include <asm/unaligned.h>
#include <media/v4l2-common.h>
@@ -43,11 +43,12 @@
#define DRIVER_VERSION "v0.1.0"
#endif
+unsigned int uvc_no_drop_param;
static unsigned int uvc_quirks_param;
unsigned int uvc_trace_param;
/* ------------------------------------------------------------------------
- * Control, formats, ...
+ * Video formats
*/
static struct uvc_format_desc uvc_fmts[] = {
@@ -288,8 +289,10 @@ static int uvc_parse_format(struct uvc_device *dev,
struct uvc_format_desc *fmtdesc;
struct uvc_frame *frame;
const unsigned char *start = buffer;
+ unsigned char *_buffer;
unsigned int interval;
unsigned int i, n;
+ int _buflen;
__u8 ftype;
format->type = buffer[2];
@@ -410,12 +413,20 @@ static int uvc_parse_format(struct uvc_device *dev,
buflen -= buffer[0];
buffer += buffer[0];
+ /* Count the number of frame descriptors to test the bFrameIndex
+ * field when parsing the descriptors. We can't rely on the
+ * bNumFrameDescriptors field as some cameras don't initialize it
+ * properly.
+ */
+ for (_buflen = buflen, _buffer = buffer;
+ _buflen > 2 && _buffer[2] == ftype;
+ _buflen -= _buffer[0], _buffer += _buffer[0])
+ format->nframes++;
+
/* Parse the frame descriptors. Only uncompressed, MJPEG and frame
* based formats have frame descriptors.
*/
while (buflen > 2 && buffer[2] == ftype) {
- frame = &format->frame[format->nframes];
-
if (ftype != VS_FRAME_FRAME_BASED)
n = buflen > 25 ? buffer[25] : 0;
else
@@ -430,29 +441,39 @@ static int uvc_parse_format(struct uvc_device *dev,
return -EINVAL;
}
+ if (buffer[3] - 1 >= format->nframes) {
+ uvc_trace(UVC_TRACE_DESCR, "device %d videostreaming"
+ "interface %d frame index %u out of range\n",
+ dev->udev->devnum, alts->desc.bInterfaceNumber,
+ buffer[3]);
+ return -EINVAL;
+ }
+
+ frame = &format->frame[buffer[3] - 1];
+
frame->bFrameIndex = buffer[3];
frame->bmCapabilities = buffer[4];
- frame->wWidth = le16_to_cpup((__le16 *)&buffer[5]);
- frame->wHeight = le16_to_cpup((__le16 *)&buffer[7]);
- frame->dwMinBitRate = le32_to_cpup((__le32 *)&buffer[9]);
- frame->dwMaxBitRate = le32_to_cpup((__le32 *)&buffer[13]);
+ frame->wWidth = get_unaligned_le16(&buffer[5]);
+ frame->wHeight = get_unaligned_le16(&buffer[7]);
+ frame->dwMinBitRate = get_unaligned_le32(&buffer[9]);
+ frame->dwMaxBitRate = get_unaligned_le32(&buffer[13]);
if (ftype != VS_FRAME_FRAME_BASED) {
frame->dwMaxVideoFrameBufferSize =
- le32_to_cpup((__le32 *)&buffer[17]);
+ get_unaligned_le32(&buffer[17]);
frame->dwDefaultFrameInterval =
- le32_to_cpup((__le32 *)&buffer[21]);
+ get_unaligned_le32(&buffer[21]);
frame->bFrameIntervalType = buffer[25];
} else {
frame->dwMaxVideoFrameBufferSize = 0;
frame->dwDefaultFrameInterval =
- le32_to_cpup((__le32 *)&buffer[17]);
+ get_unaligned_le32(&buffer[17]);
frame->bFrameIntervalType = buffer[21];
}
frame->dwFrameInterval = *intervals;
/* Several UVC chipsets screw up dwMaxVideoFrameBufferSize
* completely. Observed behaviours range from setting the
- * value to 1.1x the actual frame size of hardwiring the
+ * value to 1.1x the actual frame size to hardwiring the
* 16 low bits to 0. This results in a higher than necessary
* memory usage as well as a wrong image size information. For
* uncompressed formats this can be fixed by computing the
@@ -465,10 +486,10 @@ static int uvc_parse_format(struct uvc_device *dev,
/* Some bogus devices report dwMinFrameInterval equal to
* dwMaxFrameInterval and have dwFrameIntervalStep set to
* zero. Setting all null intervals to 1 fixes the problem and
- * some other divisions by zero which could happen.
+ * some other divisions by zero that could happen.
*/
for (i = 0; i < n; ++i) {
- interval = le32_to_cpup((__le32 *)&buffer[26+4*i]);
+ interval = get_unaligned_le32(&buffer[26+4*i]);
*(*intervals)++ = interval ? interval : 1;
}
@@ -486,7 +507,6 @@ static int uvc_parse_format(struct uvc_device *dev,
10000000/frame->dwDefaultFrameInterval,
(100000000/frame->dwDefaultFrameInterval)%10);
- format->nframes++;
buflen -= buffer[0];
buffer += buffer[0];
}
@@ -588,46 +608,55 @@ static int uvc_parse_streaming(struct uvc_device *dev,
}
/* Parse the header descriptor. */
- if (buffer[2] == VS_OUTPUT_HEADER) {
+ switch (buffer[2]) {
+ case VS_OUTPUT_HEADER:
+ streaming->type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
+ size = 9;
+ break;
+
+ case VS_INPUT_HEADER:
+ streaming->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ size = 13;
+ break;
+
+ default:
uvc_trace(UVC_TRACE_DESCR, "device %d videostreaming interface "
- "%d OUTPUT HEADER descriptor is not supported.\n",
- dev->udev->devnum, alts->desc.bInterfaceNumber);
+ "%d HEADER descriptor not found.\n", dev->udev->devnum,
+ alts->desc.bInterfaceNumber);
goto error;
- } else if (buffer[2] == VS_INPUT_HEADER) {
- p = buflen >= 5 ? buffer[3] : 0;
- n = buflen >= 12 ? buffer[12] : 0;
+ }
- if (buflen < 13 + p*n || buffer[2] != VS_INPUT_HEADER) {
- uvc_trace(UVC_TRACE_DESCR, "device %d videostreaming "
- "interface %d INPUT HEADER descriptor is "
- "invalid.\n", dev->udev->devnum,
- alts->desc.bInterfaceNumber);
- goto error;
- }
+ p = buflen >= 4 ? buffer[3] : 0;
+ n = buflen >= size ? buffer[size-1] : 0;
+
+ if (buflen < size + p*n) {
+ uvc_trace(UVC_TRACE_DESCR, "device %d videostreaming "
+ "interface %d HEADER descriptor is invalid.\n",
+ dev->udev->devnum, alts->desc.bInterfaceNumber);
+ goto error;
+ }
- streaming->header.bNumFormats = p;
- streaming->header.bEndpointAddress = buffer[6];
+ streaming->header.bNumFormats = p;
+ streaming->header.bEndpointAddress = buffer[6];
+ if (buffer[2] == VS_INPUT_HEADER) {
streaming->header.bmInfo = buffer[7];
streaming->header.bTerminalLink = buffer[8];
streaming->header.bStillCaptureMethod = buffer[9];
streaming->header.bTriggerSupport = buffer[10];
streaming->header.bTriggerUsage = buffer[11];
- streaming->header.bControlSize = n;
-
- streaming->header.bmaControls = kmalloc(p*n, GFP_KERNEL);
- if (streaming->header.bmaControls == NULL) {
- ret = -ENOMEM;
- goto error;
- }
-
- memcpy(streaming->header.bmaControls, &buffer[13], p*n);
} else {
- uvc_trace(UVC_TRACE_DESCR, "device %d videostreaming interface "
- "%d HEADER descriptor not found.\n", dev->udev->devnum,
- alts->desc.bInterfaceNumber);
+ streaming->header.bTerminalLink = buffer[7];
+ }
+ streaming->header.bControlSize = n;
+
+ streaming->header.bmaControls = kmalloc(p*n, GFP_KERNEL);
+ if (streaming->header.bmaControls == NULL) {
+ ret = -ENOMEM;
goto error;
}
+ memcpy(streaming->header.bmaControls, &buffer[size], p*n);
+
buflen -= buffer[0];
buffer += buffer[0];
@@ -813,8 +842,7 @@ static int uvc_parse_vendor_control(struct uvc_device *dev,
unit->type = VC_EXTENSION_UNIT;
memcpy(unit->extension.guidExtensionCode, &buffer[4], 16);
unit->extension.bNumControls = buffer[20];
- unit->extension.bNrInPins =
- le16_to_cpup((__le16 *)&buffer[21]);
+ unit->extension.bNrInPins = get_unaligned_le16(&buffer[21]);
unit->extension.baSourceID = (__u8 *)unit + sizeof *unit;
memcpy(unit->extension.baSourceID, &buffer[22], p);
unit->extension.bControlSize = buffer[22+p];
@@ -858,8 +886,8 @@ static int uvc_parse_standard_control(struct uvc_device *dev,
return -EINVAL;
}
- dev->uvc_version = le16_to_cpup((__le16 *)&buffer[3]);
- dev->clock_frequency = le32_to_cpup((__le32 *)&buffer[7]);
+ dev->uvc_version = get_unaligned_le16(&buffer[3]);
+ dev->clock_frequency = get_unaligned_le32(&buffer[7]);
/* Parse all USB Video Streaming interfaces. */
for (i = 0; i < n; ++i) {
@@ -886,7 +914,7 @@ static int uvc_parse_standard_control(struct uvc_device *dev,
/* Make sure the terminal type MSB is not null, otherwise it
* could be confused with a unit.
*/
- type = le16_to_cpup((__le16 *)&buffer[4]);
+ type = get_unaligned_le16(&buffer[4]);
if ((type & 0xff00) == 0) {
uvc_trace(UVC_TRACE_DESCR, "device %d videocontrol "
"interface %d INPUT_TERMINAL %d has invalid "
@@ -928,11 +956,11 @@ static int uvc_parse_standard_control(struct uvc_device *dev,
term->camera.bControlSize = n;
term->camera.bmControls = (__u8 *)term + sizeof *term;
term->camera.wObjectiveFocalLengthMin =
- le16_to_cpup((__le16 *)&buffer[8]);
+ get_unaligned_le16(&buffer[8]);
term->camera.wObjectiveFocalLengthMax =
- le16_to_cpup((__le16 *)&buffer[10]);
+ get_unaligned_le16(&buffer[10]);
term->camera.wOcularFocalLength =
- le16_to_cpup((__le16 *)&buffer[12]);
+ get_unaligned_le16(&buffer[12]);
memcpy(term->camera.bmControls, &buffer[15], n);
} else if (UVC_ENTITY_TYPE(term) == ITT_MEDIA_TRANSPORT_INPUT) {
term->media.bControlSize = n;
@@ -968,7 +996,7 @@ static int uvc_parse_standard_control(struct uvc_device *dev,
/* Make sure the terminal type MSB is not null, otherwise it
* could be confused with a unit.
*/
- type = le16_to_cpup((__le16 *)&buffer[4]);
+ type = get_unaligned_le16(&buffer[4]);
if ((type & 0xff00) == 0) {
uvc_trace(UVC_TRACE_DESCR, "device %d videocontrol "
"interface %d OUTPUT_TERMINAL %d has invalid "
@@ -1042,7 +1070,7 @@ static int uvc_parse_standard_control(struct uvc_device *dev,
unit->type = buffer[2];
unit->processing.bSourceID = buffer[4];
unit->processing.wMaxMultiplier =
- le16_to_cpup((__le16 *)&buffer[5]);
+ get_unaligned_le16(&buffer[5]);
unit->processing.bControlSize = buffer[7];
unit->processing.bmControls = (__u8 *)unit + sizeof *unit;
memcpy(unit->processing.bmControls, &buffer[8], n);
@@ -1077,8 +1105,7 @@ static int uvc_parse_standard_control(struct uvc_device *dev,
unit->type = buffer[2];
memcpy(unit->extension.guidExtensionCode, &buffer[4], 16);
unit->extension.bNumControls = buffer[20];
- unit->extension.bNrInPins =
- le16_to_cpup((__le16 *)&buffer[21]);
+ unit->extension.bNrInPins = get_unaligned_le16(&buffer[21]);
unit->extension.baSourceID = (__u8 *)unit + sizeof *unit;
memcpy(unit->extension.baSourceID, &buffer[22], p);
unit->extension.bControlSize = buffer[22+p];
@@ -1128,8 +1155,13 @@ next_descriptor:
buffer += buffer[0];
}
- /* Check if the optional status endpoint is present. */
- if (alts->desc.bNumEndpoints == 1) {
+ /* Check if the optional status endpoint is present. Built-in iSight
+ * webcams have an interrupt endpoint but spit proprietary data that
+ * don't conform to the UVC status endpoint messages. Don't try to
+ * handle the interrupt endpoint for those cameras.
+ */
+ if (alts->desc.bNumEndpoints == 1 &&
+ !(dev->quirks & UVC_QUIRK_BUILTIN_ISIGHT)) {
struct usb_host_endpoint *ep = &alts->endpoint[0];
struct usb_endpoint_descriptor *desc = &ep->desc;
@@ -1167,13 +1199,13 @@ static void uvc_unregister_video(struct uvc_device *dev)
* Scan the UVC descriptors to locate a chain starting at an Output Terminal
* and containing the following units:
*
- * - a USB Streaming Output Terminal
+ * - one Output Terminal (USB Streaming or Display)
* - zero or one Processing Unit
* - zero, one or mode single-input Selector Units
* - zero or one multiple-input Selector Units, provided all inputs are
* connected to input terminals
* - zero, one or mode single-input Extension Units
- * - one Camera Input Terminal, or one or more External terminals.
+ * - one or more Input Terminals (Camera, External or USB Streaming)
*
* A side forward scan is made on each detected entity to check for additional
* extension units.
@@ -1234,6 +1266,26 @@ static int uvc_scan_chain_entity(struct uvc_video_device *video,
list_add_tail(&entity->chain, &video->iterms);
break;
+ case TT_STREAMING:
+ if (uvc_trace_param & UVC_TRACE_PROBE)
+ printk(" <- IT %d\n", entity->id);
+
+ if (!UVC_ENTITY_IS_ITERM(entity)) {
+ uvc_trace(UVC_TRACE_DESCR, "Unsupported input "
+ "terminal %u.\n", entity->id);
+ return -1;
+ }
+
+ if (video->sterm != NULL) {
+ uvc_trace(UVC_TRACE_DESCR, "Found multiple streaming "
+ "entities in chain.\n");
+ return -1;
+ }
+
+ list_add_tail(&entity->chain, &video->iterms);
+ video->sterm = entity;
+ break;
+
default:
uvc_trace(UVC_TRACE_DESCR, "Unsupported entity type "
"0x%04x found in chain.\n", UVC_ENTITY_TYPE(entity));
@@ -1344,6 +1396,10 @@ static int uvc_scan_chain(struct uvc_video_device *video)
entity = video->oterm;
uvc_trace(UVC_TRACE_PROBE, "Scanning UVC chain: OT %d", entity->id);
+
+ if (UVC_ENTITY_TYPE(entity) == TT_STREAMING)
+ video->sterm = entity;
+
id = entity->output.bSourceID;
while (id != 0) {
prev = entity;
@@ -1372,8 +1428,11 @@ static int uvc_scan_chain(struct uvc_video_device *video)
return id;
}
- /* Initialize the video buffers queue. */
- uvc_queue_init(&video->queue);
+ if (video->sterm == NULL) {
+ uvc_trace(UVC_TRACE_DESCR, "No streaming entity found in "
+ "chain.\n");
+ return -1;
+ }
return 0;
}
@@ -1384,7 +1443,8 @@ static int uvc_scan_chain(struct uvc_video_device *video)
* The driver currently supports a single video device per control interface
* only. The terminal and units must match the following structure:
*
- * ITT_CAMERA -> VC_PROCESSING_UNIT -> VC_EXTENSION_UNIT{0,n} -> TT_STREAMING
+ * ITT_* -> VC_PROCESSING_UNIT -> VC_EXTENSION_UNIT{0,n} -> TT_STREAMING
+ * TT_STREAMING -> VC_PROCESSING_UNIT -> VC_EXTENSION_UNIT{0,n} -> OTT_*
*
* The Extension Units, if present, must have a single input pin. The
* Processing Unit and Extension Units can be in any order. Additional
@@ -1401,7 +1461,7 @@ static int uvc_register_video(struct uvc_device *dev)
list_for_each_entry(term, &dev->entities, list) {
struct uvc_streaming *streaming;
- if (UVC_ENTITY_TYPE(term) != TT_STREAMING)
+ if (!UVC_ENTITY_IS_TERM(term) || !UVC_ENTITY_IS_OTERM(term))
continue;
memset(&dev->video, 0, sizeof dev->video);
@@ -1414,7 +1474,8 @@ static int uvc_register_video(struct uvc_device *dev)
continue;
list_for_each_entry(streaming, &dev->streaming, list) {
- if (streaming->header.bTerminalLink == term->id) {
+ if (streaming->header.bTerminalLink ==
+ dev->video.sterm->id) {
dev->video.streaming = streaming;
found = 1;
break;
@@ -1440,6 +1501,9 @@ static int uvc_register_video(struct uvc_device *dev)
printk(" -> %d).\n", dev->video.oterm->id);
}
+ /* Initialize the video buffers queue. */
+ uvc_queue_init(&dev->video.queue, dev->video.streaming->type);
+
/* Initialize the streaming interface with default streaming
* parameters.
*/
@@ -1466,10 +1530,6 @@ static int uvc_register_video(struct uvc_device *dev)
/* Set the driver data before calling video_register_device, otherwise
* uvc_v4l2_open might race us.
- *
- * FIXME: usb_set_intfdata hasn't been called so far. Is that a
- * problem ? Does any function which could be called here get
- * a pointer to the usb_interface ?
*/
dev->video.vdev = vdev;
video_set_drvdata(vdev, &dev->video);
@@ -1504,7 +1564,7 @@ void uvc_delete(struct kref *kref)
struct uvc_device *dev = container_of(kref, struct uvc_device, kref);
struct list_head *p, *n;
- /* Unregister the video device */
+ /* Unregister the video device. */
uvc_unregister_video(dev);
usb_put_intf(dev->intf);
usb_put_dev(dev->udev);
@@ -1547,7 +1607,7 @@ static int uvc_probe(struct usb_interface *intf,
uvc_trace(UVC_TRACE_PROBE, "Probing generic UVC device %s\n",
udev->devpath);
- /* Allocate memory for the device and initialize it */
+ /* Allocate memory for the device and initialize it. */
if ((dev = kzalloc(sizeof *dev, GFP_KERNEL)) == NULL)
return -ENOMEM;
@@ -1568,14 +1628,14 @@ static int uvc_probe(struct usb_interface *intf,
le16_to_cpu(udev->descriptor.idVendor),
le16_to_cpu(udev->descriptor.idProduct));
- /* Parse the Video Class control descriptor */
+ /* Parse the Video Class control descriptor. */
if (uvc_parse_control(dev) < 0) {
uvc_trace(UVC_TRACE_PROBE, "Unable to parse UVC "
"descriptors.\n");
goto error;
}
- uvc_printk(KERN_INFO, "Found UVC %u.%02u device %s (%04x:%04x)\n",
+ uvc_printk(KERN_INFO, "Found UVC %u.%02x device %s (%04x:%04x)\n",
dev->uvc_version >> 8, dev->uvc_version & 0xff,
udev->product ? udev->product : "<unnamed>",
le16_to_cpu(udev->descriptor.idVendor),
@@ -1588,18 +1648,18 @@ static int uvc_probe(struct usb_interface *intf,
"linux-uvc-devel mailing list.\n");
}
- /* Initialize controls */
+ /* Initialize controls. */
if (uvc_ctrl_init_device(dev) < 0)
goto error;
- /* Register the video devices */
+ /* Register the video devices. */
if (uvc_register_video(dev) < 0)
goto error;
- /* Save our data pointer in the interface data */
+ /* Save our data pointer in the interface data. */
usb_set_intfdata(intf, dev);
- /* Initialize the interrupt URB */
+ /* Initialize the interrupt URB. */
if ((ret = uvc_status_init(dev)) < 0) {
uvc_printk(KERN_INFO, "Unable to initialize the status "
"endpoint (%d), status interrupt will not be "
@@ -1707,24 +1767,6 @@ static int uvc_reset_resume(struct usb_interface *intf)
* though they are compliant.
*/
static struct usb_device_id uvc_ids[] = {
- /* ALi M5606 (Clevo M540SR) */
- { .match_flags = USB_DEVICE_ID_MATCH_DEVICE
- | USB_DEVICE_ID_MATCH_INT_INFO,
- .idVendor = 0x0402,
- .idProduct = 0x5606,
- .bInterfaceClass = USB_CLASS_VIDEO,
- .bInterfaceSubClass = 1,
- .bInterfaceProtocol = 0,
- .driver_info = UVC_QUIRK_PROBE_MINMAX },
- /* Creative Live! Optia */
- { .match_flags = USB_DEVICE_ID_MATCH_DEVICE
- | USB_DEVICE_ID_MATCH_INT_INFO,
- .idVendor = 0x041e,
- .idProduct = 0x4057,
- .bInterfaceClass = USB_CLASS_VIDEO,
- .bInterfaceSubClass = 1,
- .bInterfaceProtocol = 0,
- .driver_info = UVC_QUIRK_PROBE_MINMAX },
/* Microsoft Lifecam NX-6000 */
{ .match_flags = USB_DEVICE_ID_MATCH_DEVICE
| USB_DEVICE_ID_MATCH_INT_INFO,
@@ -1792,33 +1834,24 @@ static struct usb_device_id uvc_ids[] = {
.bInterfaceSubClass = 1,
.bInterfaceProtocol = 0 },
/* Apple Built-In iSight */
- { .match_flags = USB_DEVICE_ID_MATCH_DEVICE
+ { .match_flags = USB_DEVICE_ID_MATCH_DEVICE
| USB_DEVICE_ID_MATCH_INT_INFO,
.idVendor = 0x05ac,
.idProduct = 0x8501,
- .bInterfaceClass = USB_CLASS_VIDEO,
- .bInterfaceSubClass = 1,
- .bInterfaceProtocol = 0,
+ .bInterfaceClass = USB_CLASS_VIDEO,
+ .bInterfaceSubClass = 1,
+ .bInterfaceProtocol = 0,
.driver_info = UVC_QUIRK_PROBE_MINMAX
| UVC_QUIRK_BUILTIN_ISIGHT },
/* Genesys Logic USB 2.0 PC Camera */
- { .match_flags = USB_DEVICE_ID_MATCH_DEVICE
- | USB_DEVICE_ID_MATCH_INT_INFO,
- .idVendor = 0x05e3,
- .idProduct = 0x0505,
- .bInterfaceClass = USB_CLASS_VIDEO,
- .bInterfaceSubClass = 1,
- .bInterfaceProtocol = 0,
- .driver_info = UVC_QUIRK_STREAM_NO_FID },
- /* Silicon Motion SM371 */
{ .match_flags = USB_DEVICE_ID_MATCH_DEVICE
| USB_DEVICE_ID_MATCH_INT_INFO,
- .idVendor = 0x090c,
- .idProduct = 0xb371,
+ .idVendor = 0x05e3,
+ .idProduct = 0x0505,
.bInterfaceClass = USB_CLASS_VIDEO,
.bInterfaceSubClass = 1,
.bInterfaceProtocol = 0,
- .driver_info = UVC_QUIRK_PROBE_MINMAX },
+ .driver_info = UVC_QUIRK_STREAM_NO_FID },
/* MT6227 */
{ .match_flags = USB_DEVICE_ID_MATCH_DEVICE
| USB_DEVICE_ID_MATCH_INT_INFO,
@@ -1837,6 +1870,15 @@ static struct usb_device_id uvc_ids[] = {
.bInterfaceSubClass = 1,
.bInterfaceProtocol = 0,
.driver_info = UVC_QUIRK_STREAM_NO_FID },
+ /* Syntek (Samsung Q310) */
+ { .match_flags = USB_DEVICE_ID_MATCH_DEVICE
+ | USB_DEVICE_ID_MATCH_INT_INFO,
+ .idVendor = 0x174f,
+ .idProduct = 0x5931,
+ .bInterfaceClass = USB_CLASS_VIDEO,
+ .bInterfaceSubClass = 1,
+ .bInterfaceProtocol = 0,
+ .driver_info = UVC_QUIRK_STREAM_NO_FID },
/* Asus F9SG */
{ .match_flags = USB_DEVICE_ID_MATCH_DEVICE
| USB_DEVICE_ID_MATCH_INT_INFO,
@@ -1855,6 +1897,15 @@ static struct usb_device_id uvc_ids[] = {
.bInterfaceSubClass = 1,
.bInterfaceProtocol = 0,
.driver_info = UVC_QUIRK_STREAM_NO_FID },
+ /* Lenovo Thinkpad SL500 */
+ { .match_flags = USB_DEVICE_ID_MATCH_DEVICE
+ | USB_DEVICE_ID_MATCH_INT_INFO,
+ .idVendor = 0x17ef,
+ .idProduct = 0x480b,
+ .bInterfaceClass = USB_CLASS_VIDEO,
+ .bInterfaceSubClass = 1,
+ .bInterfaceProtocol = 0,
+ .driver_info = UVC_QUIRK_STREAM_NO_FID },
/* Ecamm Pico iMage */
{ .match_flags = USB_DEVICE_ID_MATCH_DEVICE
| USB_DEVICE_ID_MATCH_INT_INFO,
@@ -1884,106 +1935,8 @@ static struct usb_device_id uvc_ids[] = {
.bInterfaceSubClass = 1,
.bInterfaceProtocol = 0,
.driver_info = UVC_QUIRK_PROBE_MINMAX
- | UVC_QUIRK_IGNORE_SELECTOR_UNIT},
- /* Acer OEM Webcam - Unknown vendor */
- { .match_flags = USB_DEVICE_ID_MATCH_DEVICE
- | USB_DEVICE_ID_MATCH_INT_INFO,
- .idVendor = 0x5986,
- .idProduct = 0x0100,
- .bInterfaceClass = USB_CLASS_VIDEO,
- .bInterfaceSubClass = 1,
- .bInterfaceProtocol = 0,
- .driver_info = UVC_QUIRK_PROBE_MINMAX },
- /* Packard Bell OEM Webcam - Bison Electronics */
- { .match_flags = USB_DEVICE_ID_MATCH_DEVICE
- | USB_DEVICE_ID_MATCH_INT_INFO,
- .idVendor = 0x5986,
- .idProduct = 0x0101,
- .bInterfaceClass = USB_CLASS_VIDEO,
- .bInterfaceSubClass = 1,
- .bInterfaceProtocol = 0,
- .driver_info = UVC_QUIRK_PROBE_MINMAX },
- /* Acer Crystal Eye webcam - Bison Electronics */
- { .match_flags = USB_DEVICE_ID_MATCH_DEVICE
- | USB_DEVICE_ID_MATCH_INT_INFO,
- .idVendor = 0x5986,
- .idProduct = 0x0102,
- .bInterfaceClass = USB_CLASS_VIDEO,
- .bInterfaceSubClass = 1,
- .bInterfaceProtocol = 0,
- .driver_info = UVC_QUIRK_PROBE_MINMAX },
- /* Compaq Presario B1200 - Bison Electronics */
- { .match_flags = USB_DEVICE_ID_MATCH_DEVICE
- | USB_DEVICE_ID_MATCH_INT_INFO,
- .idVendor = 0x5986,
- .idProduct = 0x0104,
- .bInterfaceClass = USB_CLASS_VIDEO,
- .bInterfaceSubClass = 1,
- .bInterfaceProtocol = 0,
- .driver_info = UVC_QUIRK_PROBE_MINMAX },
- /* Acer Travelmate 7720 - Bison Electronics */
- { .match_flags = USB_DEVICE_ID_MATCH_DEVICE
- | USB_DEVICE_ID_MATCH_INT_INFO,
- .idVendor = 0x5986,
- .idProduct = 0x0105,
- .bInterfaceClass = USB_CLASS_VIDEO,
- .bInterfaceSubClass = 1,
- .bInterfaceProtocol = 0,
- .driver_info = UVC_QUIRK_PROBE_MINMAX },
- /* Medion Akoya Mini E1210 - Bison Electronics */
- { .match_flags = USB_DEVICE_ID_MATCH_DEVICE
- | USB_DEVICE_ID_MATCH_INT_INFO,
- .idVendor = 0x5986,
- .idProduct = 0x0141,
- .bInterfaceClass = USB_CLASS_VIDEO,
- .bInterfaceSubClass = 1,
- .bInterfaceProtocol = 0,
- .driver_info = UVC_QUIRK_PROBE_MINMAX },
- /* Acer OrbiCam - Bison Electronics */
- { .match_flags = USB_DEVICE_ID_MATCH_DEVICE
- | USB_DEVICE_ID_MATCH_INT_INFO,
- .idVendor = 0x5986,
- .idProduct = 0x0200,
- .bInterfaceClass = USB_CLASS_VIDEO,
- .bInterfaceSubClass = 1,
- .bInterfaceProtocol = 0,
- .driver_info = UVC_QUIRK_PROBE_MINMAX },
- /* Fujitsu Amilo SI2636 - Bison Electronics */
- { .match_flags = USB_DEVICE_ID_MATCH_DEVICE
- | USB_DEVICE_ID_MATCH_INT_INFO,
- .idVendor = 0x5986,
- .idProduct = 0x0202,
- .bInterfaceClass = USB_CLASS_VIDEO,
- .bInterfaceSubClass = 1,
- .bInterfaceProtocol = 0,
- .driver_info = UVC_QUIRK_PROBE_MINMAX },
- /* Advent 4211 - Bison Electronics */
- { .match_flags = USB_DEVICE_ID_MATCH_DEVICE
- | USB_DEVICE_ID_MATCH_INT_INFO,
- .idVendor = 0x5986,
- .idProduct = 0x0203,
- .bInterfaceClass = USB_CLASS_VIDEO,
- .bInterfaceSubClass = 1,
- .bInterfaceProtocol = 0,
- .driver_info = UVC_QUIRK_PROBE_MINMAX },
- /* Bison Electronics */
- { .match_flags = USB_DEVICE_ID_MATCH_DEVICE
- | USB_DEVICE_ID_MATCH_INT_INFO,
- .idVendor = 0x5986,
- .idProduct = 0x0300,
- .bInterfaceClass = USB_CLASS_VIDEO,
- .bInterfaceSubClass = 1,
- .bInterfaceProtocol = 0,
- .driver_info = UVC_QUIRK_PROBE_MINMAX },
- /* Clevo M570TU - Bison Electronics */
- { .match_flags = USB_DEVICE_ID_MATCH_DEVICE
- | USB_DEVICE_ID_MATCH_INT_INFO,
- .idVendor = 0x5986,
- .idProduct = 0x0303,
- .bInterfaceClass = USB_CLASS_VIDEO,
- .bInterfaceSubClass = 1,
- .bInterfaceProtocol = 0,
- .driver_info = UVC_QUIRK_PROBE_MINMAX },
+ | UVC_QUIRK_IGNORE_SELECTOR_UNIT
+ | UVC_QUIRK_PRUNE_CONTROLS },
/* Generic USB Video Class */
{ USB_INTERFACE_INFO(USB_CLASS_VIDEO, 1, 0) },
{}
@@ -2029,6 +1982,8 @@ 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);
diff --git a/drivers/media/video/uvc/uvc_isight.c b/drivers/media/video/uvc/uvc_isight.c
index 37bdefdbead..436f462685a 100644
--- a/drivers/media/video/uvc/uvc_isight.c
+++ b/drivers/media/video/uvc/uvc_isight.c
@@ -3,6 +3,8 @@
*
* Copyright (C) 2006-2007
* Ivan N. Zlatev <contact@i-nz.net>
+ * Copyright (C) 2008-2009
+ * Laurent Pinchart <laurent.pinchart@skynet.be>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
diff --git a/drivers/media/video/uvc/uvc_queue.c b/drivers/media/video/uvc/uvc_queue.c
index 5646a6a3293..0155752e4a5 100644
--- a/drivers/media/video/uvc/uvc_queue.c
+++ b/drivers/media/video/uvc/uvc_queue.c
@@ -1,7 +1,7 @@
/*
* uvc_queue.c -- USB Video Class driver - Buffers management
*
- * Copyright (C) 2005-2008
+ * Copyright (C) 2005-2009
* Laurent Pinchart (laurent.pinchart@skynet.be)
*
* This program is free software; you can redistribute it and/or modify
@@ -12,7 +12,6 @@
*/
#include <linux/kernel.h>
-#include <linux/version.h>
#include <linux/mm.h>
#include <linux/list.h>
#include <linux/module.h>
@@ -37,22 +36,22 @@
* to user space will return -EBUSY.
*
* Video buffers are managed using two queues. However, unlike most USB video
- * drivers which use an in queue and an out queue, we use a main queue which
- * holds all queued buffers (both 'empty' and 'done' buffers), and an irq
- * queue which holds empty buffers. This design (copied from video-buf)
- * minimizes locking in interrupt, as only one queue is shared between
- * interrupt and user contexts.
+ * drivers that use an in queue and an out queue, we use a main queue to hold
+ * all queued buffers (both 'empty' and 'done' buffers), and an irq queue to
+ * hold empty buffers. This design (copied from video-buf) minimizes locking
+ * in interrupt, as only one queue is shared between interrupt and user
+ * contexts.
*
* Use cases
* ---------
*
- * Unless stated otherwise, all operations which modify the irq buffers queue
+ * Unless stated otherwise, all operations that modify the irq buffers queue
* are protected by the irq spinlock.
*
* 1. The user queues the buffers, starts streaming and dequeues a buffer.
*
* The buffers are added to the main and irq queues. Both operations are
- * protected by the queue lock, and the latert is protected by the irq
+ * protected by the queue lock, and the later is protected by the irq
* spinlock as well.
*
* The completion handler fetches a buffer from the irq queue and fills it
@@ -60,7 +59,7 @@
* returns immediately.
*
* When the buffer is full, the completion handler removes it from the irq
- * queue, marks it as ready (UVC_BUF_STATE_DONE) and wake its wait queue.
+ * queue, marks it as ready (UVC_BUF_STATE_DONE) and wakes its wait queue.
* At that point, any process waiting on the buffer will be woken up. If a
* process tries to dequeue a buffer after it has been marked ready, the
* dequeing will succeed immediately.
@@ -79,19 +78,20 @@
*
*/
-void uvc_queue_init(struct uvc_video_queue *queue)
+void uvc_queue_init(struct uvc_video_queue *queue, enum v4l2_buf_type type)
{
mutex_init(&queue->mutex);
spin_lock_init(&queue->irqlock);
INIT_LIST_HEAD(&queue->mainqueue);
INIT_LIST_HEAD(&queue->irqqueue);
+ queue->type = type;
}
/*
* Allocate the video buffers.
*
- * Pages are reserved to make sure they will not be swaped, as they will be
- * filled in URB completion handler.
+ * Pages are reserved to make sure they will not be swapped, as they will be
+ * filled in the URB completion handler.
*
* Buffers will be individually mapped, so they must all be page aligned.
*/
@@ -132,7 +132,7 @@ int uvc_alloc_buffers(struct uvc_video_queue *queue, unsigned int nbuffers,
queue->buffer[i].buf.index = i;
queue->buffer[i].buf.m.offset = i * bufsize;
queue->buffer[i].buf.length = buflength;
- queue->buffer[i].buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ queue->buffer[i].buf.type = queue->type;
queue->buffer[i].buf.sequence = 0;
queue->buffer[i].buf.field = V4L2_FIELD_NONE;
queue->buffer[i].buf.memory = V4L2_MEMORY_MMAP;
@@ -209,8 +209,8 @@ int uvc_query_buffer(struct uvc_video_queue *queue,
__uvc_query_buffer(&queue->buffer[v4l2_buf->index], v4l2_buf);
done:
- mutex_unlock(&queue->mutex);
- return ret;
+ mutex_unlock(&queue->mutex);
+ return ret;
}
/*
@@ -226,7 +226,7 @@ int uvc_queue_buffer(struct uvc_video_queue *queue,
uvc_trace(UVC_TRACE_CAPTURE, "Queuing buffer %u.\n", v4l2_buf->index);
- if (v4l2_buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE ||
+ if (v4l2_buf->type != queue->type ||
v4l2_buf->memory != V4L2_MEMORY_MMAP) {
uvc_trace(UVC_TRACE_CAPTURE, "[E] Invalid buffer type (%u) "
"and/or memory (%u).\n", v4l2_buf->type,
@@ -235,7 +235,7 @@ int uvc_queue_buffer(struct uvc_video_queue *queue,
}
mutex_lock(&queue->mutex);
- if (v4l2_buf->index >= queue->count) {
+ if (v4l2_buf->index >= queue->count) {
uvc_trace(UVC_TRACE_CAPTURE, "[E] Out of range index.\n");
ret = -EINVAL;
goto done;
@@ -249,6 +249,13 @@ int uvc_queue_buffer(struct uvc_video_queue *queue,
goto done;
}
+ if (v4l2_buf->type == V4L2_BUF_TYPE_VIDEO_OUTPUT &&
+ v4l2_buf->bytesused > buf->buf.length) {
+ uvc_trace(UVC_TRACE_CAPTURE, "[E] Bytes used out of bounds.\n");
+ ret = -EINVAL;
+ goto done;
+ }
+
spin_lock_irqsave(&queue->irqlock, flags);
if (queue->flags & UVC_QUEUE_DISCONNECTED) {
spin_unlock_irqrestore(&queue->irqlock, flags);
@@ -256,7 +263,11 @@ int uvc_queue_buffer(struct uvc_video_queue *queue,
goto done;
}
buf->state = UVC_BUF_STATE_QUEUED;
- buf->buf.bytesused = 0;
+ if (v4l2_buf->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ buf->buf.bytesused = 0;
+ else
+ buf->buf.bytesused = v4l2_buf->bytesused;
+
list_add_tail(&buf->stream, &queue->mainqueue);
list_add_tail(&buf->queue, &queue->irqqueue);
spin_unlock_irqrestore(&queue->irqlock, flags);
@@ -289,7 +300,7 @@ int uvc_dequeue_buffer(struct uvc_video_queue *queue,
struct uvc_buffer *buf;
int ret = 0;
- if (v4l2_buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE ||
+ if (v4l2_buf->type != queue->type ||
v4l2_buf->memory != V4L2_MEMORY_MMAP) {
uvc_trace(UVC_TRACE_CAPTURE, "[E] Invalid buffer type (%u) "
"and/or memory (%u).\n", v4l2_buf->type,
@@ -397,6 +408,7 @@ int uvc_queue_enable(struct uvc_video_queue *queue, int enable)
}
queue->sequence = 0;
queue->flags |= UVC_QUEUE_STREAMING;
+ queue->buf_used = 0;
} else {
uvc_queue_cancel(queue, 0);
INIT_LIST_HEAD(&queue->mainqueue);
@@ -416,7 +428,7 @@ done:
* Cancel the video buffers queue.
*
* Cancelling the queue marks all buffers on the irq queue as erroneous,
- * wakes them up and remove them from the queue.
+ * wakes them up and removes them from the queue.
*
* If the disconnect parameter is set, further calls to uvc_queue_buffer will
* fail with -ENODEV.
diff --git a/drivers/media/video/uvc/uvc_status.c b/drivers/media/video/uvc/uvc_status.c
index fdf7b4187ee..c705f248da8 100644
--- a/drivers/media/video/uvc/uvc_status.c
+++ b/drivers/media/video/uvc/uvc_status.c
@@ -1,7 +1,7 @@
/*
* uvc_status.c -- USB Video Class driver - Status endpoint
*
- * Copyright (C) 2007-2008
+ * Copyright (C) 2007-2009
* Laurent Pinchart (laurent.pinchart@skynet.be)
*
* This program is free software; you can redistribute it and/or modify
@@ -12,7 +12,6 @@
*/
#include <linux/kernel.h>
-#include <linux/version.h>
#include <linux/input.h>
#include <linux/usb.h>
#include <linux/usb/input.h>
diff --git a/drivers/media/video/uvc/uvc_v4l2.c b/drivers/media/video/uvc/uvc_v4l2.c
index 758dfefaba8..d681519d0c8 100644
--- a/drivers/media/video/uvc/uvc_v4l2.c
+++ b/drivers/media/video/uvc/uvc_v4l2.c
@@ -1,7 +1,7 @@
/*
* uvc_v4l2.c -- USB Video Class driver - V4L2 API
*
- * Copyright (C) 2005-2008
+ * Copyright (C) 2005-2009
* Laurent Pinchart (laurent.pinchart@skynet.be)
*
* This program is free software; you can redistribute it and/or modify
@@ -37,7 +37,7 @@
* must be grouped (for instance the Red Balance, Blue Balance and Do White
* Balance V4L2 controls use the White Balance Component UVC control) or
* otherwise translated. The approach we take here is to use a translation
- * table for the controls which can be mapped directly, and handle the others
+ * table for the controls that can be mapped directly, and handle the others
* manually.
*/
static int uvc_v4l2_query_menu(struct uvc_video_device *video,
@@ -110,7 +110,7 @@ static int uvc_v4l2_try_format(struct uvc_video_device *video,
int ret = 0;
__u8 *fcc;
- if (fmt->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ if (fmt->type != video->streaming->type)
return -EINVAL;
fcc = (__u8 *)&fmt->fmt.pix.pixelformat;
@@ -189,7 +189,7 @@ static int uvc_v4l2_try_format(struct uvc_video_device *video,
probe->dwMaxVideoFrameSize =
video->streaming->ctrl.dwMaxVideoFrameSize;
- /* Probe the device */
+ /* Probe the device. */
if ((ret = uvc_probe_video(video, probe)) < 0)
goto done;
@@ -216,7 +216,7 @@ static int uvc_v4l2_get_format(struct uvc_video_device *video,
struct uvc_format *format = video->streaming->cur_format;
struct uvc_frame *frame = video->streaming->cur_frame;
- if (fmt->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ if (fmt->type != video->streaming->type)
return -EINVAL;
if (format == NULL || frame == NULL)
@@ -242,7 +242,7 @@ static int uvc_v4l2_set_format(struct uvc_video_device *video,
struct uvc_frame *frame;
int ret;
- if (fmt->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ if (fmt->type != video->streaming->type)
return -EINVAL;
if (uvc_queue_streaming(&video->queue))
@@ -252,9 +252,6 @@ static int uvc_v4l2_set_format(struct uvc_video_device *video,
if (ret < 0)
return ret;
- if ((ret = uvc_set_video_ctrl(video, &probe, 0)) < 0)
- return ret;
-
memcpy(&video->streaming->ctrl, &probe, sizeof probe);
video->streaming->cur_format = format;
video->streaming->cur_frame = frame;
@@ -267,7 +264,7 @@ static int uvc_v4l2_get_streamparm(struct uvc_video_device *video,
{
uint32_t numerator, denominator;
- if (parm->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ if (parm->type != video->streaming->type)
return -EINVAL;
numerator = video->streaming->ctrl.dwFrameInterval;
@@ -275,13 +272,21 @@ static int uvc_v4l2_get_streamparm(struct uvc_video_device *video,
uvc_simplify_fraction(&numerator, &denominator, 8, 333);
memset(parm, 0, sizeof *parm);
- parm->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- parm->parm.capture.capability = V4L2_CAP_TIMEPERFRAME;
- parm->parm.capture.capturemode = 0;
- parm->parm.capture.timeperframe.numerator = numerator;
- parm->parm.capture.timeperframe.denominator = denominator;
- parm->parm.capture.extendedmode = 0;
- parm->parm.capture.readbuffers = 0;
+ parm->type = video->streaming->type;
+
+ if (video->streaming->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
+ parm->parm.capture.capability = V4L2_CAP_TIMEPERFRAME;
+ parm->parm.capture.capturemode = 0;
+ parm->parm.capture.timeperframe.numerator = numerator;
+ parm->parm.capture.timeperframe.denominator = denominator;
+ parm->parm.capture.extendedmode = 0;
+ parm->parm.capture.readbuffers = 0;
+ } else {
+ parm->parm.output.capability = V4L2_CAP_TIMEPERFRAME;
+ parm->parm.output.outputmode = 0;
+ parm->parm.output.timeperframe.numerator = numerator;
+ parm->parm.output.timeperframe.denominator = denominator;
+ }
return 0;
}
@@ -291,42 +296,45 @@ static int uvc_v4l2_set_streamparm(struct uvc_video_device *video,
{
struct uvc_frame *frame = video->streaming->cur_frame;
struct uvc_streaming_control probe;
+ struct v4l2_fract timeperframe;
uint32_t interval;
int ret;
- if (parm->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ if (parm->type != video->streaming->type)
return -EINVAL;
if (uvc_queue_streaming(&video->queue))
return -EBUSY;
+ if (parm->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ timeperframe = parm->parm.capture.timeperframe;
+ else
+ timeperframe = parm->parm.output.timeperframe;
+
memcpy(&probe, &video->streaming->ctrl, sizeof probe);
- interval = uvc_fraction_to_interval(
- parm->parm.capture.timeperframe.numerator,
- parm->parm.capture.timeperframe.denominator);
+ interval = uvc_fraction_to_interval(timeperframe.numerator,
+ timeperframe.denominator);
uvc_trace(UVC_TRACE_FORMAT, "Setting frame interval to %u/%u (%u).\n",
- parm->parm.capture.timeperframe.numerator,
- parm->parm.capture.timeperframe.denominator,
- interval);
+ timeperframe.numerator, timeperframe.denominator, interval);
probe.dwFrameInterval = uvc_try_frame_interval(frame, interval);
/* Probe the device with the new settings. */
if ((ret = uvc_probe_video(video, &probe)) < 0)
return ret;
- /* Commit the new settings. */
- if ((ret = uvc_set_video_ctrl(video, &probe, 0)) < 0)
- return ret;
-
memcpy(&video->streaming->ctrl, &probe, sizeof probe);
/* Return the actual frame period. */
- parm->parm.capture.timeperframe.numerator = probe.dwFrameInterval;
- parm->parm.capture.timeperframe.denominator = 10000000;
- uvc_simplify_fraction(&parm->parm.capture.timeperframe.numerator,
- &parm->parm.capture.timeperframe.denominator,
- 8, 333);
+ timeperframe.numerator = probe.dwFrameInterval;
+ timeperframe.denominator = 10000000;
+ uvc_simplify_fraction(&timeperframe.numerator,
+ &timeperframe.denominator, 8, 333);
+
+ if (parm->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ parm->parm.capture.timeperframe = timeperframe;
+ else
+ parm->parm.output.timeperframe = timeperframe;
return 0;
}
@@ -346,11 +354,11 @@ static int uvc_v4l2_set_streamparm(struct uvc_video_device *video,
*
* Each open instance of a UVC device can either be in a privileged or
* unprivileged state. Only a single instance can be in a privileged state at
- * a given time. Trying to perform an operation which requires privileges will
+ * a given time. Trying to perform an operation that requires privileges will
* automatically acquire the required privileges if possible, or return -EBUSY
* otherwise. Privileges are dismissed when closing the instance.
*
- * Operations which require privileges are:
+ * Operations that require privileges are:
*
* - VIDIOC_S_INPUT
* - VIDIOC_S_PARM
@@ -398,7 +406,7 @@ static int uvc_has_privileges(struct uvc_fh *handle)
* V4L2 file operations
*/
-static int uvc_v4l2_open(struct inode *inode, struct file *file)
+static int uvc_v4l2_open(struct file *file)
{
struct uvc_video_device *video;
struct uvc_fh *handle;
@@ -436,7 +444,7 @@ done:
return ret;
}
-static int uvc_v4l2_release(struct inode *inode, struct file *file)
+static int uvc_v4l2_release(struct file *file)
{
struct uvc_video_device *video = video_drvdata(file);
struct uvc_fh *handle = (struct uvc_fh *)file->private_data;
@@ -464,16 +472,12 @@ static int uvc_v4l2_release(struct inode *inode, struct file *file)
return 0;
}
-static int __uvc_v4l2_do_ioctl(struct file *file,
- unsigned int cmd, void *arg)
+static long uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg)
{
struct video_device *vdev = video_devdata(file);
struct uvc_video_device *video = video_get_drvdata(vdev);
struct uvc_fh *handle = (struct uvc_fh *)file->private_data;
- int ret = 0;
-
- if (uvc_trace_param & UVC_TRACE_IOCTL)
- v4l_printk_ioctl(cmd);
+ long ret = 0;
switch (cmd) {
/* Query capabilities */
@@ -487,8 +491,12 @@ static int __uvc_v4l2_do_ioctl(struct file *file,
strncpy(cap->bus_info, video->dev->udev->bus->bus_name,
sizeof cap->bus_info);
cap->version = DRIVER_VERSION_NUMBER;
- cap->capabilities = V4L2_CAP_VIDEO_CAPTURE
- | V4L2_CAP_STREAMING;
+ if (video->streaming->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ cap->capabilities = V4L2_CAP_VIDEO_CAPTURE
+ | V4L2_CAP_STREAMING;
+ else
+ cap->capabilities = V4L2_CAP_VIDEO_OUTPUT
+ | V4L2_CAP_STREAMING;
break;
}
@@ -666,7 +674,7 @@ static int __uvc_v4l2_do_ioctl(struct file *file,
struct v4l2_fmtdesc *fmt = arg;
struct uvc_format *format;
- if (fmt->type != V4L2_BUF_TYPE_VIDEO_CAPTURE ||
+ if (fmt->type != video->streaming->type ||
fmt->index >= video->streaming->nformats)
return -EINVAL;
@@ -805,7 +813,7 @@ static int __uvc_v4l2_do_ioctl(struct file *file,
struct v4l2_cropcap *ccap = arg;
struct uvc_frame *frame = video->streaming->cur_frame;
- if (ccap->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ if (ccap->type != video->streaming->type)
return -EINVAL;
ccap->bounds.left = 0;
@@ -831,7 +839,7 @@ static int __uvc_v4l2_do_ioctl(struct file *file,
unsigned int bufsize =
video->streaming->ctrl.dwMaxVideoFrameSize;
- if (rb->type != V4L2_BUF_TYPE_VIDEO_CAPTURE ||
+ if (rb->type != video->streaming->type ||
rb->memory != V4L2_MEMORY_MMAP)
return -EINVAL;
@@ -851,7 +859,7 @@ static int __uvc_v4l2_do_ioctl(struct file *file,
{
struct v4l2_buffer *buf = arg;
- if (buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ if (buf->type != video->streaming->type)
return -EINVAL;
if (!uvc_has_privileges(handle))
@@ -877,7 +885,7 @@ static int __uvc_v4l2_do_ioctl(struct file *file,
{
int *type = arg;
- if (*type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ if (*type != video->streaming->type)
return -EINVAL;
if (!uvc_has_privileges(handle))
@@ -892,7 +900,7 @@ static int __uvc_v4l2_do_ioctl(struct file *file,
{
int *type = arg;
- if (*type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ if (*type != video->streaming->type)
return -EINVAL;
if (!uvc_has_privileges(handle))
@@ -925,7 +933,7 @@ static int __uvc_v4l2_do_ioctl(struct file *file,
if (!capable(CAP_SYS_ADMIN))
return -EPERM;
- info = kmalloc(sizeof *info, GFP_KERNEL);
+ info = kzalloc(sizeof *info, GFP_KERNEL);
if (info == NULL)
return -ENOMEM;
@@ -952,7 +960,7 @@ static int __uvc_v4l2_do_ioctl(struct file *file,
if (!capable(CAP_SYS_ADMIN))
return -EPERM;
- map = kmalloc(sizeof *map, GFP_KERNEL);
+ map = kzalloc(sizeof *map, GFP_KERNEL);
if (map == NULL)
return -ENOMEM;
@@ -979,7 +987,7 @@ static int __uvc_v4l2_do_ioctl(struct file *file,
default:
if ((ret = v4l_compat_translate_ioctl(file, cmd, arg,
- __uvc_v4l2_do_ioctl)) == -ENOIOCTLCMD)
+ uvc_v4l2_do_ioctl)) == -ENOIOCTLCMD)
uvc_trace(UVC_TRACE_IOCTL, "Unknown ioctl 0x%08x\n",
cmd);
return ret;
@@ -988,17 +996,16 @@ static int __uvc_v4l2_do_ioctl(struct file *file,
return ret;
}
-static int uvc_v4l2_do_ioctl(struct inode *inode, struct file *file,
- unsigned int cmd, void *arg)
-{
- return __uvc_v4l2_do_ioctl(file, cmd, arg);
-}
-
-static int uvc_v4l2_ioctl(struct inode *inode, struct file *file,
+static long uvc_v4l2_ioctl(struct file *file,
unsigned int cmd, unsigned long arg)
{
- uvc_trace(UVC_TRACE_CALLS, "uvc_v4l2_ioctl\n");
- return video_usercopy(inode, file, cmd, arg, uvc_v4l2_do_ioctl);
+ if (uvc_trace_param & UVC_TRACE_IOCTL) {
+ uvc_printk(KERN_DEBUG, "uvc_v4l2_ioctl(");
+ v4l_printk_ioctl(cmd);
+ printk(")\n");
+ }
+
+ return video_usercopy(file, cmd, arg, uvc_v4l2_do_ioctl);
}
static ssize_t uvc_v4l2_read(struct file *file, char __user *data,
@@ -1090,13 +1097,11 @@ static unsigned int uvc_v4l2_poll(struct file *file, poll_table *wait)
return uvc_queue_poll(&video->queue, file, wait);
}
-struct file_operations uvc_fops = {
+const struct v4l2_file_operations uvc_fops = {
.owner = THIS_MODULE,
.open = uvc_v4l2_open,
.release = uvc_v4l2_release,
.ioctl = uvc_v4l2_ioctl,
- .compat_ioctl = v4l_compat_ioctl32,
- .llseek = no_llseek,
.read = uvc_v4l2_read,
.mmap = uvc_v4l2_mmap,
.poll = uvc_v4l2_poll,
diff --git a/drivers/media/video/uvc/uvc_video.c b/drivers/media/video/uvc/uvc_video.c
index b7bb23820d8..9bc4705be78 100644
--- a/drivers/media/video/uvc/uvc_video.c
+++ b/drivers/media/video/uvc/uvc_video.c
@@ -1,7 +1,7 @@
/*
* uvc_video.c -- USB Video Class driver - Video handling
*
- * Copyright (C) 2005-2008
+ * Copyright (C) 2005-2009
* Laurent Pinchart (laurent.pinchart@skynet.be)
*
* This program is free software; you can redistribute it and/or modify
@@ -12,7 +12,6 @@
*/
#include <linux/kernel.h>
-#include <linux/version.h>
#include <linux/list.h>
#include <linux/module.h>
#include <linux/usb.h>
@@ -36,15 +35,22 @@ static int __uvc_query_ctrl(struct uvc_device *dev, __u8 query, __u8 unit,
{
__u8 type = USB_TYPE_CLASS | USB_RECIP_INTERFACE;
unsigned int pipe;
- int ret;
pipe = (query & 0x80) ? usb_rcvctrlpipe(dev->udev, 0)
: usb_sndctrlpipe(dev->udev, 0);
type |= (query & 0x80) ? USB_DIR_IN : USB_DIR_OUT;
- ret = usb_control_msg(dev->udev, pipe, query, type, cs << 8,
+ return usb_control_msg(dev->udev, pipe, query, type, cs << 8,
unit << 8 | intfnum, data, size, timeout);
+}
+int uvc_query_ctrl(struct uvc_device *dev, __u8 query, __u8 unit,
+ __u8 intfnum, __u8 cs, void *data, __u16 size)
+{
+ int ret;
+
+ ret = __uvc_query_ctrl(dev, query, unit, intfnum, cs, data, size,
+ UVC_CTRL_CONTROL_TIMEOUT);
if (ret != size) {
uvc_printk(KERN_ERR, "Failed to query (%u) UVC control %u "
"(unit %u) : %d (exp. %u).\n", query, cs, unit, ret,
@@ -55,13 +61,6 @@ static int __uvc_query_ctrl(struct uvc_device *dev, __u8 query, __u8 unit,
return 0;
}
-int uvc_query_ctrl(struct uvc_device *dev, __u8 query, __u8 unit,
- __u8 intfnum, __u8 cs, void *data, __u16 size)
-{
- return __uvc_query_ctrl(dev, query, unit, intfnum, cs, data, size,
- UVC_CTRL_CONTROL_TIMEOUT);
-}
-
static void uvc_fixup_buffer_size(struct uvc_video_device *video,
struct uvc_streaming_control *ctrl)
{
@@ -102,8 +101,36 @@ static int uvc_get_video_ctrl(struct uvc_video_device *video,
ret = __uvc_query_ctrl(video->dev, query, 0, video->streaming->intfnum,
probe ? VS_PROBE_CONTROL : VS_COMMIT_CONTROL, data, size,
UVC_CTRL_STREAMING_TIMEOUT);
- if (ret < 0)
+
+ if ((query == GET_MIN || query == GET_MAX) && ret == 2) {
+ /* Some cameras, mostly based on Bison Electronics chipsets,
+ * answer a GET_MIN or GET_MAX request with the wCompQuality
+ * field only.
+ */
+ uvc_warn_once(video->dev, UVC_WARN_MINMAX, "UVC non "
+ "compliance - GET_MIN/MAX(PROBE) incorrectly "
+ "supported. Enabling workaround.\n");
+ memset(ctrl, 0, sizeof ctrl);
+ ctrl->wCompQuality = le16_to_cpup((__le16 *)data);
+ ret = 0;
goto out;
+ } else if (query == GET_DEF && probe == 1 && ret != size) {
+ /* Many cameras don't support the GET_DEF request on their
+ * video probe control. Warn once and return, the caller will
+ * fall back to GET_CUR.
+ */
+ uvc_warn_once(video->dev, UVC_WARN_PROBE_DEF, "UVC non "
+ "compliance - GET_DEF(PROBE) not supported. "
+ "Enabling workaround.\n");
+ ret = -EIO;
+ goto out;
+ } else if (ret != size) {
+ uvc_printk(KERN_ERR, "Failed to query (%u) UVC %s control : "
+ "%d (exp. %u).\n", query, probe ? "probe" : "commit",
+ ret, size);
+ ret = -EIO;
+ goto out;
+ }
ctrl->bmHint = le16_to_cpup((__le16 *)&data[0]);
ctrl->bFormatIndex = data[2];
@@ -114,14 +141,11 @@ static int uvc_get_video_ctrl(struct uvc_video_device *video,
ctrl->wCompQuality = le16_to_cpup((__le16 *)&data[12]);
ctrl->wCompWindowSize = le16_to_cpup((__le16 *)&data[14]);
ctrl->wDelay = le16_to_cpup((__le16 *)&data[16]);
- ctrl->dwMaxVideoFrameSize =
- le32_to_cpu(get_unaligned((__le32 *)&data[18]));
- ctrl->dwMaxPayloadTransferSize =
- le32_to_cpu(get_unaligned((__le32 *)&data[22]));
+ ctrl->dwMaxVideoFrameSize = get_unaligned_le32(&data[18]);
+ ctrl->dwMaxPayloadTransferSize = get_unaligned_le32(&data[22]);
if (size == 34) {
- ctrl->dwClockFrequency =
- le32_to_cpu(get_unaligned((__le32 *)&data[26]));
+ ctrl->dwClockFrequency = get_unaligned_le32(&data[26]);
ctrl->bmFramingInfo = data[30];
ctrl->bPreferedVersion = data[31];
ctrl->bMinVersion = data[32];
@@ -135,16 +159,17 @@ static int uvc_get_video_ctrl(struct uvc_video_device *video,
}
/* Some broken devices return a null or wrong dwMaxVideoFrameSize.
- * Try to get the value from the format and frame descriptor.
+ * Try to get the value from the format and frame descriptors.
*/
uvc_fixup_buffer_size(video, ctrl);
+ ret = 0;
out:
kfree(data);
return ret;
}
-int uvc_set_video_ctrl(struct uvc_video_device *video,
+static int uvc_set_video_ctrl(struct uvc_video_device *video,
struct uvc_streaming_control *ctrl, int probe)
{
__u8 *data;
@@ -165,17 +190,11 @@ int uvc_set_video_ctrl(struct uvc_video_device *video,
*(__le16 *)&data[12] = cpu_to_le16(ctrl->wCompQuality);
*(__le16 *)&data[14] = cpu_to_le16(ctrl->wCompWindowSize);
*(__le16 *)&data[16] = cpu_to_le16(ctrl->wDelay);
- /* Note: Some of the fields below are not required for IN devices (see
- * UVC spec, 4.3.1.1), but we still copy them in case support for OUT
- * devices is added in the future. */
- put_unaligned(cpu_to_le32(ctrl->dwMaxVideoFrameSize),
- (__le32 *)&data[18]);
- put_unaligned(cpu_to_le32(ctrl->dwMaxPayloadTransferSize),
- (__le32 *)&data[22]);
+ put_unaligned_le32(ctrl->dwMaxVideoFrameSize, &data[18]);
+ put_unaligned_le32(ctrl->dwMaxPayloadTransferSize, &data[22]);
if (size == 34) {
- put_unaligned(cpu_to_le32(ctrl->dwClockFrequency),
- (__le32 *)&data[26]);
+ put_unaligned_le32(ctrl->dwClockFrequency, &data[26]);
data[30] = ctrl->bmFramingInfo;
data[31] = ctrl->bPreferedVersion;
data[32] = ctrl->bMinVersion;
@@ -186,6 +205,12 @@ int uvc_set_video_ctrl(struct uvc_video_device *video,
video->streaming->intfnum,
probe ? VS_PROBE_CONTROL : VS_COMMIT_CONTROL, data, size,
UVC_CTRL_STREAMING_TIMEOUT);
+ if (ret != size) {
+ uvc_printk(KERN_ERR, "Failed to set UVC %s control : "
+ "%d (exp. %u).\n", probe ? "probe" : "commit",
+ ret, size);
+ ret = -EIO;
+ }
kfree(data);
return ret;
@@ -252,6 +277,12 @@ done:
return ret;
}
+int uvc_commit_video(struct uvc_video_device *video,
+ struct uvc_streaming_control *probe)
+{
+ return uvc_set_video_ctrl(video, probe, 0);
+}
+
/* ------------------------------------------------------------------------
* Video codecs
*/
@@ -333,7 +364,7 @@ static int uvc_video_decode_start(struct uvc_video_device *video,
/* Synchronize to the input stream by waiting for the FID bit to be
* toggled when the the buffer state is not UVC_BUF_STATE_ACTIVE.
- * queue->last_fid is initialized to -1, so the first isochronous
+ * video->last_fid is initialized to -1, so the first isochronous
* frame will always be in sync.
*
* If the device doesn't toggle the FID bit, invert video->last_fid
@@ -360,12 +391,12 @@ static int uvc_video_decode_start(struct uvc_video_device *video,
* last payload can be lost anyway). We thus must check if the FID has
* been toggled.
*
- * queue->last_fid is initialized to -1, so the first isochronous
+ * video->last_fid is initialized to -1, so the first isochronous
* frame will never trigger an end of frame detection.
*
* Empty buffers (bytesused == 0) don't trigger end of frame detection
* as it doesn't make sense to return an empty buffer. This also
- * avoids detecting and of frame conditions at FID toggling if the
+ * avoids detecting end of frame conditions at FID toggling if the
* previous payload had the EOF bit set.
*/
if (fid != video->last_fid && buf->buf.bytesused != 0) {
@@ -418,6 +449,45 @@ static void uvc_video_decode_end(struct uvc_video_device *video,
}
}
+/* Video payload encoding is handled by uvc_video_encode_header() and
+ * uvc_video_encode_data(). Only bulk transfers are currently supported.
+ *
+ * uvc_video_encode_header is called at the start of a payload. It adds header
+ * data to the transfer buffer and returns the header size. As the only known
+ * UVC output device transfers a whole frame in a single payload, the EOF bit
+ * is always set in the header.
+ *
+ * uvc_video_encode_data is called for every URB and copies the data from the
+ * video buffer to the transfer buffer.
+ */
+static int uvc_video_encode_header(struct uvc_video_device *video,
+ struct uvc_buffer *buf, __u8 *data, int len)
+{
+ data[0] = 2; /* Header length */
+ data[1] = UVC_STREAM_EOH | UVC_STREAM_EOF
+ | (video->last_fid & UVC_STREAM_FID);
+ return 2;
+}
+
+static int uvc_video_encode_data(struct uvc_video_device *video,
+ struct uvc_buffer *buf, __u8 *data, int len)
+{
+ struct uvc_video_queue *queue = &video->queue;
+ unsigned int nbytes;
+ void *mem;
+
+ /* Copy video data to the URB buffer. */
+ mem = queue->mem + buf->buf.m.offset + queue->buf_used;
+ nbytes = min((unsigned int)len, buf->buf.bytesused - queue->buf_used);
+ nbytes = min(video->bulk.max_payload_size - video->bulk.payload_size,
+ nbytes);
+ memcpy(data, mem, nbytes);
+
+ queue->buf_used += nbytes;
+
+ return nbytes;
+}
+
/* ------------------------------------------------------------------------
* URB handling
*/
@@ -477,7 +547,7 @@ static void uvc_video_decode_bulk(struct urb *urb,
/* If the URB is the first of its payload, decode and save the
* header.
*/
- if (video->bulk.header_size == 0) {
+ if (video->bulk.header_size == 0 && !video->bulk.skip_payload) {
do {
ret = uvc_video_decode_start(video, buf, mem, len);
if (ret == -EAGAIN)
@@ -487,14 +557,13 @@ static void uvc_video_decode_bulk(struct urb *urb,
/* If an error occured skip the rest of the payload. */
if (ret < 0 || buf == NULL) {
video->bulk.skip_payload = 1;
- return;
- }
-
- video->bulk.header_size = ret;
- memcpy(video->bulk.header, mem, video->bulk.header_size);
+ } else {
+ memcpy(video->bulk.header, mem, ret);
+ video->bulk.header_size = ret;
- mem += ret;
- len -= ret;
+ mem += ret;
+ len -= ret;
+ }
}
/* The buffer queue might have been cancelled while a bulk transfer
@@ -525,6 +594,48 @@ static void uvc_video_decode_bulk(struct urb *urb,
}
}
+static void uvc_video_encode_bulk(struct urb *urb,
+ struct uvc_video_device *video, struct uvc_buffer *buf)
+{
+ u8 *mem = urb->transfer_buffer;
+ int len = video->urb_size, ret;
+
+ if (buf == NULL) {
+ urb->transfer_buffer_length = 0;
+ return;
+ }
+
+ /* If the URB is the first of its payload, add the header. */
+ if (video->bulk.header_size == 0) {
+ ret = uvc_video_encode_header(video, buf, mem, len);
+ video->bulk.header_size = ret;
+ video->bulk.payload_size += ret;
+ mem += ret;
+ len -= ret;
+ }
+
+ /* Process video data. */
+ ret = uvc_video_encode_data(video, buf, mem, len);
+
+ video->bulk.payload_size += ret;
+ len -= ret;
+
+ if (buf->buf.bytesused == video->queue.buf_used ||
+ video->bulk.payload_size == video->bulk.max_payload_size) {
+ if (buf->buf.bytesused == video->queue.buf_used) {
+ video->queue.buf_used = 0;
+ buf->state = UVC_BUF_STATE_DONE;
+ uvc_queue_next_buffer(&video->queue, buf);
+ video->last_fid ^= UVC_STREAM_FID;
+ }
+
+ video->bulk.header_size = 0;
+ video->bulk.payload_size = 0;
+ }
+
+ urb->transfer_buffer_length = video->urb_size - len;
+}
+
static void uvc_video_complete(struct urb *urb)
{
struct uvc_video_device *video = urb->context;
@@ -722,7 +833,15 @@ static int uvc_init_video_bulk(struct uvc_video_device *video,
if (uvc_alloc_urb_buffers(video, size) < 0)
return -ENOMEM;
- pipe = usb_rcvbulkpipe(video->dev->udev, ep->desc.bEndpointAddress);
+ if (usb_endpoint_dir_in(&ep->desc))
+ pipe = usb_rcvbulkpipe(video->dev->udev,
+ ep->desc.bEndpointAddress);
+ else
+ pipe = usb_sndbulkpipe(video->dev->udev,
+ ep->desc.bEndpointAddress);
+
+ if (video->streaming->type == V4L2_BUF_TYPE_VIDEO_OUTPUT)
+ size = 0;
for (i = 0; i < UVC_URBS; ++i) {
urb = usb_alloc_urb(0, gfp_flags);
@@ -841,7 +960,7 @@ int uvc_video_suspend(struct uvc_video_device *video)
}
/*
- * Reconfigure the video interface and restart streaming if it was enable
+ * Reconfigure the video interface and restart streaming if it was enabled
* before suspend.
*
* If an error occurs, disable the video queue. This will wake all pending
@@ -854,7 +973,7 @@ int uvc_video_resume(struct uvc_video_device *video)
video->frozen = 0;
- if ((ret = uvc_set_video_ctrl(video, &video->streaming->ctrl, 0)) < 0) {
+ if ((ret = uvc_commit_video(video, &video->streaming->ctrl)) < 0) {
uvc_queue_enable(&video->queue, 0);
return ret;
}
@@ -873,8 +992,8 @@ int uvc_video_resume(struct uvc_video_device *video)
*/
/*
- * Initialize the UVC video device by retrieving the default format and
- * committing it.
+ * Initialize the UVC video device by switching to alternate setting 0 and
+ * retrieve the default format.
*
* Some cameras (namely the Fuji Finepix) set the format and frame
* indexes to zero. The UVC standard doesn't clearly make this a spec
@@ -902,7 +1021,7 @@ int uvc_video_init(struct uvc_video_device *video)
*/
usb_set_interface(video->dev->udev, video->streaming->intfnum, 0);
- /* Some webcams don't suport GET_DEF request on the probe control. We
+ /* Some webcams don't suport GET_DEF requests on the probe control. We
* fall back to GET_CUR if GET_DEF fails.
*/
if ((ret = uvc_get_video_ctrl(video, probe, 1, GET_DEF)) < 0 &&
@@ -935,23 +1054,30 @@ int uvc_video_init(struct uvc_video_device *video)
break;
}
- /* Commit the default settings. */
probe->bFormatIndex = format->index;
probe->bFrameIndex = frame->bFrameIndex;
- if ((ret = uvc_set_video_ctrl(video, probe, 0)) < 0)
- return ret;
video->streaming->cur_format = format;
video->streaming->cur_frame = frame;
atomic_set(&video->active, 0);
/* Select the video decoding function */
- if (video->dev->quirks & UVC_QUIRK_BUILTIN_ISIGHT)
- video->decode = uvc_video_decode_isight;
- else if (video->streaming->intf->num_altsetting > 1)
- video->decode = uvc_video_decode_isoc;
- else
- video->decode = uvc_video_decode_bulk;
+ if (video->streaming->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
+ if (video->dev->quirks & UVC_QUIRK_BUILTIN_ISIGHT)
+ video->decode = uvc_video_decode_isight;
+ else if (video->streaming->intf->num_altsetting > 1)
+ video->decode = uvc_video_decode_isoc;
+ else
+ video->decode = uvc_video_decode_bulk;
+ } else {
+ if (video->streaming->intf->num_altsetting == 1)
+ video->decode = uvc_video_encode_bulk;
+ else {
+ uvc_printk(KERN_INFO, "Isochronous endpoints are not "
+ "supported for video output devices.\n");
+ return -EINVAL;
+ }
+ }
return 0;
}
@@ -971,7 +1097,8 @@ int uvc_video_enable(struct uvc_video_device *video, int enable)
return 0;
}
- if (video->streaming->cur_format->flags & UVC_FMT_FLAG_COMPRESSED)
+ if ((video->streaming->cur_format->flags & UVC_FMT_FLAG_COMPRESSED) ||
+ uvc_no_drop_param)
video->queue.flags &= ~UVC_QUEUE_DROP_INCOMPLETE;
else
video->queue.flags |= UVC_QUEUE_DROP_INCOMPLETE;
@@ -979,6 +1106,10 @@ int uvc_video_enable(struct uvc_video_device *video, int enable)
if ((ret = uvc_queue_enable(&video->queue, 1)) < 0)
return ret;
+ /* Commit the streaming parameters. */
+ if ((ret = uvc_commit_video(video, &video->streaming->ctrl)) < 0)
+ return ret;
+
return uvc_init_video(video, GFP_KERNEL);
}
diff --git a/drivers/media/video/uvc/uvcvideo.h b/drivers/media/video/uvc/uvcvideo.h
index 9a6bc1aafb1..027947ea9b6 100644
--- a/drivers/media/video/uvc/uvcvideo.h
+++ b/drivers/media/video/uvc/uvcvideo.h
@@ -4,7 +4,6 @@
#include <linux/kernel.h>
#include <linux/videodev2.h>
-
/*
* Dynamic controls
*/
@@ -73,149 +72,149 @@ struct uvc_xu_control {
* UVC constants
*/
-#define SC_UNDEFINED 0x00
-#define SC_VIDEOCONTROL 0x01
-#define SC_VIDEOSTREAMING 0x02
-#define SC_VIDEO_INTERFACE_COLLECTION 0x03
+#define SC_UNDEFINED 0x00
+#define SC_VIDEOCONTROL 0x01
+#define SC_VIDEOSTREAMING 0x02
+#define SC_VIDEO_INTERFACE_COLLECTION 0x03
-#define PC_PROTOCOL_UNDEFINED 0x00
+#define PC_PROTOCOL_UNDEFINED 0x00
-#define CS_UNDEFINED 0x20
-#define CS_DEVICE 0x21
-#define CS_CONFIGURATION 0x22
-#define CS_STRING 0x23
-#define CS_INTERFACE 0x24
-#define CS_ENDPOINT 0x25
+#define CS_UNDEFINED 0x20
+#define CS_DEVICE 0x21
+#define CS_CONFIGURATION 0x22
+#define CS_STRING 0x23
+#define CS_INTERFACE 0x24
+#define CS_ENDPOINT 0x25
/* VideoControl class specific interface descriptor */
-#define VC_DESCRIPTOR_UNDEFINED 0x00
-#define VC_HEADER 0x01
-#define VC_INPUT_TERMINAL 0x02
-#define VC_OUTPUT_TERMINAL 0x03
-#define VC_SELECTOR_UNIT 0x04
-#define VC_PROCESSING_UNIT 0x05
-#define VC_EXTENSION_UNIT 0x06
+#define VC_DESCRIPTOR_UNDEFINED 0x00
+#define VC_HEADER 0x01
+#define VC_INPUT_TERMINAL 0x02
+#define VC_OUTPUT_TERMINAL 0x03
+#define VC_SELECTOR_UNIT 0x04
+#define VC_PROCESSING_UNIT 0x05
+#define VC_EXTENSION_UNIT 0x06
/* VideoStreaming class specific interface descriptor */
-#define VS_UNDEFINED 0x00
-#define VS_INPUT_HEADER 0x01
-#define VS_OUTPUT_HEADER 0x02
-#define VS_STILL_IMAGE_FRAME 0x03
-#define VS_FORMAT_UNCOMPRESSED 0x04
-#define VS_FRAME_UNCOMPRESSED 0x05
-#define VS_FORMAT_MJPEG 0x06
-#define VS_FRAME_MJPEG 0x07
-#define VS_FORMAT_MPEG2TS 0x0a
-#define VS_FORMAT_DV 0x0c
-#define VS_COLORFORMAT 0x0d
-#define VS_FORMAT_FRAME_BASED 0x10
-#define VS_FRAME_FRAME_BASED 0x11
-#define VS_FORMAT_STREAM_BASED 0x12
+#define VS_UNDEFINED 0x00
+#define VS_INPUT_HEADER 0x01
+#define VS_OUTPUT_HEADER 0x02
+#define VS_STILL_IMAGE_FRAME 0x03
+#define VS_FORMAT_UNCOMPRESSED 0x04
+#define VS_FRAME_UNCOMPRESSED 0x05
+#define VS_FORMAT_MJPEG 0x06
+#define VS_FRAME_MJPEG 0x07
+#define VS_FORMAT_MPEG2TS 0x0a
+#define VS_FORMAT_DV 0x0c
+#define VS_COLORFORMAT 0x0d
+#define VS_FORMAT_FRAME_BASED 0x10
+#define VS_FRAME_FRAME_BASED 0x11
+#define VS_FORMAT_STREAM_BASED 0x12
/* Endpoint type */
-#define EP_UNDEFINED 0x00
-#define EP_GENERAL 0x01
-#define EP_ENDPOINT 0x02
-#define EP_INTERRUPT 0x03
+#define EP_UNDEFINED 0x00
+#define EP_GENERAL 0x01
+#define EP_ENDPOINT 0x02
+#define EP_INTERRUPT 0x03
/* Request codes */
-#define RC_UNDEFINED 0x00
-#define SET_CUR 0x01
-#define GET_CUR 0x81
-#define GET_MIN 0x82
-#define GET_MAX 0x83
-#define GET_RES 0x84
-#define GET_LEN 0x85
-#define GET_INFO 0x86
-#define GET_DEF 0x87
+#define RC_UNDEFINED 0x00
+#define SET_CUR 0x01
+#define GET_CUR 0x81
+#define GET_MIN 0x82
+#define GET_MAX 0x83
+#define GET_RES 0x84
+#define GET_LEN 0x85
+#define GET_INFO 0x86
+#define GET_DEF 0x87
/* VideoControl interface controls */
-#define VC_CONTROL_UNDEFINED 0x00
-#define VC_VIDEO_POWER_MODE_CONTROL 0x01
-#define VC_REQUEST_ERROR_CODE_CONTROL 0x02
+#define VC_CONTROL_UNDEFINED 0x00
+#define VC_VIDEO_POWER_MODE_CONTROL 0x01
+#define VC_REQUEST_ERROR_CODE_CONTROL 0x02
/* Terminal controls */
-#define TE_CONTROL_UNDEFINED 0x00
+#define TE_CONTROL_UNDEFINED 0x00
/* Selector Unit controls */
-#define SU_CONTROL_UNDEFINED 0x00
-#define SU_INPUT_SELECT_CONTROL 0x01
+#define SU_CONTROL_UNDEFINED 0x00
+#define SU_INPUT_SELECT_CONTROL 0x01
/* Camera Terminal controls */
-#define CT_CONTROL_UNDEFINED 0x00
-#define CT_SCANNING_MODE_CONTROL 0x01
-#define CT_AE_MODE_CONTROL 0x02
-#define CT_AE_PRIORITY_CONTROL 0x03
-#define CT_EXPOSURE_TIME_ABSOLUTE_CONTROL 0x04
-#define CT_EXPOSURE_TIME_RELATIVE_CONTROL 0x05
-#define CT_FOCUS_ABSOLUTE_CONTROL 0x06
-#define CT_FOCUS_RELATIVE_CONTROL 0x07
-#define CT_FOCUS_AUTO_CONTROL 0x08
-#define CT_IRIS_ABSOLUTE_CONTROL 0x09
-#define CT_IRIS_RELATIVE_CONTROL 0x0a
-#define CT_ZOOM_ABSOLUTE_CONTROL 0x0b
-#define CT_ZOOM_RELATIVE_CONTROL 0x0c
-#define CT_PANTILT_ABSOLUTE_CONTROL 0x0d
-#define CT_PANTILT_RELATIVE_CONTROL 0x0e
-#define CT_ROLL_ABSOLUTE_CONTROL 0x0f
-#define CT_ROLL_RELATIVE_CONTROL 0x10
-#define CT_PRIVACY_CONTROL 0x11
+#define CT_CONTROL_UNDEFINED 0x00
+#define CT_SCANNING_MODE_CONTROL 0x01
+#define CT_AE_MODE_CONTROL 0x02
+#define CT_AE_PRIORITY_CONTROL 0x03
+#define CT_EXPOSURE_TIME_ABSOLUTE_CONTROL 0x04
+#define CT_EXPOSURE_TIME_RELATIVE_CONTROL 0x05
+#define CT_FOCUS_ABSOLUTE_CONTROL 0x06
+#define CT_FOCUS_RELATIVE_CONTROL 0x07
+#define CT_FOCUS_AUTO_CONTROL 0x08
+#define CT_IRIS_ABSOLUTE_CONTROL 0x09
+#define CT_IRIS_RELATIVE_CONTROL 0x0a
+#define CT_ZOOM_ABSOLUTE_CONTROL 0x0b
+#define CT_ZOOM_RELATIVE_CONTROL 0x0c
+#define CT_PANTILT_ABSOLUTE_CONTROL 0x0d
+#define CT_PANTILT_RELATIVE_CONTROL 0x0e
+#define CT_ROLL_ABSOLUTE_CONTROL 0x0f
+#define CT_ROLL_RELATIVE_CONTROL 0x10
+#define CT_PRIVACY_CONTROL 0x11
/* Processing Unit controls */
-#define PU_CONTROL_UNDEFINED 0x00
-#define PU_BACKLIGHT_COMPENSATION_CONTROL 0x01
-#define PU_BRIGHTNESS_CONTROL 0x02
-#define PU_CONTRAST_CONTROL 0x03
-#define PU_GAIN_CONTROL 0x04
-#define PU_POWER_LINE_FREQUENCY_CONTROL 0x05
-#define PU_HUE_CONTROL 0x06
-#define PU_SATURATION_CONTROL 0x07
-#define PU_SHARPNESS_CONTROL 0x08
-#define PU_GAMMA_CONTROL 0x09
-#define PU_WHITE_BALANCE_TEMPERATURE_CONTROL 0x0a
-#define PU_WHITE_BALANCE_TEMPERATURE_AUTO_CONTROL 0x0b
-#define PU_WHITE_BALANCE_COMPONENT_CONTROL 0x0c
-#define PU_WHITE_BALANCE_COMPONENT_AUTO_CONTROL 0x0d
-#define PU_DIGITAL_MULTIPLIER_CONTROL 0x0e
-#define PU_DIGITAL_MULTIPLIER_LIMIT_CONTROL 0x0f
-#define PU_HUE_AUTO_CONTROL 0x10
-#define PU_ANALOG_VIDEO_STANDARD_CONTROL 0x11
-#define PU_ANALOG_LOCK_STATUS_CONTROL 0x12
+#define PU_CONTROL_UNDEFINED 0x00
+#define PU_BACKLIGHT_COMPENSATION_CONTROL 0x01
+#define PU_BRIGHTNESS_CONTROL 0x02
+#define PU_CONTRAST_CONTROL 0x03
+#define PU_GAIN_CONTROL 0x04
+#define PU_POWER_LINE_FREQUENCY_CONTROL 0x05
+#define PU_HUE_CONTROL 0x06
+#define PU_SATURATION_CONTROL 0x07
+#define PU_SHARPNESS_CONTROL 0x08
+#define PU_GAMMA_CONTROL 0x09
+#define PU_WHITE_BALANCE_TEMPERATURE_CONTROL 0x0a
+#define PU_WHITE_BALANCE_TEMPERATURE_AUTO_CONTROL 0x0b
+#define PU_WHITE_BALANCE_COMPONENT_CONTROL 0x0c
+#define PU_WHITE_BALANCE_COMPONENT_AUTO_CONTROL 0x0d
+#define PU_DIGITAL_MULTIPLIER_CONTROL 0x0e
+#define PU_DIGITAL_MULTIPLIER_LIMIT_CONTROL 0x0f
+#define PU_HUE_AUTO_CONTROL 0x10
+#define PU_ANALOG_VIDEO_STANDARD_CONTROL 0x11
+#define PU_ANALOG_LOCK_STATUS_CONTROL 0x12
#define LXU_MOTOR_PANTILT_RELATIVE_CONTROL 0x01
#define LXU_MOTOR_PANTILT_RESET_CONTROL 0x02
#define LXU_MOTOR_FOCUS_MOTOR_CONTROL 0x03
/* VideoStreaming interface controls */
-#define VS_CONTROL_UNDEFINED 0x00
-#define VS_PROBE_CONTROL 0x01
-#define VS_COMMIT_CONTROL 0x02
-#define VS_STILL_PROBE_CONTROL 0x03
-#define VS_STILL_COMMIT_CONTROL 0x04
-#define VS_STILL_IMAGE_TRIGGER_CONTROL 0x05
-#define VS_STREAM_ERROR_CODE_CONTROL 0x06
-#define VS_GENERATE_KEY_FRAME_CONTROL 0x07
-#define VS_UPDATE_FRAME_SEGMENT_CONTROL 0x08
-#define VS_SYNC_DELAY_CONTROL 0x09
-
-#define TT_VENDOR_SPECIFIC 0x0100
-#define TT_STREAMING 0x0101
+#define VS_CONTROL_UNDEFINED 0x00
+#define VS_PROBE_CONTROL 0x01
+#define VS_COMMIT_CONTROL 0x02
+#define VS_STILL_PROBE_CONTROL 0x03
+#define VS_STILL_COMMIT_CONTROL 0x04
+#define VS_STILL_IMAGE_TRIGGER_CONTROL 0x05
+#define VS_STREAM_ERROR_CODE_CONTROL 0x06
+#define VS_GENERATE_KEY_FRAME_CONTROL 0x07
+#define VS_UPDATE_FRAME_SEGMENT_CONTROL 0x08
+#define VS_SYNC_DELAY_CONTROL 0x09
+
+#define TT_VENDOR_SPECIFIC 0x0100
+#define TT_STREAMING 0x0101
/* Input Terminal types */
-#define ITT_VENDOR_SPECIFIC 0x0200
-#define ITT_CAMERA 0x0201
-#define ITT_MEDIA_TRANSPORT_INPUT 0x0202
+#define ITT_VENDOR_SPECIFIC 0x0200
+#define ITT_CAMERA 0x0201
+#define ITT_MEDIA_TRANSPORT_INPUT 0x0202
/* Output Terminal types */
-#define OTT_VENDOR_SPECIFIC 0x0300
-#define OTT_DISPLAY 0x0301
-#define OTT_MEDIA_TRANSPORT_OUTPUT 0x0302
+#define OTT_VENDOR_SPECIFIC 0x0300
+#define OTT_DISPLAY 0x0301
+#define OTT_MEDIA_TRANSPORT_OUTPUT 0x0302
/* External Terminal types */
-#define EXTERNAL_VENDOR_SPECIFIC 0x0400
-#define COMPOSITE_CONNECTOR 0x0401
-#define SVIDEO_CONNECTOR 0x0402
-#define COMPONENT_CONNECTOR 0x0403
+#define EXTERNAL_VENDOR_SPECIFIC 0x0400
+#define COMPOSITE_CONNECTOR 0x0401
+#define SVIDEO_CONNECTOR 0x0402
+#define COMPONENT_CONNECTOR 0x0403
#define UVC_TERM_INPUT 0x0000
#define UVC_TERM_OUTPUT 0x8000
@@ -316,6 +315,7 @@ struct uvc_xu_control {
#define UVC_QUIRK_BUILTIN_ISIGHT 0x00000008
#define UVC_QUIRK_STREAM_NO_FID 0x00000010
#define UVC_QUIRK_IGNORE_SELECTOR_UNIT 0x00000020
+#define UVC_QUIRK_PRUNE_CONTROLS 0x00000040
/* Format flags */
#define UVC_FMT_FLAG_COMPRESSED 0x00000001
@@ -383,6 +383,11 @@ struct uvc_control_mapping {
struct uvc_menu_info *menu_info;
__u32 menu_count;
+
+ __s32 (*get) (struct uvc_control_mapping *mapping, __u8 query,
+ const __u8 *data);
+ void (*set) (struct uvc_control_mapping *mapping, __s32 value,
+ __u8 *data);
};
struct uvc_control {
@@ -523,6 +528,7 @@ struct uvc_streaming {
__u16 maxpsize;
struct uvc_streaming_header header;
+ enum v4l2_buf_type type;
unsigned int nformats;
struct uvc_format *format;
@@ -535,11 +541,11 @@ struct uvc_streaming {
};
enum uvc_buffer_state {
- UVC_BUF_STATE_IDLE = 0,
- UVC_BUF_STATE_QUEUED = 1,
- UVC_BUF_STATE_ACTIVE = 2,
- UVC_BUF_STATE_DONE = 3,
- UVC_BUF_STATE_ERROR = 4,
+ UVC_BUF_STATE_IDLE = 0,
+ UVC_BUF_STATE_QUEUED = 1,
+ UVC_BUF_STATE_ACTIVE = 2,
+ UVC_BUF_STATE_DONE = 3,
+ UVC_BUF_STATE_ERROR = 4,
};
struct uvc_buffer {
@@ -558,12 +564,15 @@ struct uvc_buffer {
#define UVC_QUEUE_DROP_INCOMPLETE (1 << 2)
struct uvc_video_queue {
+ enum v4l2_buf_type type;
+
void *mem;
unsigned int flags;
__u32 sequence;
unsigned int count;
unsigned int buf_size;
+ unsigned int buf_used;
struct uvc_buffer buffer[UVC_MAX_VIDEO_BUFFERS];
struct mutex mutex; /* protects buffers and mainqueue */
spinlock_t irqlock; /* protects irqqueue */
@@ -578,8 +587,9 @@ struct uvc_video_device {
atomic_t active;
unsigned int frozen : 1;
- struct list_head iterms;
- struct uvc_entity *oterm;
+ struct list_head iterms; /* Input terminals */
+ struct uvc_entity *oterm; /* Output terminal */
+ struct uvc_entity *sterm; /* USB streaming terminal */
struct uvc_entity *processing;
struct uvc_entity *selector;
struct list_head extensions;
@@ -617,6 +627,7 @@ enum uvc_device_state {
struct uvc_device {
struct usb_device *udev;
struct usb_interface *intf;
+ unsigned long warnings;
__u32 quirks;
int intfnum;
char name[32];
@@ -679,6 +690,10 @@ struct uvc_driver {
#define UVC_TRACE_SUSPEND (1 << 8)
#define UVC_TRACE_STATUS (1 << 9)
+#define UVC_WARN_MINMAX 0
+#define UVC_WARN_PROBE_DEF 1
+
+extern unsigned int uvc_no_drop_param;
extern unsigned int uvc_trace_param;
#define uvc_trace(flag, msg...) \
@@ -687,6 +702,12 @@ extern unsigned int uvc_trace_param;
printk(KERN_DEBUG "uvcvideo: " msg); \
} while (0)
+#define uvc_warn_once(dev, warn, msg...) \
+ do { \
+ if (!test_and_set_bit(warn, &dev->warnings)) \
+ printk(KERN_INFO "uvcvideo: " msg); \
+ } while (0)
+
#define uvc_printk(level, msg...) \
printk(level "uvcvideo: " msg)
@@ -709,7 +730,8 @@ extern struct uvc_driver uvc_driver;
extern void uvc_delete(struct kref *kref);
/* Video buffers queue management. */
-extern void uvc_queue_init(struct uvc_video_queue *queue);
+extern void uvc_queue_init(struct uvc_video_queue *queue,
+ enum v4l2_buf_type type);
extern int uvc_alloc_buffers(struct uvc_video_queue *queue,
unsigned int nbuffers, unsigned int buflength);
extern int uvc_free_buffers(struct uvc_video_queue *queue);
@@ -731,7 +753,7 @@ static inline int uvc_queue_streaming(struct uvc_video_queue *queue)
}
/* V4L2 interface */
-extern struct file_operations uvc_fops;
+extern const struct v4l2_file_operations uvc_fops;
/* Video */
extern int uvc_video_init(struct uvc_video_device *video);
@@ -740,10 +762,10 @@ extern int uvc_video_resume(struct uvc_video_device *video);
extern int uvc_video_enable(struct uvc_video_device *video, int enable);
extern int uvc_probe_video(struct uvc_video_device *video,
struct uvc_streaming_control *probe);
+extern int uvc_commit_video(struct uvc_video_device *video,
+ struct uvc_streaming_control *ctrl);
extern int uvc_query_ctrl(struct uvc_device *dev, __u8 query, __u8 unit,
__u8 intfnum, __u8 cs, void *data, __u16 size);
-extern int uvc_set_video_ctrl(struct uvc_video_device *video,
- struct uvc_streaming_control *ctrl, int probe);
/* Status */
extern int uvc_status_init(struct uvc_device *dev);