162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0+ 262306a36Sopenharmony_ci// 362306a36Sopenharmony_ci// em28xx-vbi.c - VBI driver for em28xx 462306a36Sopenharmony_ci// 562306a36Sopenharmony_ci// Copyright (C) 2009 Devin Heitmueller <dheitmueller@kernellabs.com> 662306a36Sopenharmony_ci// 762306a36Sopenharmony_ci// This work was sponsored by EyeMagnet Limited. 862306a36Sopenharmony_ci 962306a36Sopenharmony_ci#include "em28xx.h" 1062306a36Sopenharmony_ci 1162306a36Sopenharmony_ci#include <linux/kernel.h> 1262306a36Sopenharmony_ci#include <linux/module.h> 1362306a36Sopenharmony_ci#include <linux/hardirq.h> 1462306a36Sopenharmony_ci#include <linux/init.h> 1562306a36Sopenharmony_ci#include <linux/usb.h> 1662306a36Sopenharmony_ci 1762306a36Sopenharmony_ci#include "em28xx-v4l.h" 1862306a36Sopenharmony_ci 1962306a36Sopenharmony_ci/* ------------------------------------------------------------------ */ 2062306a36Sopenharmony_ci 2162306a36Sopenharmony_cistatic int vbi_queue_setup(struct vb2_queue *vq, 2262306a36Sopenharmony_ci unsigned int *nbuffers, unsigned int *nplanes, 2362306a36Sopenharmony_ci unsigned int sizes[], struct device *alloc_devs[]) 2462306a36Sopenharmony_ci{ 2562306a36Sopenharmony_ci struct em28xx *dev = vb2_get_drv_priv(vq); 2662306a36Sopenharmony_ci struct em28xx_v4l2 *v4l2 = dev->v4l2; 2762306a36Sopenharmony_ci unsigned long size = v4l2->vbi_width * v4l2->vbi_height * 2; 2862306a36Sopenharmony_ci 2962306a36Sopenharmony_ci if (*nbuffers < 2) 3062306a36Sopenharmony_ci *nbuffers = 2; 3162306a36Sopenharmony_ci 3262306a36Sopenharmony_ci if (*nplanes) { 3362306a36Sopenharmony_ci if (sizes[0] < size) 3462306a36Sopenharmony_ci return -EINVAL; 3562306a36Sopenharmony_ci size = sizes[0]; 3662306a36Sopenharmony_ci } 3762306a36Sopenharmony_ci 3862306a36Sopenharmony_ci *nplanes = 1; 3962306a36Sopenharmony_ci sizes[0] = size; 4062306a36Sopenharmony_ci 4162306a36Sopenharmony_ci return 0; 4262306a36Sopenharmony_ci} 4362306a36Sopenharmony_ci 4462306a36Sopenharmony_cistatic int vbi_buffer_prepare(struct vb2_buffer *vb) 4562306a36Sopenharmony_ci{ 4662306a36Sopenharmony_ci struct em28xx *dev = vb2_get_drv_priv(vb->vb2_queue); 4762306a36Sopenharmony_ci struct em28xx_v4l2 *v4l2 = dev->v4l2; 4862306a36Sopenharmony_ci unsigned long size; 4962306a36Sopenharmony_ci 5062306a36Sopenharmony_ci size = v4l2->vbi_width * v4l2->vbi_height * 2; 5162306a36Sopenharmony_ci 5262306a36Sopenharmony_ci if (vb2_plane_size(vb, 0) < size) { 5362306a36Sopenharmony_ci dev_info(&dev->intf->dev, 5462306a36Sopenharmony_ci "%s data will not fit into plane (%lu < %lu)\n", 5562306a36Sopenharmony_ci __func__, vb2_plane_size(vb, 0), size); 5662306a36Sopenharmony_ci return -EINVAL; 5762306a36Sopenharmony_ci } 5862306a36Sopenharmony_ci vb2_set_plane_payload(vb, 0, size); 5962306a36Sopenharmony_ci 6062306a36Sopenharmony_ci return 0; 6162306a36Sopenharmony_ci} 6262306a36Sopenharmony_ci 6362306a36Sopenharmony_cistatic void 6462306a36Sopenharmony_civbi_buffer_queue(struct vb2_buffer *vb) 6562306a36Sopenharmony_ci{ 6662306a36Sopenharmony_ci struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); 6762306a36Sopenharmony_ci struct em28xx *dev = vb2_get_drv_priv(vb->vb2_queue); 6862306a36Sopenharmony_ci struct em28xx_buffer *buf = 6962306a36Sopenharmony_ci container_of(vbuf, struct em28xx_buffer, vb); 7062306a36Sopenharmony_ci struct em28xx_dmaqueue *vbiq = &dev->vbiq; 7162306a36Sopenharmony_ci unsigned long flags = 0; 7262306a36Sopenharmony_ci 7362306a36Sopenharmony_ci buf->mem = vb2_plane_vaddr(vb, 0); 7462306a36Sopenharmony_ci buf->length = vb2_plane_size(vb, 0); 7562306a36Sopenharmony_ci 7662306a36Sopenharmony_ci spin_lock_irqsave(&dev->slock, flags); 7762306a36Sopenharmony_ci list_add_tail(&buf->list, &vbiq->active); 7862306a36Sopenharmony_ci spin_unlock_irqrestore(&dev->slock, flags); 7962306a36Sopenharmony_ci} 8062306a36Sopenharmony_ci 8162306a36Sopenharmony_ciconst struct vb2_ops em28xx_vbi_qops = { 8262306a36Sopenharmony_ci .queue_setup = vbi_queue_setup, 8362306a36Sopenharmony_ci .buf_prepare = vbi_buffer_prepare, 8462306a36Sopenharmony_ci .buf_queue = vbi_buffer_queue, 8562306a36Sopenharmony_ci .start_streaming = em28xx_start_analog_streaming, 8662306a36Sopenharmony_ci .stop_streaming = em28xx_stop_vbi_streaming, 8762306a36Sopenharmony_ci .wait_prepare = vb2_ops_wait_prepare, 8862306a36Sopenharmony_ci .wait_finish = vb2_ops_wait_finish, 8962306a36Sopenharmony_ci}; 90