Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 1e0b3aa1 authored by qctecmdr's avatar qctecmdr Committed by Gerrit - the friendly Code Review server
Browse files

Merge "media:uvc: supports dynamic setting of urb configuration"

parents 8510870e 0441dc48
Loading
Loading
Loading
Loading
+71 −0
Original line number Diff line number Diff line
@@ -2093,6 +2093,71 @@ struct uvc_device_info {
	u32	meta_format;
};

/* ------------------------------------------------------------------------
 * set urb queue size and urb packet size
 *
 */
static ssize_t store_urb_config(struct device *dev,
		struct device_attribute *attr, const char *buff, size_t count)
{
	struct uvc_streaming *stream;
	struct usb_interface *intf = to_usb_interface(dev);
	struct uvc_device *udev = usb_get_intfdata(intf);
	long max_urb, max_urb_packets;
	int ret;
	char *arr, *tmp;

	arr = kstrdup(buff, GFP_KERNEL);

	if (!arr)
		return -ENOMEM;

	tmp = strsep(&arr, ":");

	if (!tmp)
		return -EINVAL;

	ret = kstrtol(tmp, 10, &max_urb);
		if (ret < 0)
			return ret;

	tmp = strsep(&arr, ":");
	if (!tmp)
		return -EINVAL;

	ret = kstrtol(tmp, 10, &max_urb_packets);
		if (ret < 0)
			return ret;

	if (max_urb <= 0 || max_urb > 128 ||
		max_urb_packets <= 0 || max_urb_packets > 128)
		return -EINVAL;

	list_for_each_entry(stream, &udev->streams, list) {
		if (stream->refcnt)
			continue;
		stream->max_urb = max_urb;
		stream->max_urb_packets = max_urb_packets;
	}

	return count;
}

static ssize_t show_urb_config(struct device *dev,
		struct device_attribute *attr, char *buff)
{
	return 0;
}

static struct device_attribute urb_config_attr = {
	.attr = {
		.name = "urb_config",
		.mode = 00660,
	},
	.show = show_urb_config,
	.store = store_urb_config,
};

