// SPDX-License-Identifier: GPL-2.0-or-later
/*
* device driver for Conexant 2388x based TV cards
* driver core
*
* (c) 2003 Gerd Knorr <kraxel@bytesex.org> [SuSE Labs]
*
* (c) 2005-2006 Mauro Carvalho Chehab <mchehab@kernel.org>
* - Multituner support
* - video_ioctl2 conversion
* - PAL/M fixes
*/
#include "cx88.h"
#include <linux/init.h>
#include <linux/list.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/kmod.h>
#include <linux/sound.h>
#include <linux/interrupt.h>
#include <linux/pci.h>
#include <linux/delay.h>
#include <linux/videodev2.h>
#include <linux/mutex.h>
#include <media/v4l2-common.h>
#include <media/v4l2-ioctl.h>
MODULE_DESCRIPTION("v4l2 driver module for cx2388x based TV cards");
MODULE_AUTHOR("Gerd Knorr <kraxel@bytesex.org> [SuSE Labs]");
MODULE_LICENSE("GPL v2");
/* ------------------------------------------------------------------ */
unsigned int cx88_core_debug;
module_param_named(core_debug, cx88_core_debug, int, 0644);
MODULE_PARM_DESC(core_debug, "enable debug messages [core]");
static unsigned int nicam;
module_param(nicam, int, 0644);
MODULE_PARM_DESC(nicam, "tv audio is nicam");
static unsigned int nocomb;
module_param(nocomb, int, 0644);
MODULE_PARM_DESC(nocomb, "disable comb filter");
#define dprintk0(fmt, arg...) \
printk(KERN_DEBUG pr_fmt("%s: core:" fmt), \
__func__, ##arg) \
#define dprintk(level, fmt, arg...) do { \
if (cx88_core_debug >= level) \
printk(KERN_DEBUG pr_fmt("%s: core:" fmt), \
__func__, ##arg); \
} while (0)
static unsigned int cx88_devcount;
static LIST_HEAD(cx88_devlist);
static DEFINE_MUTEX(devlist);
#define NO_SYNC_LINE (-1U)
/*
* @lpi: lines per IRQ, or 0 to not generate irqs. Note: IRQ to be
* generated _after_ lpi lines are transferred.
*/
static __le32 *cx88_risc_field(__le32 *rp, struct scatterlist *sglist,
unsigned int offset, u32 sync_line,
unsigned int bpl, unsigned int padding,
unsigned int lines, unsigned int lpi, bool jump)
{
struct scatterlist *sg;
unsigned int line, todo, sol;
if (jump) {
(*rp++) = cpu_to_le32(RISC_JUMP);
(*rp++) = 0;
}
/* sync instruction */
if (sync_line != NO_SYNC_LINE)
*(rp++) = cpu_to_le32(RISC_RESYNC | sync_line);
/* scan lines */
sg = sglist;
for (line = 0; line < lines; line++) {
while (offset && offset >= sg_dma_len(sg)) {
offset -= sg_dma_len(sg);
sg = sg_next(sg);
}
if (lpi && line > 0 && !(line % lpi))
sol = RISC_SOL | RISC_IRQ1 | RISC_CNT_INC;
else
sol = RISC_SOL;
if (bpl <= sg_dma_len(sg) - offset) {
/* fits into current chunk */
*(rp++) = cpu_to_le32(RISC_WRITE | sol |
RISC_EOL | bpl);
*(rp++) = cpu_to_le32(sg_dma_address(sg) + offset);
offset += bpl;
} else {
/* scanline needs to be split */
todo = bpl;
*(rp++) = cpu_to_le32(RISC_WRITE | sol |
(sg_dma_len(sg) - offset));
*(rp++) = cpu_to_le32(sg_dma_address(sg) + offset);
todo -= (sg_dma_len(sg) - offset);
offset = 0;
sg = sg_next(sg);
while (todo > sg_dma_len(sg)) {
*(rp++) = cpu_to_le32(RISC_WRITE |
sg_dma_len(sg));
*(rp++) = cpu_to_le32(sg_dma_address(sg));
todo -= sg_dma_len(sg);
sg = sg_next(sg);
}
*(rp++) = cp