usb: gadget: uvc: support streaming bulk transfer

This patch adds bulk endpoint for uvc to be used as
video streaming transfer. By default, the uvc gadget
still uses isoc endpoint for video streaming.

The important difference between the bulk and isoc
method is that, alt-settings in a video streaming
interface are supported only for isoc endpoints as
there are different alt-settings for zero-bandwidth
and full-bandwidth use-cases, but the same is not
true for bulk endpoints, as they support only a single
alt-setting.

How to use:
1. Enable the bulk transfer:
   echo 1 >  /config/usb-gadget/g1/functions/uvc.name/streaming_bulk

2. Disable the bulk transfer:
   echo 0 >  /config/usb-gadget/g1/functions/uvc.name/streaming_bulk

3. Testing the uvc bulk function transfer:
   device: run the uvc-gadget program
   # uvc-gadget -b -u /dev/video<uvc video node #> -v /dev/video<vivid video node #>

   where uvc-gadget is this program:
        http://git.ideasonboard.org/uvc-gadget.git

   with these patches:

        http://www.spinics.net/lists/linux-usb/msg99220.html

Change-Id: Ifedfe3f5c4354dd2bdf07382290107e9bcc89f59
Signed-off-by: William Wu <william.wu@rock-chips.com>
Signed-off-by: Frank Wang <frank.wang@rock-chips.com>
This commit is contained in:
William Wu
2019-06-10 19:12:55 +08:00
committed by Tao Huang
parent 60767d93e5
commit c15a7cecb8
5 changed files with 312 additions and 77 deletions

View File

