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