From 1f93a7dfd1f8d5ff7a5c53246c7534fe2332d6f4 Mon Sep 17 00:00:00 2001
From: hc <hc@nodka.com>
Date: Mon, 11 Dec 2023 02:46:07 +0000
Subject: [PATCH] add audio

---
 kernel/drivers/usb/gadget/function/uvc_queue.c |  116 ++++++++++++++++++++++++++++++++++++++++++++++++++-------
 1 files changed, 101 insertions(+), 15 deletions(-)

diff --git a/kernel/drivers/usb/gadget/function/uvc_queue.c b/kernel/drivers/usb/gadget/function/uvc_queue.c
index a404108..d6383ac 100644
--- a/kernel/drivers/usb/gadget/function/uvc_queue.c
+++ b/kernel/drivers/usb/gadget/function/uvc_queue.c
@@ -20,6 +20,7 @@
 #include <media/videobuf2-vmalloc.h>
 
 #include "uvc.h"
+#include "u_uvc.h"
 
 /* ------------------------------------------------------------------------
  * Video buffers queue management.
@@ -43,6 +44,12 @@
 {
 	struct uvc_video_queue *queue = vb2_get_drv_priv(vq);
 	struct uvc_video *video = container_of(queue, struct uvc_video, queue);
+#if defined(CONFIG_ARCH_ROCKCHIP) && defined(CONFIG_NO_GKI)
+	struct uvc_device *uvc = container_of(video, struct uvc_device, video);
+	struct f_uvc_opts *opts = fi_to_f_uvc_opts(uvc->func.fi);
+#endif
+	unsigned int req_size;
+	unsigned int nreq;
 
 	if (*nbuffers > UVC_MAX_VIDEO_BUFFERS)
 		*nbuffers = UVC_MAX_VIDEO_BUFFERS;
@@ -51,8 +58,92 @@
 
 	sizes[0] = video->imagesize;
 
+#if defined(CONFIG_ARCH_ROCKCHIP) && defined(CONFIG_NO_GKI)
+	if (opts && opts->uvc_num_request > 0) {
+		video->uvc_num_requests = opts->uvc_num_request;
+		return 0;
+	}
+#endif
+
+	req_size = video->ep->maxpacket
+		 * max_t(unsigned int, video->ep->maxburst, 1)
+		 * (video->ep->mult);
+
+	/* We divide by two, to increase the chance to run
+	 * into fewer requests for smaller framesizes.
+	 */
+	nreq = DIV_ROUND_UP(DIV_ROUND_UP(sizes[0], 2), req_size);
+	nreq = clamp(nreq, 4U, 64U);
+	video->uvc_num_requests = nreq;
+
 	return 0;
 }