static int uvc_probe(struct usb_interface *intf,
		     const struct usb_device_id *id)
{
@@ -2225,6 +2290,12 @@ static int uvc_probe(struct usb_interface *intf,

	uvc_trace(UVC_TRACE_PROBE, "UVC device initialized.\n");
	usb_enable_autosuspend(udev);

	/* sysfs file for dynamically setting urb configs */
	ret = sysfs_create_file(&dev->intf->dev.kobj, &urb_config_attr.attr);
	if (ret != 0)
		pr_info("Unable to initialize urb configuration: %d\n", ret);

	return 0;

error:
+28 −12
Original line number Diff line number Diff line
@@ -1515,7 +1515,7 @@ static void uvc_free_urb_buffers(struct uvc_streaming *stream)
{
	unsigned int i;

	for (i = 0; i < UVC_URBS; ++i) {
	for (i = 0; i < stream->max_urb; ++i) {
		if (stream->urb_buffer[i]) {
#ifndef CONFIG_DMA_NONCOHERENT
			usb_free_coherent(stream->dev->udev, stream->urb_size,
@@ -1555,12 +1555,22 @@ static int uvc_alloc_urb_buffers(struct uvc_streaming *stream,
	 * payloads across multiple URBs.
	 */
	npackets = DIV_ROUND_UP(size, psize);
	if (npackets > UVC_MAX_PACKETS)
		npackets = UVC_MAX_PACKETS;
	if (npackets > stream->max_urb_packets)
		npackets = stream->max_urb_packets;


	/* Allocate memory for storing URB pointers */
	stream->urb = kcalloc(stream->max_urb,
			sizeof(struct urb *), gfp_flags | __GFP_NOWARN);
	stream->urb_buffer = kcalloc(stream->max_urb,
			sizeof(char *), gfp_flags | __GFP_NOWARN);
	stream->urb_dma = kcalloc(stream->max_urb,
			sizeof(dma_addr_t), gfp_flags | __GFP_NOWARN);


	/* Retry allocations until one succeed. */
	for (; npackets > 1; npackets /= 2) {
		for (i = 0; i < UVC_URBS; ++i) {
		for (i = 0; i < stream->max_urb; ++i) {
			stream->urb_size = psize * npackets;
#ifndef CONFIG_DMA_NONCOHERENT
			stream->urb_buffer[i] = usb_alloc_coherent(
@@ -1576,10 +1586,10 @@ static int uvc_alloc_urb_buffers(struct uvc_streaming *stream,
			}
		}

		if (i == UVC_URBS) {
			uvc_trace(UVC_TRACE_VIDEO, "Allocated %u URB buffers "
				"of %ux%u bytes each.\n", UVC_URBS, npackets,
				psize);
		if (i == stream->max_urb) {
			uvc_trace(UVC_TRACE_VIDEO,
				"Allocated %u URB buffers of %ux%u bytes each.\n",
				stream->max_urb, npackets, psize);
			return npackets;
		}
	}
@@ -1599,7 +1609,7 @@ static void uvc_uninit_video(struct uvc_streaming *stream, int free_buffers)

	uvc_video_stats_stop(stream);

	for (i = 0; i < UVC_URBS; ++i) {
	for (i = 0; i < stream->max_urb; ++i) {
		urb = stream->urb[i];
		if (urb == NULL)
			continue;
@@ -1611,6 +1621,8 @@ static void uvc_uninit_video(struct uvc_streaming *stream, int free_buffers)

	if (free_buffers)
		uvc_free_urb_buffers(stream);

	stream->refcnt--;
}

/*
@@ -1660,7 +1672,7 @@ static int uvc_init_video_isoc(struct uvc_streaming *stream,

	size = npackets * psize;

	for (i = 0; i < UVC_URBS; ++i) {
	for (i = 0; i < stream->max_urb; ++i) {
		urb = usb_alloc_urb(npackets, gfp_flags);
		if (urb == NULL) {
			uvc_uninit_video(stream, 1);
@@ -1726,7 +1738,7 @@ static int uvc_init_video_bulk(struct uvc_streaming *stream,
	if (stream->type == V4L2_BUF_TYPE_VIDEO_OUTPUT)
		size = 0;

	for (i = 0; i < UVC_URBS; ++i) {
	for (i = 0; i < stream->max_urb; ++i) {
		urb = usb_alloc_urb(0, gfp_flags);
		if (urb == NULL) {
			uvc_uninit_video(stream, 1);
@@ -1831,7 +1843,8 @@ static int uvc_init_video(struct uvc_streaming *stream, gfp_t gfp_flags)
		return ret;

	/* Submit the URBs. */
	for (i = 0; i < UVC_URBS; ++i) {
	stream->refcnt++;
	for (i = 0; i < stream->max_urb; ++i) {
		ret = usb_submit_urb(stream->urb[i], gfp_flags);
		if (ret < 0) {
			uvc_printk(KERN_ERR, "Failed to submit URB %u "
@@ -1992,6 +2005,9 @@ int uvc_video_init(struct uvc_streaming *stream)
	stream->cur_format = format;
	stream->cur_frame = frame;

	stream->max_urb = UVC_URBS;
	stream->max_urb_packets = UVC_MAX_PACKETS;

	/* Select the video decoding function */
	if (stream->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
		if (stream->dev->quirks & UVC_QUIRK_BUILTIN_ISIGHT)
+12 −3
Original line number Diff line number Diff line
@@ -535,9 +535,9 @@ struct uvc_streaming {
		u32 max_payload_size;
	} bulk;

	struct urb *urb[UVC_URBS];
	char *urb_buffer[UVC_URBS];
	dma_addr_t urb_dma[UVC_URBS];
	struct urb **urb;
	char **urb_buffer;
	dma_addr_t *urb_dma;
	unsigned int urb_size;

	u32 sequence;
@@ -570,6 +570,15 @@ struct uvc_streaming {

		spinlock_t lock;
	} clock;

	/* Maximum number of URBs that can be submitted */
	u32 max_urb;

	/* Maximum number of packets per URB */
	u32 max_urb_packets;

	/*set if stream in progress */
	u8 refcnt;
};

struct uvc_device {