if (primaries < ARRAY_SIZE(colorprimaries)) return colorprimaries[primaries];
return V4L2_COLORSPACE_SRGB; /* Reserved */
}
staticenum v4l2_xfer_func uvc_xfer_func(const u8 transfer_characteristics)
{ /* * V4L2 does not currently have definitions for all possible values of * UVC transfer characteristics. If v4l2_xfer_func is extended with new * values, the mapping below should be updated. * * Substitutions are taken from the mapping given for * V4L2_XFER_FUNC_DEFAULT documented in videodev2.h.
*/ staticconstenum v4l2_xfer_func xfer_funcs[] = {
V4L2_XFER_FUNC_DEFAULT, /* Unspecified */
V4L2_XFER_FUNC_709,
V4L2_XFER_FUNC_709, /* Substitution for BT.470-2 M */
V4L2_XFER_FUNC_709, /* Substitution for BT.470-2 B, G */
V4L2_XFER_FUNC_709, /* Substitution for SMPTE 170M */
V4L2_XFER_FUNC_SMPTE240M,
V4L2_XFER_FUNC_NONE,
V4L2_XFER_FUNC_SRGB,
};
if (transfer_characteristics < ARRAY_SIZE(xfer_funcs)) return xfer_funcs[transfer_characteristics];
return V4L2_XFER_FUNC_DEFAULT; /* Reserved */
}
staticenum v4l2_ycbcr_encoding uvc_ycbcr_enc(const u8 matrix_coefficients)
{ /* * V4L2 does not currently have definitions for all possible values of * UVC matrix coefficients. If v4l2_ycbcr_encoding is extended with new * values, the mapping below should be updated. * * Substitutions are taken from the mapping given for * V4L2_YCBCR_ENC_DEFAULT documented in videodev2.h. * * FCC is assumed to be close enough to 601.
*/ staticconstenum v4l2_ycbcr_encoding ycbcr_encs[] = {
V4L2_YCBCR_ENC_DEFAULT, /* Unspecified */
V4L2_YCBCR_ENC_709,
V4L2_YCBCR_ENC_601, /* Substitution for FCC */
V4L2_YCBCR_ENC_601, /* Substitution for BT.470-2 B, G */
V4L2_YCBCR_ENC_601,
V4L2_YCBCR_ENC_SMPTE240M,
};
if (matrix_coefficients < ARRAY_SIZE(ycbcr_encs)) return ycbcr_encs[matrix_coefficients];
return V4L2_YCBCR_ENC_DEFAULT; /* Reserved */
}
/* ------------------------------------------------------------------------ * Terminal and unit management
*/
/* * If the streaming entity is referenced by an invalid ID, notify the * user and use heuristics to guess the correct entity.
*/ if (count == 1 && id == UVC_INVALID_ENTITY_ID) {
dev_warn(&dev->intf->dev, "UVC non compliance: Invalid USB header. The streaming entity has an invalid ID, guessing the correct one."); return last_stream;
}
/* Allocate a stream specific work queue for asynchronous tasks. */
stream->async_wq = alloc_workqueue("uvcvideo", WQ_UNBOUND | WQ_HIGHPRI,
0); if (!stream->async_wq) {
uvc_stream_delete(stream); return NULL;
}
/* * Copy the frame intervals. * * 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 that could happen.
*/
frame->dwFrameInterval = *intervals;
for (i = 0; i < n; ++i) {
interval = get_unaligned_le32(&buffer[26 + 4 * i]);
(*intervals)[i] = interval ? interval : 1;
}
/* * Apply more fixes, quirks and workarounds to handle incorrect or * broken descriptors.
*/
/* * Several UVC chipsets screw up dwMaxVideoFrameBufferSize completely. * Observed behaviours range from setting 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 value from the frame size.
*/ if (!(format->flags & UVC_FMT_FLAG_COMPRESSED))
frame->dwMaxVideoFrameBufferSize = format->bpp * frame->wWidth
* frame->wHeight / 8;
/* * Clamp the default frame interval to the boundaries. A zero * bFrameIntervalType value indicates a continuous frame interval * range, with dwFrameInterval[0] storing the minimum value and * dwFrameInterval[1] storing the maximum value.
*/
maxIntervalIndex = frame->bFrameIntervalType ? n - 1 : 1;
frame->dwDefaultFrameInterval =
clamp(frame->dwDefaultFrameInterval,
frame->dwFrameInterval[0],
frame->dwFrameInterval[maxIntervalIndex]);
/* * Some devices report frame intervals that are not functional. If the * corresponding quirk is set, restrict operation to the first interval * only.
*/ if (dev->quirks & UVC_QUIRK_RESTRICT_FRAME_RATE) {
frame->bFrameIntervalType = 1;
(*intervals)[0] = frame->dwDefaultFrameInterval;
}
switch (buffer[2]) { case UVC_VS_FORMAT_UNCOMPRESSED: case UVC_VS_FORMAT_FRAME_BASED:
n = buffer[2] == UVC_VS_FORMAT_UNCOMPRESSED ? 27 : 28; if (buflen < n) {
uvc_dbg(dev, DESCR, "device %d videostreaming interface %d FORMAT error\n",
dev->udev->devnum,
alts->desc.bInterfaceNumber); return -EINVAL;
}
/* Find the format descriptor from its GUID. */
fmtdesc = uvc_format_by_guid(&buffer[5]);
if (!fmtdesc) { /* * Unknown video formats are not fatal errors, the * caller will skip this descriptor.
*/
dev_info(&streaming->intf->dev, "Unknown video format %pUl\n", &buffer[5]); return 0;
}
/* * Some devices report a format that doesn't match what they * really send.
*/ if (dev->quirks & UVC_QUIRK_FORCE_Y8) { if (format->fcc == V4L2_PIX_FMT_YUYV) {
format->fcc = V4L2_PIX_FMT_GREY;
format->bpp = 8;
width_multiplier = 2;
}
}
/* Some devices report bpp that doesn't match the format. */ if (dev->quirks & UVC_QUIRK_FORCE_BPP) { conststruct v4l2_format_info *info =
v4l2_format_info(format->fcc);
if (info) { unsignedint div = info->hdiv * info->vdiv;
n = info->bpp[0] * div; for (i = 1; i < info->comp_planes; i++)
n += info->bpp[i];
/* * The Pico iMage webcam has its class-specific interface descriptors * after the endpoint descriptors.
*/ if (buflen == 0) { for (i = 0; i < alts->desc.bNumEndpoints; ++i) { struct usb_host_endpoint *ep = &alts->endpoint[i];
if (ep->extralen == 0) continue;
if (ep->extralen > 2 &&
ep->extra[1] == USB_DT_CS_INTERFACE) {
uvc_dbg(dev, DESCR, "trying extra data from endpoint %u\n",
i);
buffer = alts->endpoint[i].extra;
buflen = alts->endpoint[i].extralen; break;
}
}
}
/* Skip the standard interface descriptors. */ while (buflen > 2 && buffer[1] != USB_DT_CS_INTERFACE) {
buflen -= buffer[0];
buffer += buffer[0];
}
if (buflen <= 2) {
uvc_dbg(dev, DESCR, "no class-specific streaming interface descriptors found\n"); goto error;
}
/* Parse the header descriptor. */ switch (buffer[2]) { case UVC_VS_OUTPUT_HEADER:
streaming->type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
size = 9; break;
case UVC_VS_INPUT_HEADER:
streaming->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
size = 13; break;
streaming->header.bmaControls = kmemdup(&buffer[size], p * n,
GFP_KERNEL); if (streaming->header.bmaControls == NULL) {
ret = -ENOMEM; goto error;
}
buflen -= buffer[0];
buffer += buffer[0];
_buffer = buffer;
_buflen = buflen;
/* Count the format and frame descriptors. */ while (_buflen > 2 && _buffer[1] == USB_DT_CS_INTERFACE) { switch (_buffer[2]) { case UVC_VS_FORMAT_UNCOMPRESSED: case UVC_VS_FORMAT_MJPEG: case UVC_VS_FORMAT_FRAME_BASED:
nformats++; break;
case UVC_VS_FORMAT_DV: /* * DV format has no frame descriptor. We will create a * dummy frame descriptor with a dummy frame interval.
*/
nformats++;
nframes++;
nintervals++; break;
case UVC_VS_FORMAT_MPEG2TS: case UVC_VS_FORMAT_STREAM_BASED:
uvc_dbg(dev, DESCR, "device %d videostreaming interface %d FORMAT %u is not supported\n",
dev->udev->devnum,
alts->desc.bInterfaceNumber, _buffer[2]); break;
case UVC_VS_FRAME_UNCOMPRESSED: case UVC_VS_FRAME_MJPEG:
nframes++; if (_buflen > 25)
nintervals += _buffer[25] ? _buffer[25] : 3; break;
case UVC_VS_FRAME_FRAME_BASED:
nframes++; if (_buflen > 21)
nintervals += _buffer[21] ? _buffer[21] : 3; break;
}
_buflen -= _buffer[0];
_buffer += _buffer[0];
}
if (nformats == 0) {
uvc_dbg(dev, DESCR, "device %d videostreaming interface %d has no supported formats defined\n",
dev->udev->devnum, alts->desc.bInterfaceNumber); goto error;
}
/* * Allocate memory for the formats, the frames and the intervals, * plus any required padding to guarantee that everything has the * correct alignment.
*/
size = nformats * sizeof(*format);
size = ALIGN(size, __alignof__(*frame)) + nframes * sizeof(*frame);
size = ALIGN(size, __alignof__(*interval))
+ nintervals * sizeof(*interval);
format = kzalloc(size, GFP_KERNEL); if (!format) {
ret = -ENOMEM; goto error;
}
/* Parse the format descriptors. */ while (buflen > 2 && buffer[1] == USB_DT_CS_INTERFACE) { switch (buffer[2]) { case UVC_VS_FORMAT_UNCOMPRESSED: case UVC_VS_FORMAT_MJPEG: case UVC_VS_FORMAT_DV: case UVC_VS_FORMAT_FRAME_BASED:
ret = uvc_parse_format(dev, streaming, format, frame,
&interval, buffer, buflen); if (ret < 0) goto error; if (!ret) break;
/* Per UVC 1.1+ spec 3.7.2, the ID should be non-zero. */ if (id == 0) {
dev_err(&dev->intf->dev, "Found Unit with invalid ID 0\n");
id = UVC_INVALID_ENTITY_ID;
}
/* Per UVC 1.1+ spec 3.7.2, the ID is unique. */ if (uvc_entity_by_id(dev, id)) {
dev_err(&dev->intf->dev, "Found multiple Units with ID %u\n", id);
id = UVC_INVALID_ENTITY_ID;
}
/* * Set the GUID for standard entity types. For extension units, the GUID * is initialized by the caller.
*/ switch (type) { case UVC_EXT_GPIO_UNIT:
memcpy(entity->guid, uvc_gpio_guid, 16); break; case UVC_ITT_CAMERA:
memcpy(entity->guid, uvc_camera_guid, 16); break; case UVC_ITT_MEDIA_TRANSPORT_INPUT:
memcpy(entity->guid, uvc_media_transport_input_guid, 16); break; case UVC_VC_PROCESSING_UNIT:
memcpy(entity->guid, uvc_processing_guid, 16); break;
}
for (i = 0; i < num_inputs; ++i)
entity->pads[i].flags = MEDIA_PAD_FL_SINK; if (!UVC_ENTITY_IS_OTERM(entity) && num_pads)
entity->pads[num_pads-1].flags = MEDIA_PAD_FL_SOURCE;
/* * First attempt to read the entity name from the device. If the entity * has no associated string, or if reading the string fails (most * likely due to a buggy firmware), fall back to default names based on * the entity type.
*/ if (string_id) {
ret = usb_string(dev->udev, string_id, entity->name, sizeof(entity->name)); if (!ret) return;
}
switch (le16_to_cpu(dev->udev->descriptor.idVendor)) { case 0x046d: /* Logitech */ if (buffer[1] != 0x41 || buffer[2] != 0x01) break;
/* * Logitech implements several vendor specific functions * through vendor specific extension units (LXU). * * The LXU descriptors are similar to XU descriptors * (see "USB Device Video Class for Video Devices", section * 3.7.2.6 "Extension Unit Descriptor") with the following * differences: * * ---------------------------------------------------------- * 0 bLength 1 Number * Size of this descriptor, in bytes: 24+p+n*2 * ---------------------------------------------------------- * 23+p+n bmControlsType N Bitmap * Individual bits in the set are defined: * 0: Absolute * 1: Relative * * This bitset is mapped exactly the same as bmControls. * ---------------------------------------------------------- * 23+p+n*2 bReserved 1 Boolean * ---------------------------------------------------------- * 24+p+n*2 iExtension 1 Index * Index of a string descriptor that describes this * extension unit. * ----------------------------------------------------------
*/
p = buflen >= 22 ? buffer[21] : 0;
n = buflen >= 25 + p ? buffer[22+p] : 0;
/* * Reject invalid terminal types that would cause issues: * * - The high byte must be non-zero, otherwise it would be * confused with a unit. * * - Bit 15 must be 0, as we use it internally as a terminal * direction flag. * * Other unknown types are accepted.
*/
type = get_unaligned_le16(&buffer[4]); if ((type & 0x7f00) == 0 || (type & 0x8000) != 0) {
uvc_dbg(dev, DESCR, "device %d videocontrol interface %d INPUT_TERMINAL %d has invalid type 0x%04x, skipping\n",
udev->devnum, alts->desc.bInterfaceNumber,
buffer[3], type); return 0;
}
n = 0;
p = 0;
len = 8;
if (type == UVC_ITT_CAMERA) {
n = buflen >= 15 ? buffer[14] : 0;
len = 15;
} elseif (type == UVC_ITT_MEDIA_TRANSPORT_INPUT) {
n = buflen >= 9 ? buffer[8] : 0;
p = buflen >= 10 + n ? buffer[9+n] : 0;
len = 10;
}
if (buflen < len + n + p) {
uvc_dbg(dev, DESCR, "device %d videocontrol interface %d INPUT_TERMINAL error\n",
udev->devnum, alts->desc.bInterfaceNumber); return -EINVAL;
}
term = uvc_alloc_new_entity(dev, type | UVC_TERM_INPUT,
buffer[3], 1, n + p); if (IS_ERR(term)) return PTR_ERR(term);
/* * Make sure the terminal type MSB is not null, otherwise it * could be confused with a unit.
*/
type = get_unaligned_le16(&buffer[4]); if ((type & 0xff00) == 0) {
uvc_dbg(dev, DESCR, "device %d videocontrol interface %d OUTPUT_TERMINAL %d has invalid type 0x%04x, skipping\n",
udev->devnum, alts->desc.bInterfaceNumber,
buffer[3], type); return 0;
}
term = uvc_alloc_new_entity(dev, type | UVC_TERM_OUTPUT,
buffer[3], 1, 0); if (IS_ERR(term)) return PTR_ERR(term);
/* * 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;
if (usb_endpoint_is_int_in(desc) &&
le16_to_cpu(desc->wMaxPacketSize) >= 8 &&
desc->bInterval != 0) {
uvc_dbg(dev, DESCR, "Found a Status endpoint (addr %02x)\n",
desc->bEndpointAddress);
dev->int_ep = ep;
}
}
/* GPIO entities are always on the first chain. */
chain = list_first_entry(&dev->chains, struct uvc_video_chain, list);
uvc_ctrl_status_event(chain, unit->controls, &new_val);
}
/* * Scan the UVC descriptors to locate a chain starting at an Output Terminal * and containing the following units: * * - one or more Output Terminals (USB Streaming or Display) * - zero or one Processing Unit * - zero, one or more 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 or more Input Terminals (Camera, External or USB Streaming) * * The terminal and units must match on of the following structures: * * ITT_*(0) -> +---------+ +---------+ +---------+ -> TT_STREAMING(0) * ... | SU{0,1} | -> | PU{0,1} | -> | XU{0,n} | ... * ITT_*(n) -> +---------+ +---------+ +---------+ -> TT_STREAMING(n) * * +---------+ +---------+ -> OTT_*(0) * TT_STREAMING -> | PU{0,1} | -> | XU{0,n} | ... * +---------+ +---------+ -> OTT_*(n) * * The Processing Unit and Extension Units can be in any order. Additional * Extension Units connected to the main chain as single-unit branches are * also supported. Single-input Selector Units are ignored.
*/ staticint uvc_scan_chain_entity(struct uvc_video_chain *chain, struct uvc_entity *entity)
{ switch (UVC_ENTITY_TYPE(entity)) { case UVC_VC_EXTENSION_UNIT:
uvc_dbg_cont(PROBE, " <- XU %d", entity->id);
if (entity->bNrInPins != 1) {
uvc_dbg(chain->dev, DESCR, "Extension unit %d has more than 1 input pin\n",
entity->id); return -1;
}
break;
case UVC_VC_PROCESSING_UNIT:
uvc_dbg_cont(PROBE, " <- PU %d", entity->id);
if (chain->processing != NULL) {
uvc_dbg(chain->dev, DESCR, "Found multiple Processing Units in chain\n"); return -1;
}
chain->processing = entity; break;
case UVC_VC_SELECTOR_UNIT:
uvc_dbg_cont(PROBE, " <- SU %d", entity->id);
/* Single-input selector units are ignored. */ if (entity->bNrInPins == 1) break;
if (chain->selector != NULL) {
uvc_dbg(chain->dev, DESCR, "Found multiple Selector Units in chain\n"); return -1;
}
chain->selector = entity; break;
case UVC_ITT_VENDOR_SPECIFIC: case UVC_ITT_CAMERA: case UVC_ITT_MEDIA_TRANSPORT_INPUT:
uvc_dbg_cont(PROBE, " <- IT %d\n", entity->id);
break;
case UVC_OTT_VENDOR_SPECIFIC: case UVC_OTT_DISPLAY: case UVC_OTT_MEDIA_TRANSPORT_OUTPUT:
uvc_dbg_cont(PROBE, " OT %d", entity->id);
break;
case UVC_TT_STREAMING: if (UVC_ENTITY_IS_ITERM(entity))
uvc_dbg_cont(PROBE, " <- IT %d\n", entity->id); else
uvc_dbg_cont(PROBE, " OT %d", entity->id);
break;
default:
uvc_dbg(chain->dev, DESCR, "Unsupported entity type 0x%04x found in chain\n",
UVC_ENTITY_TYPE(entity)); return -1;
}
while (1) {
forward = uvc_entity_by_reference(chain->dev, entity->id,
forward); if (forward == NULL) break; if (forward == prev) continue; if (forward->chain.next || forward->chain.prev) {
uvc_dbg(chain->dev, DESCR, "Found reference to entity %d already in chain\n",
forward->id); return -EINVAL;
}
switch (UVC_ENTITY_TYPE(forward)) { case UVC_VC_EXTENSION_UNIT: if (forward->bNrInPins != 1) {
uvc_dbg(chain->dev, DESCR, "Extension unit %d has more than 1 input pin\n",
forward->id); return -EINVAL;
}
/* * Some devices reference an output terminal as the * source of extension units. This is incorrect, as * output terminals only have an input pin, and thus * can't be connected to any entity in the forward * direction. The resulting topology would cause issues * when registering the media controller graph. To * avoid this problem, connect the extension unit to * the source of the output terminal instead.
*/ if (UVC_ENTITY_IS_OTERM(entity)) { struct uvc_entity *source;
source = uvc_entity_by_id(chain->dev,
entity->baSourceID[0]); if (!source) {
uvc_dbg(chain->dev, DESCR, "Can't connect extension unit %u in chain\n",
forward->id); break;
}
forward->baSourceID[0] = source->id;
}
list_add_tail(&forward->chain, &chain->entities); if (!found)
uvc_dbg_cont(PROBE, " (->");
uvc_dbg_cont(PROBE, " XU %d", forward->id);
found = 1; break;
case UVC_OTT_VENDOR_SPECIFIC: case UVC_OTT_DISPLAY: case UVC_OTT_MEDIA_TRANSPORT_OUTPUT: case UVC_TT_STREAMING: if (UVC_ENTITY_IS_ITERM(forward)) {
uvc_dbg(chain->dev, DESCR, "Unsupported input terminal %u\n",
forward->id); return -EINVAL;
}
if (UVC_ENTITY_IS_OTERM(entity)) {
uvc_dbg(chain->dev, DESCR, "Unsupported connection between output terminals %u and %u\n",
entity->id, forward->id); break;
}
list_add_tail(&forward->chain, &chain->entities); if (!found)
uvc_dbg_cont(PROBE, " (->");
uvc_dbg_cont(PROBE, " OT %d", forward->id);
found = 1; break;
}
} if (found)
uvc_dbg_cont(PROBE, ")");
switch (UVC_ENTITY_TYPE(entity)) { case UVC_VC_EXTENSION_UNIT: case UVC_VC_PROCESSING_UNIT:
id = entity->baSourceID[0]; break;
case UVC_VC_SELECTOR_UNIT: /* Single-input selector units are ignored. */ if (entity->bNrInPins == 1) {
id = entity->baSourceID[0]; break;
}
uvc_dbg_cont(PROBE, " <- IT");
chain->selector = entity; for (i = 0; i < entity->bNrInPins; ++i) {
id = entity->baSourceID[i];
term = uvc_entity_by_id(chain->dev, id); if (term == NULL || !UVC_ENTITY_IS_ITERM(term)) {
uvc_dbg(chain->dev, DESCR, "Selector unit %d input %d isn't connected to an input terminal\n",
entity->id, i); return -1;
}
if (term->chain.next || term->chain.prev) {
uvc_dbg(chain->dev, DESCR, "Found reference to entity %d already in chain\n",
term->id); return -EINVAL;
}
case UVC_ITT_VENDOR_SPECIFIC: case UVC_ITT_CAMERA: case UVC_ITT_MEDIA_TRANSPORT_INPUT: case UVC_OTT_VENDOR_SPECIFIC: case UVC_OTT_DISPLAY: case UVC_OTT_MEDIA_TRANSPORT_OUTPUT: case UVC_TT_STREAMING:
id = UVC_ENTITY_IS_OTERM(entity) ? entity->baSourceID[0] : 0; break;
}
while (entity != NULL) { /* Entity must not be part of an existing chain */ if (entity->chain.next || entity->chain.prev) {
uvc_dbg(chain->dev, DESCR, "Found reference to entity %d already in chain\n",
entity->id); return -EINVAL;
}
/* Process entity */ if (uvc_scan_chain_entity(chain, entity) < 0) return -EINVAL;
/* * Fallback heuristic for devices that don't connect units and terminals in a * valid chain. * * Some devices have invalid baSourceID references, causing uvc_scan_chain() * to fail, but if we just take the entities we can find and put them together * in the most sensible chain we can think of, turns out they do work anyway. * Note: This heuristic assumes there is a single chain. * * At the time of writing, devices known to have such a broken chain are * - Acer Integrated Camera (5986:055a) * - Realtek rtl157a7 (0bda:57a7)
*/ staticint uvc_scan_fallback(struct uvc_device *dev)
{ struct uvc_video_chain *chain; struct uvc_entity *iterm = NULL; struct uvc_entity *oterm = NULL; struct uvc_entity *entity; struct uvc_entity *prev;
/* * Start by locating the input and output terminals. We only support * devices with exactly one of each for now.
*/
list_for_each_entry(entity, &dev->entities, list) { if (UVC_ENTITY_IS_ITERM(entity)) { if (iterm) return -EINVAL;
iterm = entity;
}
if (UVC_ENTITY_IS_OTERM(entity)) { if (oterm) return -EINVAL;
oterm = entity;
}
}
if (iterm == NULL || oterm == NULL) return -EINVAL;
/* Allocate the chain and fill it. */
chain = uvc_alloc_chain(dev); if (chain == NULL) return -ENOMEM;
if (uvc_scan_chain_entity(chain, oterm) < 0) goto error;
prev = oterm;
/* * Add all Processing and Extension Units with two pads. The order * doesn't matter much, use reverse list traversal to connect units in * UVC descriptor order as we build the chain from output to input. This * leads to units appearing in the order meant by the manufacturer for * the cameras known to require this heuristic.
*/
list_for_each_entry_reverse(entity, &dev->entities, list) { if (entity->type != UVC_VC_PROCESSING_UNIT &&
entity->type != UVC_VC_EXTENSION_UNIT) continue;
if (entity->num_pads != 2) continue;
if (uvc_scan_chain_entity(chain, entity) < 0) goto error;
if (uvc_scan_chain_entity(chain, iterm) < 0) goto error;
prev->baSourceID[0] = iterm->id;
list_add_tail(&chain->list, &dev->chains);
uvc_dbg(dev, PROBE, "Found a video chain by fallback heuristic (%s)\n",
uvc_print_chain(chain));
return 0;
error:
kfree(chain); return -EINVAL;
}
/* * Scan the device for video chains and register video devices. * * Chains are scanned starting at their output terminals and walked backwards.
*/ staticint uvc_scan_device(struct uvc_device *dev)
{ struct uvc_video_chain *chain; struct uvc_entity *term;
list_for_each_entry(term, &dev->entities, list) { if (!UVC_ENTITY_IS_OTERM(term)) continue;
/* * If the terminal is already included in a chain, skip it. * This can happen for chains that have multiple output * terminals, where all output terminals beside the first one * will be inserted in the chain in forward scans.
*/ if (term->chain.next || term->chain.prev) continue;
chain = uvc_alloc_chain(dev); if (chain == NULL) return -ENOMEM;
term->flags |= UVC_ENTITY_FLAG_DEFAULT;
if (uvc_scan_chain(chain, term) < 0) {
kfree(chain); continue;
}
uvc_dbg(dev, PROBE, "Found a valid video chain (%s)\n",
uvc_print_chain(chain));
list_add_tail(&chain->list, &dev->chains);
}
if (list_empty(&dev->chains))
uvc_scan_fallback(dev);
if (list_empty(&dev->chains)) {
dev_info(&dev->udev->dev, "No valid video chain found.\n"); return -ENODEV;
}
/* Add GPIO entity to the first chain. */ if (dev->gpio_unit) {
chain = list_first_entry(&dev->chains, struct uvc_video_chain, list);
list_add_tail(&dev->gpio_unit->chain, &chain->entities);
}
return 0;
}
/* ------------------------------------------------------------------------ * Video device registration and unregistration
*/
/* * Delete the UVC device. * * Called by the kernel when the last reference to the uvc_device structure * is released. * * As this function is called after or during disconnect(), all URBs have * already been cancelled by the USB core. There is no need to kill the * interrupt URB manually.
*/ staticvoid uvc_delete(struct kref *kref)
{ struct uvc_device *dev = container_of(kref, struct uvc_device, ref); struct list_head *p, *n;
/* * Now both vdevs are not streaming and all the ioctls will * return -ENODEV.
*/
uvc_debugfs_cleanup_stream(stream);
}
uvc_status_unregister(dev);
if (dev->vdev.dev)
v4l2_device_unregister(&dev->vdev); #ifdef CONFIG_MEDIA_CONTROLLER if (media_devnode_is_registered(dev->mdev.devnode))
media_device_unregister(&dev->mdev); #endif
}
/* Initialize the video buffers queue. */
ret = uvc_queue_init(queue, type); if (ret) return ret;
/* Register the device with V4L. */
/* * We already hold a reference to dev->udev. The video device will be * unregistered before the reference is released, so we don't need to * get another one.
*/
vdev->v4l2_dev = &dev->vdev;
vdev->fops = fops;
vdev->ioctl_ops = ioctl_ops;
vdev->release = uvc_release;
vdev->prio = &stream->chain->prio;
vdev->queue = &queue->queue;
vdev->lock = &queue->mutex; if (type == V4L2_BUF_TYPE_VIDEO_OUTPUT)
vdev->vfl_dir = VFL_DIR_TX; else
vdev->vfl_dir = VFL_DIR_RX;
switch (type) { case V4L2_BUF_TYPE_VIDEO_CAPTURE: default:
vdev->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING; break; case V4L2_BUF_TYPE_VIDEO_OUTPUT:
vdev->device_caps = V4L2_CAP_VIDEO_OUTPUT | V4L2_CAP_STREAMING; break; case V4L2_BUF_TYPE_META_CAPTURE:
vdev->device_caps = V4L2_CAP_META_CAPTURE | V4L2_CAP_STREAMING; break;
}
/* * Set the driver data before calling video_register_device, otherwise * the file open() handler might race us.
*/
video_set_drvdata(vdev, stream);
ret = video_register_device(vdev, VFL_TYPE_VIDEO, -1); if (ret < 0) {
dev_err(&stream->intf->dev, "Failed to register %s device (%d).\n",
v4l2_type_names[type], ret); return ret;
}
kref_get(&dev->ref); return 0;
}
staticint uvc_register_video(struct uvc_device *dev, struct uvc_streaming *stream)
{ int ret;
/* Initialize the streaming interface with default parameters. */
ret = uvc_video_init(stream); if (ret < 0) {
dev_err(&stream->intf->dev, "Failed to initialize the device (%d).\n", ret); return ret;
}
/* Register the device with V4L. */ return uvc_register_video_device(dev, stream, &stream->vdev,
&stream->queue, stream->type,
&uvc_fops, &uvc_ioctl_ops);
}
/* * Register all video devices in all chains.
*/ staticint uvc_register_terms(struct uvc_device *dev, struct uvc_video_chain *chain)
{ struct uvc_streaming *stream; struct uvc_entity *term; int ret;
list_for_each_entry(term, &chain->entities, chain) { if (UVC_ENTITY_TYPE(term) != UVC_TT_STREAMING) continue;
stream = uvc_stream_by_id(dev, term->id); if (stream == NULL) {
dev_info(&dev->udev->dev, "No streaming interface found for terminal %u.",
term->id); continue;
}
stream->chain = chain;
ret = uvc_register_video(dev, stream); if (ret < 0) return ret;
/* * Register a metadata node, but ignore a possible failure, * complete registration of video nodes anyway.
*/
uvc_meta_register(stream);
term->vdev = &stream->vdev;
}
return 0;
}
staticint uvc_register_chains(struct uvc_device *dev)
{ struct uvc_video_chain *chain; int ret;
list_for_each_entry(chain, &dev->chains, list) {
ret = uvc_register_terms(dev, chain); if (ret < 0) return ret;
#ifdef CONFIG_MEDIA_CONTROLLER
ret = uvc_mc_register_entities(chain); if (ret < 0)
dev_info(&dev->udev->dev, "Failed to register entities (%d).\n", ret); #endif
}
return 0;
}
/* ------------------------------------------------------------------------ * USB probe, disconnect, suspend and resume
*/
if (udev->product != NULL)
strscpy(dev->name, udev->product, sizeof(dev->name)); else
snprintf(dev->name, sizeof(dev->name), "UVC Camera (%04x:%04x)",
le16_to_cpu(udev->descriptor.idVendor),
le16_to_cpu(udev->descriptor.idProduct));
/* * Add iFunction or iInterface to names when available as additional * distinguishers between interfaces. iFunction is prioritized over * iInterface which matches Windows behavior at the point of writing.
*/ if (intf->intf_assoc && intf->intf_assoc->iFunction != 0)
function = intf->intf_assoc->iFunction; else
function = intf->cur_altsetting->desc.iInterface; if (function != 0) {
size_t len;
/* Initialize the media device. */ #ifdef CONFIG_MEDIA_CONTROLLER
dev->mdev.dev = &intf->dev;
strscpy(dev->mdev.model, dev->name, sizeof(dev->mdev.model)); if (udev->serial)
strscpy(dev->mdev.serial, udev->serial, sizeof(dev->mdev.serial));
usb_make_path(udev, dev->mdev.bus_info, sizeof(dev->mdev.bus_info));
dev->mdev.hw_revision = le16_to_cpu(udev->descriptor.bcdDevice);
media_device_init(&dev->mdev);
dev->vdev.mdev = &dev->mdev; #endif
/* Parse the Video Class control descriptor. */
ret = uvc_parse_control(dev); if (ret < 0) {
uvc_dbg(dev, PROBE, "Unable to parse UVC descriptors\n"); goto error;
}
/* Parse the associated GPIOs. */
ret = uvc_gpio_parse(dev); if (ret < 0) goto error;
if (dev->quirks != dev->info->quirks) {
dev_info(&dev->udev->dev, "Forcing device quirks to 0x%x by module parameter for testing purpose.\n",
dev->quirks);
dev_info(&dev->udev->dev, "Please report required quirks to the linux-media mailing list.\n");
}
if (dev->info->uvc_version) {
dev->uvc_version = dev->info->uvc_version;
dev_info(&dev->udev->dev, "Forcing UVC version to %u.%02x\n",
dev->uvc_version >> 8, dev->uvc_version & 0xff);
}
/* Register the V4L2 device. */
ret = v4l2_device_register(&intf->dev, &dev->vdev); if (ret < 0) goto error;
/* Scan the device for video chains. */
ret = uvc_scan_device(dev); if (ret < 0) goto error;
/* Initialize controls. */
ret = uvc_ctrl_init_device(dev); if (ret < 0) goto error;
/* Register video device nodes. */
ret = uvc_register_chains(dev); if (ret < 0) goto error;
#ifdef CONFIG_MEDIA_CONTROLLER /* Register the media device node */
ret = media_device_register(&dev->mdev); if (ret < 0) goto error; #endif /* Save our data pointer in the interface data. */
usb_set_intfdata(intf, dev);
/* Initialize the interrupt URB. */
ret = uvc_status_init(dev); if (ret < 0) {
dev_info(&dev->udev->dev, "Unable to initialize the status endpoint (%d), status interrupt will not be supported.\n",
ret);
}
ret = uvc_gpio_init_irq(dev); if (ret < 0) {
dev_err(&dev->udev->dev, "Unable to request privacy GPIO IRQ (%d)\n", ret); goto error;
}
ret = uvc_meta_init(dev); if (ret < 0) {
dev_err(&dev->udev->dev, "Error initializing the metadata formats (%d)\n", ret); goto error;
}
if (dev->quirks & UVC_QUIRK_NO_RESET_RESUME)
udev->quirks &= ~USB_QUIRK_RESET_RESUME;
if (!(dev->quirks & UVC_QUIRK_DISABLE_AUTOSUSPEND))
usb_enable_autosuspend(udev);
/* Controls are cached on the fly so they don't need to be saved. */ if (intf->cur_altsetting->desc.bInterfaceSubClass ==
UVC_SC_VIDEOCONTROL) {
uvc_status_suspend(dev); return 0;
}
if (intf->cur_altsetting->desc.bInterfaceSubClass ==
UVC_SC_VIDEOCONTROL) { if (reset) {
ret = uvc_ctrl_restore_values(dev); if (ret < 0) return ret;
}
return uvc_status_resume(dev);
}
list_for_each_entry(stream, &dev->streams, list) { if (stream->intf == intf) {
ret = uvc_video_resume(stream, reset); if (ret < 0) {
mutex_lock(&stream->queue.mutex);
vb2_streamoff(&stream->queue.queue,
stream->queue.queue.type);
mutex_unlock(&stream->queue.mutex);
} return ret;
}
}
uvc_dbg(dev, SUSPEND, "Resume: video streaming USB interface mismatch\n"); return -EINVAL;
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.