+
+#if defined(CONFIG_ARCH_ROCKCHIP) && defined(CONFIG_NO_GKI)
+/*
+ * uvc_dma_buf_phys_to_virt - Get the physical address of the dma_buf and
+ * translate it to virtual address.
+ *
+ * @dbuf: the dma_buf of vb2_plane
+ * @dev: the device to the actual usb controller
+ *
+ * This function is used for dma buf allocated by Contiguous Memory Allocator.
+ *
+ * Returns:
+ * The virtual addresses of the dma_buf.
+ */
+static void *uvc_dma_buf_phys_to_virt(struct uvc_device *uvc,
+				      struct dma_buf *dbuf)
+{
+	struct usb_gadget *gadget = uvc->func.config->cdev->gadget;
+	struct dma_buf_attachment *attachment;
+	struct sg_table *table;
+	struct scatterlist *sgl;
+	dma_addr_t phys = 0;
+	int i;
+
+	attachment = dma_buf_attach(dbuf, gadget->dev.parent);
+	if (IS_ERR(attachment))
+		return ERR_PTR(-ENOMEM);
+
+	table = dma_buf_map_attachment(attachment, DMA_BIDIRECTIONAL);
+	if (IS_ERR(table)) {
+		dma_buf_detach(dbuf, attachment);
+		return ERR_PTR(-ENOMEM);
+	}
+
+	for_each_sgtable_sg(table, sgl, i)
+		phys = sg_phys(sgl);
+
+	dma_buf_unmap_attachment(attachment, table, DMA_BIDIRECTIONAL);
+	dma_buf_detach(dbuf, attachment);
+
+	if (i > 1) {
+		uvcg_err(&uvc->func, "Not support mult sgl for uvc zero copy\n");
+		return ERR_PTR(-ENOMEM);
+	}
+
+	return phys_to_virt(phys);
+}
+
+static void *uvc_buffer_mem_prepare(struct vb2_buffer *vb,
+				    struct uvc_video_queue *queue)
+{
+	struct uvc_video *video = container_of(queue, struct uvc_video, queue);
+	struct uvc_device *uvc = container_of(video, struct uvc_device, video);
+	struct f_uvc_opts *opts = fi_to_f_uvc_opts(uvc->func.fi);
+	void *mem;
+
+	if (!opts->uvc_zero_copy || video->fcc == V4L2_PIX_FMT_YUYV)
+		return (vb2_plane_vaddr(vb, 0) + vb2_plane_data_offset(vb, 0));
+
+	mem = uvc_dma_buf_phys_to_virt(uvc, vb->planes[0].dbuf);
+	if (IS_ERR(mem))
+		return ERR_PTR(-ENOMEM);
+
+	return (mem + vb2_plane_data_offset(vb, 0));
+}
+#endif
 
 static int uvc_buffer_prepare(struct vb2_buffer *vb)
 {
@@ -70,7 +161,13 @@
 		return -ENODEV;
 
 	buf->state = UVC_BUF_STATE_QUEUED;
+#if defined(CONFIG_ARCH_ROCKCHIP) && defined(CONFIG_NO_GKI)
+	buf->mem = uvc_buffer_mem_prepare(vb, queue);
+	if (IS_ERR(buf->mem))
+		return -ENOMEM;
+#else
 	buf->mem = vb2_plane_vaddr(vb, 0);
+#endif
 	buf->length = vb2_plane_size(vb, 0);
 	if (vb->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
 		buf->bytesused = 0;
@@ -102,7 +199,7 @@
 	spin_unlock_irqrestore(&queue->irqlock, flags);
 }
 
-static struct vb2_ops uvc_queue_qops = {
+static const struct vb2_ops uvc_queue_qops = {
 	.queue_setup = uvc_queue_setup,
 	.buf_prepare = uvc_buffer_prepare,
 	.buf_queue = uvc_buffer_queue,
@@ -171,18 +268,7 @@
 
 int uvcg_queue_buffer(struct uvc_video_queue *queue, struct v4l2_buffer *buf)
 {
-	unsigned long flags;
-	int ret;
-
-	ret = vb2_qbuf(&queue->queue, buf);
-	if (ret < 0)
-		return ret;
-
-	spin_lock_irqsave(&queue->irqlock, flags);
-	ret = (queue->flags & UVC_QUEUE_PAUSED) != 0;
-	queue->flags &= ~UVC_QUEUE_PAUSED;
-	spin_unlock_irqrestore(&queue->irqlock, flags);
-	return ret;
+	return vb2_qbuf(&queue->queue, NULL, buf);
 }
 
 /*
@@ -250,6 +336,8 @@
 		buf->state = UVC_BUF_STATE_ERROR;
 		vb2_buffer_done(&buf->buf.vb2_buf, VB2_BUF_STATE_ERROR);
 	}
+	queue->buf_used = 0;
+
 	/* This must be protected by the irqlock spinlock to avoid race
 	 * conditions between uvc_queue_buffer and the disconnection event that
 	 * could result in an interruptible wait in uvc_dequeue_buffer. Do not
@@ -348,8 +436,6 @@
 	if (!list_empty(&queue->irqqueue))
 		buf = list_first_entry(&queue->irqqueue, struct uvc_buffer,
 				       queue);
-	else
-		queue->flags |= UVC_QUEUE_PAUSED;
 
 	return buf;
 }

--
Gitblit v1.6.2