// SPDX-License-Identifier: GPL-2.0-or-later /* * Driver for the Conexant CX23885 PCIe bridge * * Copyright (c) 2007 Steven Toth <[email protected]> */ #include "cx23885.h" #include <linux/kernel.h> #include <linux/module.h> #include <linux/moduleparam.h> #include <linux/init.h> static unsigned int vbibufs = …; module_param(vbibufs, int, 0644); MODULE_PARM_DESC(…) …; static unsigned int vbi_debug; module_param(vbi_debug, int, 0644); MODULE_PARM_DESC(…) …; #define dprintk(level, fmt, arg...) … /* ------------------------------------------------------------------ */ #define VBI_LINE_LENGTH … #define VBI_NTSC_LINE_COUNT … #define VBI_PAL_LINE_COUNT … int cx23885_vbi_fmt(struct file *file, void *priv, struct v4l2_format *f) { … } /* We're given the Video Interrupt status register. * The cx23885_video_irq() func has already validated * the potential error bits, we just need to * deal with vbi payload and return indication if * we actually processed any payload. */ int cx23885_vbi_irq(struct cx23885_dev *dev, u32 status) { … } static int cx23885_start_vbi_dma(struct cx23885_dev *dev, struct cx23885_dmaqueue *q, struct cx23885_buffer *buf) { … } /* ------------------------------------------------------------------ */ static int queue_setup(struct vb2_queue *q, unsigned int *num_buffers, unsigned int *num_planes, unsigned int sizes[], struct device *alloc_devs[]) { … } static int buffer_prepare(struct vb2_buffer *vb) { … } static void buffer_finish(struct vb2_buffer *vb) { … } /* * The risc program for each buffer works as follows: it starts with a simple * 'JUMP to addr + 12', which is effectively a NOP. Then the code to DMA the * buffer follows and at the end we have a JUMP back to the start + 12 (skipping * the initial JUMP). * * This is the risc program of the first buffer to be queued if the active list * is empty and it just keeps DMAing this buffer without generating any * interrupts. * * If a new buffer is added then the initial JUMP in the code for that buffer * will generate an interrupt which signals that the previous buffer has been * DMAed successfully and that it can be returned to userspace. * * It also sets the final jump of the previous buffer to the start of the new * buffer, thus chaining the new buffer into the DMA chain. This is a single * atomic u32 write, so there is no race condition. * * The end-result of all this that you only get an interrupt when a buffer * is ready, so the control flow is very easy. */ static void buffer_queue(struct vb2_buffer *vb) { … } static int cx23885_start_streaming(struct vb2_queue *q, unsigned int count) { … } static void cx23885_stop_streaming(struct vb2_queue *q) { … } const struct vb2_ops cx23885_vbi_qops = …;