linux/drivers/media/pci/tw68/tw68-video.c

// SPDX-License-Identifier: GPL-2.0-or-later
/*
 *  tw68 functions to handle video data
 *
 *  Much of this code is derived from the cx88 and sa7134 drivers, which
 *  were in turn derived from the bt87x driver.  The original work was by
 *  Gerd Knorr; more recently the code was enhanced by Mauro Carvalho Chehab,
 *  Hans Verkuil, Andy Walls and many others.  Their work is gratefully
 *  acknowledged.  Full credit goes to them - any problems within this code
 *  are mine.
 *
 *  Copyright (C) 2009  William M. Brack
 *
 *  Refactored and updated to the latest v4l core frameworks:
 *
 *  Copyright (C) 2014 Hans Verkuil <[email protected]>
 */

#include <linux/module.h>
#include <media/v4l2-common.h>
#include <media/v4l2-event.h>
#include <media/videobuf2-dma-sg.h>

#include "tw68.h"
#include "tw68-reg.h"

/* ------------------------------------------------------------------ */
/* data structs for video                                             */
/*
 * FIXME -
 * Note that the saa7134 has formats, e.g. YUV420, which are classified
 * as "planar".  These affect overlay mode, and are flagged with a field
 * ".planar" in the format.  Do we need to implement this in this driver?
 */
static const struct tw68_format formats[] =;
#define FORMATS

#define NORM_625_50

#define NORM_525_60

/*
 * The following table is searched by tw68_s_std, first for a specific
 * match, then for an entry which contains the desired id.  The table
 * entries should therefore be ordered in ascending order of specificity.
 */
static const struct tw68_tvnorm tvnorms[] =;
#define TVNORMS

static const struct tw68_format *format_by_fourcc(unsigned int fourcc)
{}


/* ------------------------------------------------------------------ */
/*
 * Note that the cropping rectangles are described in terms of a single
 * frame, i.e. line positions are only 1/2 the interlaced equivalent
 */
static void set_tvnorm(struct tw68_dev *dev, const struct tw68_tvnorm *norm)
{}

/*
 * tw68_set_scale
 *
 * Scaling and Cropping for video decoding
 *
 * We are working with 3 values for horizontal and vertical - scale,
 * delay and active.
 *
 * HACTIVE represent the actual number of pixels in the "usable" image,
 * before scaling.  HDELAY represents the number of pixels skipped
 * between the start of the horizontal sync and the start of the image.
 * HSCALE is calculated using the formula
 *	HSCALE = (HACTIVE / (#pixels desired)) * 256
 *
 * The vertical registers are similar, except based upon the total number
 * of lines in the image, and the first line of the image (i.e. ignoring
 * vertical sync and VBI).
 *
 * Note that the number of bytes reaching the FIFO (and hence needing
 * to be processed by the DMAP program) is completely dependent upon
 * these values, especially HSCALE.
 *
 * Parameters:
 *	@dev		pointer to the device structure, needed for
 *			getting current norm (as well as debug print)
 *	@width		actual image width (from user buffer)
 *	@height		actual image height
 *	@field		indicates Top, Bottom or Interlaced
 */
static int tw68_set_scale(struct tw68_dev *dev, unsigned int width,
			  unsigned int height, enum v4l2_field field)
{}

/* ------------------------------------------------------------------ */

int tw68_video_start_dma(struct tw68_dev *dev, struct tw68_buf *buf)
{}

/* ------------------------------------------------------------------ */

/* calc max # of buffers from size (must not exceed the 4MB virtual
 * address space per DMA channel) */
static int tw68_buffer_count(unsigned int size, unsigned int count)
{}

/* ------------------------------------------------------------- */
/* vb2 queue operations                                          */

static int tw68_queue_setup(struct vb2_queue *q,
			   unsigned int *num_buffers, unsigned int *num_planes,
			   unsigned int sizes[], struct device *alloc_devs[])
{}