@@ -124,6 +124,18 @@ static struct usb_interface_descriptor uvc_streaming_intf_alt0 = {
.iInterface = 0,
};
static struct usb_interface_descriptor uvc_bulk_streaming_intf_alt0 = {
.bLength = USB_DT_INTERFACE_SIZE,
.bDescriptorType = USB_DT_INTERFACE,
.bInterfaceNumber = UVC_INTF_VIDEO_STREAMING,
.bAlternateSetting = 0,
.bNumEndpoints = 1,
.bInterfaceClass = USB_CLASS_VIDEO,
.bInterfaceSubClass = UVC_SC_VIDEOSTREAMING,
.bInterfaceProtocol = 0x00,
.iInterface = 0,
};
static struct usb_interface_descriptor uvc_streaming_intf_alt1 = {
.bLength = USB_DT_INTERFACE_SIZE,
.bDescriptorType = USB_DT_INTERFACE,
@@ -147,6 +159,16 @@ static struct usb_endpoint_descriptor uvc_fs_streaming_ep = {
*/
};
static struct usb_endpoint_descriptor uvc_fs_bulk_streaming_ep = {
.bLength = USB_DT_ENDPOINT_SIZE,
.bDescriptorType = USB_DT_ENDPOINT,
.bEndpointAddress = USB_DIR_IN,
.bmAttributes = USB_ENDPOINT_XFER_BULK,
/* The wMaxPacketSize and bInterval values will be initialized from
* module parameters.
*/
};
static struct usb_endpoint_descriptor uvc_hs_streaming_ep = {
.bLength = USB_DT_ENDPOINT_SIZE,
.bDescriptorType = USB_DT_ENDPOINT,
@@ -158,6 +180,16 @@ static struct usb_endpoint_descriptor uvc_hs_streaming_ep = {
*/
};
static struct usb_endpoint_descriptor uvc_hs_bulk_streaming_ep = {
.bLength = USB_DT_ENDPOINT_SIZE,
.bDescriptorType = USB_DT_ENDPOINT,
.bEndpointAddress = USB_DIR_IN,
.bmAttributes = USB_ENDPOINT_XFER_BULK,
/* The wMaxPacketSize and bInterval values will be initialized from
* module parameters.
*/
};
static struct usb_endpoint_descriptor uvc_ss_streaming_ep = {
.bLength = USB_DT_ENDPOINT_SIZE,
.bDescriptorType = USB_DT_ENDPOINT,
@@ -170,6 +202,17 @@ static struct usb_endpoint_descriptor uvc_ss_streaming_ep = {
*/
};
static struct usb_endpoint_descriptor uvc_ss_bulk_streaming_ep = {
.bLength = USB_DT_ENDPOINT_SIZE,
.bDescriptorType = USB_DT_ENDPOINT,
.bEndpointAddress = USB_DIR_IN,
.bmAttributes = USB_ENDPOINT_XFER_BULK,
/* The wMaxPacketSize and bInterval values will be initialized from
* module parameters.
*/
};
static struct usb_ss_ep_comp_descriptor uvc_ss_streaming_comp = {
.bLength = sizeof(uvc_ss_streaming_comp),
.bDescriptorType = USB_DT_SS_ENDPOINT_COMP,
@@ -178,18 +221,36 @@ static struct usb_ss_ep_comp_descriptor uvc_ss_streaming_comp = {
*/
};
static struct usb_ss_ep_comp_descriptor uvc_ss_bulk_streaming_comp = {
.bLength = sizeof(uvc_ss_bulk_streaming_comp),
.bDescriptorType = USB_DT_SS_ENDPOINT_COMP,
/* The bMaxBurst, bmAttributes and wBytesPerInterval values will be
* initialized from module parameters.
*/
};
static const struct usb_descriptor_header * const uvc_fs_streaming[] = {
(struct usb_descriptor_header *) &uvc_streaming_intf_alt1,
(struct usb_descriptor_header *) &uvc_fs_streaming_ep,
NULL,
};
static const struct usb_descriptor_header * const uvc_fs_bulk_streaming[] = {
(struct usb_descriptor_header *)&uvc_fs_bulk_streaming_ep,
NULL,
};
static const struct usb_descriptor_header * const uvc_hs_streaming[] = {
(struct usb_descriptor_header *) &uvc_streaming_intf_alt1,
(struct usb_descriptor_header *) &uvc_hs_streaming_ep,
NULL,
};
static const struct usb_descriptor_header * const uvc_hs_bulk_streaming[] = {
(struct usb_descriptor_header *)&uvc_hs_bulk_streaming_ep,
NULL,
};
static const struct usb_descriptor_header * const uvc_ss_streaming[] = {
(struct usb_descriptor_header *) &uvc_streaming_intf_alt1,
(struct usb_descriptor_header *) &uvc_ss_streaming_ep,
@@ -197,6 +258,12 @@ static const struct usb_descriptor_header * const uvc_ss_streaming[] = {
NULL,
};
static const struct usb_descriptor_header * const uvc_ss_bulk_streaming[] = {
(struct usb_descriptor_header *)&uvc_ss_bulk_streaming_ep,
(struct usb_descriptor_header *)&uvc_ss_bulk_streaming_comp,
NULL,
};
/* --------------------------------------------------------------------------
* Control requests
*/
@@ -260,15 +327,27 @@ static int
uvc_function_get_alt(struct usb_function *f, unsigned interface)
{
struct uvc_device *uvc = to_uvc(f);
struct f_uvc_opts *opts;
uvcg_info(f, "%s(%u)\n", __func__, interface);
opts = fi_to_f_uvc_opts(f->fi);
if (interface == uvc->control_intf)
return 0;
else if (interface != uvc->streaming_intf)
return -EINVAL;
else
else if (!opts->streaming_bulk)
return uvc->video.ep->enabled ? 1 : 0;
else
/*
* Alt settings in an interface are supported only for
* ISOC endpoints as there are different alt-settings for
* zero-bandwidth and full-bandwidth cases, but the same
* is not true for BULK endpoints, as they have a single
* alt-setting.
*/
return 0;
}
static int
@@ -278,10 +357,13 @@ uvc_function_set_alt(struct usb_function *f, unsigned interface, unsigned alt)
struct usb_composite_dev *cdev = f->config->cdev;
struct v4l2_event v4l2_event;
struct uvc_event *uvc_event = (void *)&v4l2_event.u.data;
struct f_uvc_opts *opts;
int ret;
uvcg_info(f, "%s(%u, %u)\n", __func__, interface, alt);
opts = fi_to_f_uvc_opts(f->fi);
if (interface == uvc->control_intf) {
if (alt)
return -EINVAL;
@@ -310,49 +392,94 @@ uvc_function_set_alt(struct usb_function *f, unsigned interface, unsigned alt)
if (interface != uvc->streaming_intf)
return -EINVAL;
/* TODO
if (usb_endpoint_xfer_bulk(&uvc->desc.vs_ep))
return alt ? -EINVAL : 0;
*/
if (!opts->streaming_bulk) {
switch (alt) {
case 0:
if (uvc->state != UVC_STATE_STREAMING)
return 0;
switch (alt) {
case 0:
if (uvc->state != UVC_STATE_STREAMING)
if (uvc->video.ep)
usb_ep_disable(uvc->video.ep);
memset(&v4l2_event, 0, sizeof(v4l2_event));
v4l2_event.type = UVC_EVENT_STREAMOFF;
v4l2_event_queue(&uvc->vdev, &v4l2_event);
uvc->state = UVC_STATE_CONNECTED;
return 0;
if (uvc->video.ep)
case 1:
if (uvc->state != UVC_STATE_CONNECTED)
return 0;
if (!uvc->video.ep)
return -EINVAL;
INFO(cdev, "reset UVC\n");
usb_ep_disable(uvc->video.ep);
memset(&v4l2_event, 0, sizeof(v4l2_event));
v4l2_event.type = UVC_EVENT_STREAMOFF;
v4l2_event_queue(&uvc->vdev, &v4l2_event);
ret = config_ep_by_speed(f->config->cdev->gadget,
&uvc->func, uvc->video.ep);
if (ret)
return ret;
usb_ep_enable(uvc->video.ep);
uvc->state = UVC_STATE_CONNECTED;
return 0;
memset(&v4l2_event, 0, sizeof(v4l2_event));
v4l2_event.type = UVC_EVENT_STREAMON;
v4l2_event_queue(&uvc->vdev, &v4l2_event);
return USB_GADGET_DELAYED_STATUS;
case 1:
if (uvc->state != UVC_STATE_CONNECTED)
default:
return -EINVAL;
}
} else {
switch (uvc->state) {
case UVC_STATE_CONNECTED:
if (uvc->video.ep &&
!uvc->video.ep->enabled) {
/*
* Enable the video streaming endpoint,
* but don't change the 'uvc->state'.
*/
ret = config_ep_by_speed(cdev->gadget,
&uvc->func,
uvc->video.ep);
if (ret)
return ret;
ret = usb_ep_enable(uvc->video.ep);
if (ret)
return ret;
} else {
memset(&v4l2_event, 0, sizeof(v4l2_event));
v4l2_event.type = UVC_EVENT_STREAMON;
v4l2_event_queue(&uvc->vdev, &v4l2_event);
uvc->state = UVC_STATE_STREAMING;
}
return 0;
if (!uvc->video.ep)
case UVC_STATE_STREAMING:
if (!alt) {
INFO(cdev, "bulk streaming intf not support alt 0\n");
return 0;
}
if (uvc->video.ep &&
uvc->video.ep->enabled) {
ret = usb_ep_disable(uvc->video.ep);
if (ret)
return ret;
}
memset(&v4l2_event, 0, sizeof(v4l2_event));
v4l2_event.type = UVC_EVENT_STREAMOFF;
v4l2_event_queue(&uvc->vdev, &v4l2_event);
uvc->state = UVC_STATE_CONNECTED;
return 0;
default:
return -EINVAL;
uvcg_info(f, "reset UVC\n");
usb_ep_disable(uvc->video.ep);
ret = config_ep_by_speed(f->config->cdev->gadget,
&(uvc->func), uvc->video.ep);
if (ret)
return ret;
usb_ep_enable(uvc->video.ep);
memset(&v4l2_event, 0, sizeof(v4l2_event));
v4l2_event.type = UVC_EVENT_STREAMON;
v4l2_event_queue(&uvc->vdev, &v4l2_event);
return USB_GADGET_DELAYED_STATUS;
default:
return -EINVAL;
}
}
}
@@ -467,32 +594,45 @@ uvc_copy_descriptors(struct uvc_device *uvc, enum usb_device_speed speed)
const struct uvc_descriptor_header * const *uvc_streaming_cls;
const struct usb_descriptor_header * const *uvc_streaming_std;
const struct usb_descriptor_header * const *src;
struct usb_interface_descriptor *streaming_intf_alt0;
struct usb_descriptor_header **dst;
struct usb_descriptor_header **hdr;
struct f_uvc_opts *opts;
unsigned int control_size;
unsigned int streaming_size;
unsigned int n_desc;
unsigned int bytes;
void *mem;
opts = fi_to_f_uvc_opts(uvc->func.fi);
switch (speed) {
case USB_SPEED_SUPER:
uvc_control_desc = uvc->desc.ss_control;
uvc_streaming_cls = uvc->desc.ss_streaming;
uvc_streaming_std = uvc_ss_streaming;
if (!opts->streaming_bulk)
uvc_streaming_std = uvc_ss_streaming;
else
uvc_streaming_std = uvc_ss_bulk_streaming;
break;
case USB_SPEED_HIGH:
uvc_control_desc = uvc->desc.fs_control;
uvc_streaming_cls = uvc->desc.hs_streaming;
uvc_streaming_std = uvc_hs_streaming;
if (!opts->streaming_bulk)
uvc_streaming_std = uvc_hs_streaming;
else
uvc_streaming_std = uvc_hs_bulk_streaming;
break;
case USB_SPEED_FULL:
default:
uvc_control_desc = uvc->desc.fs_control;
uvc_streaming_cls = uvc->desc.fs_streaming;
uvc_streaming_std = uvc_fs_streaming;
if (!opts->streaming_bulk)
uvc_streaming_std = uvc_fs_streaming;
else
uvc_streaming_std = uvc_fs_bulk_streaming;
break;
}
@@ -512,12 +652,17 @@ uvc_copy_descriptors(struct uvc_device *uvc, enum usb_device_speed speed)
* uvc_{fs|hs}_streaming
*/
if (!opts->streaming_bulk)
streaming_intf_alt0 = &uvc_streaming_intf_alt0;
else
streaming_intf_alt0 = &uvc_bulk_streaming_intf_alt0;
/* Count descriptors and compute their size. */
control_size = 0;
streaming_size = 0;
bytes = uvc_iad.bLength + uvc_control_intf.bLength
+ uvc_control_ep.bLength + uvc_control_cs_ep.bLength
+ uvc_streaming_intf_alt0.bLength;
+ streaming_intf_alt0->bLength;
if (speed == USB_SPEED_SUPER) {
bytes += uvc_ss_control_comp.bLength;
@@ -567,7 +712,7 @@ uvc_copy_descriptors(struct uvc_device *uvc, enum usb_device_speed speed)
UVC_COPY_DESCRIPTOR(mem, dst, &uvc_ss_control_comp);
UVC_COPY_DESCRIPTOR(mem, dst, &uvc_control_cs_ep);
UVC_COPY_DESCRIPTOR(mem, dst, &uvc_streaming_intf_alt0);
UVC_COPY_DESCRIPTOR(mem, dst, streaming_intf_alt0);
uvc_streaming_header = mem;
UVC_COPY_DESCRIPTORS(mem, dst,
@@ -592,15 +737,24 @@ uvc_function_bind(struct usb_configuration *c, struct usb_function *f)
struct usb_ep *ep;
struct f_uvc_opts *opts;
int ret = -EINVAL;
u8 address;
uvcg_info(f, "%s()\n", __func__);
opts = fi_to_f_uvc_opts(f->fi);
/* Sanity check the streaming endpoint module parameters.
*/
opts->streaming_interval = clamp(opts->streaming_interval, 1U, 16U);
opts->streaming_maxpacket = clamp(opts->streaming_maxpacket, 1U, 3072U);
opts->streaming_maxburst = min(opts->streaming_maxburst, 15U);
if (!opts->streaming_bulk) {
opts->streaming_interval = clamp(opts->streaming_interval,
1U, 16U);
opts->streaming_maxpacket = clamp(opts->streaming_maxpacket,
1U, 3072U);
opts->streaming_maxburst = min(opts->streaming_maxburst, 15U);
} else {
opts->streaming_maxpacket = clamp(opts->streaming_maxpacket,
1U, 1024U);
opts->streaming_maxburst = min(opts->streaming_maxburst, 15U);
}
/* For SS, wMaxPacketSize has to be 1024 if bMaxBurst is not 0 */
if (opts->streaming_maxburst &&
@@ -627,21 +781,37 @@ uvc_function_bind(struct usb_configuration *c, struct usb_function *f)
max_packet_size = opts->streaming_maxpacket / 3;
}
uvc_fs_streaming_ep.wMaxPacketSize =
cpu_to_le16(min(opts->streaming_maxpacket, 1023U));
uvc_fs_streaming_ep.bInterval = opts->streaming_interval;
if (!opts->streaming_bulk) {
uvc_fs_streaming_ep.wMaxPacketSize =
cpu_to_le16(min(opts->streaming_maxpacket, 1023U));
uvc_fs_streaming_ep.bInterval = opts->streaming_interval;
uvc_hs_streaming_ep.wMaxPacketSize =
cpu_to_le16(max_packet_size | ((max_packet_mult - 1) << 11));
uvc_hs_streaming_ep.bInterval = opts->streaming_interval;
uvc_hs_streaming_ep.wMaxPacketSize =
cpu_to_le16(max_packet_size |
((max_packet_mult - 1) << 11));
uvc_hs_streaming_ep.bInterval = opts->streaming_interval;
uvc_ss_streaming_ep.wMaxPacketSize = cpu_to_le16(max_packet_size);
uvc_ss_streaming_ep.bInterval = opts->streaming_interval;
uvc_ss_streaming_comp.bmAttributes = max_packet_mult - 1;
uvc_ss_streaming_comp.bMaxBurst = opts->streaming_maxburst;
uvc_ss_streaming_comp.wBytesPerInterval =
cpu_to_le16(max_packet_size * max_packet_mult *
(opts->streaming_maxburst + 1));
uvc_ss_streaming_ep.wMaxPacketSize =
cpu_to_le16(max_packet_size);
uvc_ss_streaming_ep.bInterval = opts->streaming_interval;
uvc_ss_streaming_comp.bmAttributes = max_packet_mult - 1;
uvc_ss_streaming_comp.bMaxBurst = opts->streaming_maxburst;
uvc_ss_streaming_comp.wBytesPerInterval =
cpu_to_le16(max_packet_size * max_packet_mult *
(opts->streaming_maxburst + 1));
} else {
uvc_fs_bulk_streaming_ep.wMaxPacketSize =
cpu_to_le16(min(opts->streaming_maxpacket, 64U));
uvc_hs_bulk_streaming_ep.wMaxPacketSize =
cpu_to_le16(min(opts->streaming_maxpacket, 512U));
uvc_ss_bulk_streaming_ep.wMaxPacketSize =
cpu_to_le16(max_packet_size);
uvc_ss_streaming_comp.bMaxBurst = opts->streaming_maxburst;
uvc_ss_streaming_comp.wBytesPerInterval =
cpu_to_le16(max_packet_size * opts->streaming_maxburst);
}
/* Allocate endpoints. */
ep = usb_ep_autoconfig(cdev->gadget, &uvc_control_ep);
@@ -651,23 +821,57 @@ uvc_function_bind(struct usb_configuration *c, struct usb_function *f)
}
uvc->control_ep = ep;
if (gadget_is_superspeed(c->cdev->gadget))
ep = usb_ep_autoconfig_ss(cdev->gadget, &uvc_ss_streaming_ep,
&uvc_ss_streaming_comp);
else if (gadget_is_dualspeed(cdev->gadget))
ep = usb_ep_autoconfig(cdev->gadget, &uvc_hs_streaming_ep);
else
ep = usb_ep_autoconfig(cdev->gadget, &uvc_fs_streaming_ep);
if (gadget_is_superspeed(c->cdev->gadget)) {
if (!opts->streaming_bulk)
ep = usb_ep_autoconfig_ss(cdev->gadget,
&uvc_ss_streaming_ep,
&uvc_ss_streaming_comp);
else
ep = usb_ep_autoconfig_ss(cdev->gadget,
&uvc_ss_bulk_streaming_ep,
&uvc_ss_bulk_streaming_comp);
} else if (gadget_is_dualspeed(cdev->gadget)) {
if (!opts->streaming_bulk) {
ep = usb_ep_autoconfig(cdev->gadget,
&uvc_hs_streaming_ep);
} else {
ep = usb_ep_autoconfig(cdev->gadget,
&uvc_hs_bulk_streaming_ep);
/*
* In ep_matches(), it will set wMaxPacketSize to 64
* bytes if ep is Bulk and ep_comp is NULL for hs/fs
* bulk maxpacket. So we need to set hs bulk maxpacket
* 512 bytes again here.
*/
uvc_hs_bulk_streaming_ep.wMaxPacketSize =
cpu_to_le16(min(opts->streaming_maxpacket,
512U));
}
} else {
if (!opts->streaming_bulk)
ep = usb_ep_autoconfig(cdev->gadget,
&uvc_fs_streaming_ep);
else
ep = usb_ep_autoconfig(cdev->gadget,
&uvc_fs_bulk_streaming_ep);
}
if (!ep) {
uvcg_info(f, "Unable to allocate streaming EP\n");
goto error;
}
uvc->video.ep = ep;
address = uvc->video.ep->address;
uvc_fs_streaming_ep.bEndpointAddress = uvc->video.ep->address;
uvc_hs_streaming_ep.bEndpointAddress = uvc->video.ep->address;
uvc_ss_streaming_ep.bEndpointAddress = uvc->video.ep->address;
if (!opts->streaming_bulk) {
uvc_fs_streaming_ep.bEndpointAddress = address;
uvc_hs_streaming_ep.bEndpointAddress = address;
uvc_ss_streaming_ep.bEndpointAddress = address;
} else {
uvc_fs_bulk_streaming_ep.bEndpointAddress = address;
uvc_hs_bulk_streaming_ep.bEndpointAddress = address;
uvc_ss_bulk_streaming_ep.bEndpointAddress = address;
}
us = usb_gstrings_attach(cdev, uvc_function_strings,
ARRAY_SIZE(uvc_en_us_strings));
@@ -678,8 +882,12 @@ uvc_function_bind(struct usb_configuration *c, struct usb_function *f)
uvc_iad.iFunction = us[UVC_STRING_CONTROL_IDX].id;
uvc_control_intf.iInterface = us[UVC_STRING_CONTROL_IDX].id;
ret = us[UVC_STRING_STREAMING_IDX].id;
uvc_streaming_intf_alt0.iInterface = ret;
uvc_streaming_intf_alt1.iInterface = ret;
if (!opts->streaming_bulk) {
uvc_streaming_intf_alt0.iInterface = ret;
uvc_streaming_intf_alt1.iInterface = ret;
} else {
uvc_bulk_streaming_intf_alt0.iInterface = ret;
}
/* Allocate interface IDs. */
if ((ret = usb_interface_id(c, f)) < 0)
@@ -691,8 +899,14 @@ uvc_function_bind(struct usb_configuration *c, struct usb_function *f)
if ((ret = usb_interface_id(c, f)) < 0)
goto error;
uvc_streaming_intf_alt0.bInterfaceNumber = ret;
uvc_streaming_intf_alt1.bInterfaceNumber = ret;
if (!opts->streaming_bulk) {
uvc_streaming_intf_alt0.bInterfaceNumber = ret;
uvc_streaming_intf_alt1.bInterfaceNumber = ret;
} else {
uvc_bulk_streaming_intf_alt0.bInterfaceNumber = ret;
}
uvc->streaming_intf = ret;
opts->streaming_interface = ret;
@@ -742,6 +956,8 @@ uvc_function_bind(struct usb_configuration *c, struct usb_function *f)
if (ret < 0)
goto v4l2_error;
if (opts->streaming_bulk)
uvc->video.max_payload_size = uvc->video.imagesize;
/* Register a V4L2 device. */
ret = uvc_register_video(uvc);
if (ret < 0) {

View File

@@ -22,6 +22,7 @@ DECLARE_UVC_EXTENSION_UNIT_DESCRIPTOR(1, 1);
struct f_uvc_opts {
struct usb_function_instance func_inst;
bool streaming_bulk;
unsigned int streaming_interval;
unsigned int streaming_maxpacket;
unsigned int streaming_maxburst;

View File

@@ -2424,6 +2424,7 @@ end: \
\
UVC_ATTR(f_uvc_opts_, cname, cname)
UVCG_OPTS_ATTR(streaming_bulk, streaming_bulk, 1);
UVCG_OPTS_ATTR(streaming_interval, streaming_interval, 16);
UVCG_OPTS_ATTR(streaming_maxpacket, streaming_maxpacket, 3072);
UVCG_OPTS_ATTR(streaming_maxburst, streaming_maxburst, 15);
@@ -2431,6 +2432,7 @@ UVCG_OPTS_ATTR(streaming_maxburst, streaming_maxburst, 15);
#undef UVCG_OPTS_ATTR
static struct configfs_attribute *uvc_attrs[] = {
&f_uvc_opts_attr_streaming_bulk,
&f_uvc_opts_attr_streaming_interval,
&f_uvc_opts_attr_streaming_maxpacket,
&f_uvc_opts_attr_streaming_maxburst,

View File

@@ -201,11 +201,21 @@ uvc_v4l2_streamon(struct file *file, void *fh, enum v4l2_buf_type type)
return ret;
/*
* Complete the alternate setting selection setup phase now that
* userspace is ready to provide video frames.
* Alt settings in an interface are supported only
* for ISOC endpoints as there are different alt-
* settings for zero-bandwidth and full-bandwidth
* cases, but the same is not true for BULK endpoints,
* as they have a single alt-setting.
*/
uvc_function_setup_continue(uvc);
uvc->state = UVC_STATE_STREAMING;
if (!usb_endpoint_xfer_bulk(video->ep->desc)) {
/*
* Complete the alternate setting selection
* setup phase now that userspace is ready
* to provide video frames.
*/
uvc_function_setup_continue(uvc);
uvc->state = UVC_STATE_STREAMING;
}
return 0;
}

View File

@@ -87,6 +87,7 @@ uvc_video_encode_bulk(struct usb_request *req, struct uvc_video *video,
video->fid ^= UVC_STREAM_FID;
video->payload_size = 0;
req->zero = 1;
}
if (video->payload_size == video->max_payload_size ||
@@ -135,7 +136,7 @@ static int uvcg_video_ep_queue(struct uvc_video *video, struct usb_request *req)
ret);
/* Isochronous endpoints can't be halted. */
if (usb_endpoint_xfer_bulk(video->ep->desc))
if (video->ep->desc && usb_endpoint_xfer_bulk(video->ep->desc))
usb_ep_set_halt(video->ep);
}
@@ -203,9 +204,14 @@ uvc_video_alloc_requests(struct uvc_video *video)
BUG_ON(video->req_size);
req_size = video->ep->maxpacket
* max_t(unsigned int, video->ep->maxburst, 1)
* (video->ep->mult);
if (!usb_endpoint_xfer_bulk(video->ep->desc)) {
req_size = video->ep->maxpacket
* max_t(unsigned int, video->ep->maxburst, 1)
* (video->ep->mult);
} else {
req_size = video->ep->maxpacket
* max_t(unsigned int, video->ep->maxburst, 1);
}
for (i = 0; i < UVC_NUM_REQUESTS; ++i) {
video->req_buffer[i] = kmalloc(req_size, GFP_KERNEL);