// SPDX-License-Identifier: GPL-2.0-or-later
/*
* uvc_video . c - - USB Video Class driver - Video handling
*
* Copyright ( C ) 2005 - 2010
* Laurent Pinchart ( laurent . pinchart @ ideasonboard . com )
*/
#include <linux/dma-mapping.h>
#include <linux/highmem.h>
#include <linux/kernel.h>
#include <linux/list.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/usb.h>
#include <linux/usb/hcd.h>
#include <linux/videodev2.h>
#include <linux/vmalloc.h>
#include <linux/wait.h>
#include <linux/atomic.h>
#include <linux/unaligned.h>
#include <media/jpeg.h>
#include <media/v4l2-common.h>
#include "uvcvideo.h"
/* ------------------------------------------------------------------------
* UVC Controls
*/
static int __uvc_query_ctrl(struct uvc_device *dev, u8 query, u8 unit,
u8 intfnum, u8 cs, void *data, u16 size,
int timeout)
{
u8 type = USB_TYPE_CLASS | USB_RECIP_INTERFACE;
unsigned int pipe;
pipe = (query & 0 x80) ? usb_rcvctrlpipe(dev->udev, 0 )
: usb_sndctrlpipe(dev->udev, 0 );
type |= (query & 0 x80) ? USB_DIR_IN : USB_DIR_OUT;
return usb_control_msg(dev->udev, pipe, query, type, cs << 8 ,
unit << 8 | intfnum, data, size, timeout);
}
static const char *uvc_query_name(u8 query)
{
switch (query) {
case UVC_SET_CUR:
return "SET_CUR" ;
case UVC_GET_CUR:
return "GET_CUR" ;
case UVC_GET_MIN:
return "GET_MIN" ;
case UVC_GET_MAX:
return "GET_MAX" ;
case UVC_GET_RES:
return "GET_RES" ;
case UVC_GET_LEN:
return "GET_LEN" ;
case UVC_GET_INFO:
return "GET_INFO" ;
case UVC_GET_DEF:
return "GET_DEF" ;
default :
return "<invalid>" ;
}
}
int uvc_query_ctrl(struct uvc_device *dev, u8 query, u8 unit,
u8 intfnum, u8 cs, void *data, u16 size)
{
int ret;
u8 error;
u8 tmp;
ret = __uvc_query_ctrl(dev, query, unit, intfnum, cs, data, size,
UVC_CTRL_CONTROL_TIMEOUT);
if (likely(ret == size))
return 0 ;
/*
* Some devices return shorter USB control packets than expected if the
* returned value can fit in less bytes . Zero all the bytes that the
* device has not written .
*
* This quirk is applied to all controls , regardless of their data type .
* Most controls are little - endian integers , in which case the missing
* bytes become 0 MSBs . For other data types , a different heuristic
* could be implemented if a device is found needing it .
*
* We exclude UVC_GET_INFO from the quirk . UVC_GET_LEN does not need
* to be excluded because its size is always 1 .
*/
if (ret > 0 && query != UVC_GET_INFO) {
memset(data + ret, 0 , size - ret);
dev_warn_once(&dev->udev->dev,
"UVC non compliance: %s control %u on unit %u returned %d bytes when we expected %u.\n" ,
uvc_query_name(query), cs, unit, ret, size);
return 0 ;
}
if (ret != -EPIPE) {
dev_err(&dev->udev->dev,
"Failed to query (%s) UVC control %u on unit %u: %d (exp. %u).\n" ,
uvc_query_name(query), cs, unit, ret, size);
return ret < 0 ? ret : -EPIPE;
}
/* Reuse data[0] to request the error code. */
tmp = *(u8 *)data;
ret = __uvc_query_ctrl(dev, UVC_GET_CUR, 0 , intfnum,
UVC_VC_REQUEST_ERROR_CODE_CONTROL, data, 1 ,
UVC_CTRL_CONTROL_TIMEOUT);
error = *(u8 *)data;
*(u8 *)data = tmp;
if (ret != 1 ) {
dev_err_ratelimited(&dev->udev->dev,
"Failed to query (%s) UVC error code control %u on unit %u: %d (exp. 1).\n" ,
uvc_query_name(query), cs, unit, ret);
return ret < 0 ? ret : -EPIPE;
}
uvc_dbg(dev, CONTROL, "Control error %u\n" , error);
switch (error) {
case 0 :
/* Cannot happen - we received a STALL */
return -EPIPE;
case 1 : /* Not ready */
return -EBUSY;
case 2 : /* Wrong state */
return -EACCES;
case 3 : /* Power */
return -EREMOTE;
case 4 : /* Out of range */
return -ERANGE;
case 5 : /* Invalid unit */
case 6 : /* Invalid control */
case 7 : /* Invalid Request */
/*
* The firmware has not properly implemented
* the control or there has been a HW error .
*/
return -EIO;
case 8 : /* Invalid value within range */
return -EINVAL;
default : /* reserved or unknown */
break ;
}
return -EPIPE;
}
static const struct usb_device_id elgato_cam_link_4k = {
USB_DEVICE(0 x0fd9, 0 x0066)
};
static void uvc_fixup_video_ctrl(struct uvc_streaming *stream,
struct uvc_streaming_control *ctrl)
{
const struct uvc_format *format = NULL;
const struct uvc_frame *frame = NULL;
unsigned int i;
/*
* The response of the Elgato Cam Link 4 K is incorrect : The second byte
* contains bFormatIndex ( instead of being the second byte of bmHint ) .
* The first byte is always zero . The third byte is always 1 .
*
* The UVC 1 . 5 class specification defines the first five bits in the
* bmHint bitfield . The remaining bits are reserved and should be zero .
* Therefore a valid bmHint will be less than 32 .
*
* Latest Elgato Cam Link 4 K firmware as of 2021 - 03 - 23 needs this fix .
* MCU : 20 . 02 . 19 , FPGA : 67
*/
if (usb_match_one_id(stream->dev->intf, &elgato_cam_link_4k) &&
ctrl->bmHint > 255 ) {
u8 corrected_format_index = ctrl->bmHint >> 8 ;
uvc_dbg(stream->dev, VIDEO,
"Correct USB video probe response from {bmHint: 0x%04x, bFormatIndex: %u} to {bmHint: 0x%04x, bFormatIndex: %u}\n" ,
ctrl->bmHint, ctrl->bFormatIndex,
1 , corrected_format_index);
ctrl->bmHint = 1 ;
ctrl->bFormatIndex = corrected_format_index;
}
for (i = 0 ; i < stream->nformats; ++i) {
if (stream->formats[i].index == ctrl->bFormatIndex) {
format = &stream->formats[i];
break ;
}
}
if (format == NULL)
return ;
for (i = 0 ; i < format->nframes; ++i) {
if (format->frames[i].bFrameIndex == ctrl->bFrameIndex) {
frame = &format->frames[i];
break ;
}
}
if (frame == NULL)
return ;
if (!(format->flags & UVC_FMT_FLAG_COMPRESSED) ||
(ctrl->dwMaxVideoFrameSize == 0 &&
stream->dev->uvc_version < 0 x0110))
ctrl->dwMaxVideoFrameSize =
frame->dwMaxVideoFrameBufferSize;
/*
* The " TOSHIBA Web Camera - 5 M " Chicony device ( 04 f2 : b50b ) seems to
* compute the bandwidth on 16 bits and erroneously sign - extend it to
* 32 bits , resulting in a huge bandwidth value . Detect and fix that
* condition by setting the 16 MSBs to 0 when they ' re all equal to 1 .
*/
if ((ctrl->dwMaxPayloadTransferSize & 0 xffff0000) == 0 xffff0000)
ctrl->dwMaxPayloadTransferSize &= ~0 xffff0000;
if (!(format->flags & UVC_FMT_FLAG_COMPRESSED) &&
stream->dev->quirks & UVC_QUIRK_FIX_BANDWIDTH &&
stream->intf->num_altsetting > 1 ) {
u32 interval;
u32 bandwidth;
interval = (ctrl->dwFrameInterval > 100000 )
? ctrl->dwFrameInterval
: frame->dwFrameInterval[0 ];
/*
* Compute a bandwidth estimation by multiplying the frame
* size by the number of video frames per second , divide the
* result by the number of USB frames ( or micro - frames for
* high - and super - speed devices ) per second and add the UVC
* header size ( assumed to be 12 bytes long ) .
*/
bandwidth = frame->wWidth * frame->wHeight / 8 * format->bpp;
bandwidth *= 10000000 / interval + 1 ;
bandwidth /= 1000 ;
if (stream->dev->udev->speed >= USB_SPEED_HIGH)
bandwidth /= 8 ;
bandwidth += 12 ;
/*
* The bandwidth estimate is too low for many cameras . Don ' t use
* maximum packet sizes lower than 1024 bytes to try and work
* around the problem . According to measurements done on two
* different camera models , the value is high enough to get most
* resolutions working while not preventing two simultaneous
* VGA streams at 15 fps .
*/
bandwidth = max_t(u32, bandwidth, 1024 );
ctrl->dwMaxPayloadTransferSize = bandwidth;
}
if (stream->intf->num_altsetting > 1 &&
ctrl->dwMaxPayloadTransferSize > stream->maxpsize) {
dev_warn_ratelimited(&stream->intf->dev,
"UVC non compliance: the max payload transmission size (%u) exceeds the size of the ep max packet (%u). Using the max size.\n" ,
ctrl->dwMaxPayloadTransferSize,
stream->maxpsize);
ctrl->dwMaxPayloadTransferSize = stream->maxpsize;
}
}
static size_t uvc_video_ctrl_size(struct uvc_streaming *stream)
{
/*
* Return the size of the video probe and commit controls , which depends
* on the protocol version .
*/
if (stream->dev->uvc_version < 0 x0110)
return 26 ;
else if (stream->dev->uvc_version < 0 x0150)
return 34 ;
else
return 48 ;
}
static int uvc_get_video_ctrl(struct uvc_streaming *stream,
struct uvc_streaming_control *ctrl, int probe, u8 query)
{
u16 size = uvc_video_ctrl_size(stream);
u8 *data;
int ret;
if ((stream->dev->quirks & UVC_QUIRK_PROBE_DEF) &&
query == UVC_GET_DEF)
return -EIO;
data = kmalloc(size, GFP_KERNEL);
if (data == NULL)
return -ENOMEM;
ret = __uvc_query_ctrl(stream->dev, query, 0 , stream->intfnum,
probe ? UVC_VS_PROBE_CONTROL : UVC_VS_COMMIT_CONTROL, data,
size, uvc_timeout_param);
if ((query == UVC_GET_MIN || query == UVC_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(stream->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 == UVC_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(stream->dev, UVC_WARN_PROBE_DEF, "UVC non "
"compliance - GET_DEF(PROBE) not supported. "
"Enabling workaround.\n" );
ret = -EIO;
goto out;
} else if (ret != size) {
dev_err(&stream->intf->dev,
"Failed to query (%s) UVC %s control : %d (exp. %u).\n" ,
uvc_query_name(query), probe ? "probe" : "commit" ,
ret, size);
ret = (ret == -EPROTO) ? -EPROTO : -EIO;
goto out;
}
ctrl->bmHint = le16_to_cpup((__le16 *)&data[0 ]);
ctrl->bFormatIndex = data[2 ];
ctrl->bFrameIndex = data[3 ];
ctrl->dwFrameInterval = le32_to_cpup((__le32 *)&data[4 ]);
ctrl->wKeyFrameRate = le16_to_cpup((__le16 *)&data[8 ]);
ctrl->wPFrameRate = le16_to_cpup((__le16 *)&data[10 ]);
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 = get_unaligned_le32(&data[18 ]);
ctrl->dwMaxPayloadTransferSize = get_unaligned_le32(&data[22 ]);
if (size >= 34 ) {
ctrl->dwClockFrequency = get_unaligned_le32(&data[26 ]);
ctrl->bmFramingInfo = data[30 ];
ctrl->bPreferedVersion = data[31 ];
ctrl->bMinVersion = data[32 ];
ctrl->bMaxVersion = data[33 ];
} else {
ctrl->dwClockFrequency = stream->dev->clock_frequency;
ctrl->bmFramingInfo = 0 ;
ctrl->bPreferedVersion = 0 ;
ctrl->bMinVersion = 0 ;
ctrl->bMaxVersion = 0 ;
}
/*
* Some broken devices return null or wrong dwMaxVideoFrameSize and
* dwMaxPayloadTransferSize fields . Try to get the value from the
* format and frame descriptors .
*/
uvc_fixup_video_ctrl(stream, ctrl);
ret = 0 ;
out:
kfree(data);
return ret;
}
static int uvc_set_video_ctrl(struct uvc_streaming *stream,
struct uvc_streaming_control *ctrl, int probe)
{
u16 size = uvc_video_ctrl_size(stream);
u8 *data;
int ret;
data = kzalloc(size, GFP_KERNEL);
if (data == NULL)
return -ENOMEM;
*(__le16 *)&data[0 ] = cpu_to_le16(ctrl->bmHint);
data[2 ] = ctrl->bFormatIndex;
data[3 ] = ctrl->bFrameIndex;
*(__le32 *)&data[4 ] = cpu_to_le32(ctrl->dwFrameInterval);
*(__le16 *)&data[8 ] = cpu_to_le16(ctrl->wKeyFrameRate);
*(__le16 *)&data[10 ] = cpu_to_le16(ctrl->wPFrameRate);
*(__le16 *)&data[12 ] = cpu_to_le16(ctrl->wCompQuality);
*(__le16 *)&data[14 ] = cpu_to_le16(ctrl->wCompWindowSize);
*(__le16 *)&data[16 ] = cpu_to_le16(ctrl->wDelay);
put_unaligned_le32(ctrl->dwMaxVideoFrameSize, &data[18 ]);
put_unaligned_le32(ctrl->dwMaxPayloadTransferSize, &data[22 ]);
if (size >= 34 ) {
put_unaligned_le32(ctrl->dwClockFrequency, &data[26 ]);
data[30 ] = ctrl->bmFramingInfo;
data[31 ] = ctrl->bPreferedVersion;
data[32 ] = ctrl->bMinVersion;
data[33 ] = ctrl->bMaxVersion;
}
ret = __uvc_query_ctrl(stream->dev, UVC_SET_CUR, 0 , stream->intfnum,
probe ? UVC_VS_PROBE_CONTROL : UVC_VS_COMMIT_CONTROL, data,
size, uvc_timeout_param);
if (ret != size) {
dev_err(&stream->intf->dev,
"Failed to set UVC %s control : %d (exp. %u).\n" ,
probe ? "probe" : "commit" , ret, size);
ret = -EIO;
}
kfree(data);
return ret;
}
int uvc_probe_video(struct uvc_streaming *stream,
struct uvc_streaming_control *probe)
{
struct uvc_streaming_control probe_min, probe_max;
unsigned int i;
int ret;
/*
* Perform probing . The device should adjust the requested values
* according to its capabilities . However , some devices , namely the
* first generation UVC Logitech webcams , don ' t implement the Video
* Probe control properly , and just return the needed bandwidth . For
* that reason , if the needed bandwidth exceeds the maximum available
* bandwidth , try to lower the quality .
*/
ret = uvc_set_video_ctrl(stream, probe, 1 );
if (ret < 0 )
goto done;
/* Get the minimum and maximum values for compression settings. */
if (!(stream->dev->quirks & UVC_QUIRK_PROBE_MINMAX)) {
ret = uvc_get_video_ctrl(stream, &probe_min, 1 , UVC_GET_MIN);
if (ret < 0 )
goto done;
ret = uvc_get_video_ctrl(stream, &probe_max, 1 , UVC_GET_MAX);
if (ret < 0 )
goto done;
probe->wCompQuality = probe_max.wCompQuality;
}
for (i = 0 ; i < 2 ; ++i) {
ret = uvc_set_video_ctrl(stream, probe, 1 );
if (ret < 0 )
goto done;
ret = uvc_get_video_ctrl(stream, probe, 1 , UVC_GET_CUR);
if (ret < 0 )
goto done;
if (stream->intf->num_altsetting == 1 )
break ;
if (probe->dwMaxPayloadTransferSize <= stream->maxpsize)
break ;
if (stream->dev->quirks & UVC_QUIRK_PROBE_MINMAX) {
ret = -ENOSPC;
goto done;
}
/* TODO: negotiate compression parameters */
probe->wKeyFrameRate = probe_min.wKeyFrameRate;
probe->wPFrameRate = probe_min.wPFrameRate;
probe->wCompQuality = probe_max.wCompQuality;
probe->wCompWindowSize = probe_min.wCompWindowSize;
}
done:
return ret;
}
static int uvc_commit_video(struct uvc_streaming *stream,
struct uvc_streaming_control *probe)
{
return uvc_set_video_ctrl(stream, probe, 0 );
}
/* -----------------------------------------------------------------------------
* Clocks and timestamps
*/
static inline ktime_t uvc_video_get_time(void )
{
if (uvc_clock_param == CLOCK_MONOTONIC)
return ktime_get();
else
return ktime_get_real();
}
static void uvc_video_clock_add_sample(struct uvc_clock *clock,
const struct uvc_clock_sample *sample)
{
unsigned long flags;
/*
* If we write new data on the position where we had the last
* overflow , remove the overflow pointer . There is no SOF overflow
* in the whole circular buffer .
*/
if (clock->head == clock->last_sof_overflow)
clock->last_sof_overflow = -1 ;
spin_lock_irqsave(&clock->lock, flags);
if (clock->count > 0 && clock->last_sof > sample->dev_sof) {
/*
* Remove data from the circular buffer that is older than the
* last SOF overflow . We only support one SOF overflow per
* circular buffer .
*/
if (clock->last_sof_overflow != -1 )
clock->count = (clock->head - clock->last_sof_overflow
+ clock->size) % clock->size;
clock->last_sof_overflow = clock->head;
}
/* Add sample. */
clock->samples[clock->head] = *sample;
clock->head = (clock->head + 1 ) % clock->size;
clock->count = min(clock->count + 1 , clock->size);
spin_unlock_irqrestore(&clock->lock, flags);
}
static void
uvc_video_clock_decode(struct uvc_streaming *stream, struct uvc_buffer *buf,
const u8 *data, int len)
{
struct uvc_clock_sample sample;
unsigned int header_size;
bool has_pts = false ;
bool has_scr = false ;
switch (data[1 ] & (UVC_STREAM_PTS | UVC_STREAM_SCR)) {
case UVC_STREAM_PTS | UVC_STREAM_SCR:
header_size = 12 ;
has_pts = true ;
has_scr = true ;
break ;
case UVC_STREAM_PTS:
header_size = 6 ;
has_pts = true ;
break ;
case UVC_STREAM_SCR:
header_size = 8 ;
has_scr = true ;
break ;
default :
header_size = 2 ;
break ;
}
/* Check for invalid headers. */
if (len < header_size)
return ;
/*
* Extract the timestamps :
*
* - store the frame PTS in the buffer structure
* - if the SCR field is present , retrieve the host SOF counter and
* kernel timestamps and store them with the SCR STC and SOF fields
* in the ring buffer
*/
if (has_pts && buf != NULL)
buf->pts = get_unaligned_le32(&data[2 ]);
if (!has_scr)
return ;
/*
* To limit the amount of data , drop SCRs with an SOF identical to the
* previous one . This filtering is also needed to support UVC 1 . 5 , where
* all the data packets of the same frame contains the same SOF . In that
* case only the first one will match the host_sof .
*/
sample.dev_sof = get_unaligned_le16(&data[header_size - 2 ]);
if (sample.dev_sof == stream->clock.last_sof)
return ;
sample.dev_stc = get_unaligned_le32(&data[header_size - 6 ]);
/*
* STC ( Source Time Clock ) is the clock used by the camera . The UVC 1 . 5
* standard states that it " must be captured when the first video data
* of a video frame is put on the USB bus " . This is generally understood
* as requiring devices to clear the payload header ' s SCR bit before
* the first packet containing video data .
*
* Most vendors follow that interpretation , but some ( namely SunplusIT
* on some devices ) always set the ` UVC_STREAM_SCR ` bit , fill the SCR
* field with 0 ' s , and expect that the driver only processes the SCR if
* there is data in the packet .
*
* Ignore all the hardware timestamp information if we haven ' t received
* any data for this frame yet , the packet contains no data , and both
* STC and SOF are zero . This heuristics should be safe on compliant
* devices . This should be safe with compliant devices , as in the very
* unlikely case where a UVC 1 . 1 device would send timing information
* only before the first packet containing data , and both STC and SOF
* happen to be zero for a particular frame , we would only miss one
* clock sample from many and the clock recovery algorithm wouldn ' t
* suffer from this condition .
*/
if (buf && buf->bytesused == 0 && len == header_size &&
sample.dev_stc == 0 && sample.dev_sof == 0 )
return ;
sample.host_sof = usb_get_current_frame_number(stream->dev->udev);
/*
* On some devices , like the Logitech C922 , the device SOF does not run
* at a stable rate of 1 kHz . For those devices use the host SOF instead .
* In the tests performed so far , this improves the timestamp precision .
* This is probably explained by a small packet handling jitter from the
* host , but the exact reason hasn ' t been fully determined .
*/
if (stream->dev->quirks & UVC_QUIRK_INVALID_DEVICE_SOF)
sample.dev_sof = sample.host_sof;
sample.host_time = uvc_video_get_time();
/*
* The UVC specification allows device implementations that can ' t obtain
* the USB frame number to keep their own frame counters as long as they
* match the size and frequency of the frame number associated with USB
* SOF tokens . The SOF values sent by such devices differ from the USB
* SOF tokens by a fixed offset that needs to be estimated and accounted
* for to make timestamp recovery as accurate as possible .
*
* The offset is estimated the first time a device SOF value is received
* as the difference between the host and device SOF values . As the two
* SOF values can differ slightly due to transmission delays , consider
* that the offset is null if the difference is not higher than 10 ms
* ( negative differences can not happen and are thus considered as an
* offset ) . The video commit control wDelay field should be used to
* compute a dynamic threshold instead of using a fixed 10 ms value , but
* devices don ' t report reliable wDelay values .
*
* See uvc_video_clock_host_sof ( ) for an explanation regarding why only
* the 8 LSBs of the delta are kept .
*/
if (stream->clock.sof_offset == (u16)-1 ) {
u16 delta_sof = (sample.host_sof - sample.dev_sof) & 255 ;
if (delta_sof >= 10 )
stream->clock.sof_offset = delta_sof;
else
stream->clock.sof_offset = 0 ;
}
sample.dev_sof = (sample.dev_sof + stream->clock.sof_offset) & 2047 ;
uvc_video_clock_add_sample(&stream->clock, &sample);
stream->clock.last_sof = sample.dev_sof;
}
static void uvc_video_clock_reset(struct uvc_clock *clock)
{
clock->head = 0 ;
clock->count = 0 ;
clock->last_sof = -1 ;
clock->last_sof_overflow = -1 ;
clock->sof_offset = -1 ;
}
static int uvc_video_clock_init(struct uvc_clock *clock)
{
spin_lock_init(&clock->lock);
clock->size = 32 ;
clock->samples = kmalloc_array(clock->size, sizeof (*clock->samples),
GFP_KERNEL);
if (clock->samples == NULL)
return -ENOMEM;
uvc_video_clock_reset(clock);
return 0 ;
}
static void uvc_video_clock_cleanup(struct uvc_clock *clock)
{
kfree(clock->samples);
clock->samples = NULL;
}
/*
* uvc_video_clock_host_sof - Return the host SOF value for a clock sample
*
* Host SOF counters reported by usb_get_current_frame_number ( ) usually don ' t
* cover the whole 11 - bits SOF range ( 0 - 2047 ) but are limited to the HCI frame
* schedule window . They can be limited to 8 , 9 or 10 bits depending on the host
* controller and its configuration .
*
* We thus need to recover the SOF value corresponding to the host frame number .
* As the device and host frame numbers are sampled in a short interval , the
* difference between their values should be equal to a small delta plus an
* integer multiple of 256 caused by the host frame number limited precision .
*
* To obtain the recovered host SOF value , compute the small delta by masking
* the high bits of the host frame counter and device SOF difference and add it
* to the device SOF value .
*/
static u16 uvc_video_clock_host_sof(const struct uvc_clock_sample *sample)
{
/* The delta value can be negative. */
s8 delta_sof;
delta_sof = (sample->host_sof - sample->dev_sof) & 255 ;
return (sample->dev_sof + delta_sof) & 2047 ;
}
/*
* uvc_video_clock_update - Update the buffer timestamp
*
* This function converts the buffer PTS timestamp to the host clock domain by
* going through the USB SOF clock domain and stores the result in the V4L2
* buffer timestamp field .
*
* The relationship between the device clock and the host clock isn ' t known .
* However , the device and the host share the common USB SOF clock which can be
* used to recover that relationship .
*
* The relationship between the device clock and the USB SOF clock is considered
* to be linear over the clock samples sliding window and is given by
*
* SOF = m * PTS + p
*
* Several methods to compute the slope ( m ) and intercept ( p ) can be used . As
* the clock drift should be small compared to the sliding window size , we
* assume that the line that goes through the points at both ends of the window
* is a good approximation . Naming those points P1 and P2 , we get
*
* SOF = ( SOF2 - SOF1 ) / ( STC2 - STC1 ) * PTS
* + ( SOF1 * STC2 - SOF2 * STC1 ) / ( STC2 - STC1 )
*
* or
*
* SOF = ( ( SOF2 - SOF1 ) * PTS + SOF1 * STC2 - SOF2 * STC1 ) / ( STC2 - STC1 ) ( 1 )
*
* to avoid losing precision in the division . Similarly , the host timestamp is
* computed with
*
* TS = ( ( TS2 - TS1 ) * SOF + TS1 * SOF2 - TS2 * SOF1 ) / ( SOF2 - SOF1 ) ( 2 )
*
* SOF values are coded on 11 bits by USB . We extend their precision with 16
* decimal bits , leading to a 11 . 16 coding .
*
* TODO : To avoid surprises with device clock values , PTS / STC timestamps should
* be normalized using the nominal device clock frequency reported through the
* UVC descriptors .
*
* Both the PTS / STC and SOF counters roll over , after a fixed but device
* specific amount of time for PTS / STC and after 2048 ms for SOF . As long as the
* sliding window size is smaller than the rollover period , differences computed
* on unsigned integers will produce the correct result . However , the p term in
* the linear relations will be miscomputed .
*
* To fix the issue , we subtract a constant from the PTS and STC values to bring
* PTS to half the 32 bit STC range . The sliding window STC values then fit into
* the 32 bit range without any rollover .
*
* Similarly , we add 2048 to the device SOF values to make sure that the SOF
* computed by ( 1 ) will never be smaller than 0 . This offset is then compensated
* by adding 2048 to the SOF values used in ( 2 ) . However , this doesn ' t prevent
* rollovers between ( 1 ) and ( 2 ) : the SOF value computed by ( 1 ) can be slightly
* lower than 4096 , and the host SOF counters can have rolled over to 2048 . This
* case is handled by subtracting 2048 from the SOF value if it exceeds the host
* SOF value at the end of the sliding window .
*
* Finally we subtract a constant from the host timestamps to bring the first
* timestamp of the sliding window to 1 s .
*/
void uvc_video_clock_update(struct uvc_streaming *stream,
struct vb2_v4l2_buffer *vbuf,
struct uvc_buffer *buf)
{
struct uvc_clock *clock = &stream->clock;
struct uvc_clock_sample *first;
struct uvc_clock_sample *last;
unsigned long flags;
u64 timestamp;
u32 delta_stc;
u32 y1;
u32 x1, x2;
u32 mean;
u32 sof;
u64 y, y2;
if (!uvc_hw_timestamps_param)
return ;
/*
* We will get called from _ _ vb2_queue_cancel ( ) if there are buffers
* done but not dequeued by the user , but the sample array has already
* been released at that time . Just bail out in that case .
*/
if (!clock->samples)
return ;
spin_lock_irqsave(&clock->lock, flags);
if (clock->count < 2 )
goto done;
first = &clock->samples[(clock->head - clock->count + clock->size) % clock->size];
last = &clock->samples[(clock->head - 1 + clock->size) % clock->size];
/* First step, PTS to SOF conversion. */
delta_stc = buf->pts - (1 UL << 31 );
x1 = first->dev_stc - delta_stc;
x2 = last->dev_stc - delta_stc;
if (x1 == x2)
goto done;
y1 = (first->dev_sof + 2048 ) << 16 ;
y2 = (last->dev_sof + 2048 ) << 16 ;
if (y2 < y1)
y2 += 2048 << 16 ;
/*
* Have at least 1 / 4 of a second of timestamps before we
* try to do any calculation . Otherwise we do not have enough
* precision . This value was determined by running Android CTS
* on different devices .
*
* dev_sof runs at 1 KHz , and we have a fixed point precision of
* 16 bits .
*/
if ((y2 - y1) < ((1000 / 4 ) << 16 ))
goto done;
y = (u64)(y2 - y1) * (1 ULL << 31 ) + (u64)y1 * (u64)x2
- (u64)y2 * (u64)x1;
y = div_u64(y, x2 - x1);
sof = y;
uvc_dbg(stream->dev, CLOCK,
"%s: PTS %u y %llu.%06llu SOF %u.%06llu (x1 %u x2 %u y1 %u y2 %llu SOF offset %u)\n" ,
stream->dev->name, buf->pts,
y >> 16 , div_u64((y & 0 xffff) * 1000000 , 65536 ),
sof >> 16 , div_u64(((u64)sof & 0 xffff) * 1000000 LLU, 65536 ),
x1, x2, y1, y2, clock->sof_offset);
/* Second step, SOF to host clock conversion. */
x1 = (uvc_video_clock_host_sof(first) + 2048 ) << 16 ;
x2 = (uvc_video_clock_host_sof(last) + 2048 ) << 16 ;
if (x2 < x1)
x2 += 2048 << 16 ;
if (x1 == x2)
goto done;
y1 = NSEC_PER_SEC;
y2 = ktime_to_ns(ktime_sub(last->host_time, first->host_time)) + y1;
/*
* Interpolated and host SOF timestamps can wrap around at slightly
* different times . Handle this by adding or removing 2048 to or from
* the computed SOF value to keep it close to the SOF samples mean
* value .
*/
mean = (x1 + x2) / 2 ;
if (mean - (1024 << 16 ) > sof)
sof += 2048 << 16 ;
else if (sof > mean + (1024 << 16 ))
sof -= 2048 << 16 ;
y = (u64)(y2 - y1) * (u64)sof + (u64)y1 * (u64)x2
- (u64)y2 * (u64)x1;
y = div_u64(y, x2 - x1);
timestamp = ktime_to_ns(first->host_time) + y - y1;
uvc_dbg(stream->dev, CLOCK,
"%s: SOF %u.%06llu y %llu ts %llu buf ts %llu (x1 %u/%u/%u x2 %u/%u/%u y1 %u y2 %llu)\n" ,
stream->dev->name,
sof >> 16 , div_u64(((u64)sof & 0 xffff) * 1000000 LLU, 65536 ),
y, timestamp, vbuf->vb2_buf.timestamp,
x1, first->host_sof, first->dev_sof,
x2, last->host_sof, last->dev_sof, y1, y2);
/* Update the V4L2 buffer. */
vbuf->vb2_buf.timestamp = timestamp;
done:
spin_unlock_irqrestore(&clock->lock, flags);
}
/* ------------------------------------------------------------------------
* Stream statistics
*/
static void uvc_video_stats_decode(struct uvc_streaming *stream,
const u8 *data, int len)
{
unsigned int header_size;
bool has_pts = false ;
bool has_scr = false ;
u16 scr_sof;
u32 scr_stc;
u32 pts;
if (stream->stats.stream.nb_frames == 0 &&
stream->stats.frame.nb_packets == 0 )
stream->stats.stream.start_ts = ktime_get();
switch (data[1 ] & (UVC_STREAM_PTS | UVC_STREAM_SCR)) {
case UVC_STREAM_PTS | UVC_STREAM_SCR:
header_size = 12 ;
has_pts = true ;
has_scr = true ;
break ;
case UVC_STREAM_PTS:
header_size = 6 ;
has_pts = true ;
break ;
case UVC_STREAM_SCR:
header_size = 8 ;
has_scr = true ;
break ;
default :
header_size = 2 ;
break ;
}
/* Check for invalid headers. */
if (len < header_size || data[0 ] < header_size) {
stream->stats.frame.nb_invalid++;
return ;
}
/* Extract the timestamps. */
if (has_pts)
pts = get_unaligned_le32(&data[2 ]);
if (has_scr) {
scr_stc = get_unaligned_le32(&data[header_size - 6 ]);
scr_sof = get_unaligned_le16(&data[header_size - 2 ]);
}
/* Is PTS constant through the whole frame ? */
if (has_pts && stream->stats.frame.nb_pts) {
if (stream->stats.frame.pts != pts) {
stream->stats.frame.nb_pts_diffs++;
stream->stats.frame.last_pts_diff =
stream->stats.frame.nb_packets;
}
}
if (has_pts) {
stream->stats.frame.nb_pts++;
stream->stats.frame.pts = pts;
}
/*
* Do all frames have a PTS in their first non - empty packet , or before
* their first empty packet ?
*/
if (stream->stats.frame.size == 0 ) {
if (len > header_size)
stream->stats.frame.has_initial_pts = has_pts;
if (len == header_size && has_pts)
stream->stats.frame.has_early_pts = true ;
}
/* Do the SCR.STC and SCR.SOF fields vary through the frame ? */
if (has_scr && stream->stats.frame.nb_scr) {
if (stream->stats.frame.scr_stc != scr_stc)
stream->stats.frame.nb_scr_diffs++;
}
if (has_scr) {
/* Expand the SOF counter to 32 bits and store its value. */
if (stream->stats.stream.nb_frames > 0 ||
stream->stats.frame.nb_scr > 0 )
stream->stats.stream.scr_sof_count +=
(scr_sof - stream->stats.stream.scr_sof) % 2048 ;
stream->stats.stream.scr_sof = scr_sof;
stream->stats.frame.nb_scr++;
stream->stats.frame.scr_stc = scr_stc;
stream->stats.frame.scr_sof = scr_sof;
if (scr_sof < stream->stats.stream.min_sof)
stream->stats.stream.min_sof = scr_sof;
if (scr_sof > stream->stats.stream.max_sof)
stream->stats.stream.max_sof = scr_sof;
}
/* Record the first non-empty packet number. */
if (stream->stats.frame.size == 0 && len > header_size)
stream->stats.frame.first_data = stream->stats.frame.nb_packets;
/* Update the frame size. */
stream->stats.frame.size += len - header_size;
/* Update the packets counters. */
stream->stats.frame.nb_packets++;
if (len <= header_size)
stream->stats.frame.nb_empty++;
if (data[1 ] & UVC_STREAM_ERR)
stream->stats.frame.nb_errors++;
}
static void uvc_video_stats_update(struct uvc_streaming *stream)
{
struct uvc_stats_frame *frame = &stream->stats.frame;
uvc_dbg(stream->dev, STATS,
"frame %u stats: %u/%u/%u packets, %u/%u/%u pts (%searly %sinitial), %u/%u scr, last pts/stc/sof %u/%u/%u\n" ,
stream->sequence, frame->first_data,
frame->nb_packets - frame->nb_empty, frame->nb_packets,
frame->nb_pts_diffs, frame->last_pts_diff, frame->nb_pts,
frame->has_early_pts ? "" : "!" ,
frame->has_initial_pts ? "" : "!" ,
frame->nb_scr_diffs, frame->nb_scr,
frame->pts, frame->scr_stc, frame->scr_sof);
stream->stats.stream.nb_frames++;
stream->stats.stream.nb_packets += stream->stats.frame.nb_packets;
stream->stats.stream.nb_empty += stream->stats.frame.nb_empty;
stream->stats.stream.nb_errors += stream->stats.frame.nb_errors;
stream->stats.stream.nb_invalid += stream->stats.frame.nb_invalid;
if (frame->has_early_pts)
stream->stats.stream.nb_pts_early++;
if (frame->has_initial_pts)
stream->stats.stream.nb_pts_initial++;
if (frame->last_pts_diff <= frame->first_data)
stream->stats.stream.nb_pts_constant++;
if (frame->nb_scr >= frame->nb_packets - frame->nb_empty)
stream->stats.stream.nb_scr_count_ok++;
if (frame->nb_scr_diffs + 1 == frame->nb_scr)
stream->stats.stream.nb_scr_diffs_ok++;
memset(&stream->stats.frame, 0 , sizeof (stream->stats.frame));
}
size_t uvc_video_stats_dump(struct uvc_streaming *stream, char *buf,
size_t size)
{
unsigned int scr_sof_freq;
unsigned int duration;
size_t count = 0 ;
/*
* Compute the SCR . SOF frequency estimate . At the nominal 1 kHz SOF
* frequency this will not overflow before more than 1 h .
*/
duration = ktime_ms_delta(stream->stats.stream.stop_ts,
stream->stats.stream.start_ts);
if (duration != 0 )
scr_sof_freq = stream->stats.stream.scr_sof_count * 1000
/ duration;
else
scr_sof_freq = 0 ;
count += scnprintf(buf + count, size - count,
"frames: %u\npackets: %u\nempty: %u\n"
"errors: %u\ninvalid: %u\n" ,
stream->stats.stream.nb_frames,
stream->stats.stream.nb_packets,
stream->stats.stream.nb_empty,
stream->stats.stream.nb_errors,
stream->stats.stream.nb_invalid);
count += scnprintf(buf + count, size - count,
"pts: %u early, %u initial, %u ok\n" ,
stream->stats.stream.nb_pts_early,
stream->stats.stream.nb_pts_initial,
stream->stats.stream.nb_pts_constant);
count += scnprintf(buf + count, size - count,
"scr: %u count ok, %u diff ok\n" ,
stream->stats.stream.nb_scr_count_ok,
stream->stats.stream.nb_scr_diffs_ok);
count += scnprintf(buf + count, size - count,
"sof: %u <= sof <= %u, freq %u.%03u kHz\n" ,
stream->stats.stream.min_sof,
stream->stats.stream.max_sof,
scr_sof_freq / 1000 , scr_sof_freq % 1000 );
return count;
}
static void uvc_video_stats_start(struct uvc_streaming *stream)
{
memset(&stream->stats, 0 , sizeof (stream->stats));
stream->stats.stream.min_sof = 2048 ;
}
static void uvc_video_stats_stop(struct uvc_streaming *stream)
{
stream->stats.stream.stop_ts = ktime_get();
}
/* ------------------------------------------------------------------------
* Video codecs
*/
/*
* Video payload decoding is handled by uvc_video_decode_start ( ) ,
* uvc_video_decode_data ( ) and uvc_video_decode_end ( ) .
*
* uvc_video_decode_start is called with URB data at the start of a bulk or
* isochronous payload . It processes header data and returns the header size
* in bytes if successful . If an error occurs , it returns a negative error
* code . The following error codes have special meanings .
*
* - EAGAIN informs the caller that the current video buffer should be marked
* as done , and that the function should be called again with the same data
* and a new video buffer . This is used when end of frame conditions can be
* reliably detected at the beginning of the next frame only .
*
* If an error other than - EAGAIN is returned , the caller will drop the current
* payload . No call to uvc_video_decode_data and uvc_video_decode_end will be
* made until the next payload . - ENODATA can be used to drop the current
* payload if no other error code is appropriate .
*
* uvc_video_decode_data is called for every URB with URB data . It copies the
* data to the video buffer .
*
* uvc_video_decode_end is called with header data at the end of a bulk or
* isochronous payload . It performs any additional header data processing and
* returns 0 or a negative error code if an error occurred . As header data have
* already been processed by uvc_video_decode_start , this functions isn ' t
* required to perform sanity checks a second time .
*
* For isochronous transfers where a payload is always transferred in a single
* URB , the three functions will be called in a row .
*
* To let the decoder process header data and update its internal state even
* when no video buffer is available , uvc_video_decode_start must be prepared
* to be called with a NULL buf parameter . uvc_video_decode_data and
* uvc_video_decode_end will never be called with a NULL buffer .
*/
static int uvc_video_decode_start(struct uvc_streaming *stream,
struct uvc_buffer *buf, const u8 *data, int len)
{
u8 header_len;
u8 fid;
/*
* Sanity checks :
* - packet must be at least 2 bytes long
* - bHeaderLength value must be at least 2 bytes ( see above )
* - bHeaderLength value can ' t be larger than the packet size .
*/
if (len < 2 || data[0 ] < 2 || data[0 ] > len) {
stream->stats.frame.nb_invalid++;
return -EINVAL;
}
header_len = data[0 ];
fid = data[1 ] & UVC_STREAM_FID;
/*
* Increase the sequence number regardless of any buffer states , so
* that discontinuous sequence numbers always indicate lost frames .
*/
if (stream->last_fid != fid) {
stream->sequence++;
if (stream->sequence)
uvc_video_stats_update(stream);
}
uvc_video_clock_decode(stream, buf, data, len);
uvc_video_stats_decode(stream, data, len);
/*
* Store the payload FID bit and return immediately when the buffer is
* NULL .
*/
if (buf == NULL) {
stream->last_fid = fid;
return -ENODATA;
}
/* Mark the buffer as bad if the error bit is set. */
if (data[1 ] & UVC_STREAM_ERR) {
uvc_dbg(stream->dev, FRAME,
"Marking buffer as bad (error bit set)\n" );
buf->error = 1 ;
}
/*
* Synchronize to the input stream by waiting for the FID bit to be
* toggled when the buffer state is not UVC_BUF_STATE_ACTIVE .
* stream - > 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 stream - > last_fid
* when the EOF bit is set to force synchronisation on the next packet .
*/
if (buf->state != UVC_BUF_STATE_ACTIVE) {
if (fid == stream->last_fid) {
uvc_dbg(stream->dev, FRAME,
"Dropping payload (out of sync)\n" );
if ((stream->dev->quirks & UVC_QUIRK_STREAM_NO_FID) &&
(data[1 ] & UVC_STREAM_EOF))
stream->last_fid ^= UVC_STREAM_FID;
return -ENODATA;
}
buf->buf.field = V4L2_FIELD_NONE;
buf->buf.sequence = stream->sequence;
buf->buf.vb2_buf.timestamp = ktime_to_ns(uvc_video_get_time());
/* TODO: Handle PTS and SCR. */
buf->state = UVC_BUF_STATE_ACTIVE;
}
/*
* Mark the buffer as done if we ' re at the beginning of a new frame .
* End of frame detection is better implemented by checking the EOF
* bit ( FID bit toggling is delayed by one frame compared to the EOF
* bit ) , but some devices don ' t set the bit at end of frame ( and the
* last payload can be lost anyway ) . We thus must check if the FID has
* been toggled .
*
* stream - > 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 end of frame conditions at FID toggling if the
* previous payload had the EOF bit set .
*/
if (fid != stream->last_fid && buf->bytesused != 0 ) {
uvc_dbg(stream->dev, FRAME,
"Frame complete (FID bit toggled)\n" );
buf->state = UVC_BUF_STATE_READY;
return -EAGAIN;
}
/*
* Some cameras , when running two parallel streams ( one MJPEG alongside
* another non - MJPEG stream ) , are known to lose the EOF packet for a frame .
* We can detect the end of a frame by checking for a new SOI marker , as
* the SOI always lies on the packet boundary between two frames for
* these devices .
*/
if (stream->dev->quirks & UVC_QUIRK_MJPEG_NO_EOF &&
(stream->cur_format->fcc == V4L2_PIX_FMT_MJPEG ||
stream->cur_format->fcc == V4L2_PIX_FMT_JPEG)) {
const u8 *packet = data + header_len;
if (len >= header_len + 2 &&
packet[0 ] == 0 xff && packet[1 ] == JPEG_MARKER_SOI &&
buf->bytesused != 0 ) {
buf->state = UVC_BUF_STATE_READY;
buf->error = 1 ;
stream->last_fid ^= UVC_STREAM_FID;
return -EAGAIN;
}
}
stream->last_fid = fid;
return header_len;
}
static inline enum dma_data_direction uvc_stream_dir(
struct uvc_streaming *stream)
{
if (stream->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
return DMA_FROM_DEVICE;
else
return DMA_TO_DEVICE;
}
/*
* uvc_video_decode_data_work : Asynchronous memcpy processing
*
* Copy URB data to video buffers in process context , releasing buffer
* references and requeuing the URB when done .
*/
static void uvc_video_copy_data_work(struct work_struct *work)
{
struct uvc_urb *uvc_urb = container_of(work, struct uvc_urb, work);
unsigned int i;
int ret;
for (i = 0 ; i < uvc_urb->async_operations; i++) {
struct uvc_copy_op *op = &uvc_urb->copy_operations[i];
memcpy(op->dst, op->src, op->len);
/* Release reference taken on this buffer. */
uvc_queue_buffer_release(op->buf);
}
ret = usb_submit_urb(uvc_urb->urb, GFP_KERNEL);
if (ret < 0 )
dev_err(&uvc_urb->stream->intf->dev,
"Failed to resubmit video URB (%d).\n" , ret);
}
static void uvc_video_decode_data(struct uvc_urb *uvc_urb,
struct uvc_buffer *buf, const u8 *data, int len)
{
unsigned int active_op = uvc_urb->async_operations;
struct uvc_copy_op *op = &uvc_urb->copy_operations[active_op];
unsigned int maxlen;
if (len <= 0 )
return ;
maxlen = buf->length - buf->bytesused;
/* Take a buffer reference for async work. */
kref_get(&buf->ref);
op->buf = buf;
op->src = data;
op->dst = buf->mem + buf->bytesused;
op->len = min_t(unsigned int , len, maxlen);
buf->bytesused += op->len;
/* Complete the current frame if the buffer size was exceeded. */
if (len > maxlen) {
uvc_dbg(uvc_urb->stream->dev, FRAME,
"Frame complete (overflow)\n" );
buf->error = 1 ;
buf->state = UVC_BUF_STATE_READY;
}
uvc_urb->async_operations++;
}
static void uvc_video_decode_end(struct uvc_streaming *stream,
struct uvc_buffer *buf, const u8 *data, int len)
{
/* Mark the buffer as done if the EOF marker is set. */
if (data[1 ] & UVC_STREAM_EOF && buf->bytesused != 0 ) {
uvc_dbg(stream->dev, FRAME, "Frame complete (EOF found)\n" );
if (data[0 ] == len)
uvc_dbg(stream->dev, FRAME, "EOF in empty payload\n" );
buf->state = UVC_BUF_STATE_READY;
if (stream->dev->quirks & UVC_QUIRK_STREAM_NO_FID)
stream->last_fid ^= UVC_STREAM_FID;
}
}
/*
* 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_streaming *stream,
struct uvc_buffer *buf, u8 *data, int len)
{
data[0 ] = 2 ; /* Header length */
data[1 ] = UVC_STREAM_EOH | UVC_STREAM_EOF
| (stream->last_fid & UVC_STREAM_FID);
return 2 ;
}
static int uvc_video_encode_data(struct uvc_streaming *stream,
struct uvc_buffer *buf, u8 *data, int len)
{
struct uvc_video_queue *queue = &stream->queue;
unsigned int nbytes;
void *mem;
/* Copy video data to the URB buffer. */
mem = buf->mem + queue->buf_used;
nbytes = min((unsigned int )len, buf->bytesused - queue->buf_used);
nbytes = min(stream->bulk.max_payload_size - stream->bulk.payload_size,
nbytes);
memcpy(data, mem, nbytes);
queue->buf_used += nbytes;
return nbytes;
}
/* ------------------------------------------------------------------------
* Metadata
*/
/*
* Additionally to the payload headers we also want to provide the user with USB
* Frame Numbers and system time values . The resulting buffer is thus composed
* of blocks , containing a 64 - bit timestamp in nanoseconds , a 16 - bit USB Frame
* Number , and a copy of the payload header .
*
* Ideally we want to capture all payload headers for each frame . However , their
* number is unknown and unbound . We thus drop headers that contain no vendor
* data and that either contain no SCR value or an SCR value identical to the
* previous header .
*/
static void uvc_video_decode_meta(struct uvc_streaming *stream,
struct uvc_buffer *meta_buf,
const u8 *mem, unsigned int length)
{
struct uvc_meta_buf *meta;
size_t len_std = 2 ;
bool has_pts, has_scr;
unsigned long flags;
unsigned int sof;
ktime_t time;
const u8 *scr;
if (!meta_buf || length == 2 )
return ;
has_pts = mem[1 ] & UVC_STREAM_PTS;
has_scr = mem[1 ] & UVC_STREAM_SCR;
if (has_pts) {
len_std += 4 ;
scr = mem + 6 ;
} else {
scr = mem + 2 ;
}
if (has_scr)
len_std += 6 ;
if (stream->meta.format == V4L2_META_FMT_UVC)
length = len_std;
if (length == len_std && (!has_scr ||
!memcmp(scr, stream->clock.last_scr, 6 )))
return ;
if (meta_buf->length - meta_buf->bytesused <
length + sizeof (meta->ns) + sizeof (meta->sof)) {
meta_buf->error = 1 ;
return ;
}
meta = (struct uvc_meta_buf *)((u8 *)meta_buf->mem + meta_buf->bytesused);
local_irq_save(flags);
time = uvc_video_get_time();
sof = usb_get_current_frame_number(stream->dev->udev);
local_irq_restore(flags);
put_unaligned(ktime_to_ns(time), &meta->ns);
put_unaligned(sof, &meta->sof);
if (has_scr)
memcpy(stream->clock.last_scr, scr, 6 );
meta->length = mem[0 ];
meta->flags = mem[1 ];
memcpy(meta->buf, &mem[2 ], length - 2 );
meta_buf->bytesused += length + sizeof (meta->ns) + sizeof (meta->sof);
uvc_dbg(stream->dev, FRAME,
"%s(): t-sys %lluns, SOF %u, len %u, flags 0x%x, PTS %u, STC %u frame SOF %u\n" ,
__func__, ktime_to_ns(time), meta->sof, meta->length,
meta->flags,
has_pts ? *(u32 *)meta->buf : 0 ,
has_scr ? *(u32 *)scr : 0 ,
has_scr ? *(u32 *)(scr + 4 ) & 0 x7ff : 0 );
}
/* ------------------------------------------------------------------------
* URB handling
*/
/*
* Set error flag for incomplete buffer .
*/
static void uvc_video_validate_buffer(const struct uvc_streaming *stream,
struct uvc_buffer *buf)
{
if (stream->ctrl.dwMaxVideoFrameSize != buf->bytesused &&
!(stream->cur_format->flags & UVC_FMT_FLAG_COMPRESSED))
buf->error = 1 ;
}
/*
* Completion handler for video URBs .
*/
static void uvc_video_next_buffers(struct uvc_streaming *stream,
struct uvc_buffer **video_buf, struct uvc_buffer **meta_buf)
{
uvc_video_validate_buffer(stream, *video_buf);
if (*meta_buf) {
struct vb2_v4l2_buffer *vb2_meta = &(*meta_buf)->buf;
const struct vb2_v4l2_buffer *vb2_video = &(*video_buf)->buf;
vb2_meta->sequence = vb2_video->sequence;
vb2_meta->field = vb2_video->field;
vb2_meta->vb2_buf.timestamp = vb2_video->vb2_buf.timestamp;
(*meta_buf)->state = UVC_BUF_STATE_READY;
if (!(*meta_buf)->error)
(*meta_buf)->error = (*video_buf)->error;
*meta_buf = uvc_queue_next_buffer(&stream->meta.queue,
*meta_buf);
}
*video_buf = uvc_queue_next_buffer(&stream->queue, *video_buf);
}
static void uvc_video_decode_isoc(struct uvc_urb *uvc_urb,
struct uvc_buffer *buf, struct uvc_buffer *meta_buf)
{
struct urb *urb = uvc_urb->urb;
struct uvc_streaming *stream = uvc_urb->stream;
u8 *mem;
int ret, i;
for (i = 0 ; i < urb->number_of_packets; ++i) {
if (urb->iso_frame_desc[i].status < 0 ) {
uvc_dbg(stream->dev, FRAME,
"USB isochronous frame lost (%d)\n" ,
urb->iso_frame_desc[i].status);
/* Mark the buffer as faulty. */
if (buf != NULL)
buf->error = 1 ;
continue ;
}
/* Decode the payload header. */
mem = urb->transfer_buffer + urb->iso_frame_desc[i].offset;
do {
ret = uvc_video_decode_start(stream, buf, mem,
urb->iso_frame_desc[i].actual_length);
if (ret == -EAGAIN)
uvc_video_next_buffers(stream, &buf, &meta_buf);
} while (ret == -EAGAIN);
if (ret < 0 )
continue ;
uvc_video_decode_meta(stream, meta_buf, mem, ret);
/* Decode the payload data. */
uvc_video_decode_data(uvc_urb, buf, mem + ret,
urb->iso_frame_desc[i].actual_length - ret);
/* Process the header again. */
uvc_video_decode_end(stream, buf, mem,
urb->iso_frame_desc[i].actual_length);
if (buf->state == UVC_BUF_STATE_READY)
uvc_video_next_buffers(stream, &buf, &meta_buf);
}
}
static void uvc_video_decode_bulk(struct uvc_urb *uvc_urb,
struct uvc_buffer *buf, struct uvc_buffer *meta_buf)
{
struct urb *urb = uvc_urb->urb;
struct uvc_streaming *stream = uvc_urb->stream;
u8 *mem;
int len, ret;
/*
* Ignore ZLPs if they ' re not part of a frame , otherwise process them
* to trigger the end of payload detection .
*/
if (urb->actual_length == 0 && stream->bulk.header_size == 0 )
return ;
mem = urb->transfer_buffer;
len = urb->actual_length;
stream->bulk.payload_size += len;
/*
* If the URB is the first of its payload , decode and save the
* header .
*/
if (stream->bulk.header_size == 0 && !stream->bulk.skip_payload) {
do {
ret = uvc_video_decode_start(stream, buf, mem, len);
if (ret == -EAGAIN)
uvc_video_next_buffers(stream, &buf, &meta_buf);
} while (ret == -EAGAIN);
/* If an error occurred skip the rest of the payload. */
if (ret < 0 || buf == NULL) {
stream->bulk.skip_payload = 1 ;
} else {
memcpy(stream->bulk.header, mem, ret);
stream->bulk.header_size = ret;
uvc_video_decode_meta(stream, meta_buf, mem, ret);
mem += ret;
len -= ret;
}
}
/*
* The buffer queue might have been cancelled while a bulk transfer
* was in progress , so we can reach here with buf equal to NULL . Make
* sure buf is never dereferenced if NULL .
*/
/* Prepare video data for processing. */
if (!stream->bulk.skip_payload && buf != NULL)
uvc_video_decode_data(uvc_urb, buf, mem, len);
/*
* Detect the payload end by a URB smaller than the maximum size ( or
* a payload size equal to the maximum ) and process the header again .
*/
if (urb->actual_length < urb->transfer_buffer_length ||
stream->bulk.payload_size >= stream->bulk.max_payload_size) {
if (!stream->bulk.skip_payload && buf != NULL) {
uvc_video_decode_end(stream, buf, stream->bulk.header,
stream->bulk.payload_size);
if (buf->state == UVC_BUF_STATE_READY)
uvc_video_next_buffers(stream, &buf, &meta_buf);
}
stream->bulk.header_size = 0 ;
stream->bulk.skip_payload = 0 ;
stream->bulk.payload_size = 0 ;
}
}
static void uvc_video_encode_bulk(struct uvc_urb *uvc_urb,
struct uvc_buffer *buf, struct uvc_buffer *meta_buf)
{
struct urb *urb = uvc_urb->urb;
struct uvc_streaming *stream = uvc_urb->stream;
u8 *mem = urb->transfer_buffer;
int len = stream->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 (stream->bulk.header_size == 0 ) {
ret = uvc_video_encode_header(stream, buf, mem, len);
stream->bulk.header_size = ret;
stream->bulk.payload_size += ret;
mem += ret;
len -= ret;
}
/* Process video data. */
ret = uvc_video_encode_data(stream, buf, mem, len);
stream->bulk.payload_size += ret;
len -= ret;
if (buf->bytesused == stream->queue.buf_used ||
stream->bulk.payload_size == stream->bulk.max_payload_size) {
if (buf->bytesused == stream->queue.buf_used) {
stream->queue.buf_used = 0 ;
buf->state = UVC_BUF_STATE_READY;
buf->buf.sequence = ++stream->sequence;
uvc_queue_next_buffer(&stream->queue, buf);
stream->last_fid ^= UVC_STREAM_FID;
}
stream->bulk.header_size = 0 ;
stream->bulk.payload_size = 0 ;
}
urb->transfer_buffer_length = stream->urb_size - len;
}
static void uvc_video_complete(struct urb *urb)
{
struct uvc_urb *uvc_urb = urb->context;
struct uvc_streaming *stream = uvc_urb->stream;
struct uvc_video_queue *queue = &stream->queue;
struct uvc_video_queue *qmeta = &stream->meta.queue;
struct vb2_queue *vb2_qmeta = stream->meta.vdev.queue;
struct uvc_buffer *buf = NULL;
struct uvc_buffer *buf_meta = NULL;
unsigned long flags;
int ret;
switch (urb->status) {
case 0 :
break ;
default :
dev_warn(&stream->intf->dev,
"Non-zero status (%d) in video completion handler.\n" ,
urb->status);
fallthrough;
case -ENOENT: /* usb_poison_urb() called. */
if (stream->frozen)
return ;
fallthrough;
case -ECONNRESET: /* usb_unlink_urb() called. */
case -ESHUTDOWN: /* The endpoint is being disabled. */
uvc_queue_cancel(queue, urb->status == -ESHUTDOWN);
if (vb2_qmeta)
uvc_queue_cancel(qmeta, urb->status == -ESHUTDOWN);
return ;
}
buf = uvc_queue_get_current_buffer(queue);
if (vb2_qmeta) {
spin_lock_irqsave(&qmeta->irqlock, flags);
if (!list_empty(&qmeta->irqqueue))
buf_meta = list_first_entry(&qmeta->irqqueue,
struct uvc_buffer, queue);
spin_unlock_irqrestore(&qmeta->irqlock, flags);
}
/* Re-initialise the URB async work. */
uvc_urb->async_operations = 0 ;
/*
* Process the URB headers , and optionally queue expensive memcpy tasks
* to be deferred to a work queue .
*/
stream->decode(uvc_urb, buf, buf_meta);
/* If no async work is needed, resubmit the URB immediately. */
if (!uvc_urb->async_operations) {
ret = usb_submit_urb(uvc_urb->urb, GFP_ATOMIC);
if (ret < 0 )
dev_err(&stream->intf->dev,
"Failed to resubmit video URB (%d).\n" , ret);
return ;
}
queue_work(stream->async_wq, &uvc_urb->work);
}
/*
* Free transfer buffers .
*/
static void uvc_free_urb_buffers(struct uvc_streaming *stream)
{
struct usb_device *udev = stream->dev->udev;
struct uvc_urb *uvc_urb;
for_each_uvc_urb(uvc_urb, stream) {
if (!uvc_urb->buffer)
continue ;
usb_free_noncoherent(udev, stream->urb_size, uvc_urb->buffer,
uvc_stream_dir(stream), uvc_urb->sgt);
uvc_urb->buffer = NULL;
uvc_urb->sgt = NULL;
}
stream->urb_size = 0 ;
}
static bool uvc_alloc_urb_buffer(struct uvc_streaming *stream,
struct uvc_urb *uvc_urb, gfp_t gfp_flags)
{
struct usb_device *udev = stream->dev->udev;
uvc_urb->buffer = usb_alloc_noncoherent(udev, stream->urb_size,
gfp_flags, &uvc_urb->dma,
uvc_stream_dir(stream),
&uvc_urb->sgt);
return !!uvc_urb->buffer;
}
/*
* Allocate transfer buffers . This function can be called with buffers
* already allocated when resuming from suspend , in which case it will
* return without touching the buffers .
*
* Limit the buffer size to UVC_MAX_PACKETS bulk / isochronous packets . If the
* system is too low on memory try successively smaller numbers of packets
* until allocation succeeds .
*
* Return the number of allocated packets on success or 0 when out of memory .
*/
static int uvc_alloc_urb_buffers(struct uvc_streaming *stream,
unsigned int size, unsigned int psize, gfp_t gfp_flags)
{
unsigned int npackets;
unsigned int i;
/* Buffers are already allocated, bail out. */
if (stream->urb_size)
return stream->urb_size / psize;
/*
* Compute the number of packets . Bulk endpoints might transfer UVC
* payloads across multiple URBs .
*/
npackets = DIV_ROUND_UP(size, psize);
if (npackets > UVC_MAX_PACKETS)
npackets = UVC_MAX_PACKETS;
/* Retry allocations until one succeed. */
for (; npackets > 1 ; npackets /= 2 ) {
stream->urb_size = psize * npackets;
for (i = 0 ; i < UVC_URBS; ++i) {
struct uvc_urb *uvc_urb = &stream->uvc_urb[i];
if (!uvc_alloc_urb_buffer(stream, uvc_urb, gfp_flags)) {
uvc_free_urb_buffers(stream);
break ;
}
uvc_urb->stream = stream;
}
if (i == UVC_URBS) {
uvc_dbg(stream->dev, VIDEO,
"Allocated %u URB buffers of %ux%u bytes each\n" ,
UVC_URBS, npackets, psize);
return npackets;
}
}
uvc_dbg(stream->dev, VIDEO,
"Failed to allocate URB buffers (%u bytes per packet)\n" ,
psize);
return 0 ;
}
/*
* Uninitialize isochronous / bulk URBs and free transfer buffers .
*/
static void uvc_video_stop_transfer(struct uvc_streaming *stream,
int free_buffers)
{
struct uvc_urb *uvc_urb;
uvc_video_stats_stop(stream);
/*
* We must poison the URBs rather than kill them to ensure that even
* after the completion handler returns , any asynchronous workqueues
* will be prevented from resubmitting the URBs .
*/
for_each_uvc_urb(uvc_urb, stream)
usb_poison_urb(uvc_urb->urb);
flush_workqueue(stream->async_wq);
for_each_uvc_urb(uvc_urb, stream) {
usb_free_urb(uvc_urb->urb);
uvc_urb->urb = NULL;
}
if (free_buffers)
uvc_free_urb_buffers(stream);
}
/*
* Compute the maximum number of bytes per interval for an endpoint .
*/
u16 uvc_endpoint_max_bpi(struct usb_device *dev, struct usb_host_endpoint *ep)
{
u16 psize;
switch (dev->speed) {
case USB_SPEED_SUPER:
case USB_SPEED_SUPER_PLUS:
return le16_to_cpu(ep->ss_ep_comp.wBytesPerInterval);
default :
psize = usb_endpoint_maxp(&ep->desc);
psize *= usb_endpoint_maxp_mult(&ep->desc);
return psize;
}
}
/*
* Initialize isochronous URBs and allocate transfer buffers . The packet size
* is given by the endpoint .
*/
static int uvc_init_video_isoc(struct uvc_streaming *stream,
struct usb_host_endpoint *ep, gfp_t gfp_flags)
{
struct urb *urb;
struct uvc_urb *uvc_urb;
unsigned int npackets, i;
u16 psize;
u32 size;
psize = uvc_endpoint_max_bpi(stream->dev->udev, ep);
size = stream->ctrl.dwMaxVideoFrameSize;
npackets = uvc_alloc_urb_buffers(stream, size, psize, gfp_flags);
if (npackets == 0 )
return -ENOMEM;
size = npackets * psize;
for_each_uvc_urb(uvc_urb, stream) {
urb = usb_alloc_urb(npackets, gfp_flags);
if (urb == NULL) {
uvc_video_stop_transfer(stream, 1 );
return -ENOMEM;
}
urb->dev = stream->dev->udev;
urb->context = uvc_urb;
urb->pipe = usb_rcvisocpipe(stream->dev->udev,
ep->desc.bEndpointAddress);
urb->transfer_flags = URB_ISO_ASAP | URB_NO_TRANSFER_DMA_MAP;
urb->transfer_dma = uvc_urb->dma;
urb->interval = ep->desc.bInterval;
urb->transfer_buffer = uvc_urb->buffer;
urb->complete = uvc_video_complete;
urb->number_of_packets = npackets;
urb->transfer_buffer_length = size;
urb->sgt = uvc_urb->sgt;
for (i = 0 ; i < npackets; ++i) {
urb->iso_frame_desc[i].offset = i * psize;
urb->iso_frame_desc[i].length = psize;
}
uvc_urb->urb = urb;
}
return 0 ;
}
/*
* Initialize bulk URBs and allocate transfer buffers . The packet size is
* given by the endpoint .
*/
static int uvc_init_video_bulk(struct uvc_streaming *stream,
struct usb_host_endpoint *ep, gfp_t gfp_flags)
{
struct urb *urb;
struct uvc_urb *uvc_urb;
unsigned int npackets, pipe;
u16 psize;
u32 size;
psize = usb_endpoint_maxp(&ep->desc);
size = stream->ctrl.dwMaxPayloadTransferSize;
stream->bulk.max_payload_size = size;
npackets = uvc_alloc_urb_buffers(stream, size, psize, gfp_flags);
if (npackets == 0 )
return -ENOMEM;
size = npackets * psize;
if (usb_endpoint_dir_in(&ep->desc))
pipe = usb_rcvbulkpipe(stream->dev->udev,
ep->desc.bEndpointAddress);
else
pipe = usb_sndbulkpipe(stream->dev->udev,
ep->desc.bEndpointAddress);
if (stream->type == V4L2_BUF_TYPE_VIDEO_OUTPUT)
size = 0 ;
for_each_uvc_urb(uvc_urb, stream) {
urb = usb_alloc_urb(0 , gfp_flags);
if (urb == NULL) {
uvc_video_stop_transfer(stream, 1 );
return -ENOMEM;
}
usb_fill_bulk_urb(urb, stream->dev->udev, pipe, uvc_urb->buffer,
size, uvc_video_complete, uvc_urb);
urb->transfer_flags = URB_NO_TRANSFER_DMA_MAP;
urb->transfer_dma = uvc_urb->dma;
urb->sgt = uvc_urb->sgt;
uvc_urb->urb = urb;
}
return 0 ;
}
/*
* Initialize isochronous / bulk URBs and allocate transfer buffers .
*/
static int uvc_video_start_transfer(struct uvc_streaming *stream,
gfp_t gfp_flags)
{
struct usb_interface *intf = stream->intf;
struct usb_host_endpoint *ep;
struct uvc_urb *uvc_urb;
unsigned int i;
int ret;
stream->sequence = -1 ;
stream->last_fid = -1 ;
stream->bulk.header_size = 0 ;
stream->bulk.skip_payload = 0 ;
stream->bulk.payload_size = 0 ;
uvc_video_stats_start(stream);
if (intf->num_altsetting > 1 ) {
struct usb_host_endpoint *best_ep = NULL;
unsigned int best_psize = UINT_MAX;
unsigned int bandwidth;
unsigned int altsetting;
int intfnum = stream->intfnum;
/* Isochronous endpoint, select the alternate setting. */
bandwidth = stream->ctrl.dwMaxPayloadTransferSize;
if (bandwidth == 0 ) {
uvc_dbg(stream->dev, VIDEO,
"Device requested null bandwidth, defaulting to lowest\n" );
bandwidth = 1 ;
} else {
uvc_dbg(stream->dev, VIDEO,
"Device requested %u B/frame bandwidth\n" ,
bandwidth);
}
for (i = 0 ; i < intf->num_altsetting; ++i) {
struct usb_host_interface *alts;
unsigned int psize;
alts = &intf->altsetting[i];
ep = uvc_find_endpoint(alts,
stream->header.bEndpointAddress);
if (ep == NULL)
continue ;
/* Check if the bandwidth is high enough. */
psize = uvc_endpoint_max_bpi(stream->dev->udev, ep);
if (psize >= bandwidth && psize < best_psize) {
altsetting = alts->desc.bAlternateSetting;
best_psize = psize;
best_ep = ep;
}
}
if (best_ep == NULL) {
uvc_dbg(stream->dev, VIDEO,
"No fast enough alt setting for requested bandwidth\n" );
return -EIO;
}
uvc_dbg(stream->dev, VIDEO,
"Selecting alternate setting %u (%u B/frame bandwidth)\n" ,
altsetting, best_psize);
/*
* Some devices , namely the Logitech C910 and B910 , are unable
* to recover from a USB autosuspend , unless the alternate
* setting of the streaming interface is toggled .
*/
if (stream->dev->quirks & UVC_QUIRK_WAKE_AUTOSUSPEND) {
usb_set_interface(stream->dev->udev, intfnum,
altsetting);
usb_set_interface(stream->dev->udev, intfnum, 0 );
}
ret = usb_set_interface(stream->dev->udev, intfnum, altsetting);
if (ret < 0 )
return ret;
ret = uvc_init_video_isoc(stream, best_ep, gfp_flags);
} else {
/* Bulk endpoint, proceed to URB initialization. */
ep = uvc_find_endpoint(&intf->altsetting[0 ],
stream->header.bEndpointAddress);
if (ep == NULL)
return -EIO;
/* Reject broken descriptors. */
if (usb_endpoint_maxp(&ep->desc) == 0 )
return -EIO;
ret = uvc_init_video_bulk(stream, ep, gfp_flags);
}
if (ret < 0 )
return ret;
/* Submit the URBs. */
for_each_uvc_urb(uvc_urb, stream) {
ret = usb_submit_urb(uvc_urb->urb, gfp_flags);
if (ret < 0 ) {
dev_err(&stream->intf->dev,
"Failed to submit URB %u (%d).\n" ,
uvc_urb_index(uvc_urb), ret);
uvc_video_stop_transfer(stream, 1 );
return ret;
}
}
/*
* The Logitech C920 temporarily forgets that it should not be adjusting
* Exposure Absolute during init so restore controls to stored values .
*/
if (stream->dev->quirks & UVC_QUIRK_RESTORE_CTRLS_ON_INIT)
uvc_ctrl_restore_values(stream->dev);
return 0 ;
}
/* --------------------------------------------------------------------------
* Suspend / resume
*/
/*
* Stop streaming without disabling the video queue .
*
* To let userspace applications resume without trouble , we must not touch the
* video buffers in any way . We mark the device as frozen to make sure the URB
* completion handler won ' t try to cancel the queue when we kill the URBs .
*/
int uvc_video_suspend(struct uvc_streaming *stream)
{
if (!uvc_queue_streaming(&stream->queue))
return 0 ;
stream->frozen = 1 ;
uvc_video_stop_transfer(stream, 0 );
usb_set_interface(stream->dev->udev, stream->intfnum, 0 );
return 0 ;
}
/*
* 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
* buffers , making sure userspace applications are notified of the problem
* instead of waiting forever .
*/
int uvc_video_resume(struct uvc_streaming *stream, int reset)
{
int ret;
/*
* If the bus has been reset on resume , set the alternate setting to 0 .
* This should be the default value , but some devices crash or otherwise
* misbehave if they don ' t receive a SET_INTERFACE request before any
* other video control request .
*/
if (reset)
usb_set_interface(stream->dev->udev, stream->intfnum, 0 );
stream->frozen = 0 ;
uvc_video_clock_reset(&stream->clock);
if (!uvc_queue_streaming(&stream->queue))
return 0 ;
ret = uvc_commit_video(stream, &stream->ctrl);
if (ret < 0 )
return ret;
return uvc_video_start_transfer(stream, GFP_NOIO);
}
/* ------------------------------------------------------------------------
* Video device
*/
/*
* 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
* violation , so try to silently fix the values if possible .
*
* This function is called before registering the device with V4L .
*/
int uvc_video_init(struct uvc_streaming *stream)
{
struct uvc_streaming_control *probe = &stream->ctrl;
const struct uvc_format *format = NULL;
const struct uvc_frame *frame = NULL;
struct uvc_urb *uvc_urb;
unsigned int i;
int ret;
if (stream->nformats == 0 ) {
dev_info(&stream->intf->dev,
"No supported video formats found.\n" );
return -EINVAL;
}
atomic_set(&stream->active, 0 );
/*
* Alternate setting 0 should be the default , yet the XBox Live Vision
* Cam ( and possibly other devices ) crash or otherwise misbehave if
* they don ' t receive a SET_INTERFACE request before any other video
* control request .
*/
usb_set_interface(stream->dev->udev, stream->intfnum, 0 );
/*
* Set the streaming probe control with default streaming parameters
* retrieved from the device . Webcams that don ' t support GET_DEF
* requests on the probe control will just keep their current streaming
* parameters .
*/
if (uvc_get_video_ctrl(stream, probe, 1 , UVC_GET_DEF) == 0 )
uvc_set_video_ctrl(stream, probe, 1 );
/*
* Initialize the streaming parameters with the probe control current
* value . This makes sure SET_CUR requests on the streaming commit
* control will always use values retrieved from a successful GET_CUR
* request on the probe control , as required by the UVC specification .
*/
ret = uvc_get_video_ctrl(stream, probe, 1 , UVC_GET_CUR);
/*
* Elgato Cam Link 4 k can be in a stalled state if the resolution of
* the external source has changed while the firmware initializes .
* Once in this state , the device is useless until it receives a
* USB reset . It has even been observed that the stalled state will
* continue even after unplugging the device .
*/
if (ret == -EPROTO &&
usb_match_one_id(stream->dev->intf, &elgato_cam_link_4k)) {
dev_err(&stream->intf->dev, "Elgato Cam Link 4K firmware crash detected\n" );
dev_err(&stream->intf->dev, "Resetting the device, unplug and replug to recover\n" );
usb_reset_device(stream->dev->udev);
}
if (ret < 0 )
return ret;
/*
* Check if the default format descriptor exists . Use the first
* available format otherwise .
*/
for (i = stream->nformats; i > 0 ; --i) {
format = &stream->formats[i-1 ];
if (format->index == probe->bFormatIndex)
break ;
}
if (format->nframes == 0 ) {
dev_info(&stream->intf->dev,
"No frame descriptor found for the default format.\n" );
return -EINVAL;
}
/*
* Zero bFrameIndex might be correct . Stream - based formats ( including
* MPEG - 2 TS and DV ) do not support frames but have a dummy frame
* descriptor with bFrameIndex set to zero . If the default frame
* descriptor is not found , use the first available frame .
*/
for (i = format->nframes; i > 0 ; --i) {
frame = &format->frames[i-1 ];
if (frame->bFrameIndex == probe->bFrameIndex)
break ;
}
probe->bFormatIndex = format->index;
probe->bFrameIndex = frame->bFrameIndex;
stream->def_format = format;
stream->cur_format = format;
stream->cur_frame = frame;
/* Select the video decoding function */
if (stream->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
if (stream->dev->quirks & UVC_QUIRK_BUILTIN_ISIGHT)
stream->decode = uvc_video_decode_isight;
else if (stream->intf->num_altsetting > 1 )
stream->decode = uvc_video_decode_isoc;
else
stream->decode = uvc_video_decode_bulk;
} else {
if (stream->intf->num_altsetting == 1 )
stream->decode = uvc_video_encode_bulk;
else {
dev_info(&stream->intf->dev,
"Isochronous endpoints are not supported for video output devices.\n" );
return -EINVAL;
}
}
/* Prepare asynchronous work items. */
for_each_uvc_urb(uvc_urb, stream)
INIT_WORK(&uvc_urb->work, uvc_video_copy_data_work);
return 0 ;
}
int uvc_video_start_streaming(struct uvc_streaming *stream)
{
int ret;
ret = uvc_video_clock_init(&stream->clock);
if (ret < 0 )
return ret;
/* Commit the streaming parameters. */
ret = uvc_commit_video(stream, &stream->ctrl);
if (ret < 0 )
goto error_commit;
ret = uvc_video_start_transfer(stream, GFP_KERNEL);
if (ret < 0 )
goto error_video;
return 0 ;
error_video:
usb_set_interface(stream->dev->udev, stream->intfnum, 0 );
error_commit:
uvc_video_clock_cleanup(&stream->clock);
return ret;
}
void uvc_video_stop_streaming(struct uvc_streaming *stream)
{
uvc_video_stop_transfer(stream, 1 );
if (stream->intf->num_altsetting > 1 ) {
usb_set_interface(stream->dev->udev, stream->intfnum, 0 );
} else {
/*
* UVC doesn ' t specify how to inform a bulk - based device
* when the video stream is stopped . Windows sends a
* CLEAR_FEATURE ( HALT ) request to the video streaming
* bulk endpoint , mimic the same behaviour .
*/
unsigned int epnum = stream->header.bEndpointAddress
& USB_ENDPOINT_NUMBER_MASK;
unsigned int dir = stream->header.bEndpointAddress
& USB_ENDPOINT_DIR_MASK;
unsigned int pipe;
pipe = usb_sndbulkpipe(stream->dev->udev, epnum) | dir;
usb_clear_halt(stream->dev->udev, pipe);
}
uvc_video_clock_cleanup(&stream->clock);
}
Messung V0.5 in Prozent C=95 H=92 G=93
¤ Dauer der Verarbeitung: 0.114 Sekunden
(vorverarbeitet am 2026-09-27)
¤
*© Formatika GbR, Deutschland