/*
 * The risc program for each buffers works as follows: it starts with a simple
 * 'JUMP to addr + 8', which is effectively a NOP. Then the program to DMA the
 * buffer follows and at the end we have a JUMP back to the start + 8 (skipping
 * the initial JUMP).
 *
 * This is the 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 program generates an
 * interrupt as well 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 tw68_buf_queue(struct vb2_buffer *vb)
{}

/*
 * buffer_prepare
 *
 * Set the ancillary information into the buffer structure.  This
 * includes generating the necessary risc program if it hasn't already
 * been done for the current buffer format.
 * The structure fh contains the details of the format requested by the
 * user - type, width, height and #fields.  This is compared with the
 * last format set for the current buffer.  If they differ, the risc
 * code (which controls the filling of the buffer) is (re-)generated.
 */
static int tw68_buf_prepare(struct vb2_buffer *vb)
{}

static void tw68_buf_finish(struct vb2_buffer *vb)
{}

static int tw68_start_streaming(struct vb2_queue *q, unsigned int count)
{}

static void tw68_stop_streaming(struct vb2_queue *q)
{}

static const struct vb2_ops tw68_video_qops =;

/* ------------------------------------------------------------------ */

static int tw68_s_ctrl(struct v4l2_ctrl *ctrl)
{}

/* ------------------------------------------------------------------ */

/*
 * Note that this routine returns what is stored in the fh structure, and
 * does not interrogate any of the device registers.
 */
static int tw68_g_fmt_vid_cap(struct file *file, void *priv,
				struct v4l2_format *f)
{}

static int tw68_try_fmt_vid_cap(struct file *file, void *priv,
						struct v4l2_format *f)
{}

/*
 * Note that tw68_s_fmt_vid_cap sets the information into the fh structure,
 * and it will be used for all future new buffers.  However, there could be
 * some number of buffers on the "active" chain which will be filled before
 * the change takes place.
 */
static int tw68_s_fmt_vid_cap(struct file *file, void *priv,
					struct v4l2_format *f)
{}

static int tw68_enum_input(struct file *file, void *priv,
					struct v4l2_input *i)
{}

static int tw68_g_input(struct file *file, void *priv, unsigned int *i)
{}

static int tw68_s_input(struct file *file, void *priv, unsigned int i)
{}

static int tw68_querycap(struct file *file, void  *priv,
					struct v4l2_capability *cap)
{}

static int tw68_s_std(struct file *file, void *priv, v4l2_std_id id)
{}

static int tw68_g_std(struct file *file, void *priv, v4l2_std_id *id)
{}

static int tw68_enum_fmt_vid_cap(struct file *file, void  *priv,
					struct v4l2_fmtdesc *f)
{}

/*
 * Used strictly for internal development and debugging, this routine
 * prints out the current register contents for the tw68xx device.
 */
static void tw68_dump_regs(struct tw68_dev *dev)
{}

static int vidioc_log_status(struct file *file, void *priv)
{}

#ifdef CONFIG_VIDEO_ADV_DEBUG
static int vidioc_g_register(struct file *file, void *priv,
			      struct v4l2_dbg_register *reg)
{}

static int vidioc_s_register(struct file *file, void *priv,
				const struct v4l2_dbg_register *reg)
{}
#endif

static const struct v4l2_ctrl_ops tw68_ctrl_ops =;

static const struct v4l2_file_operations video_fops =;

static const struct v4l2_ioctl_ops video_ioctl_ops =;

static const struct video_device tw68_video_template =;

/* ------------------------------------------------------------------ */
/* exported stuff                                                     */
void tw68_set_tvnorm_hw(struct tw68_dev *dev)
{}

int tw68_video_init1(struct tw68_dev *dev)
{}

int tw68_video_init2(struct tw68_dev *dev, int video_nr)
{}

/*
 * tw68_irq_video_done
 */
void tw68_irq_video_done(struct tw68_dev *dev, unsigned long status)
{}