summaryrefslogtreecommitdiffstats
path: root/drivers/media/pci/saa7134
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-11 08:27:49 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-11 08:27:49 +0000
commitace9429bb58fd418f0c81d4c2835699bddf6bde6 (patch)
treeb2d64bc10158fdd5497876388cd68142ca374ed3 /drivers/media/pci/saa7134
parentInitial commit. (diff)
downloadlinux-ace9429bb58fd418f0c81d4c2835699bddf6bde6.tar.xz
linux-ace9429bb58fd418f0c81d4c2835699bddf6bde6.zip
Adding upstream version 6.6.15.upstream/6.6.15
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'drivers/media/pci/saa7134')
-rw-r--r--drivers/media/pci/saa7134/Kconfig74
-rw-r--r--drivers/media/pci/saa7134/Makefile17
-rw-r--r--drivers/media/pci/saa7134/saa7134-alsa.c1263
-rw-r--r--drivers/media/pci/saa7134/saa7134-cards.c8126
-rw-r--r--drivers/media/pci/saa7134/saa7134-core.c1524
-rw-r--r--drivers/media/pci/saa7134/saa7134-dvb.c2004
-rw-r--r--drivers/media/pci/saa7134/saa7134-empress.c347
-rw-r--r--drivers/media/pci/saa7134/saa7134-go7007.c519
-rw-r--r--drivers/media/pci/saa7134/saa7134-i2c.c456
-rw-r--r--drivers/media/pci/saa7134/saa7134-input.c1000
-rw-r--r--drivers/media/pci/saa7134/saa7134-reg.h377
-rw-r--r--drivers/media/pci/saa7134/saa7134-ts.c328
-rw-r--r--drivers/media/pci/saa7134/saa7134-tvaudio.c1068
-rw-r--r--drivers/media/pci/saa7134/saa7134-vbi.c210
-rw-r--r--drivers/media/pci/saa7134/saa7134-video.c1864
-rw-r--r--drivers/media/pci/saa7134/saa7134.h907
16 files changed, 20084 insertions, 0 deletions
diff --git a/drivers/media/pci/saa7134/Kconfig b/drivers/media/pci/saa7134/Kconfig
new file mode 100644
index 0000000000..30c1759682
--- /dev/null
+++ b/drivers/media/pci/saa7134/Kconfig
@@ -0,0 +1,74 @@
+# SPDX-License-Identifier: GPL-2.0-only
+config VIDEO_SAA7134
+ tristate "Philips SAA7134 support"
+ depends on VIDEO_DEV && PCI && I2C
+ select VIDEOBUF2_DMA_SG
+ select VIDEO_TUNER
+ select VIDEO_TVEEPROM
+ select CRC32
+ select VIDEO_SAA6588 if MEDIA_SUBDRV_AUTOSELECT
+ select VIDEO_SAA6752HS if MEDIA_SUBDRV_AUTOSELECT
+ help
+ This is a video4linux driver for Philips SAA713x based
+ TV cards.
+
+ To compile this driver as a module, choose M here: the
+ module will be called saa7134.
+
+config VIDEO_SAA7134_ALSA
+ tristate "Philips SAA7134 DMA audio support"
+ depends on VIDEO_SAA7134 && SND
+ select SND_PCM
+ help
+ This is a video4linux driver for direct (DMA) audio in
+ Philips SAA713x based TV cards using ALSA
+
+ To compile this driver as a module, choose M here: the
+ module will be called saa7134-alsa.
+
+config VIDEO_SAA7134_RC
+ bool "Philips SAA7134 Remote Controller support"
+ depends on RC_CORE
+ depends on VIDEO_SAA7134
+ depends on !(RC_CORE=m && VIDEO_SAA7134=y)
+ default y
+ help
+ Enables Remote Controller support on saa7134 driver.
+
+config VIDEO_SAA7134_DVB
+ tristate "DVB/ATSC Support for saa7134 based TV cards"
+ depends on VIDEO_SAA7134 && DVB_CORE
+ select VIDEOBUF2_DVB
+ select DVB_PLL if MEDIA_SUBDRV_AUTOSELECT
+ select DVB_MT352 if MEDIA_SUBDRV_AUTOSELECT
+ select DVB_TDA1004X if MEDIA_SUBDRV_AUTOSELECT
+ select DVB_NXT200X if MEDIA_SUBDRV_AUTOSELECT
+ select DVB_TDA10086 if MEDIA_SUBDRV_AUTOSELECT
+ select DVB_TDA826X if MEDIA_SUBDRV_AUTOSELECT
+ select DVB_ISL6421 if MEDIA_SUBDRV_AUTOSELECT
+ select DVB_ISL6405 if MEDIA_SUBDRV_AUTOSELECT
+ select MEDIA_TUNER_TDA827X if MEDIA_SUBDRV_AUTOSELECT
+ select MEDIA_TUNER_SIMPLE if MEDIA_SUBDRV_AUTOSELECT
+ select DVB_ZL10036 if MEDIA_SUBDRV_AUTOSELECT
+ select DVB_MT312 if MEDIA_SUBDRV_AUTOSELECT
+ select DVB_LNBP21 if MEDIA_SUBDRV_AUTOSELECT
+ select DVB_ZL10353 if MEDIA_SUBDRV_AUTOSELECT
+ select DVB_LGDT3305 if MEDIA_SUBDRV_AUTOSELECT
+ select DVB_TDA10048 if MEDIA_SUBDRV_AUTOSELECT
+ select MEDIA_TUNER_TDA18271 if MEDIA_SUBDRV_AUTOSELECT
+ select MEDIA_TUNER_TDA8290 if MEDIA_SUBDRV_AUTOSELECT
+ select DVB_ZL10039 if MEDIA_SUBDRV_AUTOSELECT
+ help
+ This adds support for DVB cards based on the
+ Philips saa7134 chip.
+
+ To compile this driver as a module, choose M here: the
+ module will be called saa7134-dvb.
+
+config VIDEO_SAA7134_GO7007
+ tristate "go7007 support for saa7134 based TV cards"
+ depends on VIDEO_SAA7134
+ depends on VIDEO_GO7007
+ help
+ Enables saa7134 driver support for boards with go7007
+ MPEG encoder (WIS Voyager or compatible).
diff --git a/drivers/media/pci/saa7134/Makefile b/drivers/media/pci/saa7134/Makefile
new file mode 100644
index 0000000000..82ac7f3122
--- /dev/null
+++ b/drivers/media/pci/saa7134/Makefile
@@ -0,0 +1,17 @@
+# SPDX-License-Identifier: GPL-2.0
+
+saa7134-y += saa7134-cards.o saa7134-core.o saa7134-i2c.o
+saa7134-y += saa7134-ts.o saa7134-tvaudio.o saa7134-vbi.o
+saa7134-y += saa7134-video.o
+saa7134-$(CONFIG_VIDEO_SAA7134_RC) += saa7134-input.o
+
+obj-$(CONFIG_VIDEO_SAA7134) += saa7134.o saa7134-empress.o
+obj-$(CONFIG_VIDEO_SAA7134_GO7007) += saa7134-go7007.o
+
+obj-$(CONFIG_VIDEO_SAA7134_ALSA) += saa7134-alsa.o
+
+obj-$(CONFIG_VIDEO_SAA7134_DVB) += saa7134-dvb.o
+
+ccflags-y += -I$(srctree)/drivers/media/tuners
+ccflags-y += -I$(srctree)/drivers/media/dvb-frontends
+ccflags-y += -I$(srctree)/drivers/media/usb/go7007
diff --git a/drivers/media/pci/saa7134/saa7134-alsa.c b/drivers/media/pci/saa7134/saa7134-alsa.c
new file mode 100644
index 0000000000..d3cde05a6e
--- /dev/null
+++ b/drivers/media/pci/saa7134/saa7134-alsa.c
@@ -0,0 +1,1263 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * SAA713x ALSA support for V4L
+ */
+
+#include "saa7134.h"
+#include "saa7134-reg.h"
+
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/time.h>
+#include <linux/wait.h>
+#include <linux/module.h>
+#include <sound/core.h>
+#include <sound/control.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/initval.h>
+#include <linux/interrupt.h>
+#include <linux/vmalloc.h>
+
+/*
+ * Configuration macros
+ */
+
+/* defaults */
+#define MIXER_ADDR_UNSELECTED -1
+#define MIXER_ADDR_TVTUNER 0
+#define MIXER_ADDR_LINE1 1
+#define MIXER_ADDR_LINE2 2
+#define MIXER_ADDR_LAST 2
+
+
+static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-MAX */
+static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* ID for this card */
+static int enable[SNDRV_CARDS] = {1, [1 ... (SNDRV_CARDS - 1)] = 1};
+
+module_param_array(index, int, NULL, 0444);
+module_param_array(enable, int, NULL, 0444);
+MODULE_PARM_DESC(index, "Index value for SAA7134 capture interface(s).");
+MODULE_PARM_DESC(enable, "Enable (or not) the SAA7134 capture interface(s).");
+
+/*
+ * Main chip structure
+ */
+
+typedef struct snd_card_saa7134 {
+ struct snd_card *card;
+ spinlock_t mixer_lock;
+ int mixer_volume[MIXER_ADDR_LAST+1][2];
+ int capture_source_addr;
+ int capture_source[2];
+ struct snd_kcontrol *capture_ctl[MIXER_ADDR_LAST+1];
+ struct pci_dev *pci;
+ struct saa7134_dev *dev;
+
+ unsigned long iobase;
+ s16 irq;
+ u16 mute_was_on;
+
+ spinlock_t lock;
+} snd_card_saa7134_t;
+
+
+/*
+ * PCM structure
+ */
+
+typedef struct snd_card_saa7134_pcm {
+ struct saa7134_dev *dev;
+
+ spinlock_t lock;
+
+ struct snd_pcm_substream *substream;
+} snd_card_saa7134_pcm_t;
+
+static struct snd_card *snd_saa7134_cards[SNDRV_CARDS];
+
+
+/*
+ * saa7134 DMA audio stop
+ *
+ * Called when the capture device is released or the buffer overflows
+ *
+ * - Copied verbatim from saa7134-oss's dsp_dma_stop.
+ *
+ */
+
+static void saa7134_dma_stop(struct saa7134_dev *dev)
+{
+ dev->dmasound.dma_blk = -1;
+ dev->dmasound.dma_running = 0;
+ saa7134_set_dmabits(dev);
+}
+
+/*
+ * saa7134 DMA audio start
+ *
+ * Called when preparing the capture device for use
+ *
+ * - Copied verbatim from saa7134-oss's dsp_dma_start.
+ *
+ */
+
+static void saa7134_dma_start(struct saa7134_dev *dev)
+{
+ dev->dmasound.dma_blk = 0;
+ dev->dmasound.dma_running = 1;
+ saa7134_set_dmabits(dev);
+}
+
+/*
+ * saa7134 audio DMA IRQ handler
+ *
+ * Called whenever we get an SAA7134_IRQ_REPORT_DONE_RA3 interrupt
+ * Handles shifting between the 2 buffers, manages the read counters,
+ * and notifies ALSA when periods elapse
+ *
+ * - Mostly copied from saa7134-oss's saa7134_irq_oss_done.
+ *
+ */
+
+static void saa7134_irq_alsa_done(struct saa7134_dev *dev,
+ unsigned long status)
+{
+ int next_blk, reg = 0;
+
+ spin_lock(&dev->slock);
+ if (UNSET == dev->dmasound.dma_blk) {
+ pr_debug("irq: recording stopped\n");
+ goto done;
+ }
+ if (0 != (status & 0x0f000000))
+ pr_debug("irq: lost %ld\n", (status >> 24) & 0x0f);
+ if (0 == (status & 0x10000000)) {
+ /* odd */
+ if (0 == (dev->dmasound.dma_blk & 0x01))
+ reg = SAA7134_RS_BA1(6);
+ } else {
+ /* even */
+ if (1 == (dev->dmasound.dma_blk & 0x01))
+ reg = SAA7134_RS_BA2(6);
+ }
+ if (0 == reg) {
+ pr_debug("irq: field oops [%s]\n",
+ (status & 0x10000000) ? "even" : "odd");
+ goto done;
+ }
+
+ if (dev->dmasound.read_count >= dev->dmasound.blksize * (dev->dmasound.blocks-2)) {
+ pr_debug("irq: overrun [full=%d/%d] - Blocks in %d\n",
+ dev->dmasound.read_count,
+ dev->dmasound.bufsize, dev->dmasound.blocks);
+ spin_unlock(&dev->slock);
+ snd_pcm_stop_xrun(dev->dmasound.substream);
+ return;
+ }
+
+ /* next block addr */
+ next_blk = (dev->dmasound.dma_blk + 2) % dev->dmasound.blocks;
+ saa_writel(reg,next_blk * dev->dmasound.blksize);
+ pr_debug("irq: ok, %s, next_blk=%d, addr=%x, blocks=%u, size=%u, read=%u\n",
+ (status & 0x10000000) ? "even" : "odd ", next_blk,
+ next_blk * dev->dmasound.blksize, dev->dmasound.blocks,
+ dev->dmasound.blksize, dev->dmasound.read_count);
+
+ /* update status & wake waiting readers */
+ dev->dmasound.dma_blk = (dev->dmasound.dma_blk + 1) % dev->dmasound.blocks;
+ dev->dmasound.read_count += dev->dmasound.blksize;
+
+ dev->dmasound.recording_on = reg;
+
+ if (dev->dmasound.read_count >= snd_pcm_lib_period_bytes(dev->dmasound.substream)) {
+ spin_unlock(&dev->slock);
+ snd_pcm_period_elapsed(dev->dmasound.substream);
+ spin_lock(&dev->slock);
+ }
+
+ done:
+ spin_unlock(&dev->slock);
+
+}
+
+/*
+ * IRQ request handler
+ *
+ * Runs along with saa7134's IRQ handler, discards anything that isn't
+ * DMA sound
+ *
+ */
+
+static irqreturn_t saa7134_alsa_irq(int irq, void *dev_id)
+{
+ struct saa7134_dmasound *dmasound = dev_id;
+ struct saa7134_dev *dev = dmasound->priv_data;
+
+ unsigned long report, status;
+ int loop, handled = 0;
+
+ for (loop = 0; loop < 10; loop++) {
+ report = saa_readl(SAA7134_IRQ_REPORT);
+ status = saa_readl(SAA7134_IRQ_STATUS);
+
+ if (report & SAA7134_IRQ_REPORT_DONE_RA3) {
+ handled = 1;
+ saa_writel(SAA7134_IRQ_REPORT,
+ SAA7134_IRQ_REPORT_DONE_RA3);
+ saa7134_irq_alsa_done(dev, status);
+ } else {
+ goto out;
+ }
+ }
+
+ if (loop == 10) {
+ pr_debug("error! looping IRQ!");
+ }
+
+out:
+ return IRQ_RETVAL(handled);
+}
+
+/*
+ * ALSA capture trigger
+ *
+ * - One of the ALSA capture callbacks.
+ *
+ * Called whenever a capture is started or stopped. Must be defined,
+ * but there's nothing we want to do here
+ *
+ */
+
+static int snd_card_saa7134_capture_trigger(struct snd_pcm_substream * substream,
+ int cmd)
+{
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ snd_card_saa7134_pcm_t *pcm = runtime->private_data;
+ struct saa7134_dev *dev=pcm->dev;
+ int err = 0;
+
+ spin_lock(&dev->slock);
+ if (cmd == SNDRV_PCM_TRIGGER_START) {
+ /* start dma */
+ saa7134_dma_start(dev);
+ } else if (cmd == SNDRV_PCM_TRIGGER_STOP) {
+ /* stop dma */
+ saa7134_dma_stop(dev);
+ } else {
+ err = -EINVAL;
+ }
+ spin_unlock(&dev->slock);
+
+ return err;
+}
+
+static int saa7134_alsa_dma_init(struct saa7134_dev *dev,
+ unsigned long nr_pages)
+{
+ struct saa7134_dmasound *dma = &dev->dmasound;
+ struct page *pg;
+ int i;
+
+ dma->vaddr = vmalloc_32(nr_pages << PAGE_SHIFT);
+ if (NULL == dma->vaddr) {
+ pr_debug("vmalloc_32(%lu pages) failed\n", nr_pages);
+ return -ENOMEM;
+ }
+
+ pr_debug("vmalloc is at addr %p, size=%lu\n",
+ dma->vaddr, nr_pages << PAGE_SHIFT);
+
+ memset(dma->vaddr, 0, nr_pages << PAGE_SHIFT);
+ dma->nr_pages = nr_pages;
+
+ dma->sglist = vzalloc(array_size(sizeof(*dma->sglist), dma->nr_pages));
+ if (NULL == dma->sglist)
+ goto vzalloc_err;
+
+ sg_init_table(dma->sglist, dma->nr_pages);
+ for (i = 0; i < dma->nr_pages; i++) {
+ pg = vmalloc_to_page(dma->vaddr + i * PAGE_SIZE);
+ if (NULL == pg)
+ goto vmalloc_to_page_err;
+ sg_set_page(&dma->sglist[i], pg, PAGE_SIZE, 0);
+ }
+ return 0;
+
+vmalloc_to_page_err:
+ vfree(dma->sglist);
+ dma->sglist = NULL;
+vzalloc_err:
+ vfree(dma->vaddr);
+ dma->vaddr = NULL;
+ return -ENOMEM;
+}
+
+static int saa7134_alsa_dma_map(struct saa7134_dev *dev)
+{
+ struct saa7134_dmasound *dma = &dev->dmasound;
+
+ dma->sglen = dma_map_sg(&dev->pci->dev, dma->sglist,
+ dma->nr_pages, DMA_FROM_DEVICE);
+
+ if (0 == dma->sglen) {
+ pr_warn("%s: saa7134_alsa_map_sg failed\n", __func__);
+ return -ENOMEM;
+ }
+ return 0;
+}
+
+static int saa7134_alsa_dma_unmap(struct saa7134_dev *dev)
+{
+ struct saa7134_dmasound *dma = &dev->dmasound;
+
+ if (!dma->sglen)
+ return 0;
+
+ dma_unmap_sg(&dev->pci->dev, dma->sglist, dma->nr_pages, DMA_FROM_DEVICE);
+ dma->sglen = 0;
+ return 0;
+}
+
+static int saa7134_alsa_dma_free(struct saa7134_dmasound *dma)
+{
+ vfree(dma->sglist);
+ dma->sglist = NULL;
+ vfree(dma->vaddr);
+ dma->vaddr = NULL;
+ return 0;
+}
+
+/*
+ * DMA buffer initialization
+ *
+ * Uses V4L functions to initialize the DMA. Shouldn't be necessary in
+ * ALSA, but I was unable to use ALSA's own DMA, and had to force the
+ * usage of V4L's
+ *
+ * - Copied verbatim from saa7134-oss.
+ *
+ */
+
+static int dsp_buffer_init(struct saa7134_dev *dev)
+{
+ int err;
+
+ BUG_ON(!dev->dmasound.bufsize);
+
+ err = saa7134_alsa_dma_init(dev,
+ (dev->dmasound.bufsize + PAGE_SIZE) >> PAGE_SHIFT);
+ if (0 != err)
+ return err;
+ return 0;
+}
+
+/*
+ * DMA buffer release
+ *
+ * Called after closing the device, during snd_card_saa7134_capture_close
+ *
+ */
+
+static int dsp_buffer_free(struct saa7134_dev *dev)
+{
+ BUG_ON(!dev->dmasound.blksize);
+
+ saa7134_alsa_dma_free(&dev->dmasound);
+
+ dev->dmasound.blocks = 0;
+ dev->dmasound.blksize = 0;
+ dev->dmasound.bufsize = 0;
+
+ return 0;
+}
+
+/*
+ * Setting the capture source and updating the ALSA controls
+ */
+static int snd_saa7134_capsrc_set(struct snd_kcontrol *kcontrol,
+ int left, int right, bool force_notify)
+{
+ snd_card_saa7134_t *chip = snd_kcontrol_chip(kcontrol);
+ int change = 0, addr = kcontrol->private_value;
+ int active, old_addr;
+ u32 anabar, xbarin;
+ int analog_io, rate;
+ struct saa7134_dev *dev;
+
+ dev = chip->dev;
+
+ spin_lock_irq(&chip->mixer_lock);
+
+ active = left != 0 || right != 0;
+ old_addr = chip->capture_source_addr;
+
+ /* The active capture source cannot be deactivated */
+ if (active) {
+ change = old_addr != addr ||
+ chip->capture_source[0] != left ||
+ chip->capture_source[1] != right;
+
+ chip->capture_source[0] = left;
+ chip->capture_source[1] = right;
+ chip->capture_source_addr = addr;
+ dev->dmasound.input = addr;
+ }
+ spin_unlock_irq(&chip->mixer_lock);
+
+ if (change) {
+ switch (dev->pci->device) {
+
+ case PCI_DEVICE_ID_PHILIPS_SAA7134:
+ switch (addr) {
+ case MIXER_ADDR_TVTUNER:
+ saa_andorb(SAA7134_AUDIO_FORMAT_CTRL,
+ 0xc0, 0xc0);
+ saa_andorb(SAA7134_SIF_SAMPLE_FREQ,
+ 0x03, 0x00);
+ break;
+ case MIXER_ADDR_LINE1:
+ case MIXER_ADDR_LINE2:
+ analog_io = (MIXER_ADDR_LINE1 == addr) ?
+ 0x00 : 0x08;
+ rate = (32000 == dev->dmasound.rate) ?
+ 0x01 : 0x03;
+ saa_andorb(SAA7134_ANALOG_IO_SELECT,
+ 0x08, analog_io);
+ saa_andorb(SAA7134_AUDIO_FORMAT_CTRL,
+ 0xc0, 0x80);
+ saa_andorb(SAA7134_SIF_SAMPLE_FREQ,
+ 0x03, rate);
+ break;
+ }
+
+ break;
+ case PCI_DEVICE_ID_PHILIPS_SAA7133:
+ case PCI_DEVICE_ID_PHILIPS_SAA7135:
+ xbarin = 0x03; /* adc */
+ anabar = 0;
+ switch (addr) {
+ case MIXER_ADDR_TVTUNER:
+ xbarin = 0; /* Demodulator */
+ anabar = 2; /* DACs */
+ break;
+ case MIXER_ADDR_LINE1:
+ anabar = 0; /* aux1, aux1 */
+ break;
+ case MIXER_ADDR_LINE2:
+ anabar = 9; /* aux2, aux2 */
+ break;
+ }
+
+ /* output xbar always main channel */
+ saa_dsp_writel(dev, SAA7133_DIGITAL_OUTPUT_SEL1,
+ 0xbbbb10);
+
+ if (left || right) {
+ /* We've got data, turn the input on */
+ saa_dsp_writel(dev, SAA7133_DIGITAL_INPUT_XBAR1,
+ xbarin);
+ saa_writel(SAA7133_ANALOG_IO_SELECT, anabar);
+ } else {
+ saa_dsp_writel(dev, SAA7133_DIGITAL_INPUT_XBAR1,
+ 0);
+ saa_writel(SAA7133_ANALOG_IO_SELECT, 0);
+ }
+ break;
+ }
+ }
+
+ if (change) {
+ if (force_notify)
+ snd_ctl_notify(chip->card,
+ SNDRV_CTL_EVENT_MASK_VALUE,
+ &chip->capture_ctl[addr]->id);
+
+ if (old_addr != MIXER_ADDR_UNSELECTED && old_addr != addr)
+ snd_ctl_notify(chip->card,
+ SNDRV_CTL_EVENT_MASK_VALUE,
+ &chip->capture_ctl[old_addr]->id);
+ }
+
+ return change;
+}
+
+/*
+ * ALSA PCM preparation
+ *
+ * - One of the ALSA capture callbacks.
+ *
+ * Called right after the capture device is opened, this function configures
+ * the buffer using the previously defined functions, allocates the memory,
+ * sets up the hardware registers, and then starts the DMA. When this function
+ * returns, the audio should be flowing.
+ *
+ */
+
+static int snd_card_saa7134_capture_prepare(struct snd_pcm_substream * substream)
+{
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ int bswap, sign;
+ u32 fmt, control;
+ snd_card_saa7134_t *saa7134 = snd_pcm_substream_chip(substream);
+ struct saa7134_dev *dev;
+ snd_card_saa7134_pcm_t *pcm = runtime->private_data;
+
+ pcm->dev->dmasound.substream = substream;
+
+ dev = saa7134->dev;
+
+ if (snd_pcm_format_width(runtime->format) == 8)
+ fmt = 0x00;
+ else
+ fmt = 0x01;
+
+ if (snd_pcm_format_signed(runtime->format))
+ sign = 1;
+ else
+ sign = 0;
+
+ if (snd_pcm_format_big_endian(runtime->format))
+ bswap = 1;
+ else
+ bswap = 0;
+
+ switch (dev->pci->device) {
+ case PCI_DEVICE_ID_PHILIPS_SAA7134:
+ if (1 == runtime->channels)
+ fmt |= (1 << 3);
+ if (2 == runtime->channels)
+ fmt |= (3 << 3);
+ if (sign)
+ fmt |= 0x04;
+
+ fmt |= (MIXER_ADDR_TVTUNER == dev->dmasound.input) ? 0xc0 : 0x80;
+ saa_writeb(SAA7134_NUM_SAMPLES0, ((dev->dmasound.blksize - 1) & 0x0000ff));
+ saa_writeb(SAA7134_NUM_SAMPLES1, ((dev->dmasound.blksize - 1) & 0x00ff00) >> 8);
+ saa_writeb(SAA7134_NUM_SAMPLES2, ((dev->dmasound.blksize - 1) & 0xff0000) >> 16);
+ saa_writeb(SAA7134_AUDIO_FORMAT_CTRL, fmt);
+
+ break;
+ case PCI_DEVICE_ID_PHILIPS_SAA7133:
+ case PCI_DEVICE_ID_PHILIPS_SAA7135:
+ if (1 == runtime->channels)
+ fmt |= (1 << 4);
+ if (2 == runtime->channels)
+ fmt |= (2 << 4);
+ if (!sign)
+ fmt |= 0x04;
+ saa_writel(SAA7133_NUM_SAMPLES, dev->dmasound.blksize -1);
+ saa_writel(SAA7133_AUDIO_CHANNEL, 0x543210 | (fmt << 24));
+ break;
+ }
+
+ pr_debug("rec_start: afmt=%d ch=%d => fmt=0x%x swap=%c\n",
+ runtime->format, runtime->channels, fmt,
+ bswap ? 'b' : '-');
+ /* dma: setup channel 6 (= AUDIO) */
+ control = SAA7134_RS_CONTROL_BURST_16 |
+ SAA7134_RS_CONTROL_ME |
+ (dev->dmasound.pt.dma >> 12);
+ if (bswap)
+ control |= SAA7134_RS_CONTROL_BSWAP;
+
+ saa_writel(SAA7134_RS_BA1(6),0);
+ saa_writel(SAA7134_RS_BA2(6),dev->dmasound.blksize);
+ saa_writel(SAA7134_RS_PITCH(6),0);
+ saa_writel(SAA7134_RS_CONTROL(6),control);
+
+ dev->dmasound.rate = runtime->rate;
+
+ /* Setup and update the card/ALSA controls */
+ snd_saa7134_capsrc_set(saa7134->capture_ctl[dev->dmasound.input], 1, 1,
+ true);
+
+ return 0;
+
+}
+
+/*
+ * ALSA pointer fetching
+ *
+ * - One of the ALSA capture callbacks.
+ *
+ * Called whenever a period elapses, it must return the current hardware
+ * position of the buffer.
+ * Also resets the read counter used to prevent overruns
+ *
+ */
+
+static snd_pcm_uframes_t
+snd_card_saa7134_capture_pointer(struct snd_pcm_substream * substream)
+{
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ snd_card_saa7134_pcm_t *pcm = runtime->private_data;
+ struct saa7134_dev *dev=pcm->dev;
+
+ if (dev->dmasound.read_count) {
+ dev->dmasound.read_count -= snd_pcm_lib_period_bytes(substream);
+ dev->dmasound.read_offset += snd_pcm_lib_period_bytes(substream);
+ if (dev->dmasound.read_offset == dev->dmasound.bufsize)
+ dev->dmasound.read_offset = 0;
+ }
+
+ return bytes_to_frames(runtime, dev->dmasound.read_offset);
+}
+
+/*
+ * ALSA hardware capabilities definition
+ *
+ * Report only 32kHz for ALSA:
+ *
+ * - SAA7133/35 uses DDEP (DemDec Easy Programming mode), which works in 32kHz
+ * only
+ * - SAA7134 for TV mode uses DemDec mode (32kHz)
+ * - Radio works in 32kHz only
+ * - When recording 48kHz from Line1/Line2, switching of capture source to TV
+ * means
+ * switching to 32kHz without any frequency translation
+ */
+
+static const struct snd_pcm_hardware snd_card_saa7134_capture =
+{
+ .info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |
+ SNDRV_PCM_INFO_BLOCK_TRANSFER |
+ SNDRV_PCM_INFO_MMAP_VALID),
+ .formats = SNDRV_PCM_FMTBIT_S16_LE | \
+ SNDRV_PCM_FMTBIT_S16_BE | \
+ SNDRV_PCM_FMTBIT_S8 | \
+ SNDRV_PCM_FMTBIT_U8 | \
+ SNDRV_PCM_FMTBIT_U16_LE | \
+ SNDRV_PCM_FMTBIT_U16_BE,
+ .rates = SNDRV_PCM_RATE_32000,
+ .rate_min = 32000,
+ .rate_max = 32000,
+ .channels_min = 1,
+ .channels_max = 2,
+ .buffer_bytes_max = (256*1024),
+ .period_bytes_min = 64,
+ .period_bytes_max = (256*1024),
+ .periods_min = 4,
+ .periods_max = 1024,
+};
+
+static void snd_card_saa7134_runtime_free(struct snd_pcm_runtime *runtime)
+{
+ snd_card_saa7134_pcm_t *pcm = runtime->private_data;
+
+ kfree(pcm);
+}
+
+
+/*
+ * ALSA hardware params
+ *
+ * - One of the ALSA capture callbacks.
+ *
+ * Called on initialization, right before the PCM preparation
+ *
+ */
+
+static int snd_card_saa7134_hw_params(struct snd_pcm_substream * substream,
+ struct snd_pcm_hw_params * hw_params)
+{
+ snd_card_saa7134_t *saa7134 = snd_pcm_substream_chip(substream);
+ struct saa7134_dev *dev;
+ unsigned int period_size, periods;
+ int err;
+
+ period_size = params_period_bytes(hw_params);
+ periods = params_periods(hw_params);
+
+ if (period_size < 0x100 || period_size > 0x10000)
+ return -EINVAL;
+ if (periods < 4)
+ return -EINVAL;
+ if (period_size * periods > 1024 * 1024)
+ return -EINVAL;
+
+ dev = saa7134->dev;
+
+ if (dev->dmasound.blocks == periods &&
+ dev->dmasound.blksize == period_size)
+ return 0;
+
+ /* release the old buffer */
+ if (substream->runtime->dma_area) {
+ saa7134_pgtable_free(dev->pci, &dev->dmasound.pt);
+ saa7134_alsa_dma_unmap(dev);
+ dsp_buffer_free(dev);
+ substream->runtime->dma_area = NULL;
+ }
+ dev->dmasound.blocks = periods;
+ dev->dmasound.blksize = period_size;
+ dev->dmasound.bufsize = period_size * periods;
+
+ err = dsp_buffer_init(dev);
+ if (0 != err) {
+ dev->dmasound.blocks = 0;
+ dev->dmasound.blksize = 0;
+ dev->dmasound.bufsize = 0;
+ return err;
+ }
+
+ err = saa7134_alsa_dma_map(dev);
+ if (err) {
+ dsp_buffer_free(dev);
+ return err;
+ }
+ err = saa7134_pgtable_alloc(dev->pci, &dev->dmasound.pt);
+ if (err) {
+ saa7134_alsa_dma_unmap(dev);
+ dsp_buffer_free(dev);
+ return err;
+ }
+ err = saa7134_pgtable_build(dev->pci, &dev->dmasound.pt,
+ dev->dmasound.sglist, dev->dmasound.sglen, 0);
+ if (err) {
+ saa7134_pgtable_free(dev->pci, &dev->dmasound.pt);
+ saa7134_alsa_dma_unmap(dev);
+ dsp_buffer_free(dev);
+ return err;
+ }
+
+ /* I should be able to use runtime->dma_addr in the control
+ byte, but it doesn't work. So I allocate the DMA using the
+ V4L functions, and force ALSA to use that as the DMA area */
+
+ substream->runtime->dma_area = dev->dmasound.vaddr;
+ substream->runtime->dma_bytes = dev->dmasound.bufsize;
+ substream->runtime->dma_addr = 0;
+
+ return 0;
+
+}
+
+/*
+ * ALSA hardware release
+ *
+ * - One of the ALSA capture callbacks.
+ *
+ * Called after closing the device, but before snd_card_saa7134_capture_close
+ * It stops the DMA audio and releases the buffers.
+ *
+ */
+
+static int snd_card_saa7134_hw_free(struct snd_pcm_substream * substream)
+{
+ snd_card_saa7134_t *saa7134 = snd_pcm_substream_chip(substream);
+ struct saa7134_dev *dev;
+
+ dev = saa7134->dev;
+
+ if (substream->runtime->dma_area) {
+ saa7134_pgtable_free(dev->pci, &dev->dmasound.pt);
+ saa7134_alsa_dma_unmap(dev);
+ dsp_buffer_free(dev);
+ substream->runtime->dma_area = NULL;
+ }
+
+ return 0;
+}
+
+/*
+ * ALSA capture finish
+ *
+ * - One of the ALSA capture callbacks.
+ *
+ * Called after closing the device.
+ *
+ */
+
+static int snd_card_saa7134_capture_close(struct snd_pcm_substream * substream)
+{
+ snd_card_saa7134_t *saa7134 = snd_pcm_substream_chip(substream);
+ struct saa7134_dev *dev = saa7134->dev;
+
+ if (saa7134->mute_was_on) {
+ dev->ctl_mute = 1;
+ saa7134_tvaudio_setmute(dev);
+ }
+ return 0;
+}
+
+/*
+ * ALSA capture start
+ *
+ * - One of the ALSA capture callbacks.
+ *
+ * Called when opening the device. It creates and populates the PCM
+ * structure
+ *
+ */
+
+static int snd_card_saa7134_capture_open(struct snd_pcm_substream * substream)
+{
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ snd_card_saa7134_pcm_t *pcm;
+ snd_card_saa7134_t *saa7134 = snd_pcm_substream_chip(substream);
+ struct saa7134_dev *dev;
+ int amux, err;
+
+ if (!saa7134) {
+ pr_err("BUG: saa7134 can't find device struct. Can't proceed with open\n");
+ return -ENODEV;
+ }
+ dev = saa7134->dev;
+ mutex_lock(&dev->dmasound.lock);
+
+ dev->dmasound.read_count = 0;
+ dev->dmasound.read_offset = 0;
+
+ amux = dev->input->amux;
+ if ((amux < 1) || (amux > 3))
+ amux = 1;
+ dev->dmasound.input = amux - 1;
+
+ mutex_unlock(&dev->dmasound.lock);
+
+ pcm = kzalloc(sizeof(*pcm), GFP_KERNEL);
+ if (pcm == NULL)
+ return -ENOMEM;
+
+ pcm->dev=saa7134->dev;
+
+ spin_lock_init(&pcm->lock);
+
+ pcm->substream = substream;
+ runtime->private_data = pcm;
+ runtime->private_free = snd_card_saa7134_runtime_free;
+ runtime->hw = snd_card_saa7134_capture;
+
+ if (dev->ctl_mute != 0) {
+ saa7134->mute_was_on = 1;
+ dev->ctl_mute = 0;
+ saa7134_tvaudio_setmute(dev);
+ }
+
+ err = snd_pcm_hw_constraint_integer(runtime,
+ SNDRV_PCM_HW_PARAM_PERIODS);
+ if (err < 0)
+ return err;
+
+ err = snd_pcm_hw_constraint_step(runtime, 0,
+ SNDRV_PCM_HW_PARAM_PERIODS, 2);
+ if (err < 0)
+ return err;
+
+ return 0;
+}
+
+/*
+ * page callback (needed for mmap)
+ */
+
+static struct page *snd_card_saa7134_page(struct snd_pcm_substream *substream,
+ unsigned long offset)
+{
+ void *pageptr = substream->runtime->dma_area + offset;
+ return vmalloc_to_page(pageptr);
+}
+
+/*
+ * ALSA capture callbacks definition
+ */
+
+static const struct snd_pcm_ops snd_card_saa7134_capture_ops = {
+ .open = snd_card_saa7134_capture_open,
+ .close = snd_card_saa7134_capture_close,
+ .hw_params = snd_card_saa7134_hw_params,
+ .hw_free = snd_card_saa7134_hw_free,
+ .prepare = snd_card_saa7134_capture_prepare,
+ .trigger = snd_card_saa7134_capture_trigger,
+ .pointer = snd_card_saa7134_capture_pointer,
+ .page = snd_card_saa7134_page,
+};
+
+/*
+ * ALSA PCM setup
+ *
+ * Called when initializing the board. Sets up the name and hooks up
+ * the callbacks
+ *
+ */
+
+static int snd_card_saa7134_pcm(snd_card_saa7134_t *saa7134, int device)
+{
+ struct snd_pcm *pcm;
+ int err;
+
+ if ((err = snd_pcm_new(saa7134->card, "SAA7134 PCM", device, 0, 1, &pcm)) < 0)
+ return err;
+ snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_card_saa7134_capture_ops);
+ pcm->private_data = saa7134;
+ pcm->info_flags = 0;
+ strscpy(pcm->name, "SAA7134 PCM", sizeof(pcm->name));
+ return 0;
+}
+
+#define SAA713x_VOLUME(xname, xindex, addr) \
+{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \
+ .info = snd_saa7134_volume_info, \
+ .get = snd_saa7134_volume_get, .put = snd_saa7134_volume_put, \
+ .private_value = addr }
+
+static int snd_saa7134_volume_info(struct snd_kcontrol * kcontrol,
+ struct snd_ctl_elem_info * uinfo)
+{
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+ uinfo->count = 2;
+ uinfo->value.integer.min = 0;
+ uinfo->value.integer.max = 20;
+ return 0;
+}
+
+static int snd_saa7134_volume_get(struct snd_kcontrol * kcontrol,
+ struct snd_ctl_elem_value * ucontrol)
+{
+ snd_card_saa7134_t *chip = snd_kcontrol_chip(kcontrol);
+ int addr = kcontrol->private_value;
+
+ ucontrol->value.integer.value[0] = chip->mixer_volume[addr][0];
+ ucontrol->value.integer.value[1] = chip->mixer_volume[addr][1];
+ return 0;
+}
+
+static int snd_saa7134_volume_put(struct snd_kcontrol * kcontrol,
+ struct snd_ctl_elem_value * ucontrol)
+{
+ snd_card_saa7134_t *chip = snd_kcontrol_chip(kcontrol);
+ struct saa7134_dev *dev = chip->dev;
+
+ int change, addr = kcontrol->private_value;
+ int left, right;
+
+ left = ucontrol->value.integer.value[0];
+ if (left < 0)
+ left = 0;
+ if (left > 20)
+ left = 20;
+ right = ucontrol->value.integer.value[1];
+ if (right < 0)
+ right = 0;
+ if (right > 20)
+ right = 20;
+ spin_lock_irq(&chip->mixer_lock);
+ change = 0;
+ if (chip->mixer_volume[addr][0] != left) {
+ change = 1;
+ right = left;
+ }
+ if (chip->mixer_volume[addr][1] != right) {
+ change = 1;
+ left = right;
+ }
+ if (change) {
+ switch (dev->pci->device) {
+ case PCI_DEVICE_ID_PHILIPS_SAA7134:
+ switch (addr) {
+ case MIXER_ADDR_TVTUNER:
+ left = 20;
+ break;
+ case MIXER_ADDR_LINE1:
+ saa_andorb(SAA7134_ANALOG_IO_SELECT, 0x10,
+ (left > 10) ? 0x00 : 0x10);
+ break;
+ case MIXER_ADDR_LINE2:
+ saa_andorb(SAA7134_ANALOG_IO_SELECT, 0x20,
+ (left > 10) ? 0x00 : 0x20);
+ break;
+ }
+ break;
+ case PCI_DEVICE_ID_PHILIPS_SAA7133:
+ case PCI_DEVICE_ID_PHILIPS_SAA7135:
+ switch (addr) {
+ case MIXER_ADDR_TVTUNER:
+ left = 20;
+ break;
+ case MIXER_ADDR_LINE1:
+ saa_andorb(0x0594, 0x10,
+ (left > 10) ? 0x00 : 0x10);
+ break;
+ case MIXER_ADDR_LINE2:
+ saa_andorb(0x0594, 0x20,
+ (left > 10) ? 0x00 : 0x20);
+ break;
+ }
+ break;
+ }
+ chip->mixer_volume[addr][0] = left;
+ chip->mixer_volume[addr][1] = right;
+ }
+ spin_unlock_irq(&chip->mixer_lock);
+ return change;
+}
+
+#define SAA713x_CAPSRC(xname, xindex, addr) \
+{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \
+ .info = snd_saa7134_capsrc_info, \
+ .get = snd_saa7134_capsrc_get, .put = snd_saa7134_capsrc_put, \
+ .private_value = addr }
+
+static int snd_saa7134_capsrc_info(struct snd_kcontrol * kcontrol,
+ struct snd_ctl_elem_info * uinfo)
+{
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
+ uinfo->count = 2;
+ uinfo->value.integer.min = 0;
+ uinfo->value.integer.max = 1;
+ return 0;
+}
+
+static int snd_saa7134_capsrc_get(struct snd_kcontrol * kcontrol,
+ struct snd_ctl_elem_value * ucontrol)
+{
+ snd_card_saa7134_t *chip = snd_kcontrol_chip(kcontrol);
+ int addr = kcontrol->private_value;
+
+ spin_lock_irq(&chip->mixer_lock);
+ if (chip->capture_source_addr == addr) {
+ ucontrol->value.integer.value[0] = chip->capture_source[0];
+ ucontrol->value.integer.value[1] = chip->capture_source[1];
+ } else {
+ ucontrol->value.integer.value[0] = 0;
+ ucontrol->value.integer.value[1] = 0;
+ }
+ spin_unlock_irq(&chip->mixer_lock);
+
+ return 0;
+}
+
+static int snd_saa7134_capsrc_put(struct snd_kcontrol * kcontrol,
+ struct snd_ctl_elem_value * ucontrol)
+{
+ int left, right;
+ left = ucontrol->value.integer.value[0] & 1;
+ right = ucontrol->value.integer.value[1] & 1;
+
+ return snd_saa7134_capsrc_set(kcontrol, left, right, false);
+}
+
+static struct snd_kcontrol_new snd_saa7134_volume_controls[] = {
+SAA713x_VOLUME("Video Volume", 0, MIXER_ADDR_TVTUNER),
+SAA713x_VOLUME("Line Volume", 1, MIXER_ADDR_LINE1),
+SAA713x_VOLUME("Line Volume", 2, MIXER_ADDR_LINE2),
+};
+
+static struct snd_kcontrol_new snd_saa7134_capture_controls[] = {
+SAA713x_CAPSRC("Video Capture Switch", 0, MIXER_ADDR_TVTUNER),
+SAA713x_CAPSRC("Line Capture Switch", 1, MIXER_ADDR_LINE1),
+SAA713x_CAPSRC("Line Capture Switch", 2, MIXER_ADDR_LINE2),
+};
+
+/*
+ * ALSA mixer setup
+ *
+ * Called when initializing the board. Sets up the name and hooks up
+ * the callbacks
+ *
+ */
+
+static int snd_card_saa7134_new_mixer(snd_card_saa7134_t * chip)
+{
+ struct snd_card *card = chip->card;
+ struct snd_kcontrol *kcontrol;
+ unsigned int idx;
+ int err, addr;
+
+ strscpy(card->mixername, "SAA7134 Mixer", sizeof(card->mixername));
+
+ for (idx = 0; idx < ARRAY_SIZE(snd_saa7134_volume_controls); idx++) {
+ kcontrol = snd_ctl_new1(&snd_saa7134_volume_controls[idx],
+ chip);
+ err = snd_ctl_add(card, kcontrol);
+ if (err < 0)
+ return err;
+ }
+
+ for (idx = 0; idx < ARRAY_SIZE(snd_saa7134_capture_controls); idx++) {
+ kcontrol = snd_ctl_new1(&snd_saa7134_capture_controls[idx],
+ chip);
+ addr = snd_saa7134_capture_controls[idx].private_value;
+ chip->capture_ctl[addr] = kcontrol;
+ err = snd_ctl_add(card, kcontrol);
+ if (err < 0)
+ return err;
+ }
+
+ chip->capture_source_addr = MIXER_ADDR_UNSELECTED;
+ return 0;
+}
+
+static void snd_saa7134_free(struct snd_card * card)
+{
+ snd_card_saa7134_t *chip = card->private_data;
+
+ if (chip->dev->dmasound.priv_data == NULL)
+ return;
+
+ if (chip->irq >= 0)
+ free_irq(chip->irq, &chip->dev->dmasound);
+
+ chip->dev->dmasound.priv_data = NULL;
+
+}
+
+/*
+ * ALSA initialization
+ *
+ * Called by the init routine, once for each saa7134 device present,
+ * it creates the basic structures and registers the ALSA devices
+ *
+ */
+
+static int alsa_card_saa7134_create(struct saa7134_dev *dev, int devnum)
+{
+
+ struct snd_card *card;
+ snd_card_saa7134_t *chip;
+ int err;
+
+
+ if (devnum >= SNDRV_CARDS)
+ return -ENODEV;
+ if (!enable[devnum])
+ return -ENODEV;
+
+ err = snd_card_new(&dev->pci->dev, index[devnum], id[devnum],
+ THIS_MODULE, sizeof(snd_card_saa7134_t), &card);
+ if (err < 0)
+ return err;
+
+ strscpy(card->driver, "SAA7134", sizeof(card->driver));
+
+ /* Card "creation" */
+
+ card->private_free = snd_saa7134_free;
+ chip = card->private_data;
+
+ spin_lock_init(&chip->lock);
+ spin_lock_init(&chip->mixer_lock);
+
+ chip->dev = dev;
+
+ chip->card = card;
+
+ chip->pci = dev->pci;
+ chip->iobase = pci_resource_start(dev->pci, 0);
+
+
+ err = request_irq(dev->pci->irq, saa7134_alsa_irq,
+ IRQF_SHARED, dev->name,
+ (void*) &dev->dmasound);
+
+ if (err < 0) {
+ pr_err("%s: can't get IRQ %d for ALSA\n",
+ dev->name, dev->pci->irq);
+ goto __nodev;
+ }
+
+ chip->irq = dev->pci->irq;
+
+ mutex_init(&dev->dmasound.lock);
+
+ if ((err = snd_card_saa7134_new_mixer(chip)) < 0)
+ goto __nodev;
+
+ if ((err = snd_card_saa7134_pcm(chip, 0)) < 0)
+ goto __nodev;
+
+ /* End of "creation" */
+
+ strscpy(card->shortname, "SAA7134", sizeof(card->shortname));
+ sprintf(card->longname, "%s at 0x%lx irq %d",
+ chip->dev->name, chip->iobase, chip->irq);
+
+ pr_info("%s/alsa: %s registered as card %d\n",
+ dev->name, card->longname, index[devnum]);
+
+ if ((err = snd_card_register(card)) == 0) {
+ snd_saa7134_cards[devnum] = card;
+ return 0;
+ }
+
+__nodev:
+ snd_card_free(card);
+ return err;
+}
+
+
+static int alsa_device_init(struct saa7134_dev *dev)
+{
+ dev->dmasound.priv_data = dev;
+ alsa_card_saa7134_create(dev,dev->nr);
+ return 1;
+}
+
+static int alsa_device_exit(struct saa7134_dev *dev)
+{
+ if (!snd_saa7134_cards[dev->nr])
+ return 1;
+
+ snd_card_free(snd_saa7134_cards[dev->nr]);
+ snd_saa7134_cards[dev->nr] = NULL;
+ return 1;
+}
+
+/*
+ * Module initializer
+ *
+ * Loops through present saa7134 cards, and assigns an ALSA device
+ * to each one
+ *
+ */
+
+static int saa7134_alsa_init(void)
+{
+ struct saa7134_dev *dev;
+
+ saa7134_dmasound_init = alsa_device_init;
+ saa7134_dmasound_exit = alsa_device_exit;
+
+ pr_info("saa7134 ALSA driver for DMA sound loaded\n");
+
+ list_for_each_entry(dev, &saa7134_devlist, devlist) {
+ if (dev->pci->device == PCI_DEVICE_ID_PHILIPS_SAA7130)
+ pr_info("%s/alsa: %s doesn't support digital audio\n",
+ dev->name, saa7134_boards[dev->board].name);
+ else
+ alsa_device_init(dev);
+ }
+
+ if (list_empty(&saa7134_devlist))
+ pr_info("saa7134 ALSA: no saa7134 cards found\n");
+
+ return 0;
+
+}
+
+/*
+ * Module destructor
+ */
+
+static void saa7134_alsa_exit(void)
+{
+ int idx;
+
+ for (idx = 0; idx < SNDRV_CARDS; idx++) {
+ if (snd_saa7134_cards[idx])
+ snd_card_free(snd_saa7134_cards[idx]);
+ }
+
+ saa7134_dmasound_init = NULL;
+ saa7134_dmasound_exit = NULL;
+ pr_info("saa7134 ALSA driver for DMA sound unloaded\n");
+
+ return;
+}
+
+/* We initialize this late, to make sure the sound system is up and running */
+late_initcall(saa7134_alsa_init);
+module_exit(saa7134_alsa_exit);
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Ricardo Cerqueira");
diff --git a/drivers/media/pci/saa7134/saa7134-cards.c b/drivers/media/pci/saa7134/saa7134-cards.c
new file mode 100644
index 0000000000..1280696f65
--- /dev/null
+++ b/drivers/media/pci/saa7134/saa7134-cards.c
@@ -0,0 +1,8126 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ *
+ * device driver for philips saa7134 based TV cards
+ * card-specific stuff.
+ *
+ * (c) 2001-04 Gerd Knorr <kraxel@bytesex.org> [SuSE Labs]
+ */
+
+#include "saa7134.h"
+#include "saa7134-reg.h"
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/i2c.h>
+#include <linux/i2c-algo-bit.h>
+
+#include "xc2028.h"
+#include <media/v4l2-common.h>
+#include <media/tveeprom.h>
+#include "tea5767.h"
+#include "tda18271.h"
+#include "xc5000.h"
+#include "s5h1411.h"
+
+/* Input names */
+const char * const saa7134_input_name[] = {
+ [SAA7134_INPUT_MUTE] = "mute",
+ [SAA7134_INPUT_RADIO] = "Radio",
+ [SAA7134_INPUT_TV] = "Television",
+ [SAA7134_INPUT_TV_MONO] = "TV (mono only)",
+ [SAA7134_INPUT_COMPOSITE] = "Composite",
+ [SAA7134_INPUT_COMPOSITE0] = "Composite0",
+ [SAA7134_INPUT_COMPOSITE1] = "Composite1",
+ [SAA7134_INPUT_COMPOSITE2] = "Composite2",
+ [SAA7134_INPUT_COMPOSITE3] = "Composite3",
+ [SAA7134_INPUT_COMPOSITE4] = "Composite4",
+ [SAA7134_INPUT_SVIDEO] = "S-Video",
+ [SAA7134_INPUT_SVIDEO0] = "S-Video0",
+ [SAA7134_INPUT_SVIDEO1] = "S-Video1",
+ [SAA7134_INPUT_COMPOSITE_OVER_SVIDEO] = "Composite over S-Video",
+};
+
+/* ------------------------------------------------------------------ */
+/* board config info */
+
+static struct tda18271_std_map aver_a706_std_map = {
+ .fm_radio = { .if_freq = 5500, .fm_rfn = 0, .agc_mode = 3, .std = 0,
+ .if_lvl = 0, .rfagc_top = 0x2c, },
+};
+
+/* If radio_type !=UNSET, radio_addr should be specified
+ */
+
+struct saa7134_board saa7134_boards[] = {
+ [SAA7134_BOARD_UNKNOWN] = {
+ .name = "UNKNOWN/GENERIC",
+ .audio_clock = 0x00187de7,
+ .tuner_type = TUNER_ABSENT,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+
+ .inputs = {{
+ .type = SAA7134_INPUT_COMPOSITE,
+ .vmux = 0,
+ .amux = LINE1,
+ }},
+ },
+ [SAA7134_BOARD_PROTEUS_PRO] = {
+ /* /me */
+ .name = "Proteus Pro [philips reference design]",
+ .audio_clock = 0x00187de7,
+ .tuner_type = TUNER_PHILIPS_PAL,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+
+ .inputs = {{
+ .type = SAA7134_INPUT_COMPOSITE1,
+ .vmux = 0,
+ .amux = LINE1,
+ },{
+ .type = SAA7134_INPUT_TV,
+ .vmux = 1,
+ .amux = TV,
+ },{
+ .type = SAA7134_INPUT_TV_MONO,
+ .vmux = 1,
+ .amux = LINE2,
+ }},
+ .radio = {
+ .type = SAA7134_INPUT_RADIO,
+ .amux = LINE2,
+ },
+ },
+ [SAA7134_BOARD_FLYVIDEO3000] = {
+ /* "Marco d'Itri" <md@Linux.IT> */
+ .name = "LifeView FlyVIDEO3000",
+ .audio_clock = 0x00200000,
+ .tuner_type = TUNER_PHILIPS_PAL,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+
+ .gpiomask = 0xe000,
+ .inputs = {{
+ .type = SAA7134_INPUT_TV,
+ .vmux = 1,
+ .amux = TV,
+ .gpio = 0x8000,
+ },{
+ .type = SAA7134_INPUT_TV_MONO,
+ .vmux = 1,
+ .amux = LINE2,
+ .gpio = 0x0000,
+ },{
+ .type = SAA7134_INPUT_COMPOSITE1,
+ .vmux = 0,
+ .amux = LINE2,
+ .gpio = 0x4000,
+ },{
+ .type = SAA7134_INPUT_COMPOSITE2,
+ .vmux = 3,
+ .amux = LINE2,
+ .gpio = 0x4000,
+ },{
+ .type = SAA7134_INPUT_SVIDEO,
+ .vmux = 8,
+ .amux = LINE2,
+ .gpio = 0x4000,
+ }},
+ .radio = {
+ .type = SAA7134_INPUT_RADIO,
+ .amux = LINE2,
+ .gpio = 0x2000,
+ },
+ .mute = {
+ .type = SAA7134_INPUT_MUTE,
+ .amux = TV,
+ .gpio = 0x8000,
+ },
+ },
+ [SAA7134_BOARD_FLYVIDEO2000] = {
+ /* "TC Wan" <tcwan@cs.usm.my> */
+ .name = "LifeView/Typhoon FlyVIDEO2000",
+ .audio_clock = 0x00200000,
+ .tuner_type = TUNER_LG_PAL_NEW_TAPC,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+
+ .gpiomask = 0xe000,
+ .inputs = {{
+ .type = SAA7134_INPUT_TV,
+ .vmux = 1,
+ .amux = LINE2,
+ .gpio = 0x0000,
+ },{
+ .type = SAA7134_INPUT_COMPOSITE1,
+ .vmux = 0,
+ .amux = LINE2,
+ .gpio = 0x4000,
+ },{
+ .type = SAA7134_INPUT_COMPOSITE2,
+ .vmux = 3,
+ .amux = LINE2,
+ .gpio = 0x4000,
+ },{
+ .type = SAA7134_INPUT_SVIDEO,
+ .vmux = 8,
+ .amux = LINE2,
+ .gpio = 0x4000,
+ }},
+ .radio = {
+ .type = SAA7134_INPUT_RADIO,
+ .amux = LINE2,
+ .gpio = 0x2000,
+ },
+ .mute = {
+ .type = SAA7134_INPUT_MUTE,
+ .amux = LINE2,
+ .gpio = 0x8000,
+ },
+ },
+ [SAA7134_BOARD_FLYTVPLATINUM_MINI] = {
+ /* "Arnaud Quette" <aquette@free.fr> */
+ .name = "LifeView FlyTV Platinum Mini",
+ .audio_clock = 0x00200000,
+ .tuner_type = TUNER_PHILIPS_TDA8290,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+
+ .inputs = {{
+ .type = SAA7134_INPUT_TV,
+ .vmux = 1,
+ .amux = TV,
+ },{
+ .type = SAA7134_INPUT_COMPOSITE_OVER_SVIDEO,
+ .vmux = 0,
+ .amux = LINE2,
+ },{
+ .type = SAA7134_INPUT_COMPOSITE,
+ .vmux = 3,
+ .amux = LINE2,
+ },{
+ .type = SAA7134_INPUT_SVIDEO,
+ .vmux = 8,
+ .amux = LINE2,
+ }},
+ },
+ [SAA7134_BOARD_FLYTVPLATINUM_FM] = {
+ /* LifeView FlyTV Platinum FM (LR214WF) */
+ /* "Peter Missel <peter.missel@onlinehome.de> */
+ .name = "LifeView FlyTV Platinum FM / Gold",
+ .audio_clock = 0x00200000,
+ .tuner_type = TUNER_PHILIPS_TDA8290,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+
+ .gpiomask = 0x1E000, /* Set GP16 and unused 15,14,13 to Output */
+ .inputs = {{
+ .type = SAA7134_INPUT_TV,
+ .vmux = 1,
+ .amux = TV,
+ .gpio = 0x10000, /* GP16=1 selects TV input */
+ },{
+/* .type = SAA7134_INPUT_TV_MONO,
+ .vmux = 1,
+ .amux = LINE2,
+ .gpio = 0x0000,
+ },{
+*/ .type = SAA7134_INPUT_COMPOSITE_OVER_SVIDEO,
+ .vmux = 0,
+ .amux = LINE2,
+/* .gpio = 0x4000, */
+ },{
+ .type = SAA7134_INPUT_COMPOSITE,
+ .vmux = 3,
+ .amux = LINE2,
+/* .gpio = 0x4000, */
+ },{
+ .type = SAA7134_INPUT_SVIDEO,
+ .vmux = 8,
+ .amux = LINE2,
+/* .gpio = 0x4000, */
+ }},
+ .radio = {
+ .type = SAA7134_INPUT_RADIO,
+ .amux = TV,
+ .gpio = 0x00000, /* GP16=0 selects FM radio antenna */
+ },
+ .mute = {
+ .type = SAA7134_INPUT_MUTE,
+ .amux = TV,
+ .gpio = 0x10000,
+ },
+ },
+ [SAA7134_BOARD_ROVERMEDIA_LINK_PRO_FM] = {
+ /* RoverMedia TV Link Pro FM (LR138 REV:I) */
+ /* Eugene Yudin <Eugene.Yudin@gmail.com> */
+ .name = "RoverMedia TV Link Pro FM",
+ .audio_clock = 0x00200000,
+ .tuner_type = TUNER_PHILIPS_FM1216ME_MK3, /* TCL MFPE05 2 */
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .tda9887_conf = TDA9887_PRESENT,
+ .gpiomask = 0xe000,
+ .inputs = { {
+ .type = SAA7134_INPUT_TV,
+ .vmux = 1,
+ .amux = TV,
+ .gpio = 0x8000,
+ }, {
+ .type = SAA7134_INPUT_TV_MONO,
+ .vmux = 1,
+ .amux = LINE2,
+ .gpio = 0x0000,
+ }, {
+ .type = SAA7134_INPUT_COMPOSITE1,
+ .vmux = 0,
+ .amux = LINE2,
+ .gpio = 0x4000,
+ }, {
+ .type = SAA7134_INPUT_COMPOSITE2,
+ .vmux = 3,
+ .amux = LINE2,
+ .gpio = 0x4000,
+ }, {
+ .type = SAA7134_INPUT_SVIDEO,
+ .vmux = 8,
+ .amux = LINE2,
+ .gpio = 0x4000,
+ } },
+ .radio = {
+ .type = SAA7134_INPUT_RADIO,
+ .amux = LINE2,
+ .gpio = 0x2000,
+ },
+ .mute = {
+ .type = SAA7134_INPUT_MUTE,
+ .amux = TV,
+ .gpio = 0x8000,
+ },
+ },
+ [SAA7134_BOARD_EMPRESS] = {
+ /* "Gert Vervoort" <gert.vervoort@philips.com> */
+ .name = "EMPRESS",
+ .audio_clock = 0x00187de7,
+ .tuner_type = TUNER_PHILIPS_PAL,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .empress_addr = 0x20,
+
+ .inputs = {{
+ .type = SAA7134_INPUT_COMPOSITE1,
+ .vmux = 0,
+ .amux = LINE1,
+ },{
+ .type = SAA7134_INPUT_SVIDEO,
+ .vmux = 8,
+ .amux = LINE1,
+ },{
+ .type = SAA7134_INPUT_TV,
+ .vmux = 1,
+ .amux = LINE2,
+ }},
+ .radio = {
+ .type = SAA7134_INPUT_RADIO,
+ .amux = LINE2,
+ },
+ .mpeg = SAA7134_MPEG_EMPRESS,
+ .video_out = CCIR656,
+ },
+ [SAA7134_BOARD_MONSTERTV] = {
+ /* "K.Ohta" <alpha292@bremen.or.jp> */
+ .name = "SKNet Monster TV",
+ .audio_clock = 0x00187de7,
+ .tuner_type = TUNER_PHILIPS_NTSC_M,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+
+ .inputs = {{
+ .type = SAA7134_INPUT_TV,
+ .vmux = 1,
+ .amux = TV,
+ },{
+ .type = SAA7134_INPUT_COMPOSITE1,
+ .vmux = 0,
+ .amux = LINE1,
+ },{
+ .type = SAA7134_INPUT_SVIDEO,
+ .vmux = 8,
+ .amux = LINE1,
+ }},
+ .radio = {
+ .type = SAA7134_INPUT_RADIO,
+ .amux = LINE2,
+ },
+ },
+ [SAA7134_BOARD_MD9717] = {
+ .name = "Tevion MD 9717",
+ .audio_clock = 0x00200000,
+ .tuner_type = TUNER_PHILIPS_PAL,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .inputs = {{
+ .type = SAA7134_INPUT_TV,
+ .vmux = 1,
+ .amux = TV,
+ },{
+ /* workaround for problems with normal TV sound */
+ .type = SAA7134_INPUT_TV_MONO,
+ .vmux = 1,
+ .amux = LINE2,
+ },{
+ .type = SAA7134_INPUT_COMPOSITE1,
+ .vmux = 0,
+ .amux = LINE1,
+ },{
+ .type = SAA7134_INPUT_COMPOSITE2,
+ .vmux = 3,
+ .amux = LINE1,
+ },{
+ .type = SAA7134_INPUT_SVIDEO,
+ .vmux = 8,
+ .amux = LINE1,
+ }},
+ .radio = {
+ .type = SAA7134_INPUT_RADIO,
+ .amux = LINE2,
+ },
+ .mute = {
+ .type = SAA7134_INPUT_MUTE,
+ .amux = TV,
+ },
+ },
+ [SAA7134_BOARD_TVSTATION_RDS] = {
+ /* Typhoon TV Tuner RDS: Art.Nr. 50694 */
+ .name = "KNC One TV-Station RDS / Typhoon TV Tuner RDS",
+ .audio_clock = 0x00200000,
+ .tuner_type = TUNER_PHILIPS_FM1216ME_MK3,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .tda9887_conf = TDA9887_PRESENT,
+ .inputs = {{
+ .type = SAA7134_INPUT_TV,
+ .vmux = 1,
+ .amux = TV,
+ },{
+ .type = SAA7134_INPUT_TV_MONO,
+ .vmux = 1,
+ .amux = LINE2,
+ },{
+
+ .type = SAA7134_INPUT_SVIDEO,
+ .vmux = 8,
+ .amux = LINE1,
+ },{
+ .type = SAA7134_INPUT_COMPOSITE1,
+ .vmux = 3,
+ .amux = LINE1,
+ },{
+
+ .type = SAA7134_INPUT_COMPOSITE_OVER_SVIDEO,
+ .vmux = 0,
+ .amux = LINE1,
+ }},
+ .radio = {
+ .type = SAA7134_INPUT_RADIO,
+ .amux = LINE2,
+ },
+ },
+ [SAA7134_BOARD_TVSTATION_DVR] = {
+ .name = "KNC One TV-Station DVR",
+ .audio_clock = 0x00200000,
+ .tuner_type = TUNER_PHILIPS_FM1216ME_MK3,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .empress_addr = 0x20,
+ .tda9887_conf = TDA9887_PRESENT,
+ .gpiomask = 0x820000,
+ .inputs = {{
+ .type = SAA7134_INPUT_TV,
+ .vmux = 1,
+ .amux = TV,
+ .gpio = 0x20000,
+ },{
+ .type = SAA7134_INPUT_SVIDEO,
+ .vmux = 8,
+ .amux = LINE1,
+ .gpio = 0x20000,
+ },{
+ .type = SAA7134_INPUT_COMPOSITE1,
+ .vmux = 3,
+ .amux = LINE1,
+ .gpio = 0x20000,
+ }},
+ .radio = {
+ .type = SAA7134_INPUT_RADIO,
+ .amux = LINE2,
+ .gpio = 0x20000,
+ },
+ .mpeg = SAA7134_MPEG_EMPRESS,
+ .video_out = CCIR656,
+ },
+ [SAA7134_BOARD_CINERGY400] = {
+ .name = "Terratec Cinergy 400 TV",
+ .audio_clock = 0x00200000,
+ .tuner_type = TUNER_PHILIPS_PAL,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .inputs = {{
+ .type = SAA7134_INPUT_TV,
+ .vmux = 1,
+ .amux = TV,
+ },{
+ .type = SAA7134_INPUT_COMPOSITE,
+ .vmux = 4,
+ .amux = LINE1,
+ },{
+ .type = SAA7134_INPUT_SVIDEO,
+ .vmux = 8,
+ .amux = LINE1,
+ },{
+ .type = SAA7134_INPUT_COMPOSITE_OVER_SVIDEO,
+ .vmux = 0,
+ .amux = LINE1,
+ }}
+ },
+ [SAA7134_BOARD_MD5044] = {
+ .name = "Medion 5044",
+ .audio_clock = 0x00187de7, /* was: 0x00200000, */
+ .tuner_type = TUNER_PHILIPS_FM1216ME_MK3,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .tda9887_conf = TDA9887_PRESENT,
+ .inputs = {{
+ .type = SAA7134_INPUT_TV,
+ .vmux = 1,
+ .amux = TV,
+ },{
+ /* workaround for problems with normal TV sound */
+ .type = SAA7134_INPUT_TV_MONO,
+ .vmux = 1,
+ .amux = LINE2,
+ },{
+ .type = SAA7134_INPUT_COMPOSITE1,
+ .vmux = 0,
+ .amux = LINE2,
+ },{
+ .type = SAA7134_INPUT_COMPOSITE2,
+ .vmux = 3,
+ .amux = LINE2,
+ },{
+ .type = SAA7134_INPUT_SVIDEO,
+ .vmux = 8,
+ .amux = LINE2,
+ }},
+ .radio = {
+ .type = SAA7134_INPUT_RADIO,
+ .amux = LINE2,
+ },
+ },
+ [SAA7134_BOARD_KWORLD] = {
+ .name = "Kworld/KuroutoShikou SAA7130-TVPCI",
+ .audio_clock = 0x00187de7,
+ .tuner_type = TUNER_PHILIPS_NTSC_M,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .inputs = {{
+ .type = SAA7134_INPUT_SVIDEO,
+ .vmux = 8,
+ .amux = LINE1,
+ },{
+ .type = SAA7134_INPUT_COMPOSITE1,
+ .vmux = 3,
+ .amux = LINE1,
+ },{
+ .type = SAA7134_INPUT_TV,
+ .vmux = 1,
+ .amux = LINE2,
+ }},
+ },
+ [SAA7134_BOARD_CINERGY600] = {
+ .name = "Terratec Cinergy 600 TV",
+ .audio_clock = 0x00200000,
+ .tuner_type = TUNER_PHILIPS_PAL,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .tda9887_conf = TDA9887_PRESENT,
+ .inputs = {{
+ .type = SAA7134_INPUT_TV,
+ .vmux = 1,
+ .amux = TV,
+ },{
+ .type = SAA7134_INPUT_COMPOSITE1,
+ .vmux = 4,
+ .amux = LINE1,
+ },{
+ .type = SAA7134_INPUT_SVIDEO,
+ .vmux = 8,
+ .amux = LINE1,
+ },{
+ .type = SAA7134_INPUT_COMPOSITE_OVER_SVIDEO,
+ .vmux = 0,
+ .amux = LINE1,
+ }},
+ .radio = {
+ .type = SAA7134_INPUT_RADIO,
+ .amux = LINE2,
+ },
+ },
+ [SAA7134_BOARD_MD7134] = {
+ .name = "Medion 7134",
+ .audio_clock = 0x00187de7,
+ .tuner_type = TUNER_PHILIPS_FMD1216ME_MK3,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .tda9887_conf = TDA9887_PRESENT,
+ .mpeg = SAA7134_MPEG_DVB,
+ .inputs = {{
+ .type = SAA7134_INPUT_TV,
+ .vmux = 1,
+ .amux = TV,
+ },{
+ .type = SAA7134_INPUT_COMPOSITE1,
+ .vmux = 0,
+ .amux = LINE1,
+ },{
+ .type = SAA7134_INPUT_SVIDEO,
+ .vmux = 8,
+ .amux = LINE1,
+ }},
+ .radio = {
+ .type = SAA7134_INPUT_RADIO,
+ .amux = LINE2,
+ },
+ .mute = {
+ .type = SAA7134_INPUT_MUTE,
+ .amux = TV,
+ },
+ },
+ [SAA7134_BOARD_TYPHOON_90031] = {
+ /* aka Typhoon "TV+Radio", Art.Nr 90031 */
+ /* Tom Zoerner <tomzo at users sourceforge net> */
+ .name = "Typhoon TV+Radio 90031",
+ .audio_clock = 0x00200000,
+ .tuner_type = TUNER_PHILIPS_PAL,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .tda9887_conf = TDA9887_PRESENT,
+ .inputs = {{
+ .type = SAA7134_INPUT_TV,
+ .vmux = 1,
+ .amux = TV,
+ },{
+ .type = SAA7134_INPUT_COMPOSITE1,
+ .vmux = 3,
+ .amux = LINE1,
+ },{
+ .type = SAA7134_INPUT_SVIDEO,
+ .vmux = 8,
+ .amux = LINE1,
+ }},
+ .radio = {
+ .type = SAA7134_INPUT_RADIO,
+ .amux = LINE2,
+ },
+ },
+ [SAA7134_BOARD_ELSA] = {
+ .name = "ELSA EX-VISION 300TV",
+ .audio_clock = 0x00187de7,
+ .tuner_type = TUNER_HITACHI_NTSC,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .inputs = {{
+ .type = SAA7134_INPUT_SVIDEO,
+ .vmux = 8,
+ .amux = LINE1,
+ },{
+ .type = SAA7134_INPUT_COMPOSITE1,
+ .vmux = 0,
+ .amux = LINE1,
+ },{
+ .type = SAA7134_INPUT_TV,
+ .vmux = 4,
+ .amux = LINE2,
+ }},
+ },
+ [SAA7134_BOARD_ELSA_500TV] = {
+ .name = "ELSA EX-VISION 500TV",
+ .audio_clock = 0x00187de7,
+ .tuner_type = TUNER_HITACHI_NTSC,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .inputs = {{
+ .type = SAA7134_INPUT_SVIDEO,
+ .vmux = 7,
+ .amux = LINE1,
+ },{
+ .type = SAA7134_INPUT_TV,
+ .vmux = 8,
+ .amux = TV,
+ },{
+ .type = SAA7134_INPUT_TV_MONO,
+ .vmux = 8,
+ .amux = LINE2,
+ }},
+ },
+ [SAA7134_BOARD_ELSA_700TV] = {
+ .name = "ELSA EX-VISION 700TV",
+ .audio_clock = 0x00187de7,
+ .tuner_type = TUNER_HITACHI_NTSC,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .inputs = {{
+ .type = SAA7134_INPUT_TV,
+ .vmux = 4,
+ .amux = LINE2,
+ },{
+ .type = SAA7134_INPUT_COMPOSITE1,
+ .vmux = 6,
+ .amux = LINE1,
+ },{
+ .type = SAA7134_INPUT_SVIDEO,
+ .vmux = 7,
+ .amux = LINE1,
+ }},
+ .mute = {
+ .type = SAA7134_INPUT_MUTE,
+ .amux = TV,
+ },
+ },
+ [SAA7134_BOARD_ASUSTeK_TVFM7134] = {
+ .name = "ASUS TV-FM 7134",
+ .audio_clock = 0x00187de7,
+ .tuner_type = TUNER_PHILIPS_FM1216ME_MK3,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .tda9887_conf = TDA9887_PRESENT,
+ .inputs = {{
+ .type = SAA7134_INPUT_TV,
+ .vmux = 1,
+ .amux = TV,
+ },{
+ .type = SAA7134_INPUT_COMPOSITE1,
+ .vmux = 4,
+ .amux = LINE2,
+ },{
+ .type = SAA7134_INPUT_SVIDEO,
+ .vmux = 6,
+ .amux = LINE2,
+ }},
+ .radio = {
+ .type = SAA7134_INPUT_RADIO,
+ .amux = LINE1,
+ },
+ },
+ [SAA7134_BOARD_ASUSTeK_TVFM7135] = {
+ .name = "ASUS TV-FM 7135",
+ .audio_clock = 0x00187de7,
+ .tuner_type = TUNER_PHILIPS_TDA8290,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .gpiomask = 0x200000,
+ .inputs = {{
+ .type = SAA7134_INPUT_TV,
+ .vmux = 1,
+ .amux = TV,
+ .gpio = 0x0000,
+ },{
+ .type = SAA7134_INPUT_COMPOSITE1,
+ .vmux = 4,
+ .amux = LINE2,
+ .gpio = 0x0000,
+ },{
+ .type = SAA7134_INPUT_SVIDEO,
+ .vmux = 6,
+ .amux = LINE2,
+ .gpio = 0x0000,
+ }},
+ .radio = {
+ .type = SAA7134_INPUT_RADIO,
+ .amux = TV,
+ .gpio = 0x200000,
+ },
+ .mute = {
+ .type = SAA7134_INPUT_MUTE,
+ .gpio = 0x0000,
+ },
+
+ },
+ [SAA7134_BOARD_VA1000POWER] = {
+ .name = "AOPEN VA1000 POWER",
+ .audio_clock = 0x00187de7,
+ .tuner_type = TUNER_PHILIPS_NTSC,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .inputs = {{
+ .type = SAA7134_INPUT_SVIDEO,
+ .vmux = 8,
+ .amux = LINE1,
+ },{
+ .type = SAA7134_INPUT_COMPOSITE1,
+ .vmux = 3,
+ .amux = LINE1,
+ },{
+ .type = SAA7134_INPUT_TV,
+ .vmux = 1,
+ .amux = LINE2,
+ }},
+ },
+ [SAA7134_BOARD_10MOONSTVMASTER] = {
+ /* "lilicheng" <llc@linuxfans.org> */
+ .name = "10MOONS PCI TV CAPTURE CARD",
+ .audio_clock = 0x00200000,
+ .tuner_type = TUNER_LG_PAL_NEW_TAPC,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .gpiomask = 0xe000,
+ .inputs = {{
+ .type = SAA7134_INPUT_TV,
+ .vmux = 1,
+ .amux = LINE2,
+ .gpio = 0x0000,
+ },{
+ .type = SAA7134_INPUT_COMPOSITE1,
+ .vmux = 0,
+ .amux = LINE2,
+ .gpio = 0x4000,
+ },{
+ .type = SAA7134_INPUT_COMPOSITE2,
+ .vmux = 3,
+ .amux = LINE2,
+ .gpio = 0x4000,
+ },{
+ .type = SAA7134_INPUT_SVIDEO,
+ .vmux = 8,
+ .amux = LINE2,
+ .gpio = 0x4000,
+ }},
+ .radio = {
+ .type = SAA7134_INPUT_RADIO,
+ .amux = LINE2,
+ .gpio = 0x2000,
+ },
+ .mute = {
+ .type = SAA7134_INPUT_MUTE,
+ .amux = LINE2,
+ .gpio = 0x8000,
+ },
+ },
+ [SAA7134_BOARD_BMK_MPEX_NOTUNER] = {
+ /* "Andrew de Quincey" <adq@lidskialf.net> */
+ .name = "BMK MPEX No Tuner",
+ .audio_clock = 0x200000,
+ .tuner_type = TUNER_ABSENT,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .empress_addr = 0x20,
+ .inputs = {{
+ .type = SAA7134_INPUT_COMPOSITE1,
+ .vmux = 4,
+ .amux = LINE1,
+ },{
+ .type = SAA7134_INPUT_COMPOSITE2,
+ .vmux = 3,
+ .amux = LINE1,
+ },{
+ .type = SAA7134_INPUT_COMPOSITE3,
+ .vmux = 0,
+ .amux = LINE1,
+ },{
+ .type = SAA7134_INPUT_COMPOSITE4,
+ .vmux = 1,
+ .amux = LINE1,
+ },{
+ .type = SAA7134_INPUT_SVIDEO,
+ .vmux = 8,
+ .amux = LINE1,
+ }},
+ .mpeg = SAA7134_MPEG_EMPRESS,
+ .video_out = CCIR656,
+ },
+ [SAA7134_BOARD_VIDEOMATE_TV] = {
+ .name = "Compro VideoMate TV",
+ .audio_clock = 0x00187de7,
+ .tuner_type = TUNER_PHILIPS_NTSC_M,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .inputs = {{
+ .type = SAA7134_INPUT_SVIDEO,
+ .vmux = 8,
+ .amux = LINE1,
+ },{
+ .type = SAA7134_INPUT_COMPOSITE1,
+ .vmux = 3,
+ .amux = LINE1,
+ },{
+ .type = SAA7134_INPUT_TV,
+ .vmux = 1,
+ .amux = LINE2,
+ }},
+ },
+ [SAA7134_BOARD_VIDEOMATE_TV_GOLD_PLUS] = {
+ .name = "Compro VideoMate TV Gold+",
+ .audio_clock = 0x00187de7,
+ .tuner_type = TUNER_PHILIPS_NTSC_M,
+ .gpiomask = 0x800c0000,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .inputs = {{
+ .type = SAA7134_INPUT_SVIDEO,
+ .vmux = 8,
+ .amux = LINE1,
+ .gpio = 0x06c00012,
+ },{
+ .type = SAA7134_INPUT_COMPOSITE1,
+ .vmux = 3,
+ .amux = LINE1,
+ .gpio = 0x0ac20012,
+ },{
+ .type = SAA7134_INPUT_TV,
+ .vmux = 1,
+ .amux = LINE2,
+ .gpio = 0x08c20012,
+ }}, /* radio and probably mute is missing */
+ },
+ [SAA7134_BOARD_CRONOS_PLUS] = {
+ /*
+ gpio pins:
+ 0 .. 3 BASE_ID
+ 4 .. 7 PROTECT_ID
+ 8 .. 11 USER_OUT
+ 12 .. 13 USER_IN
+ 14 .. 15 VIDIN_SEL
+ */
+ .name = "Matrox CronosPlus",
+ .tuner_type = TUNER_ABSENT,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .gpiomask = 0xcf00,
+ .inputs = {{
+ .type = SAA7134_INPUT_COMPOSITE1,
+ .vmux = 0,
+ .gpio = 2 << 14,
+ },{
+ .type = SAA7134_INPUT_COMPOSITE2,
+ .vmux = 0,
+ .gpio = 1 << 14,
+ },{
+ .type = SAA7134_INPUT_COMPOSITE3,
+ .vmux = 0,
+ .gpio = 0 << 14,
+ },{
+ .type = SAA7134_INPUT_COMPOSITE4,
+ .vmux = 0,
+ .gpio = 3 << 14,
+ },{
+ .type = SAA7134_INPUT_SVIDEO,
+ .vmux = 8,
+ .gpio = 2 << 14,
+ }},
+ },
+ [SAA7134_BOARD_MD2819] = {
+ .name = "AverMedia M156 / Medion 2819",
+ .audio_clock = 0x00187de7,
+ .tuner_type = TUNER_PHILIPS_FM1216ME_MK3,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .tda9887_conf = TDA9887_PRESENT,
+ .gpiomask = 0x03,
+ .inputs = {{
+ .type = SAA7134_INPUT_TV,
+ .vmux = 1,
+ .amux = TV,
+ .gpio = 0x00,
+ }, {
+ .type = SAA7134_INPUT_COMPOSITE1,
+ .vmux = 3,
+ .amux = LINE1,
+ .gpio = 0x02,
+ }, {
+ .type = SAA7134_INPUT_COMPOSITE2,
+ .vmux = 0,
+ .amux = LINE1,
+ .gpio = 0x02,
+ }, {
+ .type = SAA7134_INPUT_SVIDEO,
+ .vmux = 8,
+ .amux = LINE1,
+ .gpio = 0x02,
+ } },
+ .radio = {
+ .type = SAA7134_INPUT_RADIO,
+ .amux = LINE1,
+ .gpio = 0x01,
+ },
+ .mute = {
+ .type = SAA7134_INPUT_MUTE,
+ .amux = TV,
+ .gpio = 0x00,
+ },
+ },
+ [SAA7134_BOARD_BMK_MPEX_TUNER] = {
+ /* "Greg Wickham <greg.wickham@grangenet.net> */
+ .name = "BMK MPEX Tuner",
+ .audio_clock = 0x200000,
+ .tuner_type = TUNER_PHILIPS_PAL,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .empress_addr = 0x20,
+ .inputs = {{
+ .type = SAA7134_INPUT_COMPOSITE1,
+ .vmux = 1,
+ .amux = LINE1,
+ },{
+ .type = SAA7134_INPUT_SVIDEO,
+ .vmux = 8,
+ .amux = LINE1,
+ },{
+ .type = SAA7134_INPUT_TV,
+ .vmux = 3,
+ .amux = TV,
+ }},
+ .mpeg = SAA7134_MPEG_EMPRESS,
+ .video_out = CCIR656,
+ },
+ [SAA7134_BOARD_ASUSTEK_TVFM7133] = {
+ .name = "ASUS TV-FM 7133",
+ .audio_clock = 0x00187de7,
+ /* probably wrong, the 7133 one is the NTSC version ...
+ * .tuner_type = TUNER_PHILIPS_FM1236_MK3 */
+ .tuner_type = TUNER_LG_NTSC_NEW_TAPC,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .tda9887_conf = TDA9887_PRESENT,
+ .inputs = {{
+ .type = SAA7134_INPUT_TV,
+ .vmux = 1,
+ .amux = TV,
+
+ },{
+ .type = SAA7134_INPUT_COMPOSITE1,
+ .vmux = 4,
+ .amux = LINE2,
+ },{
+ .type = SAA7134_INPUT_SVIDEO,
+ .vmux = 6,
+ .amux = LINE2,
+ }},
+ .radio = {
+ .type = SAA7134_INPUT_RADIO,
+ .amux = LINE1,
+ },
+ },
+ [SAA7134_BOARD_PINNACLE_PCTV_STEREO] = {
+ .name = "Pinnacle PCTV Stereo (saa7134)",
+ .audio_clock = 0x00187de7,
+ .tuner_type = TUNER_MT2032,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .tda9887_conf = TDA9887_PRESENT | TDA9887_INTERCARRIER | TDA9887_PORT2_INACTIVE,
+ .inputs = {{
+ .type = SAA7134_INPUT_TV,
+ .vmux = 3,
+ .amux = TV,
+ },{
+ .type = SAA7134_INPUT_COMPOSITE1,
+ .vmux = 0,
+ .amux = LINE2,
+ },{
+ .type = SAA7134_INPUT_COMPOSITE2,
+ .vmux = 1,
+ .amux = LINE2,
+ },{
+ .type = SAA7134_INPUT_SVIDEO,
+ .vmux = 8,
+ .amux = LINE2,
+ }},
+ },
+ [SAA7134_BOARD_MANLI_MTV002] = {
+ /* Ognjen Nastic <ognjen@logosoft.ba> */
+ .name = "Manli MuchTV M-TV002",
+ .audio_clock = 0x00200000,
+ .tuner_type = TUNER_PHILIPS_PAL,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .inputs = {{
+ .type = SAA7134_INPUT_SVIDEO,
+ .vmux = 8,
+ .amux = LINE1,
+ },{
+ .type = SAA7134_INPUT_COMPOSITE1,
+ .vmux = 1,
+ .amux = LINE1,
+ },{
+ .type = SAA7134_INPUT_TV,
+ .vmux = 3,
+ .amux = LINE2,
+ }},
+ .radio = {
+ .type = SAA7134_INPUT_RADIO,
+ .amux = LINE2,
+ },
+ },
+ [SAA7134_BOARD_MANLI_MTV001] = {
+ /* Ognjen Nastic <ognjen@logosoft.ba> UNTESTED */
+ .name = "Manli MuchTV M-TV001",
+ .audio_clock = 0x00200000,
+ .tuner_type = TUNER_PHILIPS_PAL,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .inputs = {{
+ .type = SAA7134_INPUT_SVIDEO,
+ .vmux = 8,
+ .amux = LINE1,
+ },{
+ .type = SAA7134_INPUT_COMPOSITE1,
+ .vmux = 1,
+ .amux = LINE1,
+ },{
+ .type = SAA7134_INPUT_TV,
+ .vmux = 3,
+ .amux = LINE2,
+ }},
+ .mute = {
+ .type = SAA7134_INPUT_MUTE,
+ .amux = LINE1,
+ },
+ },
+ [SAA7134_BOARD_TG3000TV] = {
+ /* TransGear 3000TV */
+ .name = "Nagase Sangyo TransGear 3000TV",
+ .audio_clock = 0x00187de7,
+ .tuner_type = TUNER_PHILIPS_NTSC_M,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .inputs = {{
+ .type = SAA7134_INPUT_TV,
+ .vmux = 1,
+ .amux = LINE2,
+ },{
+ .type = SAA7134_INPUT_COMPOSITE1,
+ .vmux = 3,
+ .amux = LINE2,
+ },{
+ .type = SAA7134_INPUT_SVIDEO,
+ .vmux = 8,
+ .amux = LINE2,
+ }},
+ },
+ [SAA7134_BOARD_ECS_TVP3XP] = {
+ .name = "Elitegroup ECS TVP3XP FM1216 Tuner Card(PAL-BG,FM) ",
+ .audio_clock = 0x187de7, /* xtal 32.1 MHz */
+ .tuner_type = TUNER_PHILIPS_PAL,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .inputs = {{
+ .type = SAA7134_INPUT_TV,
+ .vmux = 1,
+ .amux = TV,
+ },{
+ .type = SAA7134_INPUT_TV_MONO,
+ .vmux = 1,
+ .amux = LINE2,
+ },{
+ .type = SAA7134_INPUT_COMPOSITE1,
+ .vmux = 3,
+ .amux = LINE1,
+ },{
+ .type = SAA7134_INPUT_SVIDEO,
+ .vmux = 8,
+ .amux = LINE1,
+ },{
+ .type = SAA7134_INPUT_COMPOSITE_OVER_SVIDEO,
+ .vmux = 0,
+ .amux = LINE1,
+ }},
+ .radio = {
+ .type = SAA7134_INPUT_RADIO,
+ .amux = LINE2,
+ },
+ },
+ [SAA7134_BOARD_ECS_TVP3XP_4CB5] = {
+ .name = "Elitegroup ECS TVP3XP FM1236 Tuner Card (NTSC,FM)",
+ .audio_clock = 0x187de7,
+ .tuner_type = TUNER_PHILIPS_NTSC,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .inputs = {{
+ .type = SAA7134_INPUT_TV,
+ .vmux = 1,
+ .amux = TV,
+ },{
+ .type = SAA7134_INPUT_TV_MONO,
+ .vmux = 1,
+ .amux = LINE2,
+ },{
+ .type = SAA7134_INPUT_COMPOSITE1,
+ .vmux = 3,
+ .amux = LINE1,
+ },{
+ .type = SAA7134_INPUT_SVIDEO,
+ .vmux = 8,
+ .amux = LINE1,
+ },{
+ .type = SAA7134_INPUT_COMPOSITE_OVER_SVIDEO,
+ .vmux = 0,
+ .amux = LINE1,
+ }},
+ .radio = {
+ .type = SAA7134_INPUT_RADIO,
+ .amux = LINE2,
+ },
+ },
+ [SAA7134_BOARD_ECS_TVP3XP_4CB6] = {
+ /* Barry Scott <barry.scott@onelan.co.uk> */
+ .name = "Elitegroup ECS TVP3XP FM1246 Tuner Card (PAL,FM)",
+ .audio_clock = 0x187de7,
+ .tuner_type = TUNER_PHILIPS_PAL_I,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .inputs = {{
+ .type = SAA7134_INPUT_TV,
+ .vmux = 1,
+ .amux = TV,
+ },{
+ .type = SAA7134_INPUT_TV_MONO,
+ .vmux = 1,
+ .amux = LINE2,
+ },{
+ .type = SAA7134_INPUT_COMPOSITE1,
+ .vmux = 3,
+ .amux = LINE1,
+ },{
+ .type = SAA7134_INPUT_SVIDEO,
+ .vmux = 8,
+ .amux = LINE1,
+ },{
+ .type = SAA7134_INPUT_COMPOSITE_OVER_SVIDEO,
+ .vmux = 0,
+ .amux = LINE1,
+ }},
+ .radio = {
+ .type = SAA7134_INPUT_RADIO,
+ .amux = LINE2,
+ },
+ },
+ [SAA7134_BOARD_AVACSSMARTTV] = {
+ /* Roman Pszonczenko <romka@kolos.math.uni.lodz.pl> */
+ .name = "AVACS SmartTV",
+ .audio_clock = 0x00187de7,
+ .tuner_type = TUNER_PHILIPS_PAL,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .inputs = {{
+ .type = SAA7134_INPUT_TV,
+ .vmux = 1,
+ .amux = TV,
+ },{
+ .type = SAA7134_INPUT_TV_MONO,
+ .vmux = 1,
+ .amux = LINE2,
+ },{
+ .type = SAA7134_INPUT_COMPOSITE1,
+ .vmux = 0,
+ .amux = LINE2,
+ },{
+ .type = SAA7134_INPUT_COMPOSITE2,
+ .vmux = 3,
+ .amux = LINE2,
+ },{
+ .type = SAA7134_INPUT_SVIDEO,
+ .vmux = 8,
+ .amux = LINE2,
+ }},
+ .radio = {
+ .type = SAA7134_INPUT_RADIO,
+ .amux = LINE2,
+ .gpio = 0x200000,
+ },
+ },
+ [SAA7134_BOARD_AVERMEDIA_DVD_EZMAKER] = {
+ /* Michael Smith <msmith@cbnco.com> */
+ .name = "AVerMedia DVD EZMaker",
+ .audio_clock = 0x00187de7,
+ .tuner_type = TUNER_ABSENT,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .inputs = {{
+ .type = SAA7134_INPUT_COMPOSITE1,
+ .vmux = 3,
+ },{
+ .type = SAA7134_INPUT_SVIDEO,
+ .vmux = 8,
+ }},
+ },
+ [SAA7134_BOARD_AVERMEDIA_M103] = {
+ /* Massimo Piccioni <dafastidio@libero.it> */
+ .name = "AVerMedia MiniPCI DVB-T Hybrid M103",
+ .audio_clock = 0x187de7,
+ .tuner_type = TUNER_XC2028,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .mpeg = SAA7134_MPEG_DVB,
+ .inputs = {{
+ .type = SAA7134_INPUT_TV,
+ .vmux = 1,
+ .amux = TV,
+ } },
+ },
+ [SAA7134_BOARD_NOVAC_PRIMETV7133] = {
+ /* toshii@netbsd.org */
+ .name = "Noval Prime TV 7133",
+ .audio_clock = 0x00200000,
+ .tuner_type = TUNER_ALPS_TSBH1_NTSC,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .inputs = {{
+ .type = SAA7134_INPUT_COMPOSITE1,
+ .vmux = 3,
+ },{
+ .type = SAA7134_INPUT_TV,
+ .vmux = 1,
+ .amux = TV,
+ },{
+ .type = SAA7134_INPUT_SVIDEO,
+ .vmux = 8,
+ }},
+ },
+ [SAA7134_BOARD_AVERMEDIA_STUDIO_305] = {
+ .name = "AverMedia AverTV Studio 305",
+ .audio_clock = 0x00187de7,
+ .tuner_type = TUNER_PHILIPS_FM1256_IH3,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .tda9887_conf = TDA9887_PRESENT,
+ .inputs = {{
+ .type = SAA7134_INPUT_TV,
+ .vmux = 1,
+ .amux = LINE2,
+ },{
+ .type = SAA7134_INPUT_COMPOSITE1,
+ .vmux = 0,
+ .amux = LINE2,
+ },{
+ .type = SAA7134_INPUT_COMPOSITE2,
+ .vmux = 3,
+ .amux = LINE2,
+ },{
+ .type = SAA7134_INPUT_SVIDEO,
+ .vmux = 8,
+ .amux = LINE2,
+ }},
+ .radio = {
+ .type = SAA7134_INPUT_RADIO,
+ .amux = LINE2,
+ },
+ .mute = {
+ .type = SAA7134_INPUT_MUTE,
+ .amux = LINE1,
+ },
+ },
+ [SAA7134_BOARD_AVERMEDIA_STUDIO_505] = {
+ /* Vasiliy Temnikov <vaka@newmail.ru> */
+ .name = "AverMedia AverTV Studio 505",
+ .audio_clock = 0x00187de7,
+ .tuner_type = TUNER_PHILIPS_FM1216ME_MK3,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .tda9887_conf = TDA9887_PRESENT,
+ .inputs = { {
+ .type = SAA7134_INPUT_TV,
+ .vmux = 1,
+ .amux = LINE2,
+ }, {
+ .type = SAA7134_INPUT_COMPOSITE1,
+ .vmux = 0,
+ .amux = LINE2,
+ }, {
+ .type = SAA7134_INPUT_COMPOSITE2,
+ .vmux = 3,
+ .amux = LINE2,
+ },{
+ .type = SAA7134_INPUT_SVIDEO,
+ .vmux = 8,
+ .amux = LINE2,
+ } },
+ .radio = {
+ .type = SAA7134_INPUT_RADIO,
+ .amux = LINE2,
+ },
+ .mute = {
+ .type = SAA7134_INPUT_MUTE,
+ .amux = LINE1,
+ },
+ },
+ [SAA7134_BOARD_UPMOST_PURPLE_TV] = {
+ .name = "UPMOST PURPLE TV",
+ .audio_clock = 0x00187de7,
+ .tuner_type = TUNER_PHILIPS_FM1236_MK3,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .tda9887_conf = TDA9887_PRESENT,
+ .inputs = {{
+ .type = SAA7134_INPUT_TV,
+ .vmux = 7,
+ .amux = TV,
+ },{
+ .type = SAA7134_INPUT_SVIDEO,
+ .vmux = 7,
+ .amux = LINE1,
+ }},
+ },
+ [SAA7134_BOARD_ITEMS_MTV005] = {
+ /* Norman Jonas <normanjonas@arcor.de> */
+ .name = "Items MuchTV Plus / IT-005",
+ .audio_clock = 0x00187de7,
+ .tuner_type = TUNER_PHILIPS_PAL,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .inputs = {{
+ .type = SAA7134_INPUT_TV,
+ .vmux = 3,
+ .amux = TV,
+ },{
+ .type = SAA7134_INPUT_COMPOSITE1,
+ .vmux = 1,
+ .amux = LINE1,
+ },{
+ .type = SAA7134_INPUT_SVIDEO,
+ .vmux = 8,
+ .amux = LINE1,
+ }},
+ .radio = {
+ .type = SAA7134_INPUT_RADIO,
+ .amux = LINE2,
+ },
+ },
+ [SAA7134_BOARD_CINERGY200] = {
+ .name = "Terratec Cinergy 200 TV",
+ .audio_clock = 0x00200000,
+ .tuner_type = TUNER_PHILIPS_PAL,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .inputs = {{
+ .type = SAA7134_INPUT_TV,
+ .vmux = 1,
+ .amux = LINE2,
+ },{
+ .type = SAA7134_INPUT_COMPOSITE1,
+ .vmux = 4,
+ .amux = LINE1,
+ },{
+ .type = SAA7134_INPUT_SVIDEO,
+ .vmux = 8,
+ .amux = LINE1,
+ },{
+ .type = SAA7134_INPUT_COMPOSITE_OVER_SVIDEO,
+ .vmux = 0,
+ .amux = LINE1,
+ }},
+ .mute = {
+ .type = SAA7134_INPUT_MUTE,
+ .amux = LINE2,
+ },
+ },
+ [SAA7134_BOARD_VIDEOMATE_TV_PVR] = {
+ /* Alain St-Denis <alain@topaze.homeip.net> */
+ .name = "Compro VideoMate TV PVR/FM",
+ .audio_clock = 0x00187de7,
+ .tuner_type = TUNER_PHILIPS_NTSC_M,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .gpiomask = 0x808c0080,
+ .inputs = {{
+ .type = SAA7134_INPUT_SVIDEO,
+ .vmux = 8,
+ .amux = LINE1,
+ .gpio = 0x00080,
+ },{
+ .type = SAA7134_INPUT_COMPOSITE1,
+ .vmux = 3,
+ .amux = LINE1,
+ .gpio = 0x00080,
+ },{
+ .type = SAA7134_INPUT_TV,
+ .vmux = 1,
+ .amux = LINE2_LEFT,
+ .gpio = 0x00080,
+ }},
+ .radio = {
+ .type = SAA7134_INPUT_RADIO,
+ .amux = LINE2,
+ .gpio = 0x80000,
+ },
+ .mute = {
+ .type = SAA7134_INPUT_MUTE,
+ .amux = LINE2,
+ .gpio = 0x40000,
+ },
+ },
+ [SAA7134_BOARD_SABRENT_SBTTVFM] = {
+ /* Michael Rodriguez-Torrent <mrtorrent@asu.edu> */
+ .name = "Sabrent SBT-TVFM (saa7130)",
+ .audio_clock = 0x00187de7,
+ .tuner_type = TUNER_PHILIPS_NTSC_M,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .inputs = {{
+ .type = SAA7134_INPUT_COMPOSITE1,
+ .vmux = 1,
+ .amux = LINE1,
+ },{
+ .type = SAA7134_INPUT_TV,
+ .vmux = 3,
+ .amux = LINE2,
+ },{
+ .type = SAA7134_INPUT_SVIDEO,
+ .vmux = 8,
+ .amux = LINE1,
+ }},
+ .radio = {
+ .type = SAA7134_INPUT_RADIO,
+ .amux = LINE2,
+ },
+ },
+ [SAA7134_BOARD_ZOLID_XPERT_TV7134] = {
+ /* Helge Jensen <helge.jensen@slog.dk> */
+ .name = ":Zolid Xpert TV7134",
+ .audio_clock = 0x00187de7,
+ .tuner_type = TUNER_PHILIPS_NTSC,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .inputs = {{
+ .type = SAA7134_INPUT_SVIDEO,
+ .vmux = 8,
+ .amux = LINE1,
+ },{
+ .type = SAA7134_INPUT_COMPOSITE1,
+ .vmux = 3,
+ .amux = LINE1,
+ },{
+ .type = SAA7134_INPUT_TV,
+ .vmux = 1,
+ .amux = LINE2,
+ }},
+ },
+ [SAA7134_BOARD_EMPIRE_PCI_TV_RADIO_LE] = {
+ /* "Matteo Az" <matte.az@nospam.libero.it> ;-) */
+ .name = "Empire PCI TV-Radio LE",
+ .audio_clock = 0x00187de7,
+ .tuner_type = TUNER_PHILIPS_PAL,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .gpiomask = 0x4000,
+ .inputs = {{
+ .type = SAA7134_INPUT_TV_MONO,
+ .vmux = 1,
+ .amux = LINE2,
+ .gpio = 0x8000,
+ },{
+ .type = SAA7134_INPUT_COMPOSITE1,
+ .vmux = 3,
+ .amux = LINE1,
+ .gpio = 0x8000,
+ },{
+ .type = SAA7134_INPUT_SVIDEO,
+ .vmux = 6,
+ .amux = LINE1,
+ .gpio = 0x8000,
+ }},
+ .radio = {
+ .type = SAA7134_INPUT_RADIO,
+ .amux = LINE1,
+ .gpio = 0x8000,
+ },
+ .mute = {
+ .type = SAA7134_INPUT_MUTE,
+ .amux = TV,
+ .gpio =0x8000,
+ }
+ },
+ [SAA7134_BOARD_AVERMEDIA_STUDIO_307] = {
+ /*
+ Nickolay V. Shmyrev <nshmyrev@yandex.ru>
+ Lots of thanks to Andrey Zolotarev <zolotarev_andrey@mail.ru>
+ */
+ .name = "Avermedia AVerTV Studio 307",
+ .audio_clock = 0x00187de7,
+ .tuner_type = TUNER_PHILIPS_FM1256_IH3,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .tda9887_conf = TDA9887_PRESENT,
+ .gpiomask = 0x03,
+ .inputs = {{
+ .type = SAA7134_INPUT_TV,
+ .vmux = 1,
+ .amux = TV,
+ .gpio = 0x00,
+ },{
+ .type = SAA7134_INPUT_COMPOSITE,
+ .vmux = 3,
+ .amux = LINE1,
+ .gpio = 0x02,
+ },{
+ .type = SAA7134_INPUT_SVIDEO,
+ .vmux = 8,
+ .amux = LINE1,
+ .gpio = 0x02,
+ }},
+ .radio = {
+ .type = SAA7134_INPUT_RADIO,
+ .amux = LINE1,
+ .gpio = 0x01,
+ },
+ .mute = {
+ .type = SAA7134_INPUT_MUTE,
+ .amux = LINE1,
+ .gpio = 0x00,
+ },
+ },
+ [SAA7134_BOARD_AVERMEDIA_GO_007_FM] = {
+ .name = "Avermedia AVerTV GO 007 FM",
+ .audio_clock = 0x00187de7,
+ .tuner_type = TUNER_PHILIPS_TDA8290,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .gpiomask = 0x00300003,
+ /* .gpiomask = 0x8c240003, */
+ .inputs = {{
+ .type = SAA7134_INPUT_TV,
+ .vmux = 1,
+ .amux = TV,
+ .gpio = 0x01,
+ },{
+ .type = SAA7134_INPUT_COMPOSITE1,
+ .vmux = 0,
+ .amux = LINE1,
+ .gpio = 0x02,
+ },{
+ .type = SAA7134_INPUT_SVIDEO,
+ .vmux = 6,
+ .amux = LINE1,
+ .gpio = 0x02,
+ }},
+ .radio = {
+ .type = SAA7134_INPUT_RADIO,
+ .amux = TV,
+ .gpio = 0x00300001,
+ },
+ .mute = {
+ .type = SAA7134_INPUT_MUTE,
+ .amux = TV,
+ .gpio = 0x01,
+ },
+ },
+ [SAA7134_BOARD_AVERMEDIA_CARDBUS] = {
+ /* Kees.Blom@cwi.nl */
+ .name = "AVerMedia Cardbus TV/Radio (E500)",
+ .audio_clock = 0x187de7,
+ .tuner_type = TUNER_PHILIPS_TDA8290,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .inputs = {{
+ .type = SAA7134_INPUT_TV,
+ .vmux = 1,
+ .amux = TV,
+ },{
+ .type = SAA7134_INPUT_COMPOSITE1,
+ .vmux = 3,
+ .amux = LINE2,
+ },{
+ .type = SAA7134_INPUT_SVIDEO,
+ .vmux = 8,
+ .amux = LINE1,
+ }},
+ .radio = {
+ .type = SAA7134_INPUT_RADIO,
+ .amux = LINE1,
+ },
+ },
+ [SAA7134_BOARD_AVERMEDIA_CARDBUS_501] = {
+ /* Oldrich Jedlicka <oldium.pro@seznam.cz> */
+ .name = "AVerMedia Cardbus TV/Radio (E501R)",
+ .audio_clock = 0x187de7,
+ .tuner_type = TUNER_ALPS_TSBE5_PAL,
+ .radio_type = TUNER_TEA5767,
+ .tuner_addr = 0x61,
+ .radio_addr = 0x60,
+ .tda9887_conf = TDA9887_PRESENT,
+ .gpiomask = 0x08000000,
+ .inputs = { {
+ .type = SAA7134_INPUT_TV,
+ .vmux = 1,
+ .amux = TV,
+ .gpio = 0x08000000,
+ }, {
+ .type = SAA7134_INPUT_COMPOSITE1,
+ .vmux = 3,
+ .amux = LINE1,
+ .gpio = 0x08000000,
+ }, {
+ .type = SAA7134_INPUT_SVIDEO,
+ .vmux = 8,
+ .amux = LINE1,
+ .gpio = 0x08000000,
+ } },
+ .radio = {
+ .type = SAA7134_INPUT_RADIO,
+ .amux = LINE2,
+ .gpio = 0x00000000,
+ },
+ },
+ [SAA7134_BOARD_CINERGY400_CARDBUS] = {
+ .name = "Terratec Cinergy 400 mobile",
+ .audio_clock = 0x187de7,
+ .tuner_type = TUNER_ALPS_TSBE5_PAL,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .tda9887_conf = TDA9887_PRESENT,
+ .inputs = {{
+ .type = SAA7134_INPUT_TV,
+ .vmux = 1,
+ .amux = TV,
+ },{
+ .type = SAA7134_INPUT_TV_MONO,
+ .vmux = 1,
+ .amux = LINE2,
+ },{
+ .type = SAA7134_INPUT_COMPOSITE1,
+ .vmux = 3,
+ .amux = LINE1,
+ },{
+ .type = SAA7134_INPUT_SVIDEO,
+ .vmux = 8,
+ .amux = LINE1,
+ }},
+ },
+ [SAA7134_BOARD_CINERGY600_MK3] = {
+ .name = "Terratec Cinergy 600 TV MK3",
+ .audio_clock = 0x00200000,
+ .tuner_type = TUNER_PHILIPS_FM1216ME_MK3,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .rds_addr = 0x10,
+ .tda9887_conf = TDA9887_PRESENT,
+ .inputs = {{
+ .type = SAA7134_INPUT_TV,
+ .vmux = 1,
+ .amux = TV,
+ },{
+ .type = SAA7134_INPUT_COMPOSITE1,
+ .vmux = 4,
+ .amux = LINE1,
+ },{
+ .type = SAA7134_INPUT_SVIDEO,
+ .vmux = 8,
+ .amux = LINE1,
+ },{
+ .type = SAA7134_INPUT_COMPOSITE_OVER_SVIDEO,
+ .vmux = 0,
+ .amux = LINE1,
+ }},
+ .radio = {
+ .type = SAA7134_INPUT_RADIO,
+ .amux = LINE2,
+ },
+ },
+ [SAA7134_BOARD_VIDEOMATE_GOLD_PLUS] = {
+ /* Dylan Walkden <dylan_walkden@hotmail.com> */
+ .name = "Compro VideoMate Gold+ Pal",
+ .audio_clock = 0x00187de7,
+ .tuner_type = TUNER_PHILIPS_PAL,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .gpiomask = 0x1ce780,
+ .inputs = {{
+ .type = SAA7134_INPUT_COMPOSITE_OVER_SVIDEO,
+ .vmux = 0,
+ .amux = LINE1,
+ .gpio = 0x008080,
+ },{
+ .type = SAA7134_INPUT_COMPOSITE1,
+ .vmux = 3,
+ .amux = LINE1,
+ .gpio = 0x008080,
+ },{
+ .type = SAA7134_INPUT_TV,
+ .vmux = 1,
+ .amux = TV,
+ .gpio = 0x008080,
+ }},
+ .radio = {
+ .type = SAA7134_INPUT_RADIO,
+ .amux = LINE2,
+ .gpio = 0x80000,
+ },
+ .mute = {
+ .type = SAA7134_INPUT_MUTE,
+ .amux = LINE2,
+ .gpio = 0x0c8000,
+ },
+ },
+ [SAA7134_BOARD_PINNACLE_300I_DVBT_PAL] = {
+ .name = "Pinnacle PCTV 300i DVB-T + PAL",
+ .audio_clock = 0x00187de7,
+ .tuner_type = TUNER_MT2032,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .tda9887_conf = TDA9887_PRESENT | TDA9887_INTERCARRIER | TDA9887_PORT2_INACTIVE,
+ .mpeg = SAA7134_MPEG_DVB,
+ .inputs = {{
+ .type = SAA7134_INPUT_TV,
+ .vmux = 3,
+ .amux = TV,
+ },{
+ .type = SAA7134_INPUT_COMPOSITE1,
+ .vmux = 0,
+ .amux = LINE2,
+ },{
+ .type = SAA7134_INPUT_COMPOSITE2,
+ .vmux = 1,
+ .amux = LINE2,
+ },{
+ .type = SAA7134_INPUT_SVIDEO,
+ .vmux = 8,
+ .amux = LINE2,
+ }},
+ },
+ [SAA7134_BOARD_PROVIDEO_PV952] = {
+ /* andreas.kretschmer@web.de */
+ .name = "ProVideo PV952",
+ .audio_clock = 0x00187de7,
+ .tuner_type = TUNER_PHILIPS_FM1216ME_MK3,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .tda9887_conf = TDA9887_PRESENT,
+ .inputs = {{
+ .type = SAA7134_INPUT_COMPOSITE1,
+ .vmux = 0,
+ .amux = LINE1,
+ },{
+ .type = SAA7134_INPUT_TV,
+ .vmux = 1,
+ .amux = TV,
+ },{
+ .type = SAA7134_INPUT_TV_MONO,
+ .vmux = 1,
+ .amux = LINE2,
+ }},
+ .radio = {
+ .type = SAA7134_INPUT_RADIO,
+ .amux = LINE2,
+ },
+ },
+ [SAA7134_BOARD_AVERMEDIA_305] = {
+ /* much like the "studio" version but without radio
+ * and another tuner (sirspiritus@yandex.ru) */
+ .name = "AverMedia AverTV/305",
+ .audio_clock = 0x00187de7,
+ .tuner_type = TUNER_PHILIPS_FQ1216ME,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .tda9887_conf = TDA9887_PRESENT,
+ .inputs = {{
+ .type = SAA7134_INPUT_TV,
+ .vmux = 1,
+ .amux = LINE2,
+ },{
+ .type = SAA7134_INPUT_COMPOSITE1,
+ .vmux = 0,
+ .amux = LINE2,
+ },{
+ .type = SAA7134_INPUT_COMPOSITE2,
+ .vmux = 3,
+ .amux = LINE2,
+ },{
+ .type = SAA7134_INPUT_SVIDEO,
+ .vmux = 8,
+ .amux = LINE2,
+ }},
+ .mute = {
+ .type = SAA7134_INPUT_MUTE,
+ .amux = LINE1,
+ },
+ },
+ [SAA7134_BOARD_FLYDVBTDUO] = {
+ /* LifeView FlyDVB-T DUO */
+ /* "Nico Sabbi <nsabbi@tiscali.it> Hartmut Hackmann hartmut.hackmann@t-online.de*/
+ .name = "LifeView FlyDVB-T DUO / MSI TV@nywhere Duo",
+ .audio_clock = 0x00200000,
+ .tuner_type = TUNER_PHILIPS_TDA8290,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .gpiomask = 0x00200000,
+ .mpeg = SAA7134_MPEG_DVB,
+ .inputs = {{
+ .type = SAA7134_INPUT_TV,
+ .vmux = 1,
+ .amux = TV,
+ .gpio = 0x200000, /* GPIO21=High for TV input */
+ },{
+ .type = SAA7134_INPUT_COMPOSITE_OVER_SVIDEO,
+ .vmux = 0,
+ .amux = LINE2,
+ },{
+ .type = SAA7134_INPUT_COMPOSITE,
+ .vmux = 3,
+ .amux = LINE2,
+ },{
+ .type = SAA7134_INPUT_SVIDEO,
+ .vmux = 8,
+ .amux = LINE2,
+ }},
+ .radio = {
+ .type = SAA7134_INPUT_RADIO,
+ .amux = TV,
+ .gpio = 0x000000, /* GPIO21=Low for FM radio antenna */
+ },
+ },
+ [SAA7134_BOARD_PHILIPS_TOUGH] = {
+ .name = "Philips TOUGH DVB-T reference design",
+ .tuner_type = TUNER_ABSENT,
+ .audio_clock = 0x00187de7,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .mpeg = SAA7134_MPEG_DVB,
+ .inputs = {{
+ .type = SAA7134_INPUT_COMPOSITE1,
+ .vmux = 0,
+ .amux = LINE1,
+ },{
+ .type = SAA7134_INPUT_SVIDEO,
+ .vmux = 8,
+ .amux = LINE1,
+ }},
+ },
+ [SAA7134_BOARD_AVERMEDIA_307] = {
+ /*
+ Davydov Vladimir <vladimir@iqmedia.com>
+ */
+ .name = "Avermedia AVerTV 307",
+ .audio_clock = 0x00187de7,
+ .tuner_type = TUNER_PHILIPS_FQ1216ME,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .tda9887_conf = TDA9887_PRESENT,
+ .inputs = {{
+ .type = SAA7134_INPUT_TV,
+ .vmux = 1,
+ .amux = TV,
+ },{
+ .type = SAA7134_INPUT_COMPOSITE1,
+ .vmux = 0,
+ .amux = LINE1,
+ },{
+ .type = SAA7134_INPUT_COMPOSITE2,
+ .vmux = 3,
+ .amux = LINE1,
+ },{
+ .type = SAA7134_INPUT_SVIDEO,
+ .vmux = 8,
+ .amux = LINE1,
+ }},
+ },
+ [SAA7134_BOARD_ADS_INSTANT_TV] = {
+ .name = "ADS Tech Instant TV (saa7135)",
+ .audio_clock = 0x00187de7,
+ .tuner_type = TUNER_PHILIPS_TDA8290,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .inputs = {{
+ .type = SAA7134_INPUT_TV,
+ .vmux = 1,
+ .amux = TV,
+ },{
+ .type = SAA7134_INPUT_COMPOSITE1,
+ .vmux = 3,
+ .amux = LINE2,
+ },{
+ .type = SAA7134_INPUT_SVIDEO,
+ .vmux = 8,
+ .amux = LINE2,
+ }},
+ },
+ [SAA7134_BOARD_KWORLD_VSTREAM_XPERT] = {
+ .name = "Kworld/Tevion V-Stream Xpert TV PVR7134",
+ .audio_clock = 0x00187de7,
+ .tuner_type = TUNER_PHILIPS_PAL_I,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .gpiomask = 0x0700,
+ .inputs = {{
+ .type = SAA7134_INPUT_TV,
+ .vmux = 1,
+ .amux = TV,
+ .gpio = 0x000,
+ },{
+ .type = SAA7134_INPUT_COMPOSITE1,
+ .vmux = 3,
+ .amux = LINE1,
+ .gpio = 0x200, /* gpio by DScaler */
+ },{
+ .type = SAA7134_INPUT_SVIDEO,
+ .vmux = 0,
+ .amux = LINE1,
+ .gpio = 0x200,
+ }},
+ .radio = {
+ .type = SAA7134_INPUT_RADIO,
+ .amux = LINE1,
+ .gpio = 0x100,
+ },
+ .mute = {
+ .type = SAA7134_INPUT_MUTE,
+ .amux = TV,
+ .gpio = 0x000,
+ },
+ },
+ [SAA7134_BOARD_FLYDVBT_DUO_CARDBUS] = {
+ .name = "LifeView/Typhoon/Genius FlyDVB-T Duo Cardbus",
+ .audio_clock = 0x00200000,
+ .tuner_type = TUNER_PHILIPS_TDA8290,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .mpeg = SAA7134_MPEG_DVB,
+ .gpiomask = 0x00200000,
+ .inputs = {{
+ .type = SAA7134_INPUT_TV,
+ .vmux = 1,
+ .amux = TV,
+ .gpio = 0x200000, /* GPIO21=High for TV input */
+ },{
+ .type = SAA7134_INPUT_SVIDEO,
+ .vmux = 8,
+ .amux = LINE2,
+ },{
+ .type = SAA7134_INPUT_COMPOSITE_OVER_SVIDEO,
+ .vmux = 0,
+ .amux = LINE2,
+ },{
+ .type = SAA7134_INPUT_COMPOSITE2,
+ .vmux = 3,
+ .amux = LINE2,
+ }},
+ .radio = {
+ .type = SAA7134_INPUT_RADIO,
+ .amux = TV,
+ .gpio = 0x000000, /* GPIO21=Low for FM radio antenna */
+ },
+ },
+ [SAA7134_BOARD_VIDEOMATE_TV_GOLD_PLUSII] = {
+ .name = "Compro VideoMate TV Gold+II",
+ .audio_clock = 0x002187de7,
+ .tuner_type = TUNER_LG_PAL_NEW_TAPC,
+ .radio_type = TUNER_TEA5767,
+ .tuner_addr = 0x63,
+ .radio_addr = 0x60,
+ .gpiomask = 0x8c1880,
+ .inputs = {{
+ .type = SAA7134_INPUT_SVIDEO,
+ .vmux = 0,
+ .amux = LINE1,
+ .gpio = 0x800800,
+ },{
+ .type = SAA7134_INPUT_COMPOSITE1,
+ .vmux = 3,
+ .amux = LINE1,
+ .gpio = 0x801000,
+ },{
+ .type = SAA7134_INPUT_TV,
+ .vmux = 1,
+ .amux = TV,
+ .gpio = 0x800000,
+ }},
+ .radio = {
+ .type = SAA7134_INPUT_RADIO,
+ .amux = TV,
+ .gpio = 0x880000,
+ },
+ .mute = {
+ .type = SAA7134_INPUT_MUTE,
+ .amux = LINE2,
+ .gpio = 0x840000,
+ },
+ },
+ [SAA7134_BOARD_KWORLD_XPERT] = {
+ /*
+ FIXME:
+ - Remote control doesn't initialize properly.
+ - Audio volume starts muted,
+ then gradually increases after channel change.
+ - Composite S-Video untested.
+ From: Konrad Rzepecki <hannibal@megapolis.pl>
+ */
+ .name = "Kworld Xpert TV PVR7134",
+ .audio_clock = 0x00187de7,
+ .tuner_type = TUNER_TENA_9533_DI,
+ .radio_type = TUNER_TEA5767,
+ .tuner_addr = 0x61,
+ .radio_addr = 0x60,
+ .gpiomask = 0x0700,
+ .inputs = {{
+ .type = SAA7134_INPUT_TV,
+ .vmux = 1,
+ .amux = TV,
+ .gpio = 0x000,
+ },{
+ .type = SAA7134_INPUT_COMPOSITE1,
+ .vmux = 3,
+ .amux = LINE1,
+ .gpio = 0x200, /* gpio by DScaler */
+ },{
+ .type = SAA7134_INPUT_SVIDEO,
+ .vmux = 0,
+ .amux = LINE1,
+ .gpio = 0x200,
+ }},
+ .radio = {
+ .type = SAA7134_INPUT_RADIO,
+ .amux = LINE1,
+ .gpio = 0x100,
+ },
+ .mute = {
+ .type = SAA7134_INPUT_MUTE,
+ .amux = TV,
+ .gpio = 0x000,
+ },
+ },
+ [SAA7134_BOARD_FLYTV_DIGIMATRIX] = {
+ .name = "FlyTV mini Asus Digimatrix",
+ .audio_clock = 0x00200000,
+ .tuner_type = TUNER_LG_TALN,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .inputs = {{
+ .type = SAA7134_INPUT_TV,
+ .vmux = 1,
+ .amux = TV,
+ },{
+ .type = SAA7134_INPUT_TV_MONO,
+ .vmux = 1,
+ .amux = LINE2,
+ },{
+ .type = SAA7134_INPUT_COMPOSITE1,
+ .vmux = 0,
+ .amux = LINE2,
+ },{
+ .type = SAA7134_INPUT_COMPOSITE2,
+ .vmux = 3,
+ .amux = LINE2,
+ },{
+ .type = SAA7134_INPUT_SVIDEO,
+ .vmux = 8,
+ .amux = LINE2,
+ }},
+ .radio = {
+ .type = SAA7134_INPUT_RADIO, /* radio unconfirmed */
+ .amux = LINE2,
+ },
+ },
+ [SAA7134_BOARD_KWORLD_TERMINATOR] = {
+ /* Kworld V-Stream Studio TV Terminator */
+ /* "James Webb <jrwebb@qwest.net> */
+ .name = "V-Stream Studio TV Terminator",
+ .audio_clock = 0x00187de7,
+ .tuner_type = TUNER_PHILIPS_TDA8290,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .gpiomask = 1 << 21,
+ .inputs = {{
+ .type = SAA7134_INPUT_TV,
+ .vmux = 1,
+ .amux = TV,
+ .gpio = 0x0000000,
+ },{
+ .type = SAA7134_INPUT_COMPOSITE1,
+ .vmux = 3,
+ .amux = LINE2,
+ .gpio = 0x0000000,
+ },{
+ .type = SAA7134_INPUT_SVIDEO,
+ .vmux = 8,
+ .amux = LINE2,
+ .gpio = 0x0000000,
+ }},
+ .radio = {
+ .type = SAA7134_INPUT_RADIO,
+ .amux = TV,
+ .gpio = 0x0200000,
+ },
+ },
+ [SAA7134_BOARD_YUAN_TUN900] = {
+ /* FIXME:
+ * S-Video and composite sources untested.
+ * Radio not working.
+ * Remote control not yet implemented.
+ * From : codemaster@webgeeks.be */
+ .name = "Yuan TUN-900 (saa7135)",
+ .audio_clock = 0x00187de7,
+ .tuner_type = TUNER_PHILIPS_TDA8290,
+ .radio_type = UNSET,
+ .tuner_addr= ADDR_UNSET,
+ .radio_addr= ADDR_UNSET,
+ .gpiomask = 0x00010003,
+ .inputs = {{
+ .type = SAA7134_INPUT_TV,
+ .vmux = 1,
+ .amux = TV,
+ .gpio = 0x01,
+ },{
+ .type = SAA7134_INPUT_COMPOSITE1,
+ .vmux = 0,
+ .amux = LINE2,
+ .gpio = 0x02,
+ },{
+ .type = SAA7134_INPUT_SVIDEO,
+ .vmux = 6,
+ .amux = LINE2,
+ .gpio = 0x02,
+ }},
+ .radio = {
+ .type = SAA7134_INPUT_RADIO,
+ .amux = LINE1,
+ .gpio = 0x00010003,
+ },
+ .mute = {
+ .type = SAA7134_INPUT_MUTE,
+ .amux = TV,
+ .gpio = 0x01,
+ },
+ },
+ [SAA7134_BOARD_BEHOLD_409FM] = {
+ /* <http://tuner.beholder.ru>, Sergey <skiv@orel.ru> */
+ /* Beholder Intl. Ltd. 2008 */
+ /*Dmitry Belimov <d.belimov@gmail.com> */
+ .name = "Beholder BeholdTV 409 FM",
+ .audio_clock = 0x00187de7,
+ .tuner_type = TUNER_PHILIPS_FM1216ME_MK3,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .tda9887_conf = TDA9887_PRESENT,
+ .gpiomask = 0x00008000,
+ .inputs = {{
+ .type = SAA7134_INPUT_TV,
+ .vmux = 3,
+ .amux = TV,
+ },{
+ .type = SAA7134_INPUT_COMPOSITE1,
+ .vmux = 1,
+ .amux = LINE1,
+ },{
+ .type = SAA7134_INPUT_SVIDEO,
+ .vmux = 8,
+ .amux = LINE1,
+ }},
+ .radio = {
+ .type = SAA7134_INPUT_RADIO,
+ .amux = LINE2,
+ },
+ },
+ [SAA7134_BOARD_GOTVIEW_7135] = {
+ /* Mike Baikov <mike@baikov.com> */
+ /* Andrey Cvetcov <ays14@yandex.ru> */
+ .name = "GoTView 7135 PCI",
+ .audio_clock = 0x00187de7,
+ .tuner_type = TUNER_PHILIPS_FM1216ME_MK3,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .tda9887_conf = TDA9887_PRESENT,
+ .gpiomask = 0x00200003,
+ .inputs = {{
+ .type = SAA7134_INPUT_TV,
+ .vmux = 1,
+ .amux = TV,
+ .gpio = 0x00200003,
+ },{
+ .type = SAA7134_INPUT_TV_MONO,
+ .vmux = 1,
+ .amux = LINE2,
+ .gpio = 0x00200003,
+ },{
+ .type = SAA7134_INPUT_COMPOSITE1,
+ .vmux = 3,
+ .amux = LINE1,
+ .gpio = 0x00200003,
+ },{
+ .type = SAA7134_INPUT_SVIDEO,
+ .vmux = 8,
+ .amux = LINE1,
+ .gpio = 0x00200003,
+ }},
+ .radio = {
+ .type = SAA7134_INPUT_RADIO,
+ .amux = LINE2,
+ .gpio = 0x00200003,
+ },
+ .mute = {
+ .type = SAA7134_INPUT_MUTE,
+ .amux = TV,
+ .gpio = 0x00200003,
+ },
+ },
+ [SAA7134_BOARD_PHILIPS_EUROPA] = {
+ .name = "Philips EUROPA V3 reference design",
+ .audio_clock = 0x00187de7,
+ .tuner_type = TUNER_PHILIPS_TD1316,
+ .radio_type = UNSET,
+ .tuner_addr = 0x61,
+ .radio_addr = ADDR_UNSET,
+ .tda9887_conf = TDA9887_PRESENT | TDA9887_PORT1_ACTIVE,
+ .mpeg = SAA7134_MPEG_DVB,
+ .inputs = {{
+ .type = SAA7134_INPUT_TV,
+ .vmux = 3,
+ .amux = TV,
+ },{
+ .type = SAA7134_INPUT_COMPOSITE1,
+ .vmux = 0,
+ .amux = LINE2,
+ },{
+ .type = SAA7134_INPUT_SVIDEO,
+ .vmux = 8,
+ .amux = LINE2,
+ }},
+ },
+ [SAA7134_BOARD_VIDEOMATE_DVBT_300] = {
+ .name = "Compro Videomate DVB-T300",
+ .audio_clock = 0x00187de7,
+ .tuner_type = TUNER_PHILIPS_TD1316,
+ .radio_type = UNSET,
+ .tuner_addr = 0x61,
+ .radio_addr = ADDR_UNSET,
+ .tda9887_conf = TDA9887_PRESENT | TDA9887_PORT1_ACTIVE,
+ .mpeg = SAA7134_MPEG_DVB,
+ .inputs = {{
+ .type = SAA7134_INPUT_TV,
+ .vmux = 3,
+ .amux = TV,
+ },{
+ .type = SAA7134_INPUT_COMPOSITE1,
+ .vmux = 1,
+ .amux = LINE2,
+ },{
+ .type = SAA7134_INPUT_SVIDEO,
+ .vmux = 8,
+ .amux = LINE2,
+ }},
+ },
+ [SAA7134_BOARD_VIDEOMATE_DVBT_200] = {
+ .name = "Compro Videomate DVB-T200",
+ .tuner_type = TUNER_ABSENT,
+ .audio_clock = 0x00187de7,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .mpeg = SAA7134_MPEG_DVB,
+ .inputs = {{
+ .type = SAA7134_INPUT_COMPOSITE1,
+ .vmux = 0,
+ .amux = LINE1,
+ },{
+ .type = SAA7134_INPUT_SVIDEO,
+ .vmux = 8,
+ .amux = LINE1,
+ }},
+ },
+ [SAA7134_BOARD_RTD_VFG7350] = {
+ .name = "RTD Embedded Technologies VFG7350",
+ .audio_clock = 0x00200000,
+ .tuner_type = TUNER_ABSENT,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .empress_addr = 0x21,
+ .inputs = {{
+ .type = SAA7134_INPUT_COMPOSITE0,
+ .vmux = 0,
+ .amux = LINE1,
+ },{
+ .type = SAA7134_INPUT_COMPOSITE1,
+ .vmux = 1,
+ .amux = LINE2,
+ },{
+ .type = SAA7134_INPUT_COMPOSITE2,
+ .vmux = 2,
+ .amux = LINE1,
+ },{
+ .type = SAA7134_INPUT_COMPOSITE3,
+ .vmux = 3,
+ .amux = LINE2,
+ },{
+ .type = SAA7134_INPUT_SVIDEO0,
+
+ .vmux = 8,
+ .amux = LINE1,
+ },{
+ .type = SAA7134_INPUT_SVIDEO1,
+ .vmux = 9,
+ .amux = LINE2,
+ }},
+ .mpeg = SAA7134_MPEG_EMPRESS,
+ .video_out = CCIR656,
+ .vid_port_opts = ( SET_T_CODE_POLARITY_NON_INVERTED |
+ SET_CLOCK_NOT_DELAYED |
+ SET_CLOCK_INVERTED |
+ SET_VSYNC_OFF ),
+ },
+ [SAA7134_BOARD_RTD_VFG7330] = {
+ .name = "RTD Embedded Technologies VFG7330",
+ .audio_clock = 0x00200000,
+ .tuner_type = TUNER_ABSENT,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .inputs = {{
+ .type = SAA7134_INPUT_COMPOSITE0,
+ .vmux = 0,
+ .amux = LINE1,
+ },{
+ .type = SAA7134_INPUT_COMPOSITE1,
+ .vmux = 1,
+ .amux = LINE2,
+ },{
+ .type = SAA7134_INPUT_COMPOSITE2,
+ .vmux = 2,
+ .amux = LINE1,
+ },{
+ .type = SAA7134_INPUT_COMPOSITE3,
+ .vmux = 3,
+ .amux = LINE2,
+ },{
+ .type = SAA7134_INPUT_SVIDEO0,
+ .vmux = 8,
+ .amux = LINE1,
+ },{
+ .type = SAA7134_INPUT_SVIDEO1,
+ .vmux = 9,
+ .amux = LINE2,
+ }},
+ },
+ [SAA7134_BOARD_FLYTVPLATINUM_MINI2] = {
+ .name = "LifeView FlyTV Platinum Mini2",
+ .audio_clock = 0x00200000,
+ .tuner_type = TUNER_PHILIPS_TDA8290,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+
+ .inputs = {{
+ .type = SAA7134_INPUT_TV,
+ .vmux = 1,
+ .amux = TV,
+ },{
+ .type = SAA7134_INPUT_COMPOSITE_OVER_SVIDEO,
+ .vmux = 0,
+ .amux = LINE2,
+ },{
+ .type = SAA7134_INPUT_COMPOSITE,
+ .vmux = 3,
+ .amux = LINE2,
+ },{
+ .type = SAA7134_INPUT_SVIDEO,
+ .vmux = 8,
+ .amux = LINE2,
+ }},
+ },
+ [SAA7134_BOARD_AVERMEDIA_AVERTVHD_A180] = {
+ /* Michael Krufky <mkrufky@linuxtv.org>
+ * Uses Alps Electric TDHU2, containing NXT2004 ATSC Decoder
+ * AFAIK, there is no analog demod, thus,
+ * no support for analog television.
+ */
+ .name = "AVerMedia AVerTVHD MCE A180",
+ .audio_clock = 0x00187de7,
+ .tuner_type = TUNER_ABSENT,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .mpeg = SAA7134_MPEG_DVB,
+ .inputs = {{
+ .type = SAA7134_INPUT_COMPOSITE1,
+ .vmux = 3,
+ .amux = LINE2,
+ },{
+ .type = SAA7134_INPUT_SVIDEO,
+ .vmux = 8,
+ .amux = LINE2,
+ }},
+ },
+ [SAA7134_BOARD_MONSTERTV_MOBILE] = {
+ .name = "SKNet MonsterTV Mobile",
+ .audio_clock = 0x00187de7,
+ .tuner_type = TUNER_PHILIPS_TDA8290,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+
+ .inputs = {{
+ .type = SAA7134_INPUT_TV,
+ .vmux = 1,
+ .amux = TV,
+ },{
+ .type = SAA7134_INPUT_COMPOSITE1,
+ .vmux = 3,
+ .amux = LINE1,
+ },{
+ .type = SAA7134_INPUT_SVIDEO,
+ .vmux = 6,
+ .amux = LINE1,
+ }},
+ },
+ [SAA7134_BOARD_PINNACLE_PCTV_110i] = {
+ .name = "Pinnacle PCTV 40i/50i/110i (saa7133)",
+ .audio_clock = 0x00187de7,
+ .tuner_type = TUNER_PHILIPS_TDA8290,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .gpiomask = 0x080200000,
+ .inputs = { {
+ .type = SAA7134_INPUT_TV,
+ .vmux = 4,
+ .amux = TV,
+ }, {
+ .type = SAA7134_INPUT_COMPOSITE1,
+ .vmux = 1,
+ .amux = LINE2,
+ }, {
+ .type = SAA7134_INPUT_COMPOSITE2,
+ .vmux = 0,
+ .amux = LINE2,
+ }, {
+ .type = SAA7134_INPUT_SVIDEO,
+ .vmux = 8,
+ .amux = LINE2,
+ } },
+ .radio = {
+ .type = SAA7134_INPUT_RADIO,
+ .amux = TV,
+ .gpio = 0x0200000,
+ },
+ },
+ [SAA7134_BOARD_ASUSTeK_P7131_DUAL] = {
+ .name = "ASUSTeK P7131 Dual",
+ .audio_clock = 0x00187de7,
+ .tuner_type = TUNER_PHILIPS_TDA8290,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .gpiomask = 1 << 21,
+ .mpeg = SAA7134_MPEG_DVB,
+ .inputs = {{
+ .type = SAA7134_INPUT_TV,
+ .vmux = 1,
+ .amux = TV,
+ .gpio = 0x0000000,
+ },{
+ .type = SAA7134_INPUT_COMPOSITE1,
+ .vmux = 3,
+ .amux = LINE2,
+ .gpio = 0x0200000,
+ },{
+ .type = SAA7134_INPUT_COMPOSITE2,
+ .vmux = 0,
+ .amux = LINE2,
+ .gpio = 0x0200000,
+ },{
+ .type = SAA7134_INPUT_SVIDEO,
+ .vmux = 8,
+ .amux = LINE2,
+ .gpio = 0x0200000,
+ }},
+ .radio = {
+ .type = SAA7134_INPUT_RADIO,
+ .amux = TV,
+ .gpio = 0x0200000,
+ },
+ },
+ [SAA7134_BOARD_SEDNA_PC_TV_CARDBUS] = {
+ /* Paul Tom Zalac <pzalac@gmail.com> */
+ /* Pavel Mihaylov <bin@bash.info> */
+ .name = "Sedna/MuchTV PC TV Cardbus TV/Radio (ITO25 Rev:2B)",
+ /* Sedna/MuchTV (OEM) Cardbus TV Tuner */
+ .audio_clock = 0x00187de7,
+ .tuner_type = TUNER_PHILIPS_TDA8290,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .gpiomask = 0xe880c0,
+ .inputs = {{
+ .type = SAA7134_INPUT_TV,
+ .vmux = 3,
+ .amux = TV,
+ },{
+ .type = SAA7134_INPUT_COMPOSITE1,
+ .vmux = 1,
+ .amux = LINE1,
+ },{
+ .type = SAA7134_INPUT_SVIDEO,
+ .vmux = 6,
+ .amux = LINE1,
+ }},
+ .radio = {
+ .type = SAA7134_INPUT_RADIO,
+ .amux = LINE2,
+ },
+ },
+ [SAA7134_BOARD_ASUSTEK_DIGIMATRIX_TV] = {
+ /* "Cyril Lacoux (Yack)" <clacoux@ifeelgood.org> */
+ .name = "ASUS Digimatrix TV",
+ .audio_clock = 0x00200000,
+ .tuner_type = TUNER_PHILIPS_FQ1216ME,
+ .tda9887_conf = TDA9887_PRESENT,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .inputs = {{
+ .type = SAA7134_INPUT_TV,
+ .vmux = 1,
+ .amux = TV,
+ },{
+ .type = SAA7134_INPUT_COMPOSITE1,
+ .vmux = 3,
+ .amux = LINE1,
+ },{
+ .type = SAA7134_INPUT_SVIDEO,
+ .vmux = 8,
+ .amux = LINE1,
+ }},
+ },
+ [SAA7134_BOARD_PHILIPS_TIGER] = {
+ .name = "Philips Tiger reference design",
+ .audio_clock = 0x00187de7,
+ .tuner_type = TUNER_PHILIPS_TDA8290,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .tda829x_conf = { .lna_cfg = TDA8290_LNA_OFF },
+ .mpeg = SAA7134_MPEG_DVB,
+ .gpiomask = 0x0200000,
+ .inputs = {{
+ .type = SAA7134_INPUT_TV,
+ .vmux = 1,
+ .amux = TV,
+ },{
+ .type = SAA7134_INPUT_COMPOSITE1,
+ .vmux = 3,
+ .amux = LINE1,
+ },{
+ .type = SAA7134_INPUT_SVIDEO,
+ .vmux = 8,
+ .amux = LINE1,
+ }},
+ .radio = {
+ .type = SAA7134_INPUT_RADIO,
+ .amux = TV,
+ .gpio = 0x0200000,
+ },
+ },
+ [SAA7134_BOARD_MSI_TVATANYWHERE_PLUS] = {
+ .name = "MSI TV@Anywhere plus",
+ .audio_clock = 0x00187de7,
+ .tuner_type = TUNER_PHILIPS_TDA8290,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .gpiomask = 1 << 21,
+ .inputs = {{
+ .type = SAA7134_INPUT_TV,
+ .vmux = 1,
+ .amux = TV,
+ },{
+ .type = SAA7134_INPUT_COMPOSITE,
+ .vmux = 3,
+ .amux = LINE2, /* unconfirmed, taken from Philips driver */
+ },{
+ .type = SAA7134_INPUT_COMPOSITE_OVER_SVIDEO,
+ .vmux = 0, /* untested */
+ .amux = LINE2,
+ },{
+ .type = SAA7134_INPUT_SVIDEO,
+ .vmux = 8,
+ .amux = LINE2,
+ }},
+ .radio = {
+ .type = SAA7134_INPUT_RADIO,
+ .amux = TV,
+ .gpio = 0x0200000,
+ },
+ },
+ [SAA7134_BOARD_CINERGY250PCI] = {
+ /* remote-control does not work. The signal about a
+ key press comes in via gpio, but the key code
+ doesn't. Neither does it have an i2c remote control
+ interface. */
+ .name = "Terratec Cinergy 250 PCI TV",
+ .audio_clock = 0x00187de7,
+ .tuner_type = TUNER_PHILIPS_TDA8290,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .gpiomask = 0x80200000,
+ .inputs = {{
+ .type = SAA7134_INPUT_TV,
+ .vmux = 1,
+ .amux = TV,
+ },{
+ .type = SAA7134_INPUT_SVIDEO, /* NOT tested */
+ .vmux = 8,
+ .amux = LINE1,
+ }},
+ .radio = {
+ .type = SAA7134_INPUT_RADIO,
+ .amux = TV,
+ .gpio = 0x0200000,
+ },
+ },
+ [SAA7134_BOARD_FLYDVB_TRIO] = {
+ /* LifeView LR319 FlyDVB Trio */
+ /* Peter Missel <peter.missel@onlinehome.de> */
+ .name = "LifeView FlyDVB Trio",
+ .audio_clock = 0x00200000,
+ .tuner_type = TUNER_PHILIPS_TDA8290,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .gpiomask = 0x00200000,
+ .mpeg = SAA7134_MPEG_DVB,
+ .inputs = {{
+ .type = SAA7134_INPUT_TV, /* Analog broadcast/cable TV */
+ .vmux = 1,
+ .amux = TV,
+ .gpio = 0x200000, /* GPIO21=High for TV input */
+ },{
+ .type = SAA7134_INPUT_SVIDEO,
+ .vmux = 8,
+ .amux = LINE2,
+ },{
+ .type = SAA7134_INPUT_COMPOSITE_OVER_SVIDEO,
+ .vmux = 0,
+ .amux = LINE2,
+ },{
+ .type = SAA7134_INPUT_COMPOSITE2,
+ .vmux = 3,
+ .amux = LINE2,
+ }},
+ .radio = {
+ .type = SAA7134_INPUT_RADIO,
+ .amux = TV,
+ .gpio = 0x000000, /* GPIO21=Low for FM radio antenna */
+ },
+ },
+ [SAA7134_BOARD_AVERMEDIA_777] = {
+ .name = "AverTV DVB-T 777",
+ .audio_clock = 0x00187de7,
+ .tuner_type = TUNER_ABSENT,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .mpeg = SAA7134_MPEG_DVB,
+ .inputs = {{
+ .type = SAA7134_INPUT_COMPOSITE1,
+ .vmux = 1,
+ .amux = LINE1,
+ },{
+ .type = SAA7134_INPUT_SVIDEO,
+ .vmux = 8,
+ .amux = LINE1,
+ }},
+ },
+ [SAA7134_BOARD_FLYDVBT_LR301] = {
+ /* LifeView FlyDVB-T */
+ /* Giampiero Giancipoli <gianci@libero.it> */
+ .name = "LifeView FlyDVB-T / Genius VideoWonder DVB-T",
+ .audio_clock = 0x00200000,
+ .tuner_type = TUNER_ABSENT,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .mpeg = SAA7134_MPEG_DVB,
+ .inputs = {{
+ .type = SAA7134_INPUT_COMPOSITE1,
+ .vmux = 3,
+ .amux = LINE2,
+ },{
+ .type = SAA7134_INPUT_SVIDEO,
+ .vmux = 8,
+ .amux = LINE2,
+ }},
+ },
+ [SAA7134_BOARD_ADS_DUO_CARDBUS_PTV331] = {
+ .name = "ADS Instant TV Duo Cardbus PTV331",
+ .audio_clock = 0x00200000,
+ .tuner_type = TUNER_PHILIPS_TDA8290,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .mpeg = SAA7134_MPEG_DVB,
+ .gpiomask = 0x00600000, /* Bit 21 0=Radio, Bit 22 0=TV */
+ .inputs = {{
+ .type = SAA7134_INPUT_TV,
+ .vmux = 1,
+ .amux = TV,
+ .gpio = 0x00200000,
+ }},
+ },
+ [SAA7134_BOARD_TEVION_DVBT_220RF] = {
+ .name = "Tevion/KWorld DVB-T 220RF",
+ .audio_clock = 0x00187de7,
+ .tuner_type = TUNER_PHILIPS_TDA8290,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .mpeg = SAA7134_MPEG_DVB,
+ .gpiomask = 1 << 21,
+ .inputs = {{
+ .type = SAA7134_INPUT_TV,
+ .vmux = 1,
+ .amux = TV,
+ },{
+ .type = SAA7134_INPUT_COMPOSITE1,
+ .vmux = 3,
+ .amux = LINE1,
+ },{
+ .type = SAA7134_INPUT_COMPOSITE2,
+ .vmux = 0,
+ .amux = LINE1,
+ },{
+ .type = SAA7134_INPUT_SVIDEO,
+ .vmux = 8,
+ .amux = LINE1,
+ }},
+ .radio = {
+ .type = SAA7134_INPUT_RADIO,
+ .amux = TV,
+ .gpio = 0x0200000,
+ },
+ },
+ [SAA7134_BOARD_KWORLD_DVBT_210] = {
+ .name = "KWorld DVB-T 210",
+ .audio_clock = 0x00187de7,
+ .tuner_type = TUNER_PHILIPS_TDA8290,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .mpeg = SAA7134_MPEG_DVB,
+ .gpiomask = 1 << 21,
+ .inputs = {{
+ .type = SAA7134_INPUT_TV,
+ .vmux = 1,
+ .amux = TV,
+ },{
+ .type = SAA7134_INPUT_COMPOSITE1,
+ .vmux = 3,
+ .amux = LINE1,
+ },{
+ .type = SAA7134_INPUT_SVIDEO,
+ .vmux = 8,
+ .amux = LINE1,
+ }},
+ .radio = {
+ .type = SAA7134_INPUT_RADIO,
+ .amux = TV,
+ .gpio = 0x0200000,
+ },
+ },
+ [SAA7134_BOARD_KWORLD_ATSC110] = {
+ .name = "Kworld ATSC110/115",
+ .audio_clock = 0x00187de7,
+ .tuner_type = TUNER_PHILIPS_TUV1236D,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .tda9887_conf = TDA9887_PRESENT,
+ .mpeg = SAA7134_MPEG_DVB,
+ .inputs = {{
+ .type = SAA7134_INPUT_TV,
+ .vmux = 1,
+ .amux = TV,
+ },{
+ .type = SAA7134_INPUT_COMPOSITE1,
+ .vmux = 3,
+ .amux = LINE2,
+ },{
+ .type = SAA7134_INPUT_SVIDEO,
+ .vmux = 8,
+ .amux = LINE2,
+ }},
+ },
+ [SAA7134_BOARD_AVERMEDIA_A169_B] = {
+ /* AVerMedia A169 */
+ /* Rickard Osser <ricky@osser.se> */
+ /* This card has two saa7134 chips on it,
+ but only one of them is currently working. */
+ .name = "AVerMedia A169 B",
+ .audio_clock = 0x02187de7,
+ .tuner_type = TUNER_LG_TALN,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .tda9887_conf = TDA9887_PRESENT,
+ .gpiomask = 0x0a60000,
+ },
+ [SAA7134_BOARD_AVERMEDIA_A169_B1] = {
+ /* AVerMedia A169 */
+ /* Rickard Osser <ricky@osser.se> */
+ .name = "AVerMedia A169 B1",
+ .audio_clock = 0x02187de7,
+ .tuner_type = TUNER_LG_TALN,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .tda9887_conf = TDA9887_PRESENT,
+ .gpiomask = 0xca60000,
+ .inputs = {{
+ .type = SAA7134_INPUT_TV,
+ .vmux = 4,
+ .amux = TV,
+ .gpio = 0x04a61000,
+ },{
+ .type = SAA7134_INPUT_COMPOSITE_OVER_SVIDEO,
+ .vmux = 1,
+ .amux = LINE2,
+ },{
+ .type = SAA7134_INPUT_SVIDEO,
+ .vmux = 9, /* 9 is correct as S-VIDEO1 according to a169.inf! */
+ .amux = LINE1,
+ }},
+ },
+ [SAA7134_BOARD_MD7134_BRIDGE_2] = {
+ /* The second saa7134 on this card only serves as DVB-S host bridge */
+ .name = "Medion 7134 Bridge #2",
+ .audio_clock = 0x00187de7,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .mpeg = SAA7134_MPEG_DVB,
+ },
+ [SAA7134_BOARD_FLYDVBT_HYBRID_CARDBUS] = {
+ .name = "LifeView FlyDVB-T Hybrid Cardbus/MSI TV @nywhere A/D NB",
+ .audio_clock = 0x00200000,
+ .tuner_type = TUNER_PHILIPS_TDA8290,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .mpeg = SAA7134_MPEG_DVB,
+ .gpiomask = 0x00600000, /* Bit 21 0=Radio, Bit 22 0=TV */
+ .inputs = {{
+ .type = SAA7134_INPUT_TV,
+ .vmux = 1,
+ .amux = TV,
+ .gpio = 0x200000, /* GPIO21=High for TV input */
+ },{
+ .type = SAA7134_INPUT_SVIDEO,
+ .vmux = 8,
+ .amux = LINE2,
+ },{
+ .type = SAA7134_INPUT_COMPOSITE_OVER_SVIDEO,
+ .vmux = 0,
+ .amux = LINE2,
+ },{
+ .type = SAA7134_INPUT_COMPOSITE,
+ .vmux = 3,
+ .amux = LINE2,
+ }},
+ .radio = {
+ .type = SAA7134_INPUT_RADIO,
+ .amux = TV,
+ .gpio = 0x000000, /* GPIO21=Low for FM radio antenna */
+ },
+ },
+ [SAA7134_BOARD_FLYVIDEO3000_NTSC] = {
+ /* "Zac Bowling" <zac@zacbowling.com> */
+ .name = "LifeView FlyVIDEO3000 (NTSC)",
+ .audio_clock = 0x00200000,
+ .tuner_type = TUNER_PHILIPS_NTSC,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+
+ .gpiomask = 0xe000,
+ .inputs = {{
+ .type = SAA7134_INPUT_TV,
+ .vmux = 1,
+ .amux = TV,
+ .gpio = 0x8000,
+ },{
+ .type = SAA7134_INPUT_TV_MONO,
+ .vmux = 1,
+ .amux = LINE2,
+ .gpio = 0x0000,
+ },{
+ .type = SAA7134_INPUT_COMPOSITE1,
+ .vmux = 0,
+ .amux = LINE2,
+ .gpio = 0x4000,
+ },{
+ .type = SAA7134_INPUT_COMPOSITE2,
+ .vmux = 3,
+ .amux = LINE2,
+ .gpio = 0x4000,
+ },{
+ .type = SAA7134_INPUT_SVIDEO,
+ .vmux = 8,
+ .amux = LINE2,
+ .gpio = 0x4000,
+ }},
+ .radio = {
+ .type = SAA7134_INPUT_RADIO,
+ .amux = LINE2,
+ .gpio = 0x2000,
+ },
+ .mute = {
+ .type = SAA7134_INPUT_MUTE,
+ .amux = TV,
+ .gpio = 0x8000,
+ },
+ },
+ [SAA7134_BOARD_MEDION_MD8800_QUADRO] = {
+ .name = "Medion Md8800 Quadro",
+ .audio_clock = 0x00187de7,
+ .tuner_type = TUNER_PHILIPS_TDA8290,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .mpeg = SAA7134_MPEG_DVB,
+ .inputs = {{
+ .type = SAA7134_INPUT_TV,
+ .vmux = 1,
+ .amux = TV,
+ },{
+ .type = SAA7134_INPUT_COMPOSITE1,
+ .vmux = 0,
+ .amux = LINE1,
+ },{
+ .type = SAA7134_INPUT_SVIDEO,
+ .vmux = 8,
+ .amux = LINE1,
+ }},
+ },
+ [SAA7134_BOARD_FLYDVBS_LR300] = {
+ /* LifeView FlyDVB-s */
+ /* Igor M. Liplianin <liplianin@tut.by> */
+ .name = "LifeView FlyDVB-S /Acorp TV134DS",
+ .audio_clock = 0x00200000,
+ .tuner_type = TUNER_ABSENT,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .mpeg = SAA7134_MPEG_DVB,
+ .inputs = {{
+ .type = SAA7134_INPUT_COMPOSITE1,
+ .vmux = 3,
+ .amux = LINE1,
+ },{
+ .type = SAA7134_INPUT_SVIDEO,
+ .vmux = 8,
+ .amux = LINE1,
+ }},
+ },
+ [SAA7134_BOARD_PROTEUS_2309] = {
+ .name = "Proteus Pro 2309",
+ .audio_clock = 0x00187de7,
+ .tuner_type = TUNER_PHILIPS_FM1216ME_MK3,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .tda9887_conf = TDA9887_PRESENT,
+ .inputs = {{
+ .type = SAA7134_INPUT_TV,
+ .vmux = 1,
+ .amux = LINE2,
+ },{
+ .type = SAA7134_INPUT_COMPOSITE1,
+ .vmux = 0,
+ .amux = LINE2,
+ },{
+ .type = SAA7134_INPUT_COMPOSITE2,
+ .vmux = 3,
+ .amux = LINE2,
+ },{
+ .type = SAA7134_INPUT_SVIDEO,
+ .vmux = 8,
+ .amux = LINE2,
+ }},
+ .mute = {
+ .type = SAA7134_INPUT_MUTE,
+ .amux = LINE1,
+ },
+ },
+ [SAA7134_BOARD_AVERMEDIA_A16AR] = {
+ /* Petr Baudis <pasky@ucw.cz> */
+ .name = "AVerMedia TV Hybrid A16AR",
+ .audio_clock = 0x187de7,
+ .tuner_type = TUNER_PHILIPS_TD1316, /* untested */
+ .radio_type = TUNER_TEA5767, /* untested */
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = 0x60,
+ .tda9887_conf = TDA9887_PRESENT,
+ .mpeg = SAA7134_MPEG_DVB,
+ .inputs = {{
+ .type = SAA7134_INPUT_TV,
+ .vmux = 1,
+ .amux = TV,
+ },{
+ .type = SAA7134_INPUT_COMPOSITE1,
+ .vmux = 3,
+ .amux = LINE2,
+ },{
+ .type = SAA7134_INPUT_SVIDEO,
+ .vmux = 8,
+ .amux = LINE1,
+ }},
+ .radio = {
+ .type = SAA7134_INPUT_RADIO,
+ .amux = LINE1,
+ },
+ },
+ [SAA7134_BOARD_ASUS_EUROPA2_HYBRID] = {
+ .name = "Asus Europa2 OEM",
+ .audio_clock = 0x00187de7,
+ .tuner_type = TUNER_PHILIPS_FMD1216ME_MK3,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .tda9887_conf = TDA9887_PRESENT| TDA9887_PORT1_ACTIVE | TDA9887_PORT2_ACTIVE,
+ .mpeg = SAA7134_MPEG_DVB,
+ .inputs = {{
+ .type = SAA7134_INPUT_TV,
+ .vmux = 3,
+ .amux = TV,
+ },{
+ .type = SAA7134_INPUT_COMPOSITE1,
+ .vmux = 4,
+ .amux = LINE2,
+ },{
+ .type = SAA7134_INPUT_SVIDEO,
+ .vmux = 8,
+ .amux = LINE2,
+ }},
+ .radio = {
+ .type = SAA7134_INPUT_RADIO,
+ .amux = LINE1,
+ },
+ },
+ [SAA7134_BOARD_PINNACLE_PCTV_310i] = {
+ .name = "Pinnacle PCTV 310i",
+ .audio_clock = 0x00187de7,
+ .tuner_type = TUNER_PHILIPS_TDA8290,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .tda829x_conf = { .lna_cfg = TDA8290_LNA_GP0_HIGH_ON },
+ .mpeg = SAA7134_MPEG_DVB,
+ .gpiomask = 0x000200000,
+ .inputs = {{
+ .type = SAA7134_INPUT_TV,
+ .vmux = 4,
+ .amux = TV,
+ },{
+ .type = SAA7134_INPUT_COMPOSITE1,
+ .vmux = 1,
+ .amux = LINE2,
+ },{
+ .type = SAA7134_INPUT_COMPOSITE2,
+ .vmux = 0,
+ .amux = LINE2,
+ },{
+ .type = SAA7134_INPUT_SVIDEO,
+ .vmux = 8,
+ .amux = LINE2,
+ }},
+ .radio = {
+ .type = SAA7134_INPUT_RADIO,
+ .amux = TV,
+ .gpio = 0x0200000,
+ },
+ },
+ [SAA7134_BOARD_AVERMEDIA_STUDIO_507] = {
+ /* Mikhail Fedotov <mo_fedotov@mail.ru> */
+ .name = "Avermedia AVerTV Studio 507",
+ .audio_clock = 0x00187de7,
+ .tuner_type = TUNER_PHILIPS_FM1256_IH3,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .tda9887_conf = TDA9887_PRESENT,
+ .gpiomask = 0x03,
+ .inputs = {{
+ .type = SAA7134_INPUT_TV,
+ .vmux = 1,
+ .amux = TV,
+ .gpio = 0x00,
+ },{
+ .type = SAA7134_INPUT_COMPOSITE1,
+ .vmux = 0,
+ .amux = LINE2,
+ .gpio = 0x00,
+ },{
+ .type = SAA7134_INPUT_COMPOSITE2,
+ .vmux = 3,
+ .amux = LINE2,
+ .gpio = 0x00,
+ },{
+ .type = SAA7134_INPUT_SVIDEO,
+ .vmux = 8,
+ .amux = LINE2,
+ .gpio = 0x00,
+ }},
+ .radio = {
+ .type = SAA7134_INPUT_RADIO,
+ .amux = LINE2,
+ .gpio = 0x01,
+ },
+ .mute = {
+ .type = SAA7134_INPUT_MUTE,
+ .amux = LINE1,
+ .gpio = 0x00,
+ },
+ },
+ [SAA7134_BOARD_VIDEOMATE_DVBT_200A] = {
+ /* Francis Barber <fedora@barber-family.id.au> */
+ .name = "Compro Videomate DVB-T200A",
+ .audio_clock = 0x00187de7,
+ .tuner_type = TUNER_ABSENT,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .tda9887_conf = TDA9887_PRESENT | TDA9887_PORT1_ACTIVE,
+ .mpeg = SAA7134_MPEG_DVB,
+ .inputs = {{
+ .type = SAA7134_INPUT_TV,
+ .vmux = 3,
+ .amux = TV,
+ },{
+ .type = SAA7134_INPUT_COMPOSITE1,
+ .vmux = 1,
+ .amux = LINE2,
+ },{
+ .type = SAA7134_INPUT_SVIDEO,
+ .vmux = 8,
+ .amux = LINE2,
+ }},
+ },
+ [SAA7134_BOARD_HAUPPAUGE_HVR1110] = {
+ /* Thomas Genty <tomlohave@gmail.com> */
+ /* David Bentham <db260179@hotmail.com> */
+ .name = "Hauppauge WinTV-HVR1110 DVB-T/Hybrid",
+ .audio_clock = 0x00187de7,
+ .tuner_type = TUNER_PHILIPS_TDA8290,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .tda829x_conf = { .lna_cfg = TDA8290_LNA_GP0_HIGH_ON },
+ .mpeg = SAA7134_MPEG_DVB,
+ .gpiomask = 0x0200100,
+ .inputs = {{
+ .type = SAA7134_INPUT_TV,
+ .vmux = 1,
+ .amux = TV,
+ .gpio = 0x0000100,
+ }, {
+ .type = SAA7134_INPUT_COMPOSITE1,
+ .vmux = 3,
+ .amux = LINE1,
+ }, {
+ .type = SAA7134_INPUT_SVIDEO,
+ .vmux = 8,
+ .amux = LINE1,
+ } },
+ .radio = {
+ .type = SAA7134_INPUT_RADIO,
+ .amux = TV,
+ .gpio = 0x0200100,
+ },
+ },
+ [SAA7134_BOARD_HAUPPAUGE_HVR1150] = {
+ .name = "Hauppauge WinTV-HVR1150 ATSC/QAM-Hybrid",
+ .audio_clock = 0x00187de7,
+ .tuner_type = TUNER_PHILIPS_TDA8290,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .tda829x_conf = { .lna_cfg = TDA8290_LNA_ON_BRIDGE },
+ .mpeg = SAA7134_MPEG_DVB,
+ .ts_type = SAA7134_MPEG_TS_SERIAL,
+ .ts_force_val = 1,
+ .gpiomask = 0x0800100, /* GPIO 21 is an INPUT */
+ .inputs = {{
+ .type = SAA7134_INPUT_TV,
+ .vmux = 1,
+ .amux = TV,
+ .gpio = 0x0000100,
+ }, {
+ .type = SAA7134_INPUT_COMPOSITE1,
+ .vmux = 3,
+ .amux = LINE1,
+ }, {
+ .type = SAA7134_INPUT_SVIDEO,
+ .vmux = 8,
+ .amux = LINE1,
+ } },
+ .radio = {
+ .type = SAA7134_INPUT_RADIO,
+ .amux = TV,
+ .gpio = 0x0800100, /* GPIO 23 HI for FM */
+ },
+ },
+ [SAA7134_BOARD_HAUPPAUGE_HVR1120] = {
+ .name = "Hauppauge WinTV-HVR1120 DVB-T/Hybrid",
+ .audio_clock = 0x00187de7,
+ .tuner_type = TUNER_PHILIPS_TDA8290,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .tda829x_conf = { .lna_cfg = TDA8290_LNA_ON_BRIDGE },
+ .mpeg = SAA7134_MPEG_DVB,
+ .ts_type = SAA7134_MPEG_TS_SERIAL,
+ .gpiomask = 0x0800100, /* GPIO 21 is an INPUT */
+ .inputs = {{
+ .type = SAA7134_INPUT_TV,
+ .vmux = 1,
+ .amux = TV,
+ .gpio = 0x0000100,
+ }, {
+ .type = SAA7134_INPUT_COMPOSITE1,
+ .vmux = 3,
+ .amux = LINE1,
+ }, {
+ .type = SAA7134_INPUT_SVIDEO,
+ .vmux = 8,
+ .amux = LINE1,
+ } },
+ .radio = {
+ .type = SAA7134_INPUT_RADIO,
+ .amux = TV,
+ .gpio = 0x0800100, /* GPIO 23 HI for FM */
+ },
+ },
+ [SAA7134_BOARD_CINERGY_HT_PCMCIA] = {
+ .name = "Terratec Cinergy HT PCMCIA",
+ .audio_clock = 0x00187de7,
+ .tuner_type = TUNER_PHILIPS_TDA8290,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .mpeg = SAA7134_MPEG_DVB,
+ .inputs = {{
+ .type = SAA7134_INPUT_TV,
+ .vmux = 1,
+ .amux = TV,
+ },{
+ .type = SAA7134_INPUT_COMPOSITE1,
+ .vmux = 0,
+ .amux = LINE1,
+ },{
+ .type = SAA7134_INPUT_SVIDEO,
+ .vmux = 6,
+ .amux = LINE1,
+ }},
+ },
+ [SAA7134_BOARD_ENCORE_ENLTV] = {
+ /* Steven Walter <stevenrwalter@gmail.com>
+ Juan Pablo Sormani <sorman@gmail.com> */
+ .name = "Encore ENLTV",
+ .audio_clock = 0x00200000,
+ .tuner_type = TUNER_TNF_5335MF,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .inputs = {{
+ .type = SAA7134_INPUT_TV,
+ .vmux = 1,
+ .amux = 3,
+ },{
+ .type = SAA7134_INPUT_TV_MONO,
+ .vmux = 7,
+ .amux = 4,
+ },{
+ .type = SAA7134_INPUT_COMPOSITE1,
+ .vmux = 3,
+ .amux = 2,
+ },{
+ .type = SAA7134_INPUT_SVIDEO,
+ .vmux = 0,
+ .amux = 2,
+ }},
+ .radio = {
+ .type = SAA7134_INPUT_RADIO,
+ .amux = LINE2,
+/* .gpio = 0x00300001,*/
+ .gpio = 0x20000,
+
+ },
+ .mute = {
+ .type = SAA7134_INPUT_MUTE,
+ .amux = 0,
+ },
+ },
+ [SAA7134_BOARD_ENCORE_ENLTV_FM] = {
+ /* Juan Pablo Sormani <sorman@gmail.com> */
+ .name = "Encore ENLTV-FM",
+ .audio_clock = 0x00200000,
+ .tuner_type = TUNER_PHILIPS_FCV1236D,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .inputs = {{
+ .type = SAA7134_INPUT_TV,
+ .vmux = 1,
+ .amux = 3,
+ },{
+ .type = SAA7134_INPUT_TV_MONO,
+ .vmux = 7,
+ .amux = 4,
+ },{
+ .type = SAA7134_INPUT_COMPOSITE1,
+ .vmux = 3,
+ .amux = 2,
+ },{
+ .type = SAA7134_INPUT_SVIDEO,
+ .vmux = 0,
+ .amux = 2,
+ }},
+ .radio = {
+ .type = SAA7134_INPUT_RADIO,
+ .amux = LINE2,
+ .gpio = 0x20000,
+
+ },
+ .mute = {
+ .type = SAA7134_INPUT_MUTE,
+ .amux = 0,
+ },
+ },
+ [SAA7134_BOARD_ENCORE_ENLTV_FM53] = {
+ .name = "Encore ENLTV-FM v5.3",
+ .audio_clock = 0x00200000,
+ .tuner_type = TUNER_TNF_5335MF,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .gpiomask = 0x7000,
+ .inputs = { {
+ .type = SAA7134_INPUT_TV,
+ .vmux = 1,
+ .amux = 1,
+ .gpio = 0x50000,
+ }, {
+ .type = SAA7134_INPUT_COMPOSITE1,
+ .vmux = 3,
+ .amux = 2,
+ .gpio = 0x2000,
+ }, {
+ .type = SAA7134_INPUT_SVIDEO,
+ .vmux = 8,
+ .amux = 2,
+ .gpio = 0x2000,
+ } },
+ .radio = {
+ .type = SAA7134_INPUT_RADIO,
+ .vmux = 1,
+ .amux = 1,
+ },
+ .mute = {
+ .type = SAA7134_INPUT_MUTE,
+ .gpio = 0xf000,
+ .amux = 0,
+ },
+ },
+ [SAA7134_BOARD_ENCORE_ENLTV_FM3] = {
+ .name = "Encore ENLTV-FM 3",
+ .audio_clock = 0x02187de7,
+ .tuner_type = TUNER_TENA_TNF_5337,
+ .radio_type = TUNER_TEA5767,
+ .tuner_addr = 0x61,
+ .radio_addr = 0x60,
+ .inputs = { {
+ .type = SAA7134_INPUT_TV,
+ .vmux = 1,
+ .amux = LINE2,
+ }, {
+ .type = SAA7134_INPUT_COMPOSITE1,
+ .vmux = 3,
+ .amux = LINE1,
+ }, {
+ .type = SAA7134_INPUT_SVIDEO,
+ .vmux = 8,
+ .amux = LINE1,
+ } },
+ .radio = {
+ .type = SAA7134_INPUT_RADIO,
+ .vmux = 1,
+ .amux = LINE1,
+ },
+ .mute = {
+ .type = SAA7134_INPUT_MUTE,
+ .amux = LINE1,
+ .gpio = 0x43000,
+ },
+ },
+ [SAA7134_BOARD_CINERGY_HT_PCI] = {
+ .name = "Terratec Cinergy HT PCI",
+ .audio_clock = 0x00187de7,
+ .tuner_type = TUNER_PHILIPS_TDA8290,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .mpeg = SAA7134_MPEG_DVB,
+ .inputs = {{
+ .type = SAA7134_INPUT_TV,
+ .vmux = 1,
+ .amux = TV,
+ },{
+ .type = SAA7134_INPUT_COMPOSITE1,
+ .vmux = 0,
+ .amux = LINE1,
+ },{
+ .type = SAA7134_INPUT_SVIDEO,
+ .vmux = 6,
+ .amux = LINE1,
+ }},
+ },
+ [SAA7134_BOARD_PHILIPS_TIGER_S] = {
+ .name = "Philips Tiger - S Reference design",
+ .audio_clock = 0x00187de7,
+ .tuner_type = TUNER_PHILIPS_TDA8290,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .tda829x_conf = { .lna_cfg = TDA8290_LNA_GP0_HIGH_OFF },
+ .mpeg = SAA7134_MPEG_DVB,
+ .gpiomask = 0x0200000,
+ .inputs = {{
+ .type = SAA7134_INPUT_TV,
+ .vmux = 1,
+ .amux = TV,
+ },{
+ .type = SAA7134_INPUT_COMPOSITE1,
+ .vmux = 3,
+ .amux = LINE1,
+ },{
+ .type = SAA7134_INPUT_SVIDEO,
+ .vmux = 8,
+ .amux = LINE1,
+ }},
+ .radio = {
+ .type = SAA7134_INPUT_RADIO,
+ .amux = TV,
+ .gpio = 0x0200000,
+ },
+ },
+ [SAA7134_BOARD_AVERMEDIA_M102] = {
+ .name = "Avermedia M102",
+ .audio_clock = 0x00187de7,
+ .tuner_type = TUNER_PHILIPS_TDA8290,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .gpiomask = 1<<21,
+ .inputs = {{
+ .type = SAA7134_INPUT_TV,
+ .vmux = 1,
+ .amux = TV,
+ },{
+ .type = SAA7134_INPUT_COMPOSITE1,
+ .vmux = 0,
+ .amux = LINE2,
+ },{
+ .type = SAA7134_INPUT_SVIDEO,
+ .vmux = 6,
+ .amux = LINE2,
+ }},
+ },
+ [SAA7134_BOARD_ASUS_P7131_4871] = {
+ .name = "ASUS P7131 4871",
+ .audio_clock = 0x00187de7,
+ .tuner_type = TUNER_PHILIPS_TDA8290,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .tda829x_conf = { .lna_cfg = TDA8290_LNA_GP0_HIGH_OFF },
+ .mpeg = SAA7134_MPEG_DVB,
+ .gpiomask = 0x0200000,
+ .inputs = {{
+ .type = SAA7134_INPUT_TV,
+ .vmux = 1,
+ .amux = TV,
+ .gpio = 0x0200000,
+ },{
+ .type = SAA7134_INPUT_COMPOSITE1,
+ .vmux = 3,
+ .amux = LINE2,
+ .gpio = 0x0200000,
+ },{
+ .type = SAA7134_INPUT_COMPOSITE2,
+ .vmux = 0,
+ .amux = LINE2,
+ .gpio = 0x0200000,
+ },{
+ .type = SAA7134_INPUT_SVIDEO,
+ .vmux = 8,
+ .amux = LINE2,
+ .gpio = 0x0200000,
+ }},
+ },
+ [SAA7134_BOARD_ASUSTeK_P7131_HYBRID_LNA] = {
+ .name = "ASUSTeK P7131 Hybrid",
+ .audio_clock = 0x00187de7,
+ .tuner_type = TUNER_PHILIPS_TDA8290,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .tda829x_conf = { .lna_cfg = TDA8290_LNA_GP0_HIGH_OFF },
+ .gpiomask = 1 << 21,
+ .mpeg = SAA7134_MPEG_DVB,
+ .inputs = {{
+ .type = SAA7134_INPUT_TV,
+ .vmux = 1,
+ .amux = TV,
+ .gpio = 0x0000000,
+ },{
+ .type = SAA7134_INPUT_COMPOSITE1,
+ .vmux = 3,
+ .amux = LINE2,
+ .gpio = 0x0200000,
+ },{
+ .type = SAA7134_INPUT_COMPOSITE2,
+ .vmux = 0,
+ .amux = LINE2,
+ .gpio = 0x0200000,
+ },{
+ .type = SAA7134_INPUT_SVIDEO,
+ .vmux = 8,
+ .amux = LINE2,
+ .gpio = 0x0200000,
+ }},
+ .radio = {
+ .type = SAA7134_INPUT_RADIO,
+ .amux = TV,
+ .gpio = 0x0200000,
+ },
+ },
+ [SAA7134_BOARD_ASUSTeK_P7131_ANALOG] = {
+ .name = "ASUSTeK P7131 Analog",
+ .audio_clock = 0x00187de7,
+ .tuner_type = TUNER_PHILIPS_TDA8290,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .gpiomask = 1 << 21,
+ .inputs = {{
+ .type = SAA7134_INPUT_TV,
+ .vmux = 1,
+ .amux = TV,
+ .gpio = 0x0000000,
+ }, {
+ .type = SAA7134_INPUT_COMPOSITE1,
+ .vmux = 3,
+ .amux = LINE2,
+ }, {
+ .type = SAA7134_INPUT_COMPOSITE2,
+ .vmux = 0,
+ .amux = LINE2,
+ }, {
+ .type = SAA7134_INPUT_SVIDEO,
+ .vmux = 8,
+ .amux = LINE2,
+ } },
+ .radio = {
+ .type = SAA7134_INPUT_RADIO,
+ .amux = TV,
+ .gpio = 0x0200000,
+ },
+ },
+ [SAA7134_BOARD_SABRENT_TV_PCB05] = {
+ .name = "Sabrent PCMCIA TV-PCB05",
+ .audio_clock = 0x00187de7,
+ .tuner_type = TUNER_PHILIPS_TDA8290,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .inputs = {{
+ .type = SAA7134_INPUT_TV,
+ .vmux = 1,
+ .amux = TV,
+ },{
+ .type = SAA7134_INPUT_COMPOSITE1,
+ .vmux = 3,
+ .amux = LINE1,
+ },{
+ .type = SAA7134_INPUT_COMPOSITE2,
+ .vmux = 0,
+ .amux = LINE1,
+ },{
+ .type = SAA7134_INPUT_SVIDEO,
+ .vmux = 8,
+ .amux = LINE1,
+ }},
+ .mute = {
+ .type = SAA7134_INPUT_MUTE,
+ .amux = TV,
+ },
+ },
+ [SAA7134_BOARD_10MOONSTVMASTER3] = {
+ /* Tony Wan <aloha_cn@hotmail.com> */
+ .name = "10MOONS TM300 TV Card",
+ .audio_clock = 0x00200000,
+ .tuner_type = TUNER_LG_PAL_NEW_TAPC,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .gpiomask = 0x7000,
+ .inputs = {{
+ .type = SAA7134_INPUT_TV,
+ .vmux = 1,
+ .amux = LINE2,
+ .gpio = 0x0000,
+ },{
+ .type = SAA7134_INPUT_COMPOSITE1,
+ .vmux = 3,
+ .amux = LINE1,
+ .gpio = 0x2000,
+ },{
+ .type = SAA7134_INPUT_SVIDEO,
+ .vmux = 8,
+ .amux = LINE1,
+ .gpio = 0x2000,
+ }},
+ .mute = {
+ .type = SAA7134_INPUT_MUTE,
+ .amux = LINE2,
+ .gpio = 0x3000,
+ },
+ },
+ [SAA7134_BOARD_AVERMEDIA_SUPER_007] = {
+ .name = "Avermedia Super 007",
+ .audio_clock = 0x00187de7,
+ .tuner_type = TUNER_PHILIPS_TDA8290,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .tda829x_conf = { .lna_cfg = TDA8290_LNA_OFF },
+ .mpeg = SAA7134_MPEG_DVB,
+ .inputs = {{
+ .type = SAA7134_INPUT_TV, /* FIXME: analog tv untested */
+ .vmux = 1,
+ .amux = TV,
+ }},
+ },
+ [SAA7134_BOARD_AVERMEDIA_M135A] = {
+ .name = "Avermedia PCI pure analog (M135A)",
+ .audio_clock = 0x00187de7,
+ .tuner_type = TUNER_PHILIPS_TDA8290,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .tda829x_conf = { .lna_cfg = TDA8290_LNA_GP0_HIGH_OFF },
+ .gpiomask = 0x020200000,
+ .inputs = {{
+ .type = SAA7134_INPUT_TV,
+ .vmux = 1,
+ .amux = TV,
+ }, {
+ .type = SAA7134_INPUT_COMPOSITE1,
+ .vmux = 3,
+ .amux = LINE1,
+ }, {
+ .type = SAA7134_INPUT_SVIDEO,
+ .vmux = 8,
+ .amux = LINE1,
+ } },
+ .radio = {
+ .type = SAA7134_INPUT_RADIO,
+ .amux = TV,
+ .gpio = 0x00200000,
+ },
+ .mute = {
+ .type = SAA7134_INPUT_MUTE,
+ .amux = TV,
+ .gpio = 0x01,
+ },
+ },
+ [SAA7134_BOARD_AVERMEDIA_M733A] = {
+ .name = "Avermedia PCI M733A",
+ .audio_clock = 0x00187de7,
+ .tuner_type = TUNER_PHILIPS_TDA8290,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .tda829x_conf = { .lna_cfg = TDA8290_LNA_OFF },
+ .gpiomask = 0x020200000,
+ .inputs = {{
+ .type = SAA7134_INPUT_TV,
+ .vmux = 1,
+ .amux = TV,
+ }, {
+ .type = SAA7134_INPUT_COMPOSITE1,
+ .vmux = 3,
+ .amux = LINE1,
+ }, {
+ .type = SAA7134_INPUT_SVIDEO,
+ .vmux = 8,
+ .amux = LINE1,
+ } },
+ .radio = {
+ .type = SAA7134_INPUT_RADIO,
+ .amux = TV,
+ .gpio = 0x00200000,
+ },
+ .mute = {
+ .type = SAA7134_INPUT_MUTE,
+ .amux = TV,
+ .gpio = 0x01,
+ },
+ },
+ [SAA7134_BOARD_BEHOLD_401] = {
+ /* Beholder Intl. Ltd. 2008 */
+ /*Dmitry Belimov <d.belimov@gmail.com> */
+ .name = "Beholder BeholdTV 401",
+ .audio_clock = 0x00187de7,
+ .tuner_type = TUNER_PHILIPS_FQ1216ME,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .gpiomask = 0x00008000,
+ .inputs = {{
+ .type = SAA7134_INPUT_SVIDEO,
+ .vmux = 8,
+ .amux = LINE1,
+ },{
+ .type = SAA7134_INPUT_COMPOSITE1,
+ .vmux = 1,
+ .amux = LINE1,
+ },{
+ .type = SAA7134_INPUT_TV,
+ .vmux = 3,
+ .amux = LINE2,
+ }},
+ .mute = {
+ .type = SAA7134_INPUT_MUTE,
+ .amux = LINE1,
+ },
+ },
+ [SAA7134_BOARD_BEHOLD_403] = {
+ /* Beholder Intl. Ltd. 2008 */
+ /*Dmitry Belimov <d.belimov@gmail.com> */
+ .name = "Beholder BeholdTV 403",
+ .audio_clock = 0x00187de7,
+ .tuner_type = TUNER_PHILIPS_FQ1216ME,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .gpiomask = 0x00008000,
+ .inputs = {{
+ .type = SAA7134_INPUT_SVIDEO,
+ .vmux = 8,
+ .amux = LINE1,
+ },{
+ .type = SAA7134_INPUT_COMPOSITE1,
+ .vmux = 1,
+ .amux = LINE1,
+ },{
+ .type = SAA7134_INPUT_TV,
+ .vmux = 3,
+ .amux = LINE2,
+ }},
+ },
+ [SAA7134_BOARD_BEHOLD_403FM] = {
+ /* Beholder Intl. Ltd. 2008 */
+ /*Dmitry Belimov <d.belimov@gmail.com> */
+ .name = "Beholder BeholdTV 403 FM",
+ .audio_clock = 0x00187de7,
+ .tuner_type = TUNER_PHILIPS_FQ1216ME,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .gpiomask = 0x00008000,
+ .inputs = {{
+ .type = SAA7134_INPUT_SVIDEO,
+ .vmux = 8,
+ .amux = LINE1,
+ },{
+ .type = SAA7134_INPUT_COMPOSITE1,
+ .vmux = 1,
+ .amux = LINE1,
+ },{
+ .type = SAA7134_INPUT_TV,
+ .vmux = 3,
+ .amux = LINE2,
+ }},
+ .radio = {
+ .type = SAA7134_INPUT_RADIO,
+ .amux = LINE2,
+ },
+ },
+ [SAA7134_BOARD_BEHOLD_405] = {
+ /* Beholder Intl. Ltd. 2008 */
+ /*Dmitry Belimov <d.belimov@gmail.com> */
+ .name = "Beholder BeholdTV 405",
+ .audio_clock = 0x00187de7,
+ .tuner_type = TUNER_PHILIPS_FM1216ME_MK3,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .tda9887_conf = TDA9887_PRESENT,
+ .gpiomask = 0x00008000,
+ .inputs = {{
+ .type = SAA7134_INPUT_SVIDEO,
+ .vmux = 8,
+ .amux = LINE1,
+ },{
+ .type = SAA7134_INPUT_COMPOSITE1,
+ .vmux = 3,
+ .amux = LINE1,
+ },{
+ .type = SAA7134_INPUT_TV,
+ .vmux = 3,
+ .amux = LINE2,
+ }},
+ },
+ [SAA7134_BOARD_BEHOLD_405FM] = {
+ /* Sergey <skiv@orel.ru> */
+ /* Beholder Intl. Ltd. 2008 */
+ /*Dmitry Belimov <d.belimov@gmail.com> */
+ .name = "Beholder BeholdTV 405 FM",
+ .audio_clock = 0x00187de7,
+ .tuner_type = TUNER_PHILIPS_FM1216ME_MK3,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .tda9887_conf = TDA9887_PRESENT,
+ .gpiomask = 0x00008000,
+ .inputs = {{
+ .type = SAA7134_INPUT_SVIDEO,
+ .vmux = 8,
+ .amux = LINE1,
+ },{
+ .type = SAA7134_INPUT_COMPOSITE1,
+ .vmux = 3,
+ .amux = LINE1,
+ },{
+ .type = SAA7134_INPUT_TV,
+ .vmux = 3,
+ .amux = LINE2,
+ }},
+ .radio = {
+ .type = SAA7134_INPUT_RADIO,
+ .amux = LINE2,
+ },
+ },
+ [SAA7134_BOARD_BEHOLD_407] = {
+ /* Beholder Intl. Ltd. 2008 */
+ /*Dmitry Belimov <d.belimov@gmail.com> */
+ .name = "Beholder BeholdTV 407",
+ .audio_clock = 0x00187de7,
+ .tuner_type = TUNER_PHILIPS_FM1216ME_MK3,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .tda9887_conf = TDA9887_PRESENT,
+ .gpiomask = 0x00008000,
+ .inputs = {{
+ .type = SAA7134_INPUT_SVIDEO,
+ .vmux = 8,
+ .amux = LINE1,
+ .gpio = 0xc0c000,
+ },{
+ .type = SAA7134_INPUT_COMPOSITE1,
+ .vmux = 1,
+ .amux = LINE1,
+ .gpio = 0xc0c000,
+ },{
+ .type = SAA7134_INPUT_TV,
+ .vmux = 3,
+ .amux = TV,
+ .gpio = 0xc0c000,
+ }},
+ },
+ [SAA7134_BOARD_BEHOLD_407FM] = {
+ /* Beholder Intl. Ltd. 2008 */
+ /*Dmitry Belimov <d.belimov@gmail.com> */
+ .name = "Beholder BeholdTV 407 FM",
+ .audio_clock = 0x00187de7,
+ .tuner_type = TUNER_PHILIPS_FM1216ME_MK3,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .tda9887_conf = TDA9887_PRESENT,
+ .gpiomask = 0x00008000,
+ .inputs = {{
+ .type = SAA7134_INPUT_SVIDEO,
+ .vmux = 8,
+ .amux = LINE1,
+ .gpio = 0xc0c000,
+ },{
+ .type = SAA7134_INPUT_COMPOSITE1,
+ .vmux = 1,
+ .amux = LINE1,
+ .gpio = 0xc0c000,
+ },{
+ .type = SAA7134_INPUT_TV,
+ .vmux = 3,
+ .amux = TV,
+ .gpio = 0xc0c000,
+ }},
+ .radio = {
+ .type = SAA7134_INPUT_RADIO,
+ .amux = LINE2,
+ .gpio = 0xc0c000,
+ },
+ },
+ [SAA7134_BOARD_BEHOLD_409] = {
+ /* Beholder Intl. Ltd. 2008 */
+ /*Dmitry Belimov <d.belimov@gmail.com> */
+ .name = "Beholder BeholdTV 409",
+ .audio_clock = 0x00187de7,
+ .tuner_type = TUNER_PHILIPS_FM1216ME_MK3,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .tda9887_conf = TDA9887_PRESENT,
+ .gpiomask = 0x00008000,
+ .inputs = {{
+ .type = SAA7134_INPUT_TV,
+ .vmux = 3,
+ .amux = TV,
+ },{
+ .type = SAA7134_INPUT_COMPOSITE1,
+ .vmux = 1,
+ .amux = LINE1,
+ },{
+ .type = SAA7134_INPUT_SVIDEO,
+ .vmux = 8,
+ .amux = LINE1,
+ }},
+ },
+ [SAA7134_BOARD_BEHOLD_505FM] = {
+ /* Beholder Intl. Ltd. 2008 */
+ /*Dmitry Belimov <d.belimov@gmail.com> */
+ .name = "Beholder BeholdTV 505 FM",
+ .audio_clock = 0x00200000,
+ .tuner_type = TUNER_PHILIPS_FM1216ME_MK3,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .tda9887_conf = TDA9887_PRESENT,
+ .gpiomask = 0x00008000,
+ .inputs = {{
+ .type = SAA7134_INPUT_TV,
+ .vmux = 3,
+ .amux = LINE2,
+ }, {
+ .type = SAA7134_INPUT_COMPOSITE1,
+ .vmux = 1,
+ .amux = LINE1,
+ }, {
+ .type = SAA7134_INPUT_SVIDEO,
+ .vmux = 8,
+ .amux = LINE1,
+ } },
+ .mute = {
+ .type = SAA7134_INPUT_MUTE,
+ .amux = LINE1,
+ },
+ .radio = {
+ .type = SAA7134_INPUT_RADIO,
+ .amux = LINE2,
+ },
+ },
+ [SAA7134_BOARD_BEHOLD_505RDS_MK5] = {
+ /* Beholder Intl. Ltd. 2008 */
+ /*Dmitry Belimov <d.belimov@gmail.com> */
+ .name = "Beholder BeholdTV 505 RDS",
+ .audio_clock = 0x00200000,
+ .tuner_type = TUNER_PHILIPS_FM1216MK5,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .rds_addr = 0x10,
+ .tda9887_conf = TDA9887_PRESENT,
+ .gpiomask = 0x00008000,
+ .inputs = {{
+ .type = SAA7134_INPUT_TV,
+ .vmux = 3,
+ .amux = LINE2,
+ },{
+ .type = SAA7134_INPUT_COMPOSITE1,
+ .vmux = 1,
+ .amux = LINE1,
+ },{
+ .type = SAA7134_INPUT_SVIDEO,
+ .vmux = 8,
+ .amux = LINE1,
+ }},
+ .mute = {
+ .type = SAA7134_INPUT_MUTE,
+ .amux = LINE1,
+ },
+ .radio = {
+ .type = SAA7134_INPUT_RADIO,
+ .amux = LINE2,
+ },
+ },
+ [SAA7134_BOARD_BEHOLD_507_9FM] = {
+ /* Beholder Intl. Ltd. 2008 */
+ /*Dmitry Belimov <d.belimov@gmail.com> */
+ .name = "Beholder BeholdTV 507 FM / BeholdTV 509 FM",
+ .audio_clock = 0x00187de7,
+ .tuner_type = TUNER_PHILIPS_FM1216ME_MK3,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .tda9887_conf = TDA9887_PRESENT,
+ .gpiomask = 0x00008000,
+ .inputs = {{
+ .type = SAA7134_INPUT_TV,
+ .vmux = 3,
+ .amux = TV,
+ },{
+ .type = SAA7134_INPUT_COMPOSITE1,
+ .vmux = 1,
+ .amux = LINE1,
+ },{
+ .type = SAA7134_INPUT_SVIDEO,
+ .vmux = 8,
+ .amux = LINE1,
+ }},
+ .radio = {
+ .type = SAA7134_INPUT_RADIO,
+ .amux = LINE2,
+ },
+ },
+ [SAA7134_BOARD_BEHOLD_507RDS_MK5] = {
+ /* Beholder Intl. Ltd. 2008 */
+ /*Dmitry Belimov <d.belimov@gmail.com> */
+ .name = "Beholder BeholdTV 507 RDS",
+ .audio_clock = 0x00187de7,
+ .tuner_type = TUNER_PHILIPS_FM1216MK5,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .rds_addr = 0x10,
+ .tda9887_conf = TDA9887_PRESENT,
+ .gpiomask = 0x00008000,
+ .inputs = {{
+ .type = SAA7134_INPUT_TV,
+ .vmux = 3,
+ .amux = TV,
+ }, {
+ .type = SAA7134_INPUT_COMPOSITE1,
+ .vmux = 1,
+ .amux = LINE1,
+ }, {
+ .type = SAA7134_INPUT_SVIDEO,
+ .vmux = 8,
+ .amux = LINE1,
+ } },
+ .radio = {
+ .type = SAA7134_INPUT_RADIO,
+ .amux = LINE2,
+ },
+ },
+ [SAA7134_BOARD_BEHOLD_507RDS_MK3] = {
+ /* Beholder Intl. Ltd. 2008 */
+ /*Dmitry Belimov <d.belimov@gmail.com> */
+ .name = "Beholder BeholdTV 507 RDS",
+ .audio_clock = 0x00187de7,
+ .tuner_type = TUNER_PHILIPS_FM1216ME_MK3,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .rds_addr = 0x10,
+ .tda9887_conf = TDA9887_PRESENT,
+ .gpiomask = 0x00008000,
+ .inputs = {{
+ .type = SAA7134_INPUT_TV,
+ .vmux = 3,
+ .amux = TV,
+ }, {
+ .type = SAA7134_INPUT_COMPOSITE1,
+ .vmux = 1,
+ .amux = LINE1,
+ }, {
+ .type = SAA7134_INPUT_SVIDEO,
+ .vmux = 8,
+ .amux = LINE1,
+ } },
+ .radio = {
+ .type = SAA7134_INPUT_RADIO,
+ .amux = LINE2,
+ },
+ },
+ [SAA7134_BOARD_BEHOLD_COLUMBUS_TVFM] = {
+ /* Beholder Intl. Ltd. 2008 */
+ /* Dmitry Belimov <d.belimov@gmail.com> */
+ .name = "Beholder BeholdTV Columbus TV/FM",
+ .audio_clock = 0x00187de7,
+ .tuner_type = TUNER_ALPS_TSBE5_PAL,
+ .radio_type = TUNER_TEA5767,
+ .tuner_addr = 0xc2 >> 1,
+ .radio_addr = 0xc0 >> 1,
+ .tda9887_conf = TDA9887_PRESENT,
+ .gpiomask = 0x000A8004,
+ .inputs = {{
+ .type = SAA7134_INPUT_TV,
+ .vmux = 3,
+ .amux = TV,
+ .gpio = 0x000A8004,
+ }, {
+ .type = SAA7134_INPUT_COMPOSITE1,
+ .vmux = 1,
+ .amux = LINE1,
+ .gpio = 0x000A8000,
+ }, {
+ .type = SAA7134_INPUT_SVIDEO,
+ .vmux = 8,
+ .amux = LINE1,
+ .gpio = 0x000A8000,
+ } },
+ .radio = {
+ .type = SAA7134_INPUT_RADIO,
+ .amux = LINE2,
+ .gpio = 0x000A8000,
+ },
+ },
+ [SAA7134_BOARD_BEHOLD_607FM_MK3] = {
+ /* Andrey Melnikoff <temnota@kmv.ru> */
+ .name = "Beholder BeholdTV 607 FM",
+ .audio_clock = 0x00187de7,
+ .tuner_type = TUNER_PHILIPS_FM1216ME_MK3,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .tda9887_conf = TDA9887_PRESENT,
+ .inputs = {{
+ .type = SAA7134_INPUT_TV,
+ .vmux = 3,
+ .amux = TV,
+ }, {
+ .type = SAA7134_INPUT_COMPOSITE1,
+ .vmux = 1,
+ .amux = LINE1,
+ }, {
+ .type = SAA7134_INPUT_SVIDEO,
+ .vmux = 8,
+ .amux = LINE1,
+ } },
+ .radio = {
+ .type = SAA7134_INPUT_RADIO,
+ .amux = LINE2,
+ },
+ },
+ [SAA7134_BOARD_BEHOLD_609FM_MK3] = {
+ /* Andrey Melnikoff <temnota@kmv.ru> */
+ .name = "Beholder BeholdTV 609 FM",
+ .audio_clock = 0x00187de7,
+ .tuner_type = TUNER_PHILIPS_FM1216ME_MK3,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .tda9887_conf = TDA9887_PRESENT,
+ .inputs = {{
+ .type = SAA7134_INPUT_TV,
+ .vmux = 3,
+ .amux = TV,
+ }, {
+ .type = SAA7134_INPUT_COMPOSITE1,
+ .vmux = 1,
+ .amux = LINE1,
+ }, {
+ .type = SAA7134_INPUT_SVIDEO,
+ .vmux = 8,
+ .amux = LINE1,
+ } },
+ .radio = {
+ .type = SAA7134_INPUT_RADIO,
+ .amux = LINE2,
+ },
+ },
+ [SAA7134_BOARD_BEHOLD_607FM_MK5] = {
+ /* Andrey Melnikoff <temnota@kmv.ru> */
+ .name = "Beholder BeholdTV 607 FM",
+ .audio_clock = 0x00187de7,
+ .tuner_type = TUNER_PHILIPS_FM1216MK5,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .tda9887_conf = TDA9887_PRESENT,
+ .inputs = {{
+ .type = SAA7134_INPUT_TV,
+ .vmux = 3,
+ .amux = TV,
+ }, {
+ .type = SAA7134_INPUT_COMPOSITE1,
+ .vmux = 1,
+ .amux = LINE1,
+ }, {
+ .type = SAA7134_INPUT_SVIDEO,
+ .vmux = 8,
+ .amux = LINE1,
+ } },
+ .radio = {
+ .type = SAA7134_INPUT_RADIO,
+ .amux = LINE2,
+ },
+ },
+ [SAA7134_BOARD_BEHOLD_609FM_MK5] = {
+ /* Andrey Melnikoff <temnota@kmv.ru> */
+ .name = "Beholder BeholdTV 609 FM",
+ .audio_clock = 0x00187de7,
+ .tuner_type = TUNER_PHILIPS_FM1216MK5,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .tda9887_conf = TDA9887_PRESENT,
+ .inputs = {{
+ .type = SAA7134_INPUT_TV,
+ .vmux = 3,
+ .amux = TV,
+ }, {
+ .type = SAA7134_INPUT_COMPOSITE1,
+ .vmux = 1,
+ .amux = LINE1,
+ }, {
+ .type = SAA7134_INPUT_SVIDEO,
+ .vmux = 8,
+ .amux = LINE1,
+ } },
+ .radio = {
+ .type = SAA7134_INPUT_RADIO,
+ .amux = LINE2,
+ },
+ },
+ [SAA7134_BOARD_BEHOLD_607RDS_MK3] = {
+ /* Andrey Melnikoff <temnota@kmv.ru> */
+ .name = "Beholder BeholdTV 607 RDS",
+ .audio_clock = 0x00187de7,
+ .tuner_type = TUNER_PHILIPS_FM1216ME_MK3,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .rds_addr = 0x10,
+ .tda9887_conf = TDA9887_PRESENT,
+ .inputs = {{
+ .type = SAA7134_INPUT_TV,
+ .vmux = 3,
+ .amux = TV,
+ }, {
+ .type = SAA7134_INPUT_COMPOSITE1,
+ .vmux = 1,
+ .amux = LINE1,
+ }, {
+ .type = SAA7134_INPUT_SVIDEO,
+ .vmux = 8,
+ .amux = LINE1,
+ } },
+ .radio = {
+ .type = SAA7134_INPUT_RADIO,
+ .amux = LINE2,
+ },
+ },
+ [SAA7134_BOARD_BEHOLD_609RDS_MK3] = {
+ /* Andrey Melnikoff <temnota@kmv.ru> */
+ .name = "Beholder BeholdTV 609 RDS",
+ .audio_clock = 0x00187de7,
+ .tuner_type = TUNER_PHILIPS_FM1216ME_MK3,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .rds_addr = 0x10,
+ .tda9887_conf = TDA9887_PRESENT,
+ .inputs = {{
+ .type = SAA7134_INPUT_TV,
+ .vmux = 3,
+ .amux = TV,
+ }, {
+ .type = SAA7134_INPUT_COMPOSITE1,
+ .vmux = 1,
+ .amux = LINE1,
+ }, {
+ .type = SAA7134_INPUT_SVIDEO,
+ .vmux = 8,
+ .amux = LINE1,
+ } },
+ .radio = {
+ .type = SAA7134_INPUT_RADIO,
+ .amux = LINE2,
+ },
+ },
+ [SAA7134_BOARD_BEHOLD_607RDS_MK5] = {
+ /* Andrey Melnikoff <temnota@kmv.ru> */
+ .name = "Beholder BeholdTV 607 RDS",
+ .audio_clock = 0x00187de7,
+ .tuner_type = TUNER_PHILIPS_FM1216MK5,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .rds_addr = 0x10,
+ .tda9887_conf = TDA9887_PRESENT,
+ .inputs = {{
+ .type = SAA7134_INPUT_TV,
+ .vmux = 3,
+ .amux = TV,
+ }, {
+ .type = SAA7134_INPUT_COMPOSITE1,
+ .vmux = 1,
+ .amux = LINE1,
+ }, {
+ .type = SAA7134_INPUT_SVIDEO,
+ .vmux = 8,
+ .amux = LINE1,
+ } },
+ .radio = {
+ .type = SAA7134_INPUT_RADIO,
+ .amux = LINE2,
+ },
+ },
+ [SAA7134_BOARD_BEHOLD_609RDS_MK5] = {
+ /* Andrey Melnikoff <temnota@kmv.ru> */
+ .name = "Beholder BeholdTV 609 RDS",
+ .audio_clock = 0x00187de7,
+ .tuner_type = TUNER_PHILIPS_FM1216MK5,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .rds_addr = 0x10,
+ .tda9887_conf = TDA9887_PRESENT,
+ .inputs = {{
+ .type = SAA7134_INPUT_TV,
+ .vmux = 3,
+ .amux = TV,
+ },{
+ .type = SAA7134_INPUT_COMPOSITE1,
+ .vmux = 1,
+ .amux = LINE1,
+ },{
+ .type = SAA7134_INPUT_SVIDEO,
+ .vmux = 8,
+ .amux = LINE1,
+ }},
+ .radio = {
+ .type = SAA7134_INPUT_RADIO,
+ .amux = LINE2,
+ },
+ },
+ [SAA7134_BOARD_BEHOLD_M6] = {
+ /* Igor Kuznetsov <igk@igk.ru> */
+ /* Andrey Melnikoff <temnota@kmv.ru> */
+ /* Beholder Intl. Ltd. Dmitry Belimov <d.belimov@gmail.com> */
+ /* Alexey Osipov <lion-simba@pridelands.ru> */
+ .name = "Beholder BeholdTV M6",
+ .audio_clock = 0x00187de7,
+ .tuner_type = TUNER_PHILIPS_FM1216ME_MK3,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .empress_addr = 0x20,
+ .tda9887_conf = TDA9887_PRESENT,
+ .inputs = { {
+ .type = SAA7134_INPUT_TV,
+ .vmux = 3,
+ .amux = TV,
+ }, {
+ .type = SAA7134_INPUT_COMPOSITE1,
+ .vmux = 1,
+ .amux = LINE1,
+ }, {
+ .type = SAA7134_INPUT_SVIDEO,
+ .vmux = 8,
+ .amux = LINE1,
+ } },
+ .radio = {
+ .type = SAA7134_INPUT_RADIO,
+ .amux = LINE2,
+ },
+ .mpeg = SAA7134_MPEG_EMPRESS,
+ .video_out = CCIR656,
+ .vid_port_opts = (SET_T_CODE_POLARITY_NON_INVERTED |
+ SET_CLOCK_NOT_DELAYED |
+ SET_CLOCK_INVERTED |
+ SET_VSYNC_OFF),
+ },
+ [SAA7134_BOARD_BEHOLD_M63] = {
+ /* Igor Kuznetsov <igk@igk.ru> */
+ /* Andrey Melnikoff <temnota@kmv.ru> */
+ /* Beholder Intl. Ltd. Dmitry Belimov <d.belimov@gmail.com> */
+ .name = "Beholder BeholdTV M63",
+ .audio_clock = 0x00187de7,
+ .tuner_type = TUNER_PHILIPS_FM1216ME_MK3,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .empress_addr = 0x20,
+ .tda9887_conf = TDA9887_PRESENT,
+ .inputs = { {
+ .type = SAA7134_INPUT_TV,
+ .vmux = 3,
+ .amux = TV,
+ }, {
+ .type = SAA7134_INPUT_COMPOSITE1,
+ .vmux = 1,
+ .amux = LINE1,
+ }, {
+ .type = SAA7134_INPUT_SVIDEO,
+ .vmux = 8,
+ .amux = LINE1,
+ } },
+ .radio = {
+ .type = SAA7134_INPUT_RADIO,
+ .amux = LINE2,
+ },
+ .mpeg = SAA7134_MPEG_EMPRESS,
+ .video_out = CCIR656,
+ .vid_port_opts = (SET_T_CODE_POLARITY_NON_INVERTED |
+ SET_CLOCK_NOT_DELAYED |
+ SET_CLOCK_INVERTED |
+ SET_VSYNC_OFF),
+ },
+ [SAA7134_BOARD_BEHOLD_M6_EXTRA] = {
+ /* Igor Kuznetsov <igk@igk.ru> */
+ /* Andrey Melnikoff <temnota@kmv.ru> */
+ /* Beholder Intl. Ltd. Dmitry Belimov <d.belimov@gmail.com> */
+ /* Alexey Osipov <lion-simba@pridelands.ru> */
+ .name = "Beholder BeholdTV M6 Extra",
+ .audio_clock = 0x00187de7,
+ .tuner_type = TUNER_PHILIPS_FM1216MK5,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .rds_addr = 0x10,
+ .empress_addr = 0x20,
+ .tda9887_conf = TDA9887_PRESENT,
+ .inputs = { {
+ .type = SAA7134_INPUT_TV,
+ .vmux = 3,
+ .amux = TV,
+ }, {
+ .type = SAA7134_INPUT_COMPOSITE1,
+ .vmux = 1,
+ .amux = LINE1,
+ }, {
+ .type = SAA7134_INPUT_SVIDEO,
+ .vmux = 8,
+ .amux = LINE1,
+ } },
+ .radio = {
+ .type = SAA7134_INPUT_RADIO,
+ .amux = LINE2,
+ },
+ .mpeg = SAA7134_MPEG_EMPRESS,
+ .video_out = CCIR656,
+ .vid_port_opts = (SET_T_CODE_POLARITY_NON_INVERTED |
+ SET_CLOCK_NOT_DELAYED |
+ SET_CLOCK_INVERTED |
+ SET_VSYNC_OFF),
+ },
+ [SAA7134_BOARD_TWINHAN_DTV_DVB_3056] = {
+ .name = "Twinhan Hybrid DTV-DVB 3056 PCI",
+ .audio_clock = 0x00187de7,
+ .tuner_type = TUNER_PHILIPS_TDA8290,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .tda829x_conf = { .lna_cfg = TDA8290_LNA_GP0_HIGH_OFF },
+ .mpeg = SAA7134_MPEG_DVB,
+ .gpiomask = 0x0200000,
+ .inputs = {{
+ .type = SAA7134_INPUT_TV,
+ .vmux = 1,
+ .amux = TV,
+ }, {
+ .type = SAA7134_INPUT_COMPOSITE1,
+ .vmux = 3,
+ .amux = LINE1,
+ }, {
+ .type = SAA7134_INPUT_SVIDEO,
+ .vmux = 8, /* untested */
+ .amux = LINE1,
+ } },
+ .radio = {
+ .type = SAA7134_INPUT_RADIO,
+ .amux = TV,
+ .gpio = 0x0200000,
+ },
+ },
+ [SAA7134_BOARD_GENIUS_TVGO_A11MCE] = {
+ /* Adrian Pardini <pardo.bsso@gmail.com> */
+ .name = "Genius TVGO AM11MCE",
+ .audio_clock = 0x00200000,
+ .tuner_type = TUNER_TNF_5335MF,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .gpiomask = 0xf000,
+ .inputs = {{
+ .type = SAA7134_INPUT_TV_MONO,
+ .vmux = 1,
+ .amux = LINE2,
+ .gpio = 0x0000,
+ }, {
+ .type = SAA7134_INPUT_COMPOSITE1,
+ .vmux = 3,
+ .amux = LINE1,
+ .gpio = 0x2000,
+ }, {
+ .type = SAA7134_INPUT_SVIDEO,
+ .vmux = 8,
+ .amux = LINE1,
+ .gpio = 0x2000,
+ } },
+ .radio = {
+ .type = SAA7134_INPUT_RADIO,
+ .amux = LINE2,
+ .gpio = 0x1000,
+ },
+ .mute = {
+ .type = SAA7134_INPUT_MUTE,
+ .amux = LINE2,
+ .gpio = 0x6000,
+ },
+ },
+ [SAA7134_BOARD_PHILIPS_SNAKE] = {
+ .name = "NXP Snake DVB-S reference design",
+ .audio_clock = 0x00200000,
+ .tuner_type = TUNER_ABSENT,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .mpeg = SAA7134_MPEG_DVB,
+ .inputs = {{
+ .type = SAA7134_INPUT_COMPOSITE1,
+ .vmux = 3,
+ .amux = LINE1,
+ }, {
+ .type = SAA7134_INPUT_SVIDEO,
+ .vmux = 8,
+ .amux = LINE1,
+ } },
+ },
+ [SAA7134_BOARD_CREATIX_CTX953] = {
+ .name = "Medion/Creatix CTX953 Hybrid",
+ .audio_clock = 0x00187de7,
+ .tuner_type = TUNER_PHILIPS_TDA8290,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .tda829x_conf = { .lna_cfg = TDA8290_LNA_OFF },
+ .mpeg = SAA7134_MPEG_DVB,
+ .inputs = {{
+ .type = SAA7134_INPUT_TV,
+ .vmux = 1,
+ .amux = TV,
+ }, {
+ .type = SAA7134_INPUT_COMPOSITE1,
+ .vmux = 0,
+ .amux = LINE1,
+ }, {
+ .type = SAA7134_INPUT_SVIDEO,
+ .vmux = 8,
+ .amux = LINE1,
+ } },
+ },
+ [SAA7134_BOARD_MSI_TVANYWHERE_AD11] = {
+ .name = "MSI TV@nywhere A/D v1.1",
+ .audio_clock = 0x00187de7,
+ .tuner_type = TUNER_PHILIPS_TDA8290,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .tda829x_conf = { .lna_cfg = TDA8290_LNA_GP0_HIGH_OFF },
+ .mpeg = SAA7134_MPEG_DVB,
+ .gpiomask = 0x0200000,
+ .inputs = { {
+ .type = SAA7134_INPUT_TV,
+ .vmux = 1,
+ .amux = TV,
+ }, {
+ .type = SAA7134_INPUT_COMPOSITE1,
+ .vmux = 3,
+ .amux = LINE1,
+ }, {
+ .type = SAA7134_INPUT_SVIDEO,
+ .vmux = 8,
+ .amux = LINE1,
+ } },
+ .radio = {
+ .type = SAA7134_INPUT_RADIO,
+ .amux = TV,
+ .gpio = 0x0200000,
+ },
+ },
+ [SAA7134_BOARD_AVERMEDIA_CARDBUS_506] = {
+ .name = "AVerMedia Cardbus TV/Radio (E506R)",
+ .audio_clock = 0x187de7,
+ .tuner_type = TUNER_XC2028,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .mpeg = SAA7134_MPEG_DVB,
+ .inputs = {{
+ .type = SAA7134_INPUT_TV,
+ .vmux = 1,
+ .amux = TV,
+ }, {
+ .type = SAA7134_INPUT_COMPOSITE1,
+ .vmux = 3,
+ .amux = LINE1,
+ }, {
+ .type = SAA7134_INPUT_SVIDEO,
+ .vmux = 8,
+ .amux = LINE2,
+ } },
+ .radio = {
+ .type = SAA7134_INPUT_RADIO,
+ .amux = TV,
+ },
+ },
+ [SAA7134_BOARD_AVERMEDIA_A16D] = {
+ .name = "AVerMedia Hybrid TV/Radio (A16D)",
+ .audio_clock = 0x187de7,
+ .tuner_type = TUNER_XC2028,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .mpeg = SAA7134_MPEG_DVB,
+ .inputs = {{
+ .type = SAA7134_INPUT_TV,
+ .vmux = 1,
+ .amux = TV,
+ }, {
+ .type = SAA7134_INPUT_SVIDEO,
+ .vmux = 8,
+ .amux = LINE1,
+ }, {
+ .type = SAA7134_INPUT_COMPOSITE,
+ .vmux = 0,
+ .amux = LINE1,
+ } },
+ .radio = {
+ .type = SAA7134_INPUT_RADIO,
+ .amux = TV,
+ },
+ },
+ [SAA7134_BOARD_AVERMEDIA_M115] = {
+ .name = "Avermedia M115",
+ .audio_clock = 0x187de7,
+ .tuner_type = TUNER_XC2028,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .inputs = {{
+ .type = SAA7134_INPUT_TV,
+ .vmux = 1,
+ .amux = TV,
+ }, {
+ .type = SAA7134_INPUT_COMPOSITE1,
+ .vmux = 3,
+ .amux = LINE1,
+ }, {
+ .type = SAA7134_INPUT_SVIDEO,
+ .vmux = 8,
+ .amux = LINE2,
+ } },
+ },
+ [SAA7134_BOARD_VIDEOMATE_T750] = {
+ /* John Newbigin <jn@it.swin.edu.au> */
+ .name = "Compro VideoMate T750",
+ .audio_clock = 0x00187de7,
+ .tuner_type = TUNER_XC2028,
+ .radio_type = UNSET,
+ .tuner_addr = 0x61,
+ .radio_addr = ADDR_UNSET,
+ .mpeg = SAA7134_MPEG_DVB,
+ .inputs = {{
+ .type = SAA7134_INPUT_TV,
+ .vmux = 3,
+ .amux = TV,
+ }, {
+ .type = SAA7134_INPUT_COMPOSITE1,
+ .vmux = 1,
+ .amux = LINE2,
+ }, {
+ .type = SAA7134_INPUT_SVIDEO,
+ .vmux = 8,
+ .amux = LINE2,
+ } },
+ .radio = {
+ .type = SAA7134_INPUT_RADIO,
+ .amux = TV,
+ }
+ },
+ [SAA7134_BOARD_AVERMEDIA_A700_PRO] = {
+ /* Matthias Schwarzott <zzam@gentoo.org> */
+ .name = "Avermedia DVB-S Pro A700",
+ .audio_clock = 0x00187de7,
+ .tuner_type = TUNER_ABSENT,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .mpeg = SAA7134_MPEG_DVB,
+ .inputs = { {
+ .type = SAA7134_INPUT_COMPOSITE,
+ .vmux = 1,
+ .amux = LINE1,
+ }, {
+ .type = SAA7134_INPUT_SVIDEO,
+ .vmux = 6,
+ .amux = LINE1,
+ } },
+ },
+ [SAA7134_BOARD_AVERMEDIA_A700_HYBRID] = {
+ /* Matthias Schwarzott <zzam@gentoo.org> */
+ .name = "Avermedia DVB-S Hybrid+FM A700",
+ .audio_clock = 0x00187de7,
+ .tuner_type = TUNER_XC2028,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .mpeg = SAA7134_MPEG_DVB,
+ .inputs = { {
+ .type = SAA7134_INPUT_TV,
+ .vmux = 4,
+ .amux = TV,
+ }, {
+ .type = SAA7134_INPUT_COMPOSITE,
+ .vmux = 1,
+ .amux = LINE1,
+ }, {
+ .type = SAA7134_INPUT_SVIDEO,
+ .vmux = 6,
+ .amux = LINE1,
+ } },
+ .radio = {
+ .type = SAA7134_INPUT_RADIO,
+ .amux = TV,
+ },
+ },
+ [SAA7134_BOARD_BEHOLD_H6] = {
+ /* Igor Kuznetsov <igk@igk.ru> */
+ .name = "Beholder BeholdTV H6",
+ .audio_clock = 0x00187de7,
+ .tuner_type = TUNER_PHILIPS_FMD1216MEX_MK3,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .tda9887_conf = TDA9887_PRESENT,
+ .mpeg = SAA7134_MPEG_DVB,
+ .inputs = {{
+ .type = SAA7134_INPUT_TV,
+ .vmux = 3,
+ .amux = TV,
+ }, {
+ .type = SAA7134_INPUT_COMPOSITE1,
+ .vmux = 1,
+ .amux = LINE1,
+ }, {
+ .type = SAA7134_INPUT_SVIDEO,
+ .vmux = 8,
+ .amux = LINE1,
+ } },
+ .radio = {
+ .type = SAA7134_INPUT_RADIO,
+ .amux = LINE2,
+ },
+ },
+ [SAA7134_BOARD_ASUSTeK_TIGER_3IN1] = {
+ .name = "Asus Tiger 3in1",
+ .audio_clock = 0x00187de7,
+ .tuner_type = TUNER_PHILIPS_TDA8290,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .tda829x_conf = { .lna_cfg = TDA8290_LNA_GP0_HIGH_OFF },
+ .gpiomask = 1 << 21,
+ .mpeg = SAA7134_MPEG_DVB,
+ .inputs = {{
+ .type = SAA7134_INPUT_TV,
+ .vmux = 1,
+ .amux = TV,
+ }, {
+ .type = SAA7134_INPUT_COMPOSITE,
+ .vmux = 0,
+ .amux = LINE2,
+ }, {
+ .type = SAA7134_INPUT_SVIDEO,
+ .vmux = 8,
+ .amux = LINE2,
+ } },
+ .radio = {
+ .type = SAA7134_INPUT_RADIO,
+ .amux = TV,
+ .gpio = 0x0200000,
+ },
+ },
+ [SAA7134_BOARD_ASUSTeK_PS3_100] = {
+ .name = "Asus My Cinema PS3-100",
+ .audio_clock = 0x00187de7,
+ .tuner_type = TUNER_PHILIPS_TDA8290,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .tda829x_conf = { .lna_cfg = TDA8290_LNA_GP0_HIGH_OFF },
+ .gpiomask = 1 << 21,
+ .mpeg = SAA7134_MPEG_DVB,
+ .inputs = {{
+ .type = SAA7134_INPUT_TV,
+ .vmux = 1,
+ .amux = TV,
+ }, {
+ .type = SAA7134_INPUT_COMPOSITE,
+ .vmux = 0,
+ .amux = LINE2,
+ }, {
+ .type = SAA7134_INPUT_SVIDEO,
+ .vmux = 8,
+ .amux = LINE2,
+ } },
+ .radio = {
+ .type = SAA7134_INPUT_RADIO,
+ .amux = TV,
+ .gpio = 0x0200000,
+ },
+ },
+ [SAA7134_BOARD_REAL_ANGEL_220] = {
+ .name = "Zogis Real Angel 220",
+ .audio_clock = 0x00187de7,
+ .tuner_type = TUNER_TNF_5335MF,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .gpiomask = 0x801a8087,
+ .inputs = { {
+ .type = SAA7134_INPUT_TV,
+ .vmux = 3,
+ .amux = LINE2,
+ .gpio = 0x624000,
+ }, {
+ .type = SAA7134_INPUT_COMPOSITE1,
+ .vmux = 1,
+ .amux = LINE1,
+ .gpio = 0x624000,
+ }, {
+ .type = SAA7134_INPUT_SVIDEO,
+ .vmux = 1,
+ .amux = LINE1,
+ .gpio = 0x624000,
+ } },
+ .radio = {
+ .type = SAA7134_INPUT_RADIO,
+ .amux = LINE2,
+ .gpio = 0x624001,
+ },
+ .mute = {
+ .type = SAA7134_INPUT_MUTE,
+ .amux = TV,
+ },
+ },
+ [SAA7134_BOARD_ADS_INSTANT_HDTV_PCI] = {
+ .name = "ADS Tech Instant HDTV",
+ .audio_clock = 0x00187de7,
+ .tuner_type = TUNER_PHILIPS_TUV1236D,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .tda9887_conf = TDA9887_PRESENT,
+ .mpeg = SAA7134_MPEG_DVB,
+ .inputs = { {
+ .type = SAA7134_INPUT_TV,
+ .vmux = 1,
+ .amux = TV,
+ }, {
+ .type = SAA7134_INPUT_COMPOSITE,
+ .vmux = 4,
+ .amux = LINE1,
+ }, {
+ .type = SAA7134_INPUT_SVIDEO,
+ .vmux = 8,
+ .amux = LINE1,
+ } },
+ },
+ [SAA7134_BOARD_ASUSTeK_TIGER] = {
+ .name = "Asus Tiger Rev:1.00",
+ .audio_clock = 0x00187de7,
+ .tuner_type = TUNER_PHILIPS_TDA8290,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .tda829x_conf = { .lna_cfg = TDA8290_LNA_OFF },
+ .mpeg = SAA7134_MPEG_DVB,
+ .gpiomask = 0x0200000,
+ .inputs = { {
+ .type = SAA7134_INPUT_TV,
+ .vmux = 1,
+ .amux = TV,
+ }, {
+ .type = SAA7134_INPUT_COMPOSITE1,
+ .vmux = 3,
+ .amux = LINE2,
+ }, {
+ .type = SAA7134_INPUT_COMPOSITE2,
+ .vmux = 0,
+ .amux = LINE2,
+ }, {
+ .type = SAA7134_INPUT_SVIDEO,
+ .vmux = 8,
+ .amux = LINE2,
+ } },
+ .radio = {
+ .type = SAA7134_INPUT_RADIO,
+ .amux = TV,
+ .gpio = 0x0200000,
+ },
+ },
+ [SAA7134_BOARD_KWORLD_PLUS_TV_ANALOG] = {
+ .name = "Kworld Plus TV Analog Lite PCI",
+ .audio_clock = 0x00187de7,
+ .tuner_type = TUNER_YMEC_TVF_5533MF,
+ .radio_type = TUNER_TEA5767,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = 0x60,
+ .gpiomask = 0x80000700,
+ .inputs = { {
+ .type = SAA7134_INPUT_TV,
+ .vmux = 1,
+ .amux = LINE2,
+ .gpio = 0x100,
+ }, {
+ .type = SAA7134_INPUT_COMPOSITE1,
+ .vmux = 3,
+ .amux = LINE1,
+ .gpio = 0x200,
+ }, {
+ .type = SAA7134_INPUT_SVIDEO,
+ .vmux = 8,
+ .amux = LINE1,
+ .gpio = 0x200,
+ } },
+ .radio = {
+ .type = SAA7134_INPUT_RADIO,
+ .vmux = 1,
+ .amux = LINE1,
+ .gpio = 0x100,
+ },
+ .mute = {
+ .type = SAA7134_INPUT_MUTE,
+ .vmux = 8,
+ .amux = 2,
+ },
+ },
+ [SAA7134_BOARD_KWORLD_PCI_SBTVD_FULLSEG] = {
+ .name = "Kworld PCI SBTVD/ISDB-T Full-Seg Hybrid",
+ .audio_clock = 0x00187de7,
+ .tuner_type = TUNER_PHILIPS_TDA8290,
+ .tuner_addr = ADDR_UNSET,
+ .radio_type = UNSET,
+ .radio_addr = ADDR_UNSET,
+ .gpiomask = 0x8e054000,
+ .mpeg = SAA7134_MPEG_DVB,
+ .ts_type = SAA7134_MPEG_TS_PARALLEL,
+ .inputs = { {
+ .type = SAA7134_INPUT_TV,
+ .vmux = 1,
+ .amux = TV,
+#if 0 /* FIXME */
+ }, {
+ .type = SAA7134_INPUT_COMPOSITE1,
+ .vmux = 3,
+ .amux = LINE1,
+ .gpio = 0x200,
+ }, {
+ .type = SAA7134_INPUT_SVIDEO,
+ .vmux = 8,
+ .amux = LINE1,
+ .gpio = 0x200,
+#endif
+ } },
+#if 0
+ .radio = {
+ .type = SAA7134_INPUT_RADIO,
+ .vmux = 1,
+ .amux = LINE1,
+ .gpio = 0x100,
+ },
+#endif
+ .mute = {
+ .type = SAA7134_INPUT_MUTE,
+ .vmux = 0,
+ .amux = TV,
+ },
+ },
+ [SAA7134_BOARD_AVERMEDIA_GO_007_FM_PLUS] = {
+ .name = "Avermedia AVerTV GO 007 FM Plus",
+ .audio_clock = 0x00187de7,
+ .tuner_type = TUNER_PHILIPS_TDA8290,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .gpiomask = 0x00300003,
+ /* .gpiomask = 0x8c240003, */
+ .inputs = { {
+ .type = SAA7134_INPUT_TV,
+ .vmux = 1,
+ .amux = TV,
+ .gpio = 0x01,
+ }, {
+ .type = SAA7134_INPUT_SVIDEO,
+ .vmux = 6,
+ .amux = LINE1,
+ .gpio = 0x02,
+ } },
+ .radio = {
+ .type = SAA7134_INPUT_RADIO,
+ .amux = TV,
+ .gpio = 0x00300001,
+ },
+ .mute = {
+ .type = SAA7134_INPUT_MUTE,
+ .amux = TV,
+ .gpio = 0x01,
+ },
+ },
+ [SAA7134_BOARD_AVERMEDIA_STUDIO_507UA] = {
+ /* Andy Shevchenko <andy@smile.org.ua> */
+ .name = "Avermedia AVerTV Studio 507UA",
+ .audio_clock = 0x00187de7,
+ .tuner_type = TUNER_PHILIPS_FM1216ME_MK3, /* Should be MK5 */
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .tda9887_conf = TDA9887_PRESENT,
+ .gpiomask = 0x03,
+ .inputs = { {
+ .type = SAA7134_INPUT_TV,
+ .vmux = 1,
+ .amux = TV,
+ .gpio = 0x00,
+ }, {
+ .type = SAA7134_INPUT_COMPOSITE1,
+ .vmux = 3,
+ .amux = LINE1,
+ .gpio = 0x00,
+ }, {
+ .type = SAA7134_INPUT_SVIDEO,
+ .vmux = 8,
+ .amux = LINE1,
+ .gpio = 0x00,
+ } },
+ .radio = {
+ .type = SAA7134_INPUT_RADIO,
+ .amux = LINE2,
+ .gpio = 0x01,
+ },
+ .mute = {
+ .type = SAA7134_INPUT_MUTE,
+ .amux = LINE1,
+ .gpio = 0x00,
+ },
+ },
+ [SAA7134_BOARD_VIDEOMATE_S350] = {
+ /* Jan D. Louw <jd.louw@mweb.co.za */
+ .name = "Compro VideoMate S350/S300",
+ .audio_clock = 0x00187de7,
+ .tuner_type = TUNER_ABSENT,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .mpeg = SAA7134_MPEG_DVB,
+ .inputs = { {
+ .type = SAA7134_INPUT_COMPOSITE1,
+ .vmux = 0,
+ .amux = LINE1,
+ }, {
+ .type = SAA7134_INPUT_SVIDEO,
+ .vmux = 8, /* Not tested */
+ .amux = LINE1
+ } },
+ },
+ [SAA7134_BOARD_BEHOLD_X7] = {
+ /* Beholder Intl. Ltd. Dmitry Belimov <d.belimov@gmail.com> */
+ .name = "Beholder BeholdTV X7",
+ .audio_clock = 0x00187de7,
+ .tuner_type = TUNER_XC5000,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .mpeg = SAA7134_MPEG_DVB,
+ .inputs = { {
+ .type = SAA7134_INPUT_TV,
+ .vmux = 2,
+ .amux = TV,
+ }, {
+ .type = SAA7134_INPUT_COMPOSITE1,
+ .vmux = 0,
+ .amux = LINE1,
+ }, {
+ .type = SAA7134_INPUT_SVIDEO,
+ .vmux = 9,
+ .amux = LINE1,
+ } },
+ .radio = {
+ .type = SAA7134_INPUT_RADIO,
+ .amux = TV,
+ },
+ },
+ [SAA7134_BOARD_ZOLID_HYBRID_PCI] = {
+ .name = "Zolid Hybrid TV Tuner PCI",
+ .audio_clock = 0x00187de7,
+ .tuner_type = TUNER_PHILIPS_TDA8290,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .tda829x_conf = { .lna_cfg = TDA8290_LNA_OFF },
+ .mpeg = SAA7134_MPEG_DVB,
+ .ts_type = SAA7134_MPEG_TS_PARALLEL,
+ .inputs = {{
+ .type = SAA7134_INPUT_TV,
+ .vmux = 1,
+ .amux = TV,
+ } },
+ .radio = { /* untested */
+ .type = SAA7134_INPUT_RADIO,
+ .amux = TV,
+ },
+ },
+ [SAA7134_BOARD_ASUS_EUROPA_HYBRID] = {
+ .name = "Asus Europa Hybrid OEM",
+ .audio_clock = 0x00187de7,
+ .tuner_type = TUNER_PHILIPS_TD1316,
+ .radio_type = UNSET,
+ .tuner_addr = 0x61,
+ .radio_addr = ADDR_UNSET,
+ .tda9887_conf = TDA9887_PRESENT | TDA9887_PORT1_ACTIVE,
+ .mpeg = SAA7134_MPEG_DVB,
+ .inputs = { {
+ .type = SAA7134_INPUT_TV,
+ .vmux = 3,
+ .amux = TV,
+ }, {
+ .type = SAA7134_INPUT_COMPOSITE1,
+ .vmux = 4,
+ .amux = LINE2,
+ }, {
+ .type = SAA7134_INPUT_SVIDEO,
+ .vmux = 8,
+ .amux = LINE2,
+ } },
+ },
+ [SAA7134_BOARD_LEADTEK_WINFAST_DTV1000S] = {
+ .name = "Leadtek Winfast DTV1000S",
+ .audio_clock = 0x00187de7,
+ .tuner_type = TUNER_PHILIPS_TDA8290,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .mpeg = SAA7134_MPEG_DVB,
+ .inputs = { {
+ .type = SAA7134_INPUT_COMPOSITE1,
+ .vmux = 3,
+ }, {
+ .type = SAA7134_INPUT_SVIDEO,
+ .vmux = 8,
+ } },
+ },
+ [SAA7134_BOARD_BEHOLD_505RDS_MK3] = {
+ /* Beholder Intl. Ltd. 2008 */
+ /*Dmitry Belimov <d.belimov@gmail.com> */
+ .name = "Beholder BeholdTV 505 RDS",
+ .audio_clock = 0x00200000,
+ .tuner_type = TUNER_PHILIPS_FM1216ME_MK3,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .rds_addr = 0x10,
+ .tda9887_conf = TDA9887_PRESENT,
+ .gpiomask = 0x00008000,
+ .inputs = {{
+ .type = SAA7134_INPUT_TV,
+ .vmux = 3,
+ .amux = LINE2,
+ }, {
+ .type = SAA7134_INPUT_COMPOSITE1,
+ .vmux = 1,
+ .amux = LINE1,
+ }, {
+ .type = SAA7134_INPUT_SVIDEO,
+ .vmux = 8,
+ .amux = LINE1,
+ } },
+ .mute = {
+ .type = SAA7134_INPUT_MUTE,
+ .amux = LINE1,
+ },
+ .radio = {
+ .type = SAA7134_INPUT_RADIO,
+ .amux = LINE2,
+ },
+ },
+ [SAA7134_BOARD_HAWELL_HW_404M7] = {
+ /* Hawell HW-404M7 & Hawell HW-808M7 */
+ /* Bogoslovskiy Viktor <bogovic@bk.ru> */
+ .name = "Hawell HW-404M7",
+ .audio_clock = 0x00200000,
+ .tuner_type = UNSET,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .gpiomask = 0x389c00,
+ .inputs = {{
+ .type = SAA7134_INPUT_COMPOSITE1,
+ .vmux = 3,
+ .amux = LINE1,
+ .gpio = 0x01fc00,
+ } },
+ },
+ [SAA7134_BOARD_BEHOLD_H7] = {
+ /* Beholder Intl. Ltd. Dmitry Belimov <d.belimov@gmail.com> */
+ .name = "Beholder BeholdTV H7",
+ .audio_clock = 0x00187de7,
+ .tuner_type = TUNER_XC5000,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .mpeg = SAA7134_MPEG_DVB,
+ .ts_type = SAA7134_MPEG_TS_PARALLEL,
+ .inputs = { {
+ .type = SAA7134_INPUT_TV,
+ .vmux = 2,
+ .amux = TV,
+ }, {
+ .type = SAA7134_INPUT_COMPOSITE1,
+ .vmux = 0,
+ .amux = LINE1,
+ }, {
+ .type = SAA7134_INPUT_SVIDEO,
+ .vmux = 9,
+ .amux = LINE1,
+ } },
+ .radio = {
+ .type = SAA7134_INPUT_RADIO,
+ .amux = TV,
+ },
+ },
+ [SAA7134_BOARD_BEHOLD_A7] = {
+ /* Beholder Intl. Ltd. Dmitry Belimov <d.belimov@gmail.com> */
+ .name = "Beholder BeholdTV A7",
+ .audio_clock = 0x00187de7,
+ .tuner_type = TUNER_XC5000,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .inputs = { {
+ .type = SAA7134_INPUT_TV,
+ .vmux = 2,
+ .amux = TV,
+ }, {
+ .type = SAA7134_INPUT_COMPOSITE1,
+ .vmux = 0,
+ .amux = LINE1,
+ }, {
+ .type = SAA7134_INPUT_SVIDEO,
+ .vmux = 9,
+ .amux = LINE1,
+ } },
+ .radio = {
+ .type = SAA7134_INPUT_RADIO,
+ .amux = TV,
+ },
+ },
+ [SAA7134_BOARD_TECHNOTREND_BUDGET_T3000] = {
+ .name = "TechoTrend TT-budget T-3000",
+ .tuner_type = TUNER_PHILIPS_TD1316,
+ .audio_clock = 0x00187de7,
+ .radio_type = UNSET,
+ .tuner_addr = 0x63,
+ .radio_addr = ADDR_UNSET,
+ .tda9887_conf = TDA9887_PRESENT | TDA9887_PORT1_ACTIVE,
+ .mpeg = SAA7134_MPEG_DVB,
+ .inputs = {{
+ .type = SAA7134_INPUT_TV,
+ .vmux = 3,
+ .amux = TV,
+ }, {
+ .type = SAA7134_INPUT_COMPOSITE1,
+ .vmux = 0,
+ .amux = LINE2,
+ }, {
+ .type = SAA7134_INPUT_SVIDEO,
+ .vmux = 8,
+ .amux = LINE2,
+ } },
+ },
+ [SAA7134_BOARD_VIDEOMATE_M1F] = {
+ /* Pavel Osnova <pvosnova@gmail.com> */
+ .name = "Compro VideoMate Vista M1F",
+ .audio_clock = 0x00187de7,
+ .tuner_type = TUNER_LG_PAL_NEW_TAPC,
+ .radio_type = TUNER_TEA5767,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = 0x60,
+ .inputs = { {
+ .type = SAA7134_INPUT_TV,
+ .vmux = 1,
+ .amux = TV,
+ }, {
+ .type = SAA7134_INPUT_COMPOSITE1,
+ .vmux = 3,
+ .amux = LINE2,
+ }, {
+ .type = SAA7134_INPUT_SVIDEO,
+ .vmux = 8,
+ .amux = LINE2,
+ } },
+ .radio = {
+ .type = SAA7134_INPUT_RADIO,
+ .amux = LINE1,
+ },
+ .mute = {
+ .type = SAA7134_INPUT_MUTE,
+ .amux = TV,
+ },
+ },
+ [SAA7134_BOARD_MAGICPRO_PROHDTV_PRO2] = {
+ /* Timothy Lee <timothy.lee@siriushk.com> */
+ .name = "MagicPro ProHDTV Pro2 DMB-TH/Hybrid",
+ .audio_clock = 0x00187de7,
+ .tuner_type = TUNER_PHILIPS_TDA8290,
+ .radio_type = UNSET,
+ .tda829x_conf = { .lna_cfg = TDA8290_LNA_ON_BRIDGE },
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .gpiomask = 0x02050000,
+ .mpeg = SAA7134_MPEG_DVB,
+ .ts_type = SAA7134_MPEG_TS_PARALLEL,
+ .inputs = { {
+ .type = SAA7134_INPUT_TV,
+ .vmux = 1,
+ .amux = TV,
+ .gpio = 0x00050000,
+ }, {
+ .type = SAA7134_INPUT_COMPOSITE1,
+ .vmux = 3,
+ .amux = LINE1,
+ .gpio = 0x00050000,
+ }, {
+ .type = SAA7134_INPUT_SVIDEO,
+ .vmux = 8,
+ .amux = LINE1,
+ .gpio = 0x00050000,
+ } },
+ .radio = {
+ .type = SAA7134_INPUT_RADIO,
+ .amux = TV,
+ .gpio = 0x00050000,
+ },
+ .mute = {
+ .type = SAA7134_INPUT_MUTE,
+ .vmux = 0,
+ .amux = TV,
+ .gpio = 0x00050000,
+ },
+ },
+ [SAA7134_BOARD_BEHOLD_501] = {
+ /* Beholder Intl. Ltd. 2010 */
+ /* Dmitry Belimov <d.belimov@gmail.com> */
+ .name = "Beholder BeholdTV 501",
+ .audio_clock = 0x00200000,
+ .tuner_type = TUNER_ABSENT,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .gpiomask = 0x00008000,
+ .inputs = { {
+ .type = SAA7134_INPUT_TV,
+ .vmux = 3,
+ .amux = LINE2,
+ }, {
+ .type = SAA7134_INPUT_COMPOSITE1,
+ .vmux = 1,
+ .amux = LINE1,
+ }, {
+ .type = SAA7134_INPUT_SVIDEO,
+ .vmux = 8,
+ .amux = LINE1,
+ } },
+ .mute = {
+ .type = SAA7134_INPUT_MUTE,
+ .amux = LINE1,
+ },
+ },
+ [SAA7134_BOARD_BEHOLD_503FM] = {
+ /* Beholder Intl. Ltd. 2010 */
+ /* Dmitry Belimov <d.belimov@gmail.com> */
+ .name = "Beholder BeholdTV 503 FM",
+ .audio_clock = 0x00200000,
+ .tuner_type = TUNER_ABSENT,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .gpiomask = 0x00008000,
+ .inputs = { {
+ .type = SAA7134_INPUT_TV,
+ .vmux = 3,
+ .amux = LINE2,
+ }, {
+ .type = SAA7134_INPUT_COMPOSITE1,
+ .vmux = 1,
+ .amux = LINE1,
+ }, {
+ .type = SAA7134_INPUT_SVIDEO,
+ .vmux = 8,
+ .amux = LINE1,
+ } },
+ .mute = {
+ .type = SAA7134_INPUT_MUTE,
+ .amux = LINE1,
+ },
+ },
+ [SAA7134_BOARD_SENSORAY811_911] = {
+ .name = "Sensoray 811/911",
+ .audio_clock = 0x00200000,
+ .tuner_type = TUNER_ABSENT,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .inputs = {{
+ .type = SAA7134_INPUT_COMPOSITE1,
+ .vmux = 0,
+ .amux = LINE1,
+ }, {
+ .type = SAA7134_INPUT_COMPOSITE3,
+ .vmux = 2,
+ .amux = LINE1,
+ }, {
+ .type = SAA7134_INPUT_SVIDEO,
+ .vmux = 8,
+ .amux = LINE1,
+ } },
+ },
+ [SAA7134_BOARD_KWORLD_PC150U] = {
+ .name = "Kworld PC150-U",
+ .audio_clock = 0x00187de7,
+ .tuner_type = TUNER_PHILIPS_TDA8290,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .mpeg = SAA7134_MPEG_DVB,
+ .gpiomask = 1 << 21,
+ .ts_type = SAA7134_MPEG_TS_PARALLEL,
+ .inputs = { {
+ .type = SAA7134_INPUT_TV,
+ .vmux = 1,
+ .amux = TV,
+ }, {
+ .type = SAA7134_INPUT_COMPOSITE,
+ .vmux = 3,
+ .amux = LINE1,
+ }, {
+ .type = SAA7134_INPUT_SVIDEO,
+ .vmux = 8,
+ .amux = LINE2,
+ } },
+ .radio = {
+ .type = SAA7134_INPUT_RADIO,
+ .amux = TV,
+ .gpio = 0x0000000,
+ },
+ },
+ [SAA7134_BOARD_HAWELL_HW_9004V1] = {
+ /* Hawell HW-9004V1 */
+ /* Vadim Frolov <fralik@gmail.com> */
+ .name = "Hawell HW-9004V1",
+ .audio_clock = 0x00200000,
+ .tuner_type = UNSET,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .gpiomask = 0x618E700,
+ .inputs = {{
+ .type = SAA7134_INPUT_COMPOSITE1,
+ .vmux = 3,
+ .amux = LINE1,
+ .gpio = 0x6010000,
+ } },
+ },
+ [SAA7134_BOARD_AVERMEDIA_A706] = {
+ .name = "AverMedia AverTV Satellite Hybrid+FM A706",
+ .audio_clock = 0x00187de7,
+ .tuner_type = TUNER_PHILIPS_TDA8290,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .tda829x_conf = { .lna_cfg = TDA8290_LNA_OFF,
+ .no_i2c_gate = 1,
+ .tda18271_std_map = &aver_a706_std_map },
+ .gpiomask = 1 << 11,
+ .mpeg = SAA7134_MPEG_DVB,
+ .inputs = {{
+ .type = SAA7134_INPUT_TV,
+ .vmux = 1,
+ .amux = TV,
+ }, {
+ .type = SAA7134_INPUT_COMPOSITE,
+ .vmux = 4,
+ .amux = LINE1,
+ }, {
+ .type = SAA7134_INPUT_SVIDEO,
+ .vmux = 8,
+ .amux = LINE1,
+ } },
+ .radio = {
+ .type = SAA7134_INPUT_RADIO,
+ .amux = TV,
+ .gpio = 0x0000800,
+ },
+ },
+ [SAA7134_BOARD_WIS_VOYAGER] = {
+ .name = "WIS Voyager or compatible",
+ .audio_clock = 0x00200000,
+ .tuner_type = TUNER_PHILIPS_TDA8290,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .mpeg = SAA7134_MPEG_GO7007,
+ .inputs = { {
+ .type = SAA7134_INPUT_COMPOSITE1,
+ .vmux = 0,
+ .amux = LINE2,
+ }, {
+ .type = SAA7134_INPUT_TV,
+ .vmux = 3,
+ .amux = TV,
+ }, {
+ .type = SAA7134_INPUT_SVIDEO,
+ .vmux = 6,
+ .amux = LINE1,
+ } },
+ },
+ [SAA7134_BOARD_AVERMEDIA_505] = {
+ /* much like the "studio" version but without radio
+ * and another tuner (dbaryshkov@gmail.com) */
+ .name = "AverMedia AverTV/505",
+ .audio_clock = 0x00187de7,
+ .tuner_type = TUNER_PHILIPS_FQ1216ME,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .tda9887_conf = TDA9887_PRESENT,
+ .inputs = {{
+ .type = SAA7134_INPUT_TV,
+ .vmux = 1,
+ .amux = LINE2,
+ }, {
+ .type = SAA7134_INPUT_COMPOSITE1,
+ .vmux = 0,
+ .amux = LINE2,
+ }, {
+ .type = SAA7134_INPUT_COMPOSITE2,
+ .vmux = 3,
+ .amux = LINE2,
+ }, {
+ .type = SAA7134_INPUT_SVIDEO,
+ .vmux = 8,
+ .amux = LINE2,
+ } },
+ .mute = {
+ .type = SAA7134_INPUT_MUTE,
+ .amux = LINE1,
+ },
+ },
+ [SAA7134_BOARD_LEADTEK_WINFAST_TV2100_FM] = {
+ .name = "Leadtek Winfast TV2100 FM",
+ .audio_clock = 0x00187de7,
+ .tuner_type = TUNER_TNF_5335MF,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .gpiomask = 0x0d,
+ .inputs = {{
+ .type = SAA7134_INPUT_TV_MONO,
+ .vmux = 1,
+ .amux = LINE1,
+ .gpio = 0x00,
+ }, {
+ .type = SAA7134_INPUT_COMPOSITE1,
+ .vmux = 3,
+ .amux = LINE2,
+ .gpio = 0x08,
+ }, {
+ .type = SAA7134_INPUT_SVIDEO,
+ .vmux = 8,
+ .amux = LINE2,
+ .gpio = 0x08,
+ } },
+ .radio = {
+ .type = SAA7134_INPUT_RADIO,
+ .amux = LINE1,
+ .gpio = 0x04,
+ },
+ .mute = {
+ .type = SAA7134_INPUT_MUTE,
+ .amux = LINE1,
+ .gpio = 0x08,
+ },
+ },
+ [SAA7134_BOARD_SNAZIO_TVPVR_PRO] = {
+ .name = "SnaZio* TVPVR PRO",
+ .audio_clock = 0x00187de7,
+ .tuner_type = TUNER_PHILIPS_TDA8290,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .gpiomask = 1 << 21,
+ .inputs = { {
+ .type = SAA7134_INPUT_TV,
+ .vmux = 1,
+ .amux = TV,
+ .gpio = 0x0000000,
+ }, {
+ .type = SAA7134_INPUT_COMPOSITE1,
+ .vmux = 3,
+ .amux = LINE2,
+ .gpio = 0x0000000,
+ }, {
+ .type = SAA7134_INPUT_SVIDEO,
+ .vmux = 8,
+ .amux = LINE2,
+ .gpio = 0x0000000,
+ } },
+ .radio = {
+ .type = SAA7134_INPUT_RADIO,
+ .amux = TV,
+ .gpio = 0x0200000,
+ },
+ },
+ [SAA7134_BOARD_LEADTEK_WINFAST_HDTV200_H] = {
+ .name = "Leadtek Winfast HDTV200 H",
+ .audio_clock = 0x00187de7,
+ .tuner_type = TUNER_PHILIPS_TDA8290,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .mpeg = SAA7134_MPEG_DVB,
+ .ts_type = SAA7134_MPEG_TS_PARALLEL,
+ .gpiomask = 0x00200700,
+ .inputs = { {
+ .type = SAA7134_INPUT_TV,
+ .vmux = 1,
+ .amux = TV,
+ .gpio = 0x00000300,
+ }, {
+ .type = SAA7134_INPUT_COMPOSITE,
+ .vmux = 3,
+ .amux = LINE1,
+ .gpio = 0x00200300,
+ }, {
+ .type = SAA7134_INPUT_SVIDEO,
+ .vmux = 8,
+ .amux = LINE1,
+ .gpio = 0x00200300,
+ } },
+ },
+};
+
+const unsigned int saa7134_bcount = ARRAY_SIZE(saa7134_boards);
+
+/* ------------------------------------------------------------------ */
+/* PCI ids + subsystem IDs */
+
+struct pci_device_id saa7134_pci_tbl[] = {
+ {
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7134,
+ .subvendor = PCI_VENDOR_ID_PHILIPS,
+ .subdevice = 0x2001,
+ .driver_data = SAA7134_BOARD_PROTEUS_PRO,
+ },{
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7133,
+ .subvendor = PCI_VENDOR_ID_PHILIPS,
+ .subdevice = 0x2001,
+ .driver_data = SAA7134_BOARD_PROTEUS_PRO,
+ },{
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7134,
+ .subvendor = PCI_VENDOR_ID_PHILIPS,
+ .subdevice = 0x6752,
+ .driver_data = SAA7134_BOARD_EMPRESS,
+ },{
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7134,
+ .subvendor = 0x1131,
+ .subdevice = 0x4e85,
+ .driver_data = SAA7134_BOARD_MONSTERTV,
+ },{
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7134,
+ .subvendor = 0x153b,
+ .subdevice = 0x1142,
+ .driver_data = SAA7134_BOARD_CINERGY400,
+ },{
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7134,
+ .subvendor = 0x153b,
+ .subdevice = 0x1143,
+ .driver_data = SAA7134_BOARD_CINERGY600,
+ },{
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7134,
+ .subvendor = 0x153b,
+ .subdevice = 0x1158,
+ .driver_data = SAA7134_BOARD_CINERGY600_MK3,
+ },{
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7133,
+ .subvendor = 0x153b,
+ .subdevice = 0x1162,
+ .driver_data = SAA7134_BOARD_CINERGY400_CARDBUS,
+ },{
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7134,
+ .subvendor = 0x5169,
+ .subdevice = 0x0138,
+ .driver_data = SAA7134_BOARD_FLYVIDEO3000_NTSC,
+ },{
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7134,
+ .subvendor = 0x5168,
+ .subdevice = 0x0138,
+ .driver_data = SAA7134_BOARD_FLYVIDEO3000,
+ },{
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7134,
+ .subvendor = 0x4e42, /* "Typhoon PCI Capture TV Card" Art.No. 50673 */
+ .subdevice = 0x0138,
+ .driver_data = SAA7134_BOARD_FLYVIDEO3000,
+ },{
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7130,
+ .subvendor = 0x5168,
+ .subdevice = 0x0138,
+ .driver_data = SAA7134_BOARD_FLYVIDEO2000,
+ },{
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7130,
+ .subvendor = 0x4e42, /* Typhoon */
+ .subdevice = 0x0138, /* LifeView FlyTV Prime30 OEM */
+ .driver_data = SAA7134_BOARD_FLYVIDEO2000,
+ },{
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7133,
+ .subvendor = 0x5168,
+ .subdevice = 0x0212, /* minipci, LR212 */
+ .driver_data = SAA7134_BOARD_FLYTVPLATINUM_MINI,
+ },{
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7133,
+ .subvendor = 0x14c0,
+ .subdevice = 0x1212, /* minipci, LR1212 */
+ .driver_data = SAA7134_BOARD_FLYTVPLATINUM_MINI2,
+ },{
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7133,
+ .subvendor = 0x4e42,
+ .subdevice = 0x0212, /* OEM minipci, LR212 */
+ .driver_data = SAA7134_BOARD_FLYTVPLATINUM_MINI,
+ },{
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7133,
+ .subvendor = 0x5168, /* Animation Technologies (LifeView) */
+ .subdevice = 0x0214, /* Standard PCI, LR214 Rev E and earlier (SAA7135) */
+ .driver_data = SAA7134_BOARD_FLYTVPLATINUM_FM,
+ },{
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7133,
+ .subvendor = 0x5168, /* Animation Technologies (LifeView) */
+ .subdevice = 0x5214, /* Standard PCI, LR214 Rev F onwards (SAA7131) */
+ .driver_data = SAA7134_BOARD_FLYTVPLATINUM_FM,
+ },{
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7133,
+ .subvendor = 0x1489, /* KYE */
+ .subdevice = 0x0214, /* Genius VideoWonder ProTV */
+ .driver_data = SAA7134_BOARD_FLYTVPLATINUM_FM, /* is an LR214WF actually */
+ },{
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7134,
+ .subvendor = 0x16be,
+ .subdevice = 0x0003,
+ .driver_data = SAA7134_BOARD_MD7134,
+ },{
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7134,
+ .subvendor = 0x16be, /* CTX946 analog TV, HW mpeg, DVB-T */
+ .subdevice = 0x5000, /* only analog TV and DVB-T for now */
+ .driver_data = SAA7134_BOARD_MD7134,
+ }, {
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7130,
+ .subvendor = 0x1048,
+ .subdevice = 0x226b,
+ .driver_data = SAA7134_BOARD_ELSA,
+ },{
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7130,
+ .subvendor = 0x1048,
+ .subdevice = 0x226a,
+ .driver_data = SAA7134_BOARD_ELSA_500TV,
+ },{
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7130,
+ .subvendor = 0x1048,
+ .subdevice = 0x226c,
+ .driver_data = SAA7134_BOARD_ELSA_700TV,
+ },{
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7134,
+ .subvendor = PCI_VENDOR_ID_ASUSTEK,
+ .subdevice = 0x4842,
+ .driver_data = SAA7134_BOARD_ASUSTeK_TVFM7134,
+ },{
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7133,
+ .subvendor = PCI_VENDOR_ID_ASUSTEK,
+ .subdevice = 0x4845,
+ .driver_data = SAA7134_BOARD_ASUSTeK_TVFM7135,
+ },{
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7134,
+ .subvendor = PCI_VENDOR_ID_ASUSTEK,
+ .subdevice = 0x4830,
+ .driver_data = SAA7134_BOARD_ASUSTeK_TVFM7134,
+ },{
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7133,
+ .subvendor = PCI_VENDOR_ID_ASUSTEK,
+ .subdevice = 0x4843,
+ .driver_data = SAA7134_BOARD_ASUSTEK_TVFM7133,
+ },{
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7134,
+ .subvendor = PCI_VENDOR_ID_ASUSTEK,
+ .subdevice = 0x4840,
+ .driver_data = SAA7134_BOARD_ASUSTeK_TVFM7134,
+ },{
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7134,
+ .subvendor = PCI_VENDOR_ID_PHILIPS,
+ .subdevice = 0xfe01,
+ .driver_data = SAA7134_BOARD_TVSTATION_RDS,
+ },{
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7134,
+ .subvendor = 0x1894,
+ .subdevice = 0xfe01,
+ .driver_data = SAA7134_BOARD_TVSTATION_RDS,
+ },{
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7134,
+ .subvendor = 0x1894,
+ .subdevice = 0xa006,
+ .driver_data = SAA7134_BOARD_TVSTATION_DVR,
+ },{
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7134,
+ .subvendor = 0x1131,
+ .subdevice = 0x7133,
+ .driver_data = SAA7134_BOARD_VA1000POWER,
+ },{
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7130,
+ .subvendor = PCI_VENDOR_ID_PHILIPS,
+ .subdevice = 0x2001,
+ .driver_data = SAA7134_BOARD_10MOONSTVMASTER,
+ },{
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7133,
+ .subvendor = 0x185b,
+ .subdevice = 0xc100,
+ .driver_data = SAA7134_BOARD_VIDEOMATE_TV,
+ },{
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7133,
+ .subvendor = 0x185b,
+ .subdevice = 0xc100,
+ .driver_data = SAA7134_BOARD_VIDEOMATE_TV_GOLD_PLUS,
+ },{
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7130,
+ .subvendor = PCI_VENDOR_ID_MATROX,
+ .subdevice = 0x48d0,
+ .driver_data = SAA7134_BOARD_CRONOS_PLUS,
+ },{
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7134,
+ .subvendor = 0x1461, /* Avermedia Technologies Inc */
+ .subdevice = 0xa70b,
+ .driver_data = SAA7134_BOARD_MD2819,
+ },{
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7133,
+ .subvendor = 0x1461, /* Avermedia Technologies Inc */
+ .subdevice = 0xa7a1,
+ .driver_data = SAA7134_BOARD_AVERMEDIA_A700_PRO,
+ }, {
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7133,
+ .subvendor = 0x1461, /* Avermedia Technologies Inc */
+ .subdevice = 0xa7a2,
+ .driver_data = SAA7134_BOARD_AVERMEDIA_A700_HYBRID,
+ }, {
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7130,
+ .subvendor = 0x1461, /* Avermedia Technologies Inc */
+ .subdevice = 0x2115,
+ .driver_data = SAA7134_BOARD_AVERMEDIA_STUDIO_305,
+ },{
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7130,
+ .subvendor = 0x1461, /* Avermedia Technologies Inc */
+ .subdevice = 0xa115,
+ .driver_data = SAA7134_BOARD_AVERMEDIA_STUDIO_505,
+ }, {
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7130,
+ .subvendor = 0x1461, /* Avermedia Technologies Inc */
+ .subdevice = 0x2108,
+ .driver_data = SAA7134_BOARD_AVERMEDIA_305,
+ },{
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7130,
+ .subvendor = 0x1461, /* Avermedia Technologies Inc */
+ .subdevice = 0x10ff,
+ .driver_data = SAA7134_BOARD_AVERMEDIA_DVD_EZMAKER,
+ },{
+ /* AVerMedia CardBus */
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7134,
+ .subvendor = 0x1461, /* Avermedia Technologies Inc */
+ .subdevice = 0xd6ee,
+ .driver_data = SAA7134_BOARD_AVERMEDIA_CARDBUS,
+ },{
+ /* AVerMedia CardBus */
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7134,
+ .subvendor = 0x1461, /* Avermedia Technologies Inc */
+ .subdevice = 0xb7e9,
+ .driver_data = SAA7134_BOARD_AVERMEDIA_CARDBUS_501,
+ }, {
+ /* TransGear 3000TV */
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7130,
+ .subvendor = 0x1461, /* Avermedia Technologies Inc */
+ .subdevice = 0x050c,
+ .driver_data = SAA7134_BOARD_TG3000TV,
+ },{
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7134,
+ .subvendor = 0x11bd,
+ .subdevice = 0x002b,
+ .driver_data = SAA7134_BOARD_PINNACLE_PCTV_STEREO,
+ },{
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7134,
+ .subvendor = 0x11bd,
+ .subdevice = 0x002d,
+ .driver_data = SAA7134_BOARD_PINNACLE_300I_DVBT_PAL,
+ },{
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7134,
+ .subvendor = 0x1019,
+ .subdevice = 0x4cb4,
+ .driver_data = SAA7134_BOARD_ECS_TVP3XP,
+ },{
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7133,
+ .subvendor = 0x1019,
+ .subdevice = 0x4cb5,
+ .driver_data = SAA7134_BOARD_ECS_TVP3XP_4CB5,
+ },{
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7134,
+ .subvendor = 0x1019,
+ .subdevice = 0x4cb6,
+ .driver_data = SAA7134_BOARD_ECS_TVP3XP_4CB6,
+ },{
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7133,
+ .subvendor = 0x12ab,
+ .subdevice = 0x0800,
+ .driver_data = SAA7134_BOARD_UPMOST_PURPLE_TV,
+ },{
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7130,
+ .subvendor = 0x153b,
+ .subdevice = 0x1152,
+ .driver_data = SAA7134_BOARD_CINERGY200,
+ },{
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7130,
+ .subvendor = 0x185b,
+ .subdevice = 0xc100,
+ .driver_data = SAA7134_BOARD_VIDEOMATE_TV_PVR,
+ },{
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7134,
+ .subvendor = 0x1461, /* Avermedia Technologies Inc */
+ .subdevice = 0x9715,
+ .driver_data = SAA7134_BOARD_AVERMEDIA_STUDIO_307,
+ },{
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7134,
+ .subvendor = 0x1461, /* Avermedia Technologies Inc */
+ .subdevice = 0xa70a,
+ .driver_data = SAA7134_BOARD_AVERMEDIA_307,
+ },{
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7134,
+ .subvendor = 0x185b,
+ .subdevice = 0xc200,
+ .driver_data = SAA7134_BOARD_VIDEOMATE_GOLD_PLUS,
+ },{
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7134,
+ .subvendor = 0x1540,
+ .subdevice = 0x9524,
+ .driver_data = SAA7134_BOARD_PROVIDEO_PV952,
+
+ },{
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7133,
+ .subvendor = 0x5168,
+ .subdevice = 0x0502, /* Cardbus version */
+ .driver_data = SAA7134_BOARD_FLYDVBT_DUO_CARDBUS,
+ },{
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7133,
+ .subvendor = 0x5168,
+ .subdevice = 0x0306, /* PCI version */
+ .driver_data = SAA7134_BOARD_FLYDVBTDUO,
+ },{
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7133,
+ .subvendor = 0x1461, /* Avermedia Technologies Inc */
+ .subdevice = 0xf31f,
+ .driver_data = SAA7134_BOARD_AVERMEDIA_GO_007_FM,
+
+ },{
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7133,
+ .subvendor = 0x1461, /* Avermedia Technologies Inc */
+ .subdevice = 0xf11d,
+ .driver_data = SAA7134_BOARD_AVERMEDIA_M135A,
+ }, {
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7133,
+ .subvendor = 0x1461, /* Avermedia Technologies Inc */
+ .subdevice = 0x4155,
+ .driver_data = SAA7134_BOARD_AVERMEDIA_M733A,
+ }, {
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7133,
+ .subvendor = 0x1461, /* Avermedia Technologies Inc */
+ .subdevice = 0x4255,
+ .driver_data = SAA7134_BOARD_AVERMEDIA_M733A,
+ }, {
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7130,
+ .subvendor = PCI_VENDOR_ID_PHILIPS,
+ .subdevice = 0x2004,
+ .driver_data = SAA7134_BOARD_PHILIPS_TOUGH,
+ },{
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7133,
+ .subvendor = 0x1421,
+ .subdevice = 0x0350, /* PCI version */
+ .driver_data = SAA7134_BOARD_ADS_INSTANT_TV,
+ },{
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7133,
+ .subvendor = 0x1421,
+ .subdevice = 0x0351, /* PCI version, new revision */
+ .driver_data = SAA7134_BOARD_ADS_INSTANT_TV,
+ },{
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7133,
+ .subvendor = 0x1421,
+ .subdevice = 0x0370, /* cardbus version */
+ .driver_data = SAA7134_BOARD_ADS_INSTANT_TV,
+ },{
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7133,
+ .subvendor = 0x1421,
+ .subdevice = 0x1370, /* cardbus version */
+ .driver_data = SAA7134_BOARD_ADS_INSTANT_TV,
+
+ },{
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7133,
+ .subvendor = 0x4e42, /* Typhoon */
+ .subdevice = 0x0502, /* LifeView LR502 OEM */
+ .driver_data = SAA7134_BOARD_FLYDVBT_DUO_CARDBUS,
+ },{
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7133,
+ .subvendor = 0x1043,
+ .subdevice = 0x0210, /* mini pci NTSC version */
+ .driver_data = SAA7134_BOARD_FLYTV_DIGIMATRIX,
+ },{
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7134,
+ .subvendor = 0x1043,
+ .subdevice = 0x0210, /* mini pci PAL/SECAM version */
+ .driver_data = SAA7134_BOARD_ASUSTEK_DIGIMATRIX_TV,
+
+ },{
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7133,
+ .subvendor = 0x0000, /* It shouldn't break anything, since subdevice id seems unique */
+ .subdevice = 0x4091,
+ .driver_data = SAA7134_BOARD_BEHOLD_409FM,
+ },{
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7133,
+ .subvendor = 0x5456, /* GoTView */
+ .subdevice = 0x7135,
+ .driver_data = SAA7134_BOARD_GOTVIEW_7135,
+ },{
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7134,
+ .subvendor = PCI_VENDOR_ID_PHILIPS,
+ .subdevice = 0x2004,
+ .driver_data = SAA7134_BOARD_PHILIPS_EUROPA,
+ },{
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7134,
+ .subvendor = 0x185b,
+ .subdevice = 0xc900,
+ .driver_data = SAA7134_BOARD_VIDEOMATE_DVBT_300,
+ },{
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7130,
+ .subvendor = 0x185b,
+ .subdevice = 0xc901,
+ .driver_data = SAA7134_BOARD_VIDEOMATE_DVBT_200,
+ },{
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7133,
+ .subvendor = 0x1435,
+ .subdevice = 0x7350,
+ .driver_data = SAA7134_BOARD_RTD_VFG7350,
+ },{
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7133,
+ .subvendor = 0x1435,
+ .subdevice = 0x7330,
+ .driver_data = SAA7134_BOARD_RTD_VFG7330,
+ },{
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7133,
+ .subvendor = 0x1461,
+ .subdevice = 0x1044,
+ .driver_data = SAA7134_BOARD_AVERMEDIA_AVERTVHD_A180,
+ },{
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7133,
+ .subvendor = 0x1131,
+ .subdevice = 0x4ee9,
+ .driver_data = SAA7134_BOARD_MONSTERTV_MOBILE,
+ },{
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7133,
+ .subvendor = 0x11bd,
+ .subdevice = 0x002e,
+ .driver_data = SAA7134_BOARD_PINNACLE_PCTV_110i,
+ },{
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7133,
+ .subvendor = 0x1043,
+ .subdevice = 0x4862,
+ .driver_data = SAA7134_BOARD_ASUSTeK_P7131_DUAL,
+ },{
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7133,
+ .subvendor = PCI_VENDOR_ID_PHILIPS,
+ .subdevice = 0x2018,
+ .driver_data = SAA7134_BOARD_PHILIPS_TIGER,
+ },{
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7133,
+ .subvendor = 0x1462,
+ .subdevice = 0x6231, /* tda8275a, ks003 IR */
+ .driver_data = SAA7134_BOARD_MSI_TVATANYWHERE_PLUS,
+ },{
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7133,
+ .subvendor = 0x1462,
+ .subdevice = 0x8624, /* tda8275, ks003 IR */
+ .driver_data = SAA7134_BOARD_MSI_TVATANYWHERE_PLUS,
+ },{
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7133,
+ .subvendor = 0x153b,
+ .subdevice = 0x1160,
+ .driver_data = SAA7134_BOARD_CINERGY250PCI,
+ },{
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7133, /* SAA 7131E */
+ .subvendor = 0x5168,
+ .subdevice = 0x0319,
+ .driver_data = SAA7134_BOARD_FLYDVB_TRIO,
+ },{
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7134,
+ .subvendor = 0x1461,
+ .subdevice = 0x2c05,
+ .driver_data = SAA7134_BOARD_AVERMEDIA_777,
+ },{
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7134,
+ .subvendor = 0x5168,
+ .subdevice = 0x0301,
+ .driver_data = SAA7134_BOARD_FLYDVBT_LR301,
+ },{
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7133,
+ .subvendor = 0x0331,
+ .subdevice = 0x1421,
+ .driver_data = SAA7134_BOARD_ADS_DUO_CARDBUS_PTV331,
+ },{
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7133,
+ .subvendor = 0x17de,
+ .subdevice = 0x7201,
+ .driver_data = SAA7134_BOARD_TEVION_DVBT_220RF,
+ },{
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7133,
+ .subvendor = 0x17de,
+ .subdevice = 0x7250,
+ .driver_data = SAA7134_BOARD_KWORLD_DVBT_210,
+ },{
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7133, /* SAA7135HL */
+ .subvendor = 0x17de,
+ .subdevice = 0x7350,
+ .driver_data = SAA7134_BOARD_KWORLD_ATSC110,
+ },{
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7133, /* SAA7135HL */
+ .subvendor = 0x17de,
+ .subdevice = 0x7352,
+ .driver_data = SAA7134_BOARD_KWORLD_ATSC110, /* ATSC 115 */
+ },{
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7133, /* SAA7135HL */
+ .subvendor = 0x17de,
+ .subdevice = 0xa134,
+ .driver_data = SAA7134_BOARD_KWORLD_PC150U,
+ }, {
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7134,
+ .subvendor = 0x1461,
+ .subdevice = 0x7360,
+ .driver_data = SAA7134_BOARD_AVERMEDIA_A169_B,
+ },{
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7134,
+ .subvendor = 0x1461,
+ .subdevice = 0x6360,
+ .driver_data = SAA7134_BOARD_AVERMEDIA_A169_B1,
+ },{
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7134,
+ .subvendor = 0x16be,
+ .subdevice = 0x0005,
+ .driver_data = SAA7134_BOARD_MD7134_BRIDGE_2,
+ },{
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7134,
+ .subvendor = 0x5168,
+ .subdevice = 0x0300,
+ .driver_data = SAA7134_BOARD_FLYDVBS_LR300,
+ },{
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7134,
+ .subvendor = 0x4e42,
+ .subdevice = 0x0300,/* LR300 */
+ .driver_data = SAA7134_BOARD_FLYDVBS_LR300,
+ },{
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7134,
+ .subvendor = 0x1489,
+ .subdevice = 0x0301,
+ .driver_data = SAA7134_BOARD_FLYDVBT_LR301,
+ },{
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7133,
+ .subvendor = 0x5168, /* Animation Technologies (LifeView) */
+ .subdevice = 0x0304,
+ .driver_data = SAA7134_BOARD_FLYTVPLATINUM_FM,
+ },{
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7133,
+ .subvendor = 0x5168,
+ .subdevice = 0x3306,
+ .driver_data = SAA7134_BOARD_FLYDVBT_HYBRID_CARDBUS,
+ },{
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7133,
+ .subvendor = 0x5168,
+ .subdevice = 0x3502, /* what's the difference to 0x3306 ?*/
+ .driver_data = SAA7134_BOARD_FLYDVBT_HYBRID_CARDBUS,
+ },{
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7133,
+ .subvendor = 0x5168,
+ .subdevice = 0x3307, /* FlyDVB-T Hybrid Mini PCI */
+ .driver_data = SAA7134_BOARD_FLYDVBT_HYBRID_CARDBUS,
+ }, {
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7133,
+ .subvendor = 0x16be,
+ .subdevice = 0x0007,
+ .driver_data = SAA7134_BOARD_MEDION_MD8800_QUADRO,
+ },{
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7133,
+ .subvendor = 0x16be,
+ .subdevice = 0x0008,
+ .driver_data = SAA7134_BOARD_MEDION_MD8800_QUADRO,
+ },{
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7133,
+ .subvendor = 0x16be,
+ .subdevice = 0x000d, /* triple CTX948_V1.1.1 */
+ .driver_data = SAA7134_BOARD_MEDION_MD8800_QUADRO,
+ }, {
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7133,
+ .subvendor = 0x1461,
+ .subdevice = 0x2c05,
+ .driver_data = SAA7134_BOARD_AVERMEDIA_777,
+ },{
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7133,
+ .subvendor = 0x1489,
+ .subdevice = 0x0502, /* Cardbus version */
+ .driver_data = SAA7134_BOARD_FLYDVBT_DUO_CARDBUS,
+ },{
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7130,
+ .subvendor = 0x0919, /* Philips Proteus PRO 2309 */
+ .subdevice = 0x2003,
+ .driver_data = SAA7134_BOARD_PROTEUS_2309,
+ },{
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7134,
+ .subvendor = 0x1461,
+ .subdevice = 0x2c00,
+ .driver_data = SAA7134_BOARD_AVERMEDIA_A16AR,
+ },{
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7134,
+ .subvendor = 0x1043,
+ .subdevice = 0x4860,
+ .driver_data = SAA7134_BOARD_ASUS_EUROPA2_HYBRID,
+ },{
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7133,
+ .subvendor = 0x11bd,
+ .subdevice = 0x002f,
+ .driver_data = SAA7134_BOARD_PINNACLE_PCTV_310i,
+ },{
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7133,
+ .subvendor = 0x1461, /* Avermedia Technologies Inc */
+ .subdevice = 0x9715,
+ .driver_data = SAA7134_BOARD_AVERMEDIA_STUDIO_507,
+ },{
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7134,
+ .subvendor = 0x1461, /* Avermedia Technologies Inc */
+ .subdevice = 0xa11b,
+ .driver_data = SAA7134_BOARD_AVERMEDIA_STUDIO_507UA,
+ }, {
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7133,
+ .subvendor = 0x1043,
+ .subdevice = 0x4876,
+ .driver_data = SAA7134_BOARD_ASUSTeK_P7131_HYBRID_LNA,
+ },{
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7133,
+ .subvendor = 0x0070,
+ .subdevice = 0x6700,
+ .driver_data = SAA7134_BOARD_HAUPPAUGE_HVR1110,
+ },{
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7133,
+ .subvendor = 0x0070,
+ .subdevice = 0x6701,
+ .driver_data = SAA7134_BOARD_HAUPPAUGE_HVR1110,
+ },{
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7133,
+ .subvendor = 0x0070,
+ .subdevice = 0x6702,
+ .driver_data = SAA7134_BOARD_HAUPPAUGE_HVR1110,
+ },{
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7133,
+ .subvendor = 0x0070,
+ .subdevice = 0x6703,
+ .driver_data = SAA7134_BOARD_HAUPPAUGE_HVR1110,
+ },{
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7133,
+ .subvendor = 0x0070,
+ .subdevice = 0x6704,
+ .driver_data = SAA7134_BOARD_HAUPPAUGE_HVR1110,
+ },{
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7133,
+ .subvendor = 0x0070,
+ .subdevice = 0x6705,
+ .driver_data = SAA7134_BOARD_HAUPPAUGE_HVR1110,
+ },{
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7133,
+ .subvendor = 0x0070,
+ .subdevice = 0x6706,
+ .driver_data = SAA7134_BOARD_HAUPPAUGE_HVR1150,
+ },{
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7133,
+ .subvendor = 0x0070,
+ .subdevice = 0x6707,
+ .driver_data = SAA7134_BOARD_HAUPPAUGE_HVR1120,
+ },{
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7133,
+ .subvendor = 0x0070,
+ .subdevice = 0x6708,
+ .driver_data = SAA7134_BOARD_HAUPPAUGE_HVR1150,
+ },{
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7133,
+ .subvendor = 0x0070,
+ .subdevice = 0x6709,
+ .driver_data = SAA7134_BOARD_HAUPPAUGE_HVR1120,
+ },{
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7133,
+ .subvendor = 0x0070,
+ .subdevice = 0x670a,
+ .driver_data = SAA7134_BOARD_HAUPPAUGE_HVR1120,
+ },{
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7133,
+ .subvendor = 0x153b,
+ .subdevice = 0x1172,
+ .driver_data = SAA7134_BOARD_CINERGY_HT_PCMCIA,
+ },{
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7130,
+ .subvendor = PCI_VENDOR_ID_PHILIPS,
+ .subdevice = 0x2342,
+ .driver_data = SAA7134_BOARD_ENCORE_ENLTV,
+ },{
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7130,
+ .subvendor = 0x1131,
+ .subdevice = 0x2341,
+ .driver_data = SAA7134_BOARD_ENCORE_ENLTV,
+ },{
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7130,
+ .subvendor = 0x3016,
+ .subdevice = 0x2344,
+ .driver_data = SAA7134_BOARD_ENCORE_ENLTV,
+ },{
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7130,
+ .subvendor = 0x1131,
+ .subdevice = 0x230f,
+ .driver_data = SAA7134_BOARD_ENCORE_ENLTV_FM,
+ },{
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7130,
+ .subvendor = 0x1a7f,
+ .subdevice = 0x2008,
+ .driver_data = SAA7134_BOARD_ENCORE_ENLTV_FM53,
+ }, {
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7134,
+ .subvendor = 0x1a7f,
+ .subdevice = 0x2108,
+ .driver_data = SAA7134_BOARD_ENCORE_ENLTV_FM3,
+ }, {
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7133,
+ .subvendor = 0x153b,
+ .subdevice = 0x1175,
+ .driver_data = SAA7134_BOARD_CINERGY_HT_PCI,
+ },{
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7133,
+ .subvendor = 0x1461, /* Avermedia Technologies Inc */
+ .subdevice = 0xf31e,
+ .driver_data = SAA7134_BOARD_AVERMEDIA_M102,
+ },{
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7133,
+ .subvendor = 0x4E42, /* MSI */
+ .subdevice = 0x0306, /* TV@nywhere DUO */
+ .driver_data = SAA7134_BOARD_FLYDVBTDUO,
+ },{
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7133,
+ .subvendor = 0x1043,
+ .subdevice = 0x4871,
+ .driver_data = SAA7134_BOARD_ASUS_P7131_4871,
+ },{
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7133,
+ .subvendor = 0x1043,
+ .subdevice = 0x4857, /* REV:1.00 */
+ .driver_data = SAA7134_BOARD_ASUSTeK_TIGER,
+ },{
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7134,
+ .subvendor = 0x0919, /* SinoVideo PCI 2309 Proteus (7134) */
+ .subdevice = 0x2003, /* OEM cardbus */
+ .driver_data = SAA7134_BOARD_SABRENT_TV_PCB05,
+ },{
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7130,
+ .subvendor = PCI_VENDOR_ID_PHILIPS,
+ .subdevice = 0x2304,
+ .driver_data = SAA7134_BOARD_10MOONSTVMASTER3,
+ },{
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7133,
+ .subvendor = 0x1461, /* Avermedia Technologies Inc */
+ .subdevice = 0xf01d, /* AVerTV DVB-T Super 007 */
+ .driver_data = SAA7134_BOARD_AVERMEDIA_SUPER_007,
+ },{
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7130,
+ .subvendor = 0x0000,
+ .subdevice = 0x4016,
+ .driver_data = SAA7134_BOARD_BEHOLD_401,
+ },{
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7134,
+ .subvendor = 0x0000,
+ .subdevice = 0x4036,
+ .driver_data = SAA7134_BOARD_BEHOLD_403,
+ },{
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7134,
+ .subvendor = 0x0000,
+ .subdevice = 0x4037,
+ .driver_data = SAA7134_BOARD_BEHOLD_403FM,
+ },{
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7130,
+ .subvendor = 0x0000,
+ .subdevice = 0x4050,
+ .driver_data = SAA7134_BOARD_BEHOLD_405,
+ },{
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7130,
+ .subvendor = 0x0000,
+ .subdevice = 0x4051,
+ .driver_data = SAA7134_BOARD_BEHOLD_405FM,
+ },{
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7134,
+ .subvendor = 0x0000,
+ .subdevice = 0x4070,
+ .driver_data = SAA7134_BOARD_BEHOLD_407,
+ },{
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7134,
+ .subvendor = 0x0000,
+ .subdevice = 0x4071,
+ .driver_data = SAA7134_BOARD_BEHOLD_407FM,
+ },{
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7133,
+ .subvendor = 0x0000,
+ .subdevice = 0x4090,
+ .driver_data = SAA7134_BOARD_BEHOLD_409,
+ },{
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7130,
+ .subvendor = 0x0000,
+ .subdevice = 0x505B,
+ .driver_data = SAA7134_BOARD_BEHOLD_505RDS_MK5,
+ }, {
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7130,
+ .subvendor = 0x0000,
+ .subdevice = 0x5051,
+ .driver_data = SAA7134_BOARD_BEHOLD_505RDS_MK3,
+ },{
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7130,
+ .subvendor = 0x5ace,
+ .subdevice = 0x5050,
+ .driver_data = SAA7134_BOARD_BEHOLD_505FM,
+ },{
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7133,
+ .subvendor = 0x0000,
+ .subdevice = 0x5071,
+ .driver_data = SAA7134_BOARD_BEHOLD_507RDS_MK3,
+ },{
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7133,
+ .subvendor = 0x0000,
+ .subdevice = 0x507B,
+ .driver_data = SAA7134_BOARD_BEHOLD_507RDS_MK5,
+ },{
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7134,
+ .subvendor = 0x5ace,
+ .subdevice = 0x5070,
+ .driver_data = SAA7134_BOARD_BEHOLD_507_9FM,
+ },{
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7133,
+ .subvendor = 0x5ace,
+ .subdevice = 0x5090,
+ .driver_data = SAA7134_BOARD_BEHOLD_507_9FM,
+ },{
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7133,
+ .subvendor = 0x0000,
+ .subdevice = 0x5201,
+ .driver_data = SAA7134_BOARD_BEHOLD_COLUMBUS_TVFM,
+ },{
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7134,
+ .subvendor = 0x5ace,
+ .subdevice = 0x6070,
+ .driver_data = SAA7134_BOARD_BEHOLD_607FM_MK3,
+ },{
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7134,
+ .subvendor = 0x5ace,
+ .subdevice = 0x6071,
+ .driver_data = SAA7134_BOARD_BEHOLD_607FM_MK5,
+ },{
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7134,
+ .subvendor = 0x5ace,
+ .subdevice = 0x6072,
+ .driver_data = SAA7134_BOARD_BEHOLD_607RDS_MK3,
+ },{
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7134,
+ .subvendor = 0x5ace,
+ .subdevice = 0x6073,
+ .driver_data = SAA7134_BOARD_BEHOLD_607RDS_MK5,
+ },{
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7133,
+ .subvendor = 0x5ace,
+ .subdevice = 0x6090,
+ .driver_data = SAA7134_BOARD_BEHOLD_609FM_MK3,
+ },{
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7133,
+ .subvendor = 0x5ace,
+ .subdevice = 0x6091,
+ .driver_data = SAA7134_BOARD_BEHOLD_609FM_MK5,
+ },{
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7133,
+ .subvendor = 0x5ace,
+ .subdevice = 0x6092,
+ .driver_data = SAA7134_BOARD_BEHOLD_609RDS_MK3,
+ },{
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7133,
+ .subvendor = 0x5ace,
+ .subdevice = 0x6093,
+ .driver_data = SAA7134_BOARD_BEHOLD_609RDS_MK5,
+ },{
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7133,
+ .subvendor = 0x5ace,
+ .subdevice = 0x6190,
+ .driver_data = SAA7134_BOARD_BEHOLD_M6,
+ },{
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7133,
+ .subvendor = 0x5ace,
+ .subdevice = 0x6193,
+ .driver_data = SAA7134_BOARD_BEHOLD_M6_EXTRA,
+ }, {
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7133,
+ .subvendor = 0x5ace,
+ .subdevice = 0x6191,
+ .driver_data = SAA7134_BOARD_BEHOLD_M63,
+ },{
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7133,
+ .subvendor = 0x4e42,
+ .subdevice = 0x3502,
+ .driver_data = SAA7134_BOARD_FLYDVBT_HYBRID_CARDBUS,
+ }, {
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7133,
+ .subvendor = 0x1822, /*Twinhan Technology Co. Ltd*/
+ .subdevice = 0x0022,
+ .driver_data = SAA7134_BOARD_TWINHAN_DTV_DVB_3056,
+ }, {
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7133,
+ .subvendor = 0x16be,
+ .subdevice = 0x0010, /* Medion version CTX953_V.1.4.3 */
+ .driver_data = SAA7134_BOARD_CREATIX_CTX953,
+ }, {
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7133,
+ .subvendor = 0x1462, /* MSI */
+ .subdevice = 0x8625, /* TV@nywhere A/D v1.1 */
+ .driver_data = SAA7134_BOARD_MSI_TVANYWHERE_AD11,
+ },{
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7133,
+ .subvendor = 0x1461, /* Avermedia Technologies Inc */
+ .subdevice = 0xf436,
+ .driver_data = SAA7134_BOARD_AVERMEDIA_CARDBUS_506,
+ }, {
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7133,
+ .subvendor = 0x1461, /* Avermedia Technologies Inc */
+ .subdevice = 0xf936,
+ .driver_data = SAA7134_BOARD_AVERMEDIA_A16D,
+ }, {
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7133,
+ .subvendor = 0x1461, /* Avermedia Technologies Inc */
+ .subdevice = 0xa836,
+ .driver_data = SAA7134_BOARD_AVERMEDIA_M115,
+ }, {
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7133,
+ .subvendor = 0x185b,
+ .subdevice = 0xc900,
+ .driver_data = SAA7134_BOARD_VIDEOMATE_T750,
+ }, {
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7133, /* SAA7135HL */
+ .subvendor = 0x1421,
+ .subdevice = 0x0380,
+ .driver_data = SAA7134_BOARD_ADS_INSTANT_HDTV_PCI,
+ }, {
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7133,
+ .subvendor = 0x5169,
+ .subdevice = 0x1502,
+ .driver_data = SAA7134_BOARD_FLYTVPLATINUM_MINI,
+ }, {
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7133,
+ .subvendor = 0x5ace,
+ .subdevice = 0x6290,
+ .driver_data = SAA7134_BOARD_BEHOLD_H6,
+ }, {
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7133,
+ .subvendor = 0x1461, /* Avermedia Technologies Inc */
+ .subdevice = 0xf636,
+ .driver_data = SAA7134_BOARD_AVERMEDIA_M103,
+ }, {
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7133,
+ .subvendor = 0x1461, /* Avermedia Technologies Inc */
+ .subdevice = 0xf736,
+ .driver_data = SAA7134_BOARD_AVERMEDIA_M103,
+ }, {
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7133,
+ .subvendor = 0x1043,
+ .subdevice = 0x4878, /* REV:1.02G */
+ .driver_data = SAA7134_BOARD_ASUSTeK_TIGER_3IN1,
+ }, {
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7133,
+ .subvendor = 0x1043,
+ .subdevice = 0x48cd,
+ .driver_data = SAA7134_BOARD_ASUSTeK_PS3_100,
+ }, {
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7134,
+ .subvendor = 0x17de,
+ .subdevice = 0x7128,
+ .driver_data = SAA7134_BOARD_KWORLD_PLUS_TV_ANALOG,
+ }, {
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7133,
+ .subvendor = 0x17de,
+ .subdevice = 0xb136,
+ .driver_data = SAA7134_BOARD_KWORLD_PCI_SBTVD_FULLSEG,
+ }, {
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7133,
+ .subvendor = 0x1461, /* Avermedia Technologies Inc */
+ .subdevice = 0xf31d,
+ .driver_data = SAA7134_BOARD_AVERMEDIA_GO_007_FM_PLUS,
+ }, {
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7130,
+ .subvendor = 0x185b,
+ .subdevice = 0xc900,
+ .driver_data = SAA7134_BOARD_VIDEOMATE_S350,
+ }, {
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7133,
+ .subvendor = 0x5ace, /* Beholder Intl. Ltd. */
+ .subdevice = 0x7595,
+ .driver_data = SAA7134_BOARD_BEHOLD_X7,
+ }, {
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7134,
+ .subvendor = 0x19d1, /* RoverMedia */
+ .subdevice = 0x0138, /* LifeView FlyTV Prime30 OEM */
+ .driver_data = SAA7134_BOARD_ROVERMEDIA_LINK_PRO_FM,
+ }, {
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7133,
+ .subvendor = PCI_VENDOR_ID_PHILIPS,
+ .subdevice = 0x2004,
+ .driver_data = SAA7134_BOARD_ZOLID_HYBRID_PCI,
+ }, {
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7134,
+ .subvendor = 0x1043,
+ .subdevice = 0x4847,
+ .driver_data = SAA7134_BOARD_ASUS_EUROPA_HYBRID,
+ }, {
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7130,
+ .subvendor = 0x107d,
+ .subdevice = 0x6655,
+ .driver_data = SAA7134_BOARD_LEADTEK_WINFAST_DTV1000S,
+ }, {
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7133,
+ .subvendor = 0x13c2,
+ .subdevice = 0x2804,
+ .driver_data = SAA7134_BOARD_TECHNOTREND_BUDGET_T3000,
+ }, {
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7133,
+ .subvendor = 0x5ace, /* Beholder Intl. Ltd. */
+ .subdevice = 0x7190,
+ .driver_data = SAA7134_BOARD_BEHOLD_H7,
+ }, {
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7133,
+ .subvendor = 0x5ace, /* Beholder Intl. Ltd. */
+ .subdevice = 0x7090,
+ .driver_data = SAA7134_BOARD_BEHOLD_A7,
+ }, {
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7135,
+ .subvendor = 0x185b,
+ .subdevice = 0xc900,
+ .driver_data = SAA7134_BOARD_VIDEOMATE_M1F,
+ }, {
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7133,
+ .subvendor = 0x5ace,
+ .subdevice = 0x5030,
+ .driver_data = SAA7134_BOARD_BEHOLD_503FM,
+ }, {
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7130,
+ .subvendor = 0x5ace,
+ .subdevice = 0x5010,
+ .driver_data = SAA7134_BOARD_BEHOLD_501,
+ }, {
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7134,
+ .subvendor = 0x17de,
+ .subdevice = 0xd136,
+ .driver_data = SAA7134_BOARD_MAGICPRO_PROHDTV_PRO2,
+ }, {
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7133,
+ .subvendor = 0x6000,
+ .subdevice = 0x0811,
+ .driver_data = SAA7134_BOARD_SENSORAY811_911,
+ }, {
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7133,
+ .subvendor = 0x6000,
+ .subdevice = 0x0911,
+ .driver_data = SAA7134_BOARD_SENSORAY811_911,
+ }, {
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7133,
+ .subvendor = 0x1461, /* Avermedia Technologies Inc */
+ .subdevice = 0x2055, /* AverTV Satellite Hybrid+FM A706 */
+ .driver_data = SAA7134_BOARD_AVERMEDIA_A706,
+ }, {
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7133,
+ .subvendor = 0x1905, /* WIS */
+ .subdevice = 0x7007,
+ .driver_data = SAA7134_BOARD_WIS_VOYAGER,
+ }, {
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7130,
+ .subvendor = 0x1461, /* Avermedia Technologies Inc */
+ .subdevice = 0xa10a,
+ .driver_data = SAA7134_BOARD_AVERMEDIA_505,
+ }, {
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7130,
+ .subvendor = 0x107d,
+ .subdevice = 0x6f3a,
+ .driver_data = SAA7134_BOARD_LEADTEK_WINFAST_TV2100_FM,
+ }, {
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7133,
+ .subvendor = 0x1779, /* V One Multimedia PTE Ltd */
+ .subdevice = 0x13cf,
+ .driver_data = SAA7134_BOARD_SNAZIO_TVPVR_PRO,
+ }, {
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7133,
+ .subvendor = 0x107d,
+ .subdevice = 0x6f2e,
+ .driver_data = SAA7134_BOARD_LEADTEK_WINFAST_HDTV200_H,
+ }, {
+ /* --- boards without eeprom + subsystem ID --- */
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7134,
+ .subvendor = PCI_VENDOR_ID_PHILIPS,
+ .subdevice = 0,
+ .driver_data = SAA7134_BOARD_NOAUTO,
+ },{
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7130,
+ .subvendor = PCI_VENDOR_ID_PHILIPS,
+ .subdevice = 0,
+ .driver_data = SAA7134_BOARD_NOAUTO,
+ },{
+ /* --- default catch --- */
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7130,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ .driver_data = SAA7134_BOARD_UNKNOWN,
+ },{
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7133,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ .driver_data = SAA7134_BOARD_UNKNOWN,
+ },{
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7134,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ .driver_data = SAA7134_BOARD_UNKNOWN,
+ },{
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7135,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ .driver_data = SAA7134_BOARD_UNKNOWN,
+ },{
+ /* --- end of list --- */
+ }
+};
+MODULE_DEVICE_TABLE(pci, saa7134_pci_tbl);
+
+/* ----------------------------------------------------------- */
+/* flyvideo tweaks */
+
+
+static void board_flyvideo(struct saa7134_dev *dev)
+{
+ pr_warn("%s: there are different flyvideo cards with different tuners\n"
+ "%s: out there, you might have to use the tuner=<nr> insmod\n"
+ "%s: option to override the default value.\n",
+ dev->name, dev->name, dev->name);
+}
+
+static int saa7134_xc2028_callback(struct saa7134_dev *dev,
+ int command, int arg)
+{
+ switch (command) {
+ case XC2028_TUNER_RESET:
+ saa_andorl(SAA7134_GPIO_GPSTATUS0 >> 2, 0x00008000, 0x00000000);
+ saa_andorl(SAA7134_GPIO_GPSTATUS0 >> 2, 0x00008000, 0x00008000);
+ switch (dev->board) {
+ case SAA7134_BOARD_AVERMEDIA_CARDBUS_506:
+ case SAA7134_BOARD_AVERMEDIA_M103:
+ saa7134_set_gpio(dev, 23, 0);
+ msleep(10);
+ saa7134_set_gpio(dev, 23, 1);
+ break;
+ case SAA7134_BOARD_AVERMEDIA_A16D:
+ saa7134_set_gpio(dev, 21, 0);
+ msleep(10);
+ saa7134_set_gpio(dev, 21, 1);
+ break;
+ case SAA7134_BOARD_AVERMEDIA_A700_HYBRID:
+ saa7134_set_gpio(dev, 18, 0);
+ msleep(10);
+ saa7134_set_gpio(dev, 18, 1);
+ break;
+ case SAA7134_BOARD_VIDEOMATE_T750:
+ saa7134_set_gpio(dev, 20, 0);
+ msleep(10);
+ saa7134_set_gpio(dev, 20, 1);
+ break;
+ }
+ return 0;
+ }
+ return -EINVAL;
+}
+
+static int saa7134_xc5000_callback(struct saa7134_dev *dev,
+ int command, int arg)
+{
+ switch (dev->board) {
+ case SAA7134_BOARD_BEHOLD_X7:
+ case SAA7134_BOARD_BEHOLD_H7:
+ case SAA7134_BOARD_BEHOLD_A7:
+ if (command == XC5000_TUNER_RESET) {
+ /* Down and UP pheripherial RESET pin for reset all chips */
+ saa_writeb(SAA7134_SPECIAL_MODE, 0x00);
+ msleep(10);
+ saa_writeb(SAA7134_SPECIAL_MODE, 0x01);
+ msleep(10);
+ }
+ break;
+ default:
+ saa_andorl(SAA7134_GPIO_GPMODE0 >> 2, 0x06e20000, 0x06e20000);
+ saa_andorl(SAA7134_GPIO_GPSTATUS0 >> 2, 0x06a20000, 0x06a20000);
+ saa_andorl(SAA7133_ANALOG_IO_SELECT >> 2, 0x02, 0x02);
+ saa_andorl(SAA7134_ANALOG_IN_CTRL1 >> 2, 0x81, 0x81);
+ saa_andorl(SAA7134_AUDIO_CLOCK0 >> 2, 0x03187de7, 0x03187de7);
+ saa_andorl(SAA7134_AUDIO_PLL_CTRL >> 2, 0x03, 0x03);
+ saa_andorl(SAA7134_AUDIO_CLOCKS_PER_FIELD0 >> 2,
+ 0x0001e000, 0x0001e000);
+ break;
+ }
+ return 0;
+}
+
+static int saa7134_tda8290_827x_callback(struct saa7134_dev *dev,
+ int command, int arg)
+{
+ u8 sync_control;
+
+ switch (command) {
+ case 0: /* switch LNA gain through GPIO 22*/
+ saa7134_set_gpio(dev, 22, arg) ;
+ break;
+ case 1: /* vsync output at GPIO22. 50 / 60Hz */
+ saa_andorb(SAA7134_VIDEO_PORT_CTRL3, 0x80, 0x80);
+ saa_andorb(SAA7134_VIDEO_PORT_CTRL6, 0x0f, 0x03);
+ if (arg == 1)
+ sync_control = 11;
+ else
+ sync_control = 17;
+ saa_writeb(SAA7134_VGATE_START, sync_control);
+ saa_writeb(SAA7134_VGATE_STOP, sync_control + 1);
+ saa_andorb(SAA7134_MISC_VGATE_MSB, 0x03, 0x00);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static inline int saa7134_tda18271_hvr11x0_toggle_agc(struct saa7134_dev *dev,
+ enum tda18271_mode mode)
+{
+ /* toggle AGC switch through GPIO 26 */
+ switch (mode) {
+ case TDA18271_ANALOG:
+ saa7134_set_gpio(dev, 26, 0);
+ break;
+ case TDA18271_DIGITAL:
+ saa7134_set_gpio(dev, 26, 1);
+ break;
+ default:
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static inline int saa7134_kworld_sbtvd_toggle_agc(struct saa7134_dev *dev,
+ enum tda18271_mode mode)
+{
+ /* toggle AGC switch through GPIO 27 */
+ switch (mode) {
+ case TDA18271_ANALOG:
+ saa_writel(SAA7134_GPIO_GPMODE0 >> 2, 0x4000);
+ saa_writel(SAA7134_GPIO_GPSTATUS0 >> 2, 0x4000);
+ msleep(20);
+ break;
+ case TDA18271_DIGITAL:
+ saa_writel(SAA7134_GPIO_GPMODE0 >> 2, 0x14000);
+ saa_writel(SAA7134_GPIO_GPSTATUS0 >> 2, 0x14000);
+ msleep(20);
+ saa_writel(SAA7134_GPIO_GPMODE0 >> 2, 0x54000);
+ saa_writel(SAA7134_GPIO_GPSTATUS0 >> 2, 0x54000);
+ msleep(30);
+ break;
+ default:
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static int saa7134_kworld_pc150u_toggle_agc(struct saa7134_dev *dev,
+ enum tda18271_mode mode)
+{
+ switch (mode) {
+ case TDA18271_ANALOG:
+ saa7134_set_gpio(dev, 18, 0);
+ break;
+ case TDA18271_DIGITAL:
+ saa7134_set_gpio(dev, 18, 1);
+ msleep(30);
+ break;
+ default:
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static int saa7134_leadtek_hdtv200h_toggle_agc(struct saa7134_dev *dev,
+ enum tda18271_mode mode)
+{
+ switch (mode) {
+ case TDA18271_ANALOG:
+ saa7134_set_gpio(dev, 10, 0);
+ break;
+ case TDA18271_DIGITAL:
+ saa7134_set_gpio(dev, 10, 1);
+ break;
+ default:
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static int saa7134_tda8290_18271_callback(struct saa7134_dev *dev,
+ int command, int arg)
+{
+ int ret = 0;
+
+ switch (command) {
+ case TDA18271_CALLBACK_CMD_AGC_ENABLE: /* 0 */
+ switch (dev->board) {
+ case SAA7134_BOARD_HAUPPAUGE_HVR1150:
+ case SAA7134_BOARD_HAUPPAUGE_HVR1120:
+ case SAA7134_BOARD_MAGICPRO_PROHDTV_PRO2:
+ ret = saa7134_tda18271_hvr11x0_toggle_agc(dev, arg);
+ break;
+ case SAA7134_BOARD_KWORLD_PCI_SBTVD_FULLSEG:
+ ret = saa7134_kworld_sbtvd_toggle_agc(dev, arg);
+ break;
+ case SAA7134_BOARD_KWORLD_PC150U:
+ ret = saa7134_kworld_pc150u_toggle_agc(dev, arg);
+ break;
+ case SAA7134_BOARD_LEADTEK_WINFAST_HDTV200_H:
+ ret = saa7134_leadtek_hdtv200h_toggle_agc(dev, arg);
+ break;
+ default:
+ break;
+ }
+ break;
+ default:
+ ret = -EINVAL;
+ break;
+ }
+ return ret;
+}
+
+static int saa7134_tda8290_callback(struct saa7134_dev *dev,
+ int command, int arg)
+{
+ int ret;
+
+ switch (dev->board) {
+ case SAA7134_BOARD_HAUPPAUGE_HVR1150:
+ case SAA7134_BOARD_HAUPPAUGE_HVR1120:
+ case SAA7134_BOARD_AVERMEDIA_M733A:
+ case SAA7134_BOARD_KWORLD_PCI_SBTVD_FULLSEG:
+ case SAA7134_BOARD_KWORLD_PC150U:
+ case SAA7134_BOARD_MAGICPRO_PROHDTV_PRO2:
+ case SAA7134_BOARD_LEADTEK_WINFAST_HDTV200_H:
+ /* tda8290 + tda18271 */
+ ret = saa7134_tda8290_18271_callback(dev, command, arg);
+ break;
+ default:
+ /* tda8290 + tda827x */
+ ret = saa7134_tda8290_827x_callback(dev, command, arg);
+ break;
+ }
+ return ret;
+}
+
+int saa7134_tuner_callback(void *priv, int component, int command, int arg)
+{
+ struct saa7134_dev *dev = priv;
+
+ if (dev != NULL) {
+ switch (dev->tuner_type) {
+ case TUNER_PHILIPS_TDA8290:
+ return saa7134_tda8290_callback(dev, command, arg);
+ case TUNER_XC2028:
+ return saa7134_xc2028_callback(dev, command, arg);
+ case TUNER_XC5000:
+ return saa7134_xc5000_callback(dev, command, arg);
+ }
+ } else {
+ pr_err("saa7134: Error - device struct undefined.\n");
+ return -EINVAL;
+ }
+ return -EINVAL;
+}
+EXPORT_SYMBOL(saa7134_tuner_callback);
+
+/* ----------------------------------------------------------- */
+
+static void hauppauge_eeprom(struct saa7134_dev *dev, u8 *eeprom_data)
+{
+ struct tveeprom tv;
+
+ tveeprom_hauppauge_analog(&tv, eeprom_data);
+
+ /* Make sure we support the board model */
+ switch (tv.model) {
+ case 67019: /* WinTV-HVR1110 (Retail, IR Blaster, hybrid, FM, SVid/Comp, 3.5mm audio in) */
+ case 67109: /* WinTV-HVR1000 (Retail, IR Receive, analog, no FM, SVid/Comp, 3.5mm audio in) */
+ case 67201: /* WinTV-HVR1150 (Retail, IR Receive, hybrid, FM, SVid/Comp, 3.5mm audio in) */
+ case 67301: /* WinTV-HVR1000 (Retail, IR Receive, analog, no FM, SVid/Comp, 3.5mm audio in) */
+ case 67209: /* WinTV-HVR1110 (Retail, IR Receive, hybrid, FM, SVid/Comp, 3.5mm audio in) */
+ case 67559: /* WinTV-HVR1110 (OEM, no IR, hybrid, FM, SVid/Comp, RCA aud) */
+ case 67569: /* WinTV-HVR1110 (OEM, no IR, hybrid, FM) */
+ case 67579: /* WinTV-HVR1110 (OEM, no IR, hybrid, no FM) */
+ case 67589: /* WinTV-HVR1110 (OEM, no IR, hybrid, no FM, SVid/Comp, RCA aud) */
+ case 67599: /* WinTV-HVR1110 (OEM, no IR, hybrid, no FM, SVid/Comp, RCA aud) */
+ case 67651: /* WinTV-HVR1150 (OEM, no IR, hybrid, FM, SVid/Comp, RCA aud) */
+ case 67659: /* WinTV-HVR1110 (OEM, no IR, hybrid, FM, SVid/Comp, RCA aud) */
+ break;
+ default:
+ pr_warn("%s: warning: unknown hauppauge model #%d\n",
+ dev->name, tv.model);
+ break;
+ }
+
+ pr_info("%s: hauppauge eeprom: model=%d\n",
+ dev->name, tv.model);
+}
+
+/* ----------------------------------------------------------- */
+
+int saa7134_board_init1(struct saa7134_dev *dev)
+{
+ /* Always print gpio, often manufacturers encode tuner type and other info. */
+ saa_writel(SAA7134_GPIO_GPMODE0 >> 2, 0);
+ dev->gpio_value = saa_readl(SAA7134_GPIO_GPSTATUS0 >> 2);
+ pr_info("%s: board init: gpio is %x\n", dev->name, dev->gpio_value);
+
+ switch (dev->board) {
+ case SAA7134_BOARD_FLYVIDEO2000:
+ case SAA7134_BOARD_FLYVIDEO3000:
+ case SAA7134_BOARD_FLYVIDEO3000_NTSC:
+ dev->has_remote = SAA7134_REMOTE_GPIO;
+ board_flyvideo(dev);
+ break;
+ case SAA7134_BOARD_FLYTVPLATINUM_MINI2:
+ case SAA7134_BOARD_FLYTVPLATINUM_FM:
+ case SAA7134_BOARD_CINERGY400:
+ case SAA7134_BOARD_CINERGY600:
+ case SAA7134_BOARD_CINERGY600_MK3:
+ case SAA7134_BOARD_ECS_TVP3XP:
+ case SAA7134_BOARD_ECS_TVP3XP_4CB5:
+ case SAA7134_BOARD_ECS_TVP3XP_4CB6:
+ case SAA7134_BOARD_MD2819:
+ case SAA7134_BOARD_KWORLD_VSTREAM_XPERT:
+ case SAA7134_BOARD_KWORLD_XPERT:
+ case SAA7134_BOARD_AVERMEDIA_STUDIO_305:
+ case SAA7134_BOARD_AVERMEDIA_305:
+ case SAA7134_BOARD_AVERMEDIA_STUDIO_505:
+ case SAA7134_BOARD_AVERMEDIA_505:
+ case SAA7134_BOARD_AVERMEDIA_STUDIO_307:
+ case SAA7134_BOARD_AVERMEDIA_307:
+ case SAA7134_BOARD_AVERMEDIA_STUDIO_507:
+ case SAA7134_BOARD_AVERMEDIA_GO_007_FM:
+ case SAA7134_BOARD_AVERMEDIA_777:
+ case SAA7134_BOARD_AVERMEDIA_M135A:
+/* case SAA7134_BOARD_SABRENT_SBTTVFM: */ /* not finished yet */
+ case SAA7134_BOARD_VIDEOMATE_TV_PVR:
+ case SAA7134_BOARD_VIDEOMATE_GOLD_PLUS:
+ case SAA7134_BOARD_VIDEOMATE_TV_GOLD_PLUSII:
+ case SAA7134_BOARD_VIDEOMATE_M1F:
+ case SAA7134_BOARD_VIDEOMATE_DVBT_300:
+ case SAA7134_BOARD_VIDEOMATE_DVBT_200:
+ case SAA7134_BOARD_VIDEOMATE_DVBT_200A:
+ case SAA7134_BOARD_MANLI_MTV001:
+ case SAA7134_BOARD_MANLI_MTV002:
+ case SAA7134_BOARD_BEHOLD_409FM:
+ case SAA7134_BOARD_AVACSSMARTTV:
+ case SAA7134_BOARD_GOTVIEW_7135:
+ case SAA7134_BOARD_KWORLD_TERMINATOR:
+ case SAA7134_BOARD_SEDNA_PC_TV_CARDBUS:
+ case SAA7134_BOARD_FLYDVBT_LR301:
+ case SAA7134_BOARD_ASUSTeK_PS3_100:
+ case SAA7134_BOARD_ASUSTeK_P7131_DUAL:
+ case SAA7134_BOARD_ASUSTeK_P7131_HYBRID_LNA:
+ case SAA7134_BOARD_ASUSTeK_P7131_ANALOG:
+ case SAA7134_BOARD_FLYDVBTDUO:
+ case SAA7134_BOARD_PROTEUS_2309:
+ case SAA7134_BOARD_AVERMEDIA_A16AR:
+ case SAA7134_BOARD_ENCORE_ENLTV:
+ case SAA7134_BOARD_ENCORE_ENLTV_FM:
+ case SAA7134_BOARD_ENCORE_ENLTV_FM53:
+ case SAA7134_BOARD_ENCORE_ENLTV_FM3:
+ case SAA7134_BOARD_10MOONSTVMASTER3:
+ case SAA7134_BOARD_BEHOLD_401:
+ case SAA7134_BOARD_BEHOLD_403:
+ case SAA7134_BOARD_BEHOLD_403FM:
+ case SAA7134_BOARD_BEHOLD_405:
+ case SAA7134_BOARD_BEHOLD_405FM:
+ case SAA7134_BOARD_BEHOLD_407:
+ case SAA7134_BOARD_BEHOLD_407FM:
+ case SAA7134_BOARD_BEHOLD_409:
+ case SAA7134_BOARD_BEHOLD_505FM:
+ case SAA7134_BOARD_BEHOLD_505RDS_MK5:
+ case SAA7134_BOARD_BEHOLD_505RDS_MK3:
+ case SAA7134_BOARD_BEHOLD_507_9FM:
+ case SAA7134_BOARD_BEHOLD_507RDS_MK3:
+ case SAA7134_BOARD_BEHOLD_507RDS_MK5:
+ case SAA7134_BOARD_GENIUS_TVGO_A11MCE:
+ case SAA7134_BOARD_REAL_ANGEL_220:
+ case SAA7134_BOARD_KWORLD_PLUS_TV_ANALOG:
+ case SAA7134_BOARD_AVERMEDIA_GO_007_FM_PLUS:
+ case SAA7134_BOARD_ROVERMEDIA_LINK_PRO_FM:
+ case SAA7134_BOARD_LEADTEK_WINFAST_DTV1000S:
+ case SAA7134_BOARD_LEADTEK_WINFAST_TV2100_FM:
+ dev->has_remote = SAA7134_REMOTE_GPIO;
+ break;
+ case SAA7134_BOARD_FLYDVBS_LR300:
+ saa_writeb(SAA7134_GPIO_GPMODE3, 0x80);
+ saa_writeb(SAA7134_GPIO_GPSTATUS2, 0x40);
+ dev->has_remote = SAA7134_REMOTE_GPIO;
+ break;
+ case SAA7134_BOARD_MD5044:
+ pr_warn("%s: seems there are two different versions of the MD5044\n"
+ "%s: (with the same ID) out there. If sound doesn't work for\n"
+ "%s: you try the audio_clock_override=0x200000 insmod option.\n",
+ dev->name, dev->name, dev->name);
+ break;
+ case SAA7134_BOARD_CINERGY400_CARDBUS:
+ /* power-up tuner chip */
+ saa_andorl(SAA7134_GPIO_GPMODE0 >> 2, 0x00040000, 0x00040000);
+ saa_andorl(SAA7134_GPIO_GPSTATUS0 >> 2, 0x00040000, 0x00000000);
+ break;
+ case SAA7134_BOARD_PINNACLE_300I_DVBT_PAL:
+ /* this turns the remote control chip off to work around a bug in it */
+ saa_writeb(SAA7134_GPIO_GPMODE1, 0x80);
+ saa_writeb(SAA7134_GPIO_GPSTATUS1, 0x80);
+ break;
+ case SAA7134_BOARD_MONSTERTV_MOBILE:
+ /* power-up tuner chip */
+ saa_andorl(SAA7134_GPIO_GPMODE0 >> 2, 0x00040000, 0x00040000);
+ saa_andorl(SAA7134_GPIO_GPSTATUS0 >> 2, 0x00040000, 0x00000004);
+ break;
+ case SAA7134_BOARD_FLYDVBT_DUO_CARDBUS:
+ /* turn the fan on */
+ saa_writeb(SAA7134_GPIO_GPMODE3, 0x08);
+ saa_writeb(SAA7134_GPIO_GPSTATUS3, 0x06);
+ break;
+ case SAA7134_BOARD_ADS_DUO_CARDBUS_PTV331:
+ case SAA7134_BOARD_FLYDVBT_HYBRID_CARDBUS:
+ saa_andorl(SAA7134_GPIO_GPMODE0 >> 2, 0x08000000, 0x08000000);
+ saa_andorl(SAA7134_GPIO_GPSTATUS0 >> 2, 0x08000000, 0x00000000);
+ break;
+ case SAA7134_BOARD_AVERMEDIA_CARDBUS:
+ case SAA7134_BOARD_AVERMEDIA_M115:
+ /* power-down tuner chip */
+ saa_andorl(SAA7134_GPIO_GPMODE0 >> 2, 0xffffffff, 0);
+ saa_andorl(SAA7134_GPIO_GPSTATUS0 >> 2, 0xffffffff, 0);
+ msleep(10);
+ /* power-up tuner chip */
+ saa_andorl(SAA7134_GPIO_GPMODE0 >> 2, 0xffffffff, 0xffffffff);
+ saa_andorl(SAA7134_GPIO_GPSTATUS0 >> 2, 0xffffffff, 0xffffffff);
+ msleep(10);
+ break;
+ case SAA7134_BOARD_AVERMEDIA_CARDBUS_501:
+ /* power-down tuner chip */
+ saa_andorl(SAA7134_GPIO_GPMODE0 >> 2, 0x08400000, 0x08400000);
+ saa_andorl(SAA7134_GPIO_GPSTATUS0 >> 2, 0x08400000, 0);
+ msleep(10);
+ saa_andorl(SAA7134_GPIO_GPMODE0 >> 2, 0x08400000, 0x08400000);
+ saa_andorl(SAA7134_GPIO_GPSTATUS0 >> 2, 0x08400000, 0x08400000);
+ msleep(10);
+ dev->has_remote = SAA7134_REMOTE_I2C;
+ break;
+ case SAA7134_BOARD_AVERMEDIA_CARDBUS_506:
+ saa7134_set_gpio(dev, 23, 0);
+ msleep(10);
+ saa7134_set_gpio(dev, 23, 1);
+ dev->has_remote = SAA7134_REMOTE_I2C;
+ break;
+ case SAA7134_BOARD_AVERMEDIA_M103:
+ saa7134_set_gpio(dev, 23, 0);
+ msleep(10);
+ saa7134_set_gpio(dev, 23, 1);
+ break;
+ case SAA7134_BOARD_AVERMEDIA_A16D:
+ saa7134_set_gpio(dev, 21, 0);
+ msleep(10);
+ saa7134_set_gpio(dev, 21, 1);
+ msleep(1);
+ dev->has_remote = SAA7134_REMOTE_GPIO;
+ break;
+ case SAA7134_BOARD_BEHOLD_COLUMBUS_TVFM:
+ /* power-down tuner chip */
+ saa_andorl(SAA7134_GPIO_GPMODE0 >> 2, 0x000A8004, 0x000A8004);
+ saa_andorl(SAA7134_GPIO_GPSTATUS0 >> 2, 0x000A8004, 0);
+ msleep(10);
+ /* power-up tuner chip */
+ saa_andorl(SAA7134_GPIO_GPMODE0 >> 2, 0x000A8004, 0x000A8004);
+ saa_andorl(SAA7134_GPIO_GPSTATUS0 >> 2, 0x000A8004, 0x000A8004);
+ msleep(10);
+ /* remote via GPIO */
+ dev->has_remote = SAA7134_REMOTE_GPIO;
+ break;
+ case SAA7134_BOARD_RTD_VFG7350:
+
+ /*
+ * Make sure Production Test Register at offset 0x1D1 is cleared
+ * to take chip out of test mode. Clearing bit 4 (TST_EN_AOUT)
+ * prevents pin 105 from remaining low; keeping pin 105 low
+ * continually resets the SAA6752 chip.
+ */
+
+ saa_writeb (SAA7134_PRODUCTION_TEST_MODE, 0x00);
+ break;
+ case SAA7134_BOARD_HAUPPAUGE_HVR1150:
+ case SAA7134_BOARD_HAUPPAUGE_HVR1120:
+ dev->has_remote = SAA7134_REMOTE_GPIO;
+ /* GPIO 26 high for digital, low for analog */
+ saa7134_set_gpio(dev, 26, 0);
+ msleep(1);
+
+ saa7134_set_gpio(dev, 22, 0);
+ msleep(10);
+ saa7134_set_gpio(dev, 22, 1);
+ break;
+ /* i2c remotes */
+ case SAA7134_BOARD_PINNACLE_PCTV_110i:
+ case SAA7134_BOARD_PINNACLE_PCTV_310i:
+ case SAA7134_BOARD_UPMOST_PURPLE_TV:
+ case SAA7134_BOARD_MSI_TVATANYWHERE_PLUS:
+ case SAA7134_BOARD_HAUPPAUGE_HVR1110:
+ case SAA7134_BOARD_BEHOLD_607FM_MK3:
+ case SAA7134_BOARD_BEHOLD_607FM_MK5:
+ case SAA7134_BOARD_BEHOLD_609FM_MK3:
+ case SAA7134_BOARD_BEHOLD_609FM_MK5:
+ case SAA7134_BOARD_BEHOLD_607RDS_MK3:
+ case SAA7134_BOARD_BEHOLD_607RDS_MK5:
+ case SAA7134_BOARD_BEHOLD_609RDS_MK3:
+ case SAA7134_BOARD_BEHOLD_609RDS_MK5:
+ case SAA7134_BOARD_BEHOLD_M6:
+ case SAA7134_BOARD_BEHOLD_M63:
+ case SAA7134_BOARD_BEHOLD_M6_EXTRA:
+ case SAA7134_BOARD_BEHOLD_H6:
+ case SAA7134_BOARD_BEHOLD_X7:
+ case SAA7134_BOARD_BEHOLD_H7:
+ case SAA7134_BOARD_BEHOLD_A7:
+ case SAA7134_BOARD_KWORLD_PC150U:
+ case SAA7134_BOARD_SNAZIO_TVPVR_PRO:
+ dev->has_remote = SAA7134_REMOTE_I2C;
+ break;
+ case SAA7134_BOARD_AVERMEDIA_A169_B:
+ pr_warn("%s: %s: dual saa713x broadcast decoders\n"
+ "%s: Sorry, none of the inputs to this chip are supported yet.\n"
+ "%s: Dual decoder functionality is disabled for now, use the other chip.\n",
+ dev->name, card(dev).name, dev->name, dev->name);
+ break;
+ case SAA7134_BOARD_AVERMEDIA_M102:
+ /* enable tuner */
+ dev->has_remote = SAA7134_REMOTE_GPIO;
+ saa_andorl(SAA7134_GPIO_GPMODE0 >> 2, 0x8c040007, 0x8c040007);
+ saa_andorl(SAA7134_GPIO_GPSTATUS0 >> 2, 0x0c0007cd, 0x0c0007cd);
+ break;
+ case SAA7134_BOARD_AVERMEDIA_A700_HYBRID:
+ case SAA7134_BOARD_AVERMEDIA_A700_PRO:
+ /* write windows gpio values */
+ saa_andorl(SAA7134_GPIO_GPMODE0 >> 2, 0x80040100, 0x80040100);
+ saa_andorl(SAA7134_GPIO_GPSTATUS0 >> 2, 0x80040100, 0x00040100);
+ break;
+ case SAA7134_BOARD_AVERMEDIA_A706:
+ /* radio antenna select: tristate both as in Windows driver */
+ saa7134_set_gpio(dev, 12, 3); /* TV antenna */
+ saa7134_set_gpio(dev, 13, 3); /* FM antenna */
+ dev->has_remote = SAA7134_REMOTE_I2C;
+ /*
+ * Disable CE5039 DVB-S tuner now (SLEEP pin high) to prevent
+ * it from interfering with analog tuner detection
+ */
+ saa7134_set_gpio(dev, 23, 1);
+ break;
+ case SAA7134_BOARD_VIDEOMATE_S350:
+ dev->has_remote = SAA7134_REMOTE_GPIO;
+ saa_andorl(SAA7134_GPIO_GPMODE0 >> 2, 0x0000C000, 0x0000C000);
+ saa_andorl(SAA7134_GPIO_GPSTATUS0 >> 2, 0x0000C000, 0x0000C000);
+ break;
+ case SAA7134_BOARD_AVERMEDIA_M733A:
+ saa7134_set_gpio(dev, 1, 1);
+ msleep(10);
+ saa7134_set_gpio(dev, 1, 0);
+ msleep(10);
+ saa7134_set_gpio(dev, 1, 1);
+ dev->has_remote = SAA7134_REMOTE_GPIO;
+ break;
+ case SAA7134_BOARD_MAGICPRO_PROHDTV_PRO2:
+ /* enable LGS-8G75 */
+ saa_andorl(SAA7134_GPIO_GPMODE0 >> 2, 0x0e050000, 0x0c050000);
+ saa_andorl(SAA7134_GPIO_GPSTATUS0 >> 2, 0x0e050000, 0x0c050000);
+ break;
+ case SAA7134_BOARD_VIDEOMATE_T750:
+ /* enable the analog tuner */
+ saa_andorl(SAA7134_GPIO_GPMODE0 >> 2, 0x00008000, 0x00008000);
+ saa_andorl(SAA7134_GPIO_GPSTATUS0 >> 2, 0x00008000, 0x00008000);
+ break;
+ }
+ return 0;
+}
+
+static void saa7134_tuner_setup(struct saa7134_dev *dev)
+{
+ struct tuner_setup tun_setup;
+ unsigned int mode_mask = T_RADIO | T_ANALOG_TV;
+
+ memset(&tun_setup, 0, sizeof(tun_setup));
+ tun_setup.tuner_callback = saa7134_tuner_callback;
+
+ if (saa7134_boards[dev->board].radio_type != UNSET) {
+ tun_setup.type = saa7134_boards[dev->board].radio_type;
+ tun_setup.addr = saa7134_boards[dev->board].radio_addr;
+
+ tun_setup.mode_mask = T_RADIO;
+
+ saa_call_all(dev, tuner, s_type_addr, &tun_setup);
+ mode_mask &= ~T_RADIO;
+ }
+
+ if ((dev->tuner_type != TUNER_ABSENT) && (dev->tuner_type != UNSET)) {
+ tun_setup.type = dev->tuner_type;
+ tun_setup.addr = dev->tuner_addr;
+ tun_setup.config = &saa7134_boards[dev->board].tda829x_conf;
+ tun_setup.tuner_callback = saa7134_tuner_callback;
+
+ tun_setup.mode_mask = mode_mask;
+
+ saa_call_all(dev, tuner, s_type_addr, &tun_setup);
+ }
+
+ if (dev->tda9887_conf) {
+ struct v4l2_priv_tun_config tda9887_cfg;
+
+ tda9887_cfg.tuner = TUNER_TDA9887;
+ tda9887_cfg.priv = &dev->tda9887_conf;
+
+ saa_call_all(dev, tuner, s_config, &tda9887_cfg);
+ }
+
+ if (dev->tuner_type == TUNER_XC2028) {
+ struct v4l2_priv_tun_config xc2028_cfg;
+ struct xc2028_ctrl ctl;
+
+ memset(&xc2028_cfg, 0, sizeof(xc2028_cfg));
+ memset(&ctl, 0, sizeof(ctl));
+
+ ctl.fname = XC2028_DEFAULT_FIRMWARE;
+ ctl.max_len = 64;
+
+ switch (dev->board) {
+ case SAA7134_BOARD_AVERMEDIA_A16D:
+ case SAA7134_BOARD_AVERMEDIA_CARDBUS_506:
+ case SAA7134_BOARD_AVERMEDIA_M103:
+ case SAA7134_BOARD_AVERMEDIA_A700_HYBRID:
+ ctl.demod = XC3028_FE_ZARLINK456;
+ break;
+ default:
+ ctl.demod = XC3028_FE_OREN538;
+ ctl.mts = 1;
+ }
+
+ xc2028_cfg.tuner = TUNER_XC2028;
+ xc2028_cfg.priv = &ctl;
+
+ saa_call_all(dev, tuner, s_config, &xc2028_cfg);
+ }
+}
+
+/* stuff which needs working i2c */
+int saa7134_board_init2(struct saa7134_dev *dev)
+{
+ unsigned char buf;
+ int board;
+
+ /* Put here the code that enables the chips that are needed
+ for analog mode and doesn't depend on the tuner attachment.
+ It is also a good idea to get tuner type from eeprom, etc before
+ initializing tuner, since we can avoid loading tuner driver
+ on devices that has TUNER_ABSENT
+ */
+ switch (dev->board) {
+ case SAA7134_BOARD_BMK_MPEX_NOTUNER:
+ case SAA7134_BOARD_BMK_MPEX_TUNER:
+ /* Checks if the device has a tuner at 0x60 addr
+ If the device doesn't have a tuner, TUNER_ABSENT
+ will be used at tuner_type, avoiding loading tuner
+ without needing it
+ */
+ dev->i2c_client.addr = 0x60;
+ board = (i2c_master_recv(&dev->i2c_client, &buf, 0) < 0)
+ ? SAA7134_BOARD_BMK_MPEX_NOTUNER
+ : SAA7134_BOARD_BMK_MPEX_TUNER;
+ if (board == dev->board)
+ break;
+ dev->board = board;
+ pr_warn("%s: board type fixup: %s\n", dev->name,
+ saa7134_boards[dev->board].name);
+ dev->tuner_type = saa7134_boards[dev->board].tuner_type;
+
+ break;
+ case SAA7134_BOARD_MD7134:
+ {
+ u8 subaddr;
+ u8 data[3], data1[] = { 0x09, 0x9f, 0x86, 0x11};
+ int ret, tuner_t;
+ struct i2c_msg msg[] = {{.addr = 0x50, .flags = 0, .buf = &subaddr, .len = 1},
+ {.addr = 0x50, .flags = I2C_M_RD, .buf = data, .len = 3}},
+ msg1 = {.addr = 0x61, .flags = 0, .buf = data1, .len = sizeof(data1)};
+
+ subaddr= 0x14;
+ tuner_t = 0;
+
+ /* Retrieve device data from eeprom, checking for the
+ proper tuner_type.
+ */
+ ret = i2c_transfer(&dev->i2c_adap, msg, 2);
+ if (ret != 2) {
+ pr_err("EEPROM read failure\n");
+ } else if ((data[0] != 0) && (data[0] != 0xff)) {
+ /* old config structure */
+ subaddr = data[0] + 2;
+ msg[1].len = 2;
+ i2c_transfer(&dev->i2c_adap, msg, 2);
+ tuner_t = (data[0] << 8) + data[1];
+ switch (tuner_t){
+ case 0x0103:
+ dev->tuner_type = TUNER_PHILIPS_PAL;
+ break;
+ case 0x010C:
+ dev->tuner_type = TUNER_PHILIPS_FM1216ME_MK3;
+ break;
+ default:
+ pr_err("%s Can't determine tuner type %x from EEPROM\n",
+ dev->name, tuner_t);
+ }
+ } else if ((data[1] != 0) && (data[1] != 0xff)) {
+ /* new config structure */
+ subaddr = data[1] + 1;
+ msg[1].len = 1;
+ i2c_transfer(&dev->i2c_adap, msg, 2);
+ subaddr = data[0] + 1;
+ msg[1].len = 2;
+ i2c_transfer(&dev->i2c_adap, msg, 2);
+ tuner_t = (data[1] << 8) + data[0];
+ switch (tuner_t) {
+ case 0x0005:
+ dev->tuner_type = TUNER_PHILIPS_FM1216ME_MK3;
+ break;
+ case 0x001d:
+ dev->tuner_type = TUNER_PHILIPS_FMD1216ME_MK3;
+ pr_info("%s Board has DVB-T\n",
+ dev->name);
+ break;
+ default:
+ pr_err("%s Can't determine tuner type %x from EEPROM\n",
+ dev->name, tuner_t);
+ }
+ } else {
+ pr_err("%s unexpected config structure\n", dev->name);
+ }
+
+ pr_info("%s Tuner type is %d\n", dev->name, dev->tuner_type);
+
+ /* The tuner TUNER_PHILIPS_FMD1216ME_MK3 after hardware */
+ /* start has disabled IF and enabled DVB-T. When saa7134 */
+ /* scan I2C devices it will not detect IF tda9887 and can`t*/
+ /* watch TV without software reboot. To solve this problem */
+ /* switch the tuner to analog TV mode manually. */
+ if (dev->tuner_type == TUNER_PHILIPS_FMD1216ME_MK3) {
+ if (i2c_transfer(&dev->i2c_adap, &msg1, 1) != 1)
+ printk(KERN_WARNING "%s: Unable to enable IF of the tuner.\n", dev->name);
+ }
+ break;
+ }
+ case SAA7134_BOARD_PHILIPS_EUROPA:
+ if (dev->autodetected && (dev->eedata[0x41] == 0x1c)) {
+ /* Reconfigure board as Snake reference design */
+ dev->board = SAA7134_BOARD_PHILIPS_SNAKE;
+ dev->tuner_type = saa7134_boards[dev->board].tuner_type;
+ pr_info("%s: Reconfigured board as %s\n",
+ dev->name, saa7134_boards[dev->board].name);
+ break;
+ }
+ fallthrough;
+ case SAA7134_BOARD_VIDEOMATE_DVBT_300:
+ case SAA7134_BOARD_ASUS_EUROPA2_HYBRID:
+ case SAA7134_BOARD_ASUS_EUROPA_HYBRID:
+ case SAA7134_BOARD_TECHNOTREND_BUDGET_T3000:
+ {
+
+ /* The Philips EUROPA based hybrid boards have the tuner
+ connected through the channel decoder. We have to make it
+ transparent to find it
+ */
+ u8 data[] = { 0x07, 0x02};
+ struct i2c_msg msg = {.addr=0x08, .flags=0, .buf=data, .len = sizeof(data)};
+ i2c_transfer(&dev->i2c_adap, &msg, 1);
+
+ break;
+ }
+ case SAA7134_BOARD_PHILIPS_TIGER:
+ case SAA7134_BOARD_PHILIPS_TIGER_S:
+ {
+ u8 data[] = { 0x3c, 0x33, 0x60};
+ struct i2c_msg msg = {.addr=0x08, .flags=0, .buf=data, .len = sizeof(data)};
+ if (dev->autodetected && (dev->eedata[0x49] == 0x50)) {
+ dev->board = SAA7134_BOARD_PHILIPS_TIGER_S;
+ pr_info("%s: Reconfigured board as %s\n",
+ dev->name, saa7134_boards[dev->board].name);
+ }
+ if (dev->board == SAA7134_BOARD_PHILIPS_TIGER_S) {
+ dev->tuner_type = TUNER_PHILIPS_TDA8290;
+
+ data[2] = 0x68;
+ i2c_transfer(&dev->i2c_adap, &msg, 1);
+ break;
+ }
+ i2c_transfer(&dev->i2c_adap, &msg, 1);
+ break;
+ }
+ case SAA7134_BOARD_ASUSTeK_TVFM7135:
+ /* The card below is detected as card=53, but is different */
+ if (dev->autodetected && (dev->eedata[0x27] == 0x03)) {
+ dev->board = SAA7134_BOARD_ASUSTeK_P7131_ANALOG;
+ pr_info("%s: P7131 analog only, using entry of %s\n",
+ dev->name, saa7134_boards[dev->board].name);
+
+ /*
+ * IR init has already happened for other cards, so
+ * we have to catch up.
+ */
+ dev->has_remote = SAA7134_REMOTE_GPIO;
+ saa7134_input_init1(dev);
+ }
+ break;
+ case SAA7134_BOARD_HAUPPAUGE_HVR1150:
+ case SAA7134_BOARD_HAUPPAUGE_HVR1120:
+ hauppauge_eeprom(dev, dev->eedata+0x80);
+ break;
+ case SAA7134_BOARD_HAUPPAUGE_HVR1110:
+ hauppauge_eeprom(dev, dev->eedata+0x80);
+ fallthrough;
+ case SAA7134_BOARD_PINNACLE_PCTV_310i:
+ case SAA7134_BOARD_KWORLD_DVBT_210:
+ case SAA7134_BOARD_TEVION_DVBT_220RF:
+ case SAA7134_BOARD_ASUSTeK_TIGER:
+ case SAA7134_BOARD_ASUSTeK_P7131_DUAL:
+ case SAA7134_BOARD_ASUSTeK_P7131_HYBRID_LNA:
+ case SAA7134_BOARD_MEDION_MD8800_QUADRO:
+ case SAA7134_BOARD_AVERMEDIA_SUPER_007:
+ case SAA7134_BOARD_TWINHAN_DTV_DVB_3056:
+ case SAA7134_BOARD_CREATIX_CTX953:
+ {
+ /* this is a hybrid board, initialize to analog mode
+ * and configure firmware eeprom address
+ */
+ u8 data[] = { 0x3c, 0x33, 0x60};
+ struct i2c_msg msg = {.addr=0x08, .flags=0, .buf=data, .len = sizeof(data)};
+ i2c_transfer(&dev->i2c_adap, &msg, 1);
+ break;
+ }
+ case SAA7134_BOARD_ASUSTeK_TIGER_3IN1:
+ {
+ u8 data[] = { 0x3c, 0x33, 0x60};
+ struct i2c_msg msg = {.addr = 0x0b, .flags = 0, .buf = data,
+ .len = sizeof(data)};
+ i2c_transfer(&dev->i2c_adap, &msg, 1);
+ break;
+ }
+ case SAA7134_BOARD_ASUSTeK_PS3_100:
+ {
+ u8 data[] = { 0x3c, 0x33, 0x60};
+ struct i2c_msg msg = {.addr = 0x0b, .flags = 0, .buf = data,
+ .len = sizeof(data)};
+ i2c_transfer(&dev->i2c_adap, &msg, 1);
+ break;
+ }
+ case SAA7134_BOARD_FLYDVB_TRIO:
+ {
+ u8 temp = 0;
+ int rc;
+ u8 data[] = { 0x3c, 0x33, 0x62};
+ struct i2c_msg msg = {.addr=0x09, .flags=0, .buf=data, .len = sizeof(data)};
+ i2c_transfer(&dev->i2c_adap, &msg, 1);
+
+ /*
+ * send weak up message to pic16C505 chip
+ * @ LifeView FlyDVB Trio
+ */
+ msg.buf = &temp;
+ msg.addr = 0x0b;
+ msg.len = 1;
+ if (1 != i2c_transfer(&dev->i2c_adap, &msg, 1)) {
+ pr_warn("%s: send wake up byte to pic16C505(IR chip) failed\n",
+ dev->name);
+ } else {
+ msg.flags = I2C_M_RD;
+ rc = i2c_transfer(&dev->i2c_adap, &msg, 1);
+ pr_info("%s: probe IR chip @ i2c 0x%02x: %s\n",
+ dev->name, msg.addr,
+ (1 == rc) ? "yes" : "no");
+ if (rc == 1)
+ dev->has_remote = SAA7134_REMOTE_I2C;
+ }
+ break;
+ }
+ case SAA7134_BOARD_ADS_DUO_CARDBUS_PTV331:
+ case SAA7134_BOARD_FLYDVBT_HYBRID_CARDBUS:
+ {
+ /* initialize analog mode */
+ u8 data[] = { 0x3c, 0x33, 0x6a};
+ struct i2c_msg msg = {.addr=0x08, .flags=0, .buf=data, .len = sizeof(data)};
+ i2c_transfer(&dev->i2c_adap, &msg, 1);
+ break;
+ }
+ case SAA7134_BOARD_CINERGY_HT_PCMCIA:
+ case SAA7134_BOARD_CINERGY_HT_PCI:
+ {
+ /* initialize analog mode */
+ u8 data[] = { 0x3c, 0x33, 0x68};
+ struct i2c_msg msg = {.addr=0x08, .flags=0, .buf=data, .len = sizeof(data)};
+ i2c_transfer(&dev->i2c_adap, &msg, 1);
+ break;
+ }
+ case SAA7134_BOARD_VIDEOMATE_DVBT_200:
+ case SAA7134_BOARD_VIDEOMATE_DVBT_200A:
+ /* The T200 and the T200A share the same pci id. Consequently,
+ * we are going to query eeprom to try to find out which one we
+ * are actually looking at. */
+
+ /* Don't do this if the board was specifically selected with an
+ * insmod option or if we have the default configuration T200*/
+ if (!dev->autodetected || (dev->eedata[0x41] == 0xd0))
+ break;
+ if (dev->eedata[0x41] == 0x02) {
+ /* Reconfigure board as T200A */
+ dev->board = SAA7134_BOARD_VIDEOMATE_DVBT_200A;
+ dev->tuner_type = saa7134_boards[dev->board].tuner_type;
+ dev->tda9887_conf = saa7134_boards[dev->board].tda9887_conf;
+ pr_info("%s: Reconfigured board as %s\n",
+ dev->name, saa7134_boards[dev->board].name);
+ } else {
+ pr_warn("%s: Unexpected tuner type info: %x in eeprom\n",
+ dev->name, dev->eedata[0x41]);
+ break;
+ }
+ break;
+ case SAA7134_BOARD_ADS_INSTANT_HDTV_PCI:
+ case SAA7134_BOARD_KWORLD_ATSC110:
+ {
+ struct i2c_msg msg = { .addr = 0x0a, .flags = 0 };
+ int i;
+ static u8 buffer[][2] = {
+ { 0x10, 0x12 },
+ { 0x13, 0x04 },
+ { 0x16, 0x00 },
+ { 0x14, 0x04 },
+ { 0x17, 0x00 },
+ };
+
+ for (i = 0; i < ARRAY_SIZE(buffer); i++) {
+ msg.buf = &buffer[i][0];
+ msg.len = ARRAY_SIZE(buffer[0]);
+ if (i2c_transfer(&dev->i2c_adap, &msg, 1) != 1)
+ pr_warn("%s: Unable to enable tuner(%i).\n",
+ dev->name, i);
+ }
+ break;
+ }
+ case SAA7134_BOARD_BEHOLD_H6:
+ {
+ u8 data[] = { 0x09, 0x9f, 0x86, 0x11};
+ struct i2c_msg msg = {.addr = 0x61, .flags = 0, .buf = data,
+ .len = sizeof(data)};
+
+ /* The tuner TUNER_PHILIPS_FMD1216MEX_MK3 after hardware */
+ /* start has disabled IF and enabled DVB-T. When saa7134 */
+ /* scan I2C devices it not detect IF tda9887 and can`t */
+ /* watch TV without software reboot. For solve this problem */
+ /* switch the tuner to analog TV mode manually. */
+ if (i2c_transfer(&dev->i2c_adap, &msg, 1) != 1)
+ pr_warn("%s: Unable to enable IF of the tuner.\n",
+ dev->name);
+ break;
+ }
+ case SAA7134_BOARD_KWORLD_PCI_SBTVD_FULLSEG:
+ saa_writel(SAA7134_GPIO_GPMODE0 >> 2, 0x4000);
+ saa_writel(SAA7134_GPIO_GPSTATUS0 >> 2, 0x4000);
+
+ saa7134_set_gpio(dev, 27, 0);
+ break;
+ } /* switch() */
+
+ /* initialize tuner (don't do this when resuming) */
+ if (!dev->insuspend && TUNER_ABSENT != dev->tuner_type) {
+ int has_demod = (dev->tda9887_conf & TDA9887_PRESENT);
+
+ /* Note: radio tuner address is always filled in,
+ so we do not need to probe for a radio tuner device. */
+ if (dev->radio_type != UNSET)
+ v4l2_i2c_new_subdev(&dev->v4l2_dev,
+ &dev->i2c_adap, "tuner",
+ dev->radio_addr, NULL);
+ if (has_demod)
+ v4l2_i2c_new_subdev(&dev->v4l2_dev,
+ &dev->i2c_adap, "tuner",
+ 0, v4l2_i2c_tuner_addrs(ADDRS_DEMOD));
+ if (dev->tuner_addr == ADDR_UNSET) {
+ enum v4l2_i2c_tuner_type type =
+ has_demod ? ADDRS_TV_WITH_DEMOD : ADDRS_TV;
+
+ v4l2_i2c_new_subdev(&dev->v4l2_dev,
+ &dev->i2c_adap, "tuner",
+ 0, v4l2_i2c_tuner_addrs(type));
+ } else {
+ v4l2_i2c_new_subdev(&dev->v4l2_dev,
+ &dev->i2c_adap, "tuner",
+ dev->tuner_addr, NULL);
+ }
+ }
+
+ saa7134_tuner_setup(dev);
+
+ switch (dev->board) {
+ case SAA7134_BOARD_BEHOLD_COLUMBUS_TVFM:
+ case SAA7134_BOARD_AVERMEDIA_CARDBUS_501:
+ {
+ struct v4l2_priv_tun_config tea5767_cfg;
+ struct tea5767_ctrl ctl;
+
+ dev->i2c_client.addr = 0xC0;
+ /* set TEA5767(analog FM) defines */
+ memset(&ctl, 0, sizeof(ctl));
+ ctl.xtal_freq = TEA5767_HIGH_LO_13MHz;
+ tea5767_cfg.tuner = TUNER_TEA5767;
+ tea5767_cfg.priv = &ctl;
+ saa_call_all(dev, tuner, s_config, &tea5767_cfg);
+ break;
+ }
+ } /* switch() */
+
+ return 0;
+}
diff --git a/drivers/media/pci/saa7134/saa7134-core.c b/drivers/media/pci/saa7134/saa7134-core.c
new file mode 100644
index 0000000000..ea0585e43a
--- /dev/null
+++ b/drivers/media/pci/saa7134/saa7134-core.c
@@ -0,0 +1,1524 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ *
+ * device driver for philips saa7134 based TV cards
+ * driver core
+ *
+ * (c) 2001-03 Gerd Knorr <kraxel@bytesex.org> [SuSE Labs]
+ */
+
+#include "saa7134.h"
+#include "saa7134-reg.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/delay.h>
+#include <linux/mutex.h>
+#include <linux/dma-mapping.h>
+#include <linux/pm.h>
+
+MODULE_DESCRIPTION("v4l2 driver module for saa7130/34 based TV cards");
+MODULE_AUTHOR("Gerd Knorr <kraxel@bytesex.org> [SuSE Labs]");
+MODULE_LICENSE("GPL");
+MODULE_VERSION(SAA7134_VERSION);
+
+
+/* ------------------------------------------------------------------ */
+
+static unsigned int irq_debug;
+module_param(irq_debug, int, 0644);
+MODULE_PARM_DESC(irq_debug,"enable debug messages [IRQ handler]");
+
+static unsigned int core_debug;
+module_param(core_debug, int, 0644);
+MODULE_PARM_DESC(core_debug,"enable debug messages [core]");
+
+static unsigned int gpio_tracking;
+module_param(gpio_tracking, int, 0644);
+MODULE_PARM_DESC(gpio_tracking,"enable debug messages [gpio]");
+
+static unsigned int alsa = 1;
+module_param(alsa, int, 0644);
+MODULE_PARM_DESC(alsa,"enable/disable ALSA DMA sound [dmasound]");
+
+static unsigned int latency = UNSET;
+module_param(latency, int, 0444);
+MODULE_PARM_DESC(latency,"pci latency timer");
+
+bool saa7134_userptr;
+module_param(saa7134_userptr, bool, 0644);
+MODULE_PARM_DESC(saa7134_userptr, "enable page-aligned userptr support");
+
+static unsigned int video_nr[] = {[0 ... (SAA7134_MAXBOARDS - 1)] = UNSET };
+static unsigned int vbi_nr[] = {[0 ... (SAA7134_MAXBOARDS - 1)] = UNSET };
+static unsigned int radio_nr[] = {[0 ... (SAA7134_MAXBOARDS - 1)] = UNSET };
+static unsigned int tuner[] = {[0 ... (SAA7134_MAXBOARDS - 1)] = UNSET };
+static unsigned int card[] = {[0 ... (SAA7134_MAXBOARDS - 1)] = UNSET };
+
+
+module_param_array(video_nr, int, NULL, 0444);
+module_param_array(vbi_nr, int, NULL, 0444);
+module_param_array(radio_nr, int, NULL, 0444);
+module_param_array(tuner, int, NULL, 0444);
+module_param_array(card, int, NULL, 0444);
+
+MODULE_PARM_DESC(video_nr, "video device number");
+MODULE_PARM_DESC(vbi_nr, "vbi device number");
+MODULE_PARM_DESC(radio_nr, "radio device number");
+MODULE_PARM_DESC(tuner, "tuner type");
+MODULE_PARM_DESC(card, "card type");
+
+DEFINE_MUTEX(saa7134_devlist_lock);
+EXPORT_SYMBOL(saa7134_devlist_lock);
+LIST_HEAD(saa7134_devlist);
+EXPORT_SYMBOL(saa7134_devlist);
+static LIST_HEAD(mops_list);
+static unsigned int saa7134_devcount;
+
+int (*saa7134_dmasound_init)(struct saa7134_dev *dev);
+int (*saa7134_dmasound_exit)(struct saa7134_dev *dev);
+
+#define core_dbg(fmt, arg...) do { \
+ if (core_debug) \
+ printk(KERN_DEBUG pr_fmt("core: " fmt), ## arg); \
+ } while (0)
+
+#define irq_dbg(level, fmt, arg...) do {\
+ if (irq_debug > level) \
+ printk(KERN_DEBUG pr_fmt("irq: " fmt), ## arg); \
+ } while (0)
+
+void saa7134_track_gpio(struct saa7134_dev *dev, const char *msg)
+{
+ unsigned long mode,status;
+
+ if (!gpio_tracking)
+ return;
+ /* rising SAA7134_GPIO_GPRESCAN reads the status */
+ saa_andorb(SAA7134_GPIO_GPMODE3,SAA7134_GPIO_GPRESCAN,0);
+ saa_andorb(SAA7134_GPIO_GPMODE3,SAA7134_GPIO_GPRESCAN,SAA7134_GPIO_GPRESCAN);
+ mode = saa_readl(SAA7134_GPIO_GPMODE0 >> 2) & 0xfffffff;
+ status = saa_readl(SAA7134_GPIO_GPSTATUS0 >> 2) & 0xfffffff;
+ core_dbg("%s: gpio: mode=0x%07lx in=0x%07lx out=0x%07lx [%s]\n",
+ dev->name, mode, (~mode) & status, mode & status, msg);
+}
+
+void saa7134_set_gpio(struct saa7134_dev *dev, int bit_no, int value)
+{
+ u32 index, bitval;
+
+ index = 1 << bit_no;
+ switch (value) {
+ case 0: /* static value */
+ case 1:
+ core_dbg("setting GPIO%d to static %d\n", bit_no, value);
+ /* turn sync mode off if necessary */
+ if (index & 0x00c00000)
+ saa_andorb(SAA7134_VIDEO_PORT_CTRL6, 0x0f, 0x00);
+ if (value)
+ bitval = index;
+ else
+ bitval = 0;
+ saa_andorl(SAA7134_GPIO_GPMODE0 >> 2, index, index);
+ saa_andorl(SAA7134_GPIO_GPSTATUS0 >> 2, index, bitval);
+ break;
+ case 3: /* tristate */
+ core_dbg("setting GPIO%d to tristate\n", bit_no);
+ saa_andorl(SAA7134_GPIO_GPMODE0 >> 2, index, 0);
+ break;
+ }
+}
+
+/* ------------------------------------------------------------------ */
+
+
+/* ----------------------------------------------------------- */
+/* delayed request_module */
+
+#if defined(CONFIG_MODULES) && defined(MODULE)
+
+static void request_module_async(struct work_struct *work){
+ struct saa7134_dev* dev = container_of(work, struct saa7134_dev, request_module_wk);
+ if (card_is_empress(dev))
+ request_module("saa7134-empress");
+ if (card_is_dvb(dev))
+ request_module("saa7134-dvb");
+ if (card_is_go7007(dev))
+ request_module("saa7134-go7007");
+ if (alsa) {
+ if (dev->pci->device != PCI_DEVICE_ID_PHILIPS_SAA7130)
+ request_module("saa7134-alsa");
+ }
+}
+
+static void request_submodules(struct saa7134_dev *dev)
+{
+ INIT_WORK(&dev->request_module_wk, request_module_async);
+ schedule_work(&dev->request_module_wk);
+}
+
+static void flush_request_submodules(struct saa7134_dev *dev)
+{
+ flush_work(&dev->request_module_wk);
+}
+
+#else
+#define request_submodules(dev)
+#define flush_request_submodules(dev)
+#endif /* CONFIG_MODULES */
+
+/* ------------------------------------------------------------------ */
+
+/* nr of (saa7134-)pages for the given buffer size */
+static int saa7134_buffer_pages(int size)
+{
+ size = PAGE_ALIGN(size);
+ size += PAGE_SIZE; /* for non-page-aligned buffers */
+ size /= 4096;
+ return size;
+}
+
+/* calc max # of buffers from size (must not exceed the 4MB virtual
+ * address space per DMA channel) */
+int saa7134_buffer_count(unsigned int size, unsigned int count)
+{
+ unsigned int maxcount;
+
+ maxcount = 1024 / saa7134_buffer_pages(size);
+ if (count > maxcount)
+ count = maxcount;
+ return count;
+}
+
+int saa7134_buffer_startpage(struct saa7134_buf *buf)
+{
+ return saa7134_buffer_pages(vb2_plane_size(&buf->vb2.vb2_buf, 0))
+ * buf->vb2.vb2_buf.index;
+}
+
+unsigned long saa7134_buffer_base(struct saa7134_buf *buf)
+{
+ unsigned long base;
+ struct sg_table *dma = vb2_dma_sg_plane_desc(&buf->vb2.vb2_buf, 0);
+
+ base = saa7134_buffer_startpage(buf) * 4096;
+ base += dma->sgl[0].offset;
+ return base;
+}
+
+/* ------------------------------------------------------------------ */
+
+int saa7134_pgtable_alloc(struct pci_dev *pci, struct saa7134_pgtable *pt)
+{
+ __le32 *cpu;
+ dma_addr_t dma_addr = 0;
+
+ cpu = dma_alloc_coherent(&pci->dev, SAA7134_PGTABLE_SIZE, &dma_addr,
+ GFP_KERNEL);
+ if (NULL == cpu)
+ return -ENOMEM;
+ pt->size = SAA7134_PGTABLE_SIZE;
+ pt->cpu = cpu;
+ pt->dma = dma_addr;
+ return 0;
+}
+
+int saa7134_pgtable_build(struct pci_dev *pci, struct saa7134_pgtable *pt,
+ struct scatterlist *list, unsigned int length,
+ unsigned int startpage)
+{
+ __le32 *ptr;
+ unsigned int i, p;
+
+ BUG_ON(NULL == pt || NULL == pt->cpu);
+
+ ptr = pt->cpu + startpage;
+ for (i = 0; i < length; i++, list = sg_next(list)) {
+ for (p = 0; p * 4096 < sg_dma_len(list); p++, ptr++)
+ *ptr = cpu_to_le32(sg_dma_address(list) +
+ list->offset + p * 4096);
+ }
+ return 0;
+}
+
+void saa7134_pgtable_free(struct pci_dev *pci, struct saa7134_pgtable *pt)
+{
+ if (NULL == pt->cpu)
+ return;
+ dma_free_coherent(&pci->dev, pt->size, pt->cpu, pt->dma);
+ pt->cpu = NULL;
+}
+
+/* ------------------------------------------------------------------ */
+
+int saa7134_buffer_queue(struct saa7134_dev *dev,
+ struct saa7134_dmaqueue *q,
+ struct saa7134_buf *buf)
+{
+ struct saa7134_buf *next = NULL;
+ unsigned long flags;
+
+ spin_lock_irqsave(&dev->slock, flags);
+ core_dbg("buffer_queue %p\n", buf);
+ if (NULL == q->curr) {
+ if (!q->need_two) {
+ q->curr = buf;
+ buf->activate(dev, buf, NULL);
+ } else if (list_empty(&q->queue)) {
+ list_add_tail(&buf->entry, &q->queue);
+ } else {
+ next = list_entry(q->queue.next, struct saa7134_buf,
+ entry);
+ q->curr = buf;
+ buf->activate(dev, buf, next);
+ }
+ } else {
+ list_add_tail(&buf->entry, &q->queue);
+ }
+ spin_unlock_irqrestore(&dev->slock, flags);
+ return 0;
+}
+
+void saa7134_buffer_finish(struct saa7134_dev *dev,
+ struct saa7134_dmaqueue *q,
+ unsigned int state)
+{
+ core_dbg("buffer_finish %p\n", q->curr);
+
+ /* finish current buffer */
+ q->curr->vb2.vb2_buf.timestamp = ktime_get_ns();
+ q->curr->vb2.sequence = q->seq_nr++;
+ vb2_buffer_done(&q->curr->vb2.vb2_buf, state);
+ q->curr = NULL;
+}
+
+void saa7134_buffer_next(struct saa7134_dev *dev,
+ struct saa7134_dmaqueue *q)
+{
+ struct saa7134_buf *buf,*next = NULL;
+
+ assert_spin_locked(&dev->slock);
+ BUG_ON(NULL != q->curr);
+
+ if (!list_empty(&q->queue)) {
+ /* activate next one from queue */
+ buf = list_entry(q->queue.next, struct saa7134_buf, entry);
+ core_dbg("buffer_next %p [prev=%p/next=%p]\n",
+ buf, q->queue.prev, q->queue.next);
+ list_del(&buf->entry);
+ if (!list_empty(&q->queue))
+ next = list_entry(q->queue.next, struct saa7134_buf, entry);
+ q->curr = buf;
+ buf->activate(dev, buf, next);
+ core_dbg("buffer_next #2 prev=%p/next=%p\n",
+ q->queue.prev, q->queue.next);
+ } else {
+ /* nothing to do -- just stop DMA */
+ core_dbg("buffer_next %p\n", NULL);
+ saa7134_set_dmabits(dev);
+ del_timer(&q->timeout);
+ }
+}
+
+void saa7134_buffer_timeout(struct timer_list *t)
+{
+ struct saa7134_dmaqueue *q = from_timer(q, t, timeout);
+ struct saa7134_dev *dev = q->dev;
+ unsigned long flags;
+
+ spin_lock_irqsave(&dev->slock, flags);
+
+ /* try to reset the hardware (SWRST) */
+ saa_writeb(SAA7134_REGION_ENABLE, 0x00);
+ saa_writeb(SAA7134_REGION_ENABLE, 0x80);
+ saa_writeb(SAA7134_REGION_ENABLE, 0x00);
+
+ /* flag current buffer as failed,
+ try to start over with the next one. */
+ if (q->curr) {
+ core_dbg("timeout on %p\n", q->curr);
+ saa7134_buffer_finish(dev, q, VB2_BUF_STATE_ERROR);
+ }
+ saa7134_buffer_next(dev, q);
+ spin_unlock_irqrestore(&dev->slock, flags);
+}
+
+void saa7134_stop_streaming(struct saa7134_dev *dev, struct saa7134_dmaqueue *q)
+{
+ unsigned long flags;
+ struct list_head *pos, *n;
+ struct saa7134_buf *tmp;
+
+ spin_lock_irqsave(&dev->slock, flags);
+ list_for_each_safe(pos, n, &q->queue) {
+ tmp = list_entry(pos, struct saa7134_buf, entry);
+ vb2_buffer_done(&tmp->vb2.vb2_buf,
+ VB2_BUF_STATE_ERROR);
+ list_del(pos);
+ tmp = NULL;
+ }
+ spin_unlock_irqrestore(&dev->slock, flags);
+ saa7134_buffer_timeout(&q->timeout); /* also calls del_timer(&q->timeout) */
+}
+EXPORT_SYMBOL_GPL(saa7134_stop_streaming);
+
+/* ------------------------------------------------------------------ */
+
+int saa7134_set_dmabits(struct saa7134_dev *dev)
+{
+ u32 split, task=0, ctrl=0, irq=0;
+ enum v4l2_field cap = V4L2_FIELD_ANY;
+ enum v4l2_field ov = V4L2_FIELD_ANY;
+
+ assert_spin_locked(&dev->slock);
+
+ if (dev->insuspend)
+ return 0;
+
+ /* video capture -- dma 0 + video task A */
+ if (dev->video_q.curr) {
+ task |= 0x01;
+ ctrl |= SAA7134_MAIN_CTRL_TE0;
+ irq |= SAA7134_IRQ1_INTE_RA0_1 |
+ SAA7134_IRQ1_INTE_RA0_0;
+ cap = dev->field;
+ }
+
+ /* video capture -- dma 1+2 (planar modes) */
+ if (dev->video_q.curr && dev->fmt->planar) {
+ ctrl |= SAA7134_MAIN_CTRL_TE4 |
+ SAA7134_MAIN_CTRL_TE5;
+ }
+
+ /* vbi capture -- dma 0 + vbi task A+B */
+ if (dev->vbi_q.curr) {
+ task |= 0x22;
+ ctrl |= SAA7134_MAIN_CTRL_TE2 |
+ SAA7134_MAIN_CTRL_TE3;
+ irq |= SAA7134_IRQ1_INTE_RA0_7 |
+ SAA7134_IRQ1_INTE_RA0_6 |
+ SAA7134_IRQ1_INTE_RA0_5 |
+ SAA7134_IRQ1_INTE_RA0_4;
+ }
+
+ /* audio capture -- dma 3 */
+ if (dev->dmasound.dma_running) {
+ ctrl |= SAA7134_MAIN_CTRL_TE6;
+ irq |= SAA7134_IRQ1_INTE_RA3_1 |
+ SAA7134_IRQ1_INTE_RA3_0;
+ }
+
+ /* TS capture -- dma 5 */
+ if (dev->ts_q.curr) {
+ ctrl |= SAA7134_MAIN_CTRL_TE5;
+ irq |= SAA7134_IRQ1_INTE_RA2_1 |
+ SAA7134_IRQ1_INTE_RA2_0;
+ }
+
+ /* set task conditions + field handling */
+ if (V4L2_FIELD_HAS_BOTH(cap) || V4L2_FIELD_HAS_BOTH(ov) || cap == ov) {
+ /* default config -- use full frames */
+ saa_writeb(SAA7134_TASK_CONDITIONS(TASK_A), 0x0d);
+ saa_writeb(SAA7134_TASK_CONDITIONS(TASK_B), 0x0d);
+ saa_writeb(SAA7134_FIELD_HANDLING(TASK_A), 0x02);
+ saa_writeb(SAA7134_FIELD_HANDLING(TASK_B), 0x02);
+ split = 0;
+ } else {
+ /* split fields between tasks */
+ if (V4L2_FIELD_TOP == cap) {
+ /* odd A, even B, repeat */
+ saa_writeb(SAA7134_TASK_CONDITIONS(TASK_A), 0x0d);
+ saa_writeb(SAA7134_TASK_CONDITIONS(TASK_B), 0x0e);
+ } else {
+ /* odd B, even A, repeat */
+ saa_writeb(SAA7134_TASK_CONDITIONS(TASK_A), 0x0e);
+ saa_writeb(SAA7134_TASK_CONDITIONS(TASK_B), 0x0d);
+ }
+ saa_writeb(SAA7134_FIELD_HANDLING(TASK_A), 0x01);
+ saa_writeb(SAA7134_FIELD_HANDLING(TASK_B), 0x01);
+ split = 1;
+ }
+
+ /* irqs */
+ saa_writeb(SAA7134_REGION_ENABLE, task);
+ saa_writel(SAA7134_IRQ1, irq);
+ saa_andorl(SAA7134_MAIN_CTRL,
+ SAA7134_MAIN_CTRL_TE0 |
+ SAA7134_MAIN_CTRL_TE1 |
+ SAA7134_MAIN_CTRL_TE2 |
+ SAA7134_MAIN_CTRL_TE3 |
+ SAA7134_MAIN_CTRL_TE4 |
+ SAA7134_MAIN_CTRL_TE5 |
+ SAA7134_MAIN_CTRL_TE6,
+ ctrl);
+ core_dbg("dmabits: task=0x%02x ctrl=0x%02x irq=0x%x split=%s\n",
+ task, ctrl, irq, split ? "no" : "yes");
+
+ return 0;
+}
+
+/* ------------------------------------------------------------------ */
+/* IRQ handler + helpers */
+
+static char *irqbits[] = {
+ "DONE_RA0", "DONE_RA1", "DONE_RA2", "DONE_RA3",
+ "AR", "PE", "PWR_ON", "RDCAP", "INTL", "FIDT", "MMC",
+ "TRIG_ERR", "CONF_ERR", "LOAD_ERR",
+ "GPIO16", "GPIO18", "GPIO22", "GPIO23"
+};
+#define IRQBITS ARRAY_SIZE(irqbits)
+
+static void print_irqstatus(struct saa7134_dev *dev, int loop,
+ unsigned long report, unsigned long status)
+{
+ unsigned int i;
+
+ irq_dbg(1, "[%d,%ld]: r=0x%lx s=0x%02lx",
+ loop, jiffies, report, status);
+ for (i = 0; i < IRQBITS; i++) {
+ if (!(report & (1 << i)))
+ continue;
+ pr_cont(" %s", irqbits[i]);
+ }
+ if (report & SAA7134_IRQ_REPORT_DONE_RA0) {
+ pr_cont(" | RA0=%s,%s,%s,%ld",
+ (status & 0x40) ? "vbi" : "video",
+ (status & 0x20) ? "b" : "a",
+ (status & 0x10) ? "odd" : "even",
+ (status & 0x0f));
+ }
+ pr_cont("\n");
+}
+
+static irqreturn_t saa7134_irq(int irq, void *dev_id)
+{
+ struct saa7134_dev *dev = (struct saa7134_dev*) dev_id;
+ unsigned long report,status;
+ int loop, handled = 0;
+
+ if (dev->insuspend)
+ goto out;
+
+ for (loop = 0; loop < 10; loop++) {
+ report = saa_readl(SAA7134_IRQ_REPORT);
+ status = saa_readl(SAA7134_IRQ_STATUS);
+
+ /* If dmasound support is active and we get a sound report,
+ * mask out the report and let the saa7134-alsa module deal
+ * with it */
+ if ((report & SAA7134_IRQ_REPORT_DONE_RA3) &&
+ (dev->dmasound.priv_data != NULL) )
+ {
+ irq_dbg(2, "preserving DMA sound interrupt\n");
+ report &= ~SAA7134_IRQ_REPORT_DONE_RA3;
+ }
+
+ if (0 == report) {
+ irq_dbg(2, "no (more) work\n");
+ goto out;
+ }
+
+ handled = 1;
+ saa_writel(SAA7134_IRQ_REPORT,report);
+ if (irq_debug)
+ print_irqstatus(dev,loop,report,status);
+
+
+ if ((report & SAA7134_IRQ_REPORT_RDCAP) ||
+ (report & SAA7134_IRQ_REPORT_INTL))
+ saa7134_irq_video_signalchange(dev);
+
+
+ if ((report & SAA7134_IRQ_REPORT_DONE_RA0) &&
+ (status & 0x60) == 0)
+ saa7134_irq_video_done(dev,status);
+
+ if ((report & SAA7134_IRQ_REPORT_DONE_RA0) &&
+ (status & 0x40) == 0x40)
+ saa7134_irq_vbi_done(dev,status);
+
+ if ((report & SAA7134_IRQ_REPORT_DONE_RA2) &&
+ card_has_mpeg(dev)) {
+ if (dev->mops->irq_ts_done != NULL)
+ dev->mops->irq_ts_done(dev, status);
+ else
+ saa7134_irq_ts_done(dev, status);
+ }
+
+ if (report & SAA7134_IRQ_REPORT_GPIO16) {
+ switch (dev->has_remote) {
+ case SAA7134_REMOTE_GPIO:
+ if (!dev->remote)
+ break;
+ if (dev->remote->mask_keydown & 0x10000) {
+ saa7134_input_irq(dev);
+ }
+ break;
+
+ case SAA7134_REMOTE_I2C:
+ break; /* FIXME: invoke I2C get_key() */
+
+ default: /* GPIO16 not used by IR remote */
+ break;
+ }
+ }
+
+ if (report & SAA7134_IRQ_REPORT_GPIO18) {
+ switch (dev->has_remote) {
+ case SAA7134_REMOTE_GPIO:
+ if (!dev->remote)
+ break;
+ if ((dev->remote->mask_keydown & 0x40000) ||
+ (dev->remote->mask_keyup & 0x40000)) {
+ saa7134_input_irq(dev);
+ }
+ break;
+
+ case SAA7134_REMOTE_I2C:
+ break; /* FIXME: invoke I2C get_key() */
+
+ default: /* GPIO18 not used by IR remote */
+ break;
+ }
+ }
+ }
+
+ if (10 == loop) {
+ print_irqstatus(dev,loop,report,status);
+ if (report & SAA7134_IRQ_REPORT_PE) {
+ /* disable all parity error */
+ pr_warn("%s/irq: looping -- clearing PE (parity error!) enable bit\n",
+ dev->name);
+ saa_clearl(SAA7134_IRQ2,SAA7134_IRQ2_INTE_PE);
+ } else if (report & SAA7134_IRQ_REPORT_GPIO16) {
+ /* disable gpio16 IRQ */
+ pr_warn("%s/irq: looping -- clearing GPIO16 enable bit\n",
+ dev->name);
+ saa_clearl(SAA7134_IRQ2, SAA7134_IRQ2_INTE_GPIO16_P);
+ saa_clearl(SAA7134_IRQ2, SAA7134_IRQ2_INTE_GPIO16_N);
+ } else if (report & SAA7134_IRQ_REPORT_GPIO18) {
+ /* disable gpio18 IRQs */
+ pr_warn("%s/irq: looping -- clearing GPIO18 enable bit\n",
+ dev->name);
+ saa_clearl(SAA7134_IRQ2, SAA7134_IRQ2_INTE_GPIO18_P);
+ saa_clearl(SAA7134_IRQ2, SAA7134_IRQ2_INTE_GPIO18_N);
+ } else {
+ /* disable all irqs */
+ pr_warn("%s/irq: looping -- clearing all enable bits\n",
+ dev->name);
+ saa_writel(SAA7134_IRQ1,0);
+ saa_writel(SAA7134_IRQ2,0);
+ }
+ }
+
+ out:
+ return IRQ_RETVAL(handled);
+}
+
+/* ------------------------------------------------------------------ */
+
+/* early init (no i2c, no irq) */
+
+static int saa7134_hw_enable1(struct saa7134_dev *dev)
+{
+ /* RAM FIFO config */
+ saa_writel(SAA7134_FIFO_SIZE, 0x08070503);
+ saa_writel(SAA7134_THRESHOULD, 0x02020202);
+
+ /* enable audio + video processing */
+ saa_writel(SAA7134_MAIN_CTRL,
+ SAA7134_MAIN_CTRL_VPLLE |
+ SAA7134_MAIN_CTRL_APLLE |
+ SAA7134_MAIN_CTRL_EXOSC |
+ SAA7134_MAIN_CTRL_EVFE1 |
+ SAA7134_MAIN_CTRL_EVFE2 |
+ SAA7134_MAIN_CTRL_ESFE |
+ SAA7134_MAIN_CTRL_EBDAC);
+
+ /*
+ * Initialize OSS _after_ enabling audio clock PLL and audio processing.
+ * OSS initialization writes to registers via the audio DSP; these
+ * writes will fail unless the audio clock has been started. At worst,
+ * audio will not work.
+ */
+
+ /* enable peripheral devices */
+ saa_writeb(SAA7134_SPECIAL_MODE, 0x01);
+
+ /* set vertical line numbering start (vbi needs this) */
+ saa_writeb(SAA7134_SOURCE_TIMING2, 0x20);
+
+ return 0;
+}
+
+static int saa7134_hwinit1(struct saa7134_dev *dev)
+{
+ core_dbg("hwinit1\n");
+
+ saa_writel(SAA7134_IRQ1, 0);
+ saa_writel(SAA7134_IRQ2, 0);
+
+ /* Clear any stale IRQ reports */
+ saa_writel(SAA7134_IRQ_REPORT, saa_readl(SAA7134_IRQ_REPORT));
+
+ mutex_init(&dev->lock);
+ spin_lock_init(&dev->slock);
+
+ saa7134_track_gpio(dev,"pre-init");
+ saa7134_video_init1(dev);
+ saa7134_vbi_init1(dev);
+ if (card_has_mpeg(dev))
+ saa7134_ts_init1(dev);
+ saa7134_input_init1(dev);
+
+ saa7134_hw_enable1(dev);
+
+ return 0;
+}
+
+/* late init (with i2c + irq) */
+static int saa7134_hw_enable2(struct saa7134_dev *dev)
+{
+
+ unsigned int irq2_mask;
+
+ /* enable IRQ's */
+ irq2_mask =
+ SAA7134_IRQ2_INTE_DEC3 |
+ SAA7134_IRQ2_INTE_DEC2 |
+ SAA7134_IRQ2_INTE_DEC1 |
+ SAA7134_IRQ2_INTE_DEC0 |
+ SAA7134_IRQ2_INTE_PE |
+ SAA7134_IRQ2_INTE_AR;
+
+ if (dev->has_remote == SAA7134_REMOTE_GPIO && dev->remote) {
+ if (dev->remote->mask_keydown & 0x10000)
+ irq2_mask |= SAA7134_IRQ2_INTE_GPIO16_N;
+ else { /* Allow enabling both IRQ edge triggers */
+ if (dev->remote->mask_keydown & 0x40000)
+ irq2_mask |= SAA7134_IRQ2_INTE_GPIO18_P;
+ if (dev->remote->mask_keyup & 0x40000)
+ irq2_mask |= SAA7134_IRQ2_INTE_GPIO18_N;
+ }
+ }
+
+ if (dev->has_remote == SAA7134_REMOTE_I2C) {
+ request_module("ir-kbd-i2c");
+ }
+
+ saa_writel(SAA7134_IRQ1, 0);
+ saa_writel(SAA7134_IRQ2, irq2_mask);
+
+ return 0;
+}
+
+static int saa7134_hwinit2(struct saa7134_dev *dev)
+{
+
+ core_dbg("hwinit2\n");
+
+ saa7134_video_init2(dev);
+ saa7134_tvaudio_init2(dev);
+
+ saa7134_hw_enable2(dev);
+
+ return 0;
+}
+
+
+/* shutdown */
+static int saa7134_hwfini(struct saa7134_dev *dev)
+{
+ core_dbg("hwfini\n");
+
+ if (card_has_mpeg(dev))
+ saa7134_ts_fini(dev);
+ saa7134_input_fini(dev);
+ saa7134_vbi_fini(dev);
+ saa7134_tvaudio_fini(dev);
+ saa7134_video_fini(dev);
+ return 0;
+}
+
+static void must_configure_manually(int has_eeprom)
+{
+ unsigned int i,p;
+
+ if (!has_eeprom)
+ pr_warn("saa7134: <rant>\n"
+ "saa7134: Congratulations! Your TV card vendor saved a few\n"
+ "saa7134: cents for a eeprom, thus your pci board has no\n"
+ "saa7134: subsystem ID and I can't identify it automatically\n"
+ "saa7134: </rant>\n"
+ "saa7134: I feel better now. Ok, here are the good news:\n"
+ "saa7134: You can use the card=<nr> insmod option to specify\n"
+ "saa7134: which board do you have. The list:\n");
+ else
+ pr_warn("saa7134: Board is currently unknown. You might try to use the card=<nr>\n"
+ "saa7134: insmod option to specify which board do you have, but this is\n"
+ "saa7134: somewhat risky, as might damage your card. It is better to ask\n"
+ "saa7134: for support at linux-media@vger.kernel.org.\n"
+ "saa7134: The supported cards are:\n");
+
+ for (i = 0; i < saa7134_bcount; i++) {
+ pr_warn("saa7134: card=%d -> %-40.40s",
+ i,saa7134_boards[i].name);
+ for (p = 0; saa7134_pci_tbl[p].driver_data; p++) {
+ if (saa7134_pci_tbl[p].driver_data != i)
+ continue;
+ pr_cont(" %04x:%04x",
+ saa7134_pci_tbl[p].subvendor,
+ saa7134_pci_tbl[p].subdevice);
+ }
+ pr_cont("\n");
+ }
+}
+
+static void saa7134_unregister_media_device(struct saa7134_dev *dev)
+{
+
+#ifdef CONFIG_MEDIA_CONTROLLER
+ if (!dev->media_dev)
+ return;
+ media_device_unregister(dev->media_dev);
+ media_device_cleanup(dev->media_dev);
+ kfree(dev->media_dev);
+ dev->media_dev = NULL;
+#endif
+}
+
+static void saa7134_media_release(struct saa7134_dev *dev)
+{
+#ifdef CONFIG_MEDIA_CONTROLLER
+ int i;
+
+ for (i = 0; i < SAA7134_INPUT_MAX + 1; i++)
+ media_device_unregister_entity(&dev->input_ent[i]);
+#endif
+}
+
+#if defined(CONFIG_MEDIA_CONTROLLER)
+static void saa7134_create_entities(struct saa7134_dev *dev)
+{
+ int ret, i;
+ struct media_entity *entity;
+ struct media_entity *decoder = NULL;
+
+ /* Check if it is using an external analog TV demod */
+ media_device_for_each_entity(entity, dev->media_dev) {
+ if (entity->function == MEDIA_ENT_F_ATV_DECODER) {
+ decoder = entity;
+ break;
+ }
+ }
+
+ /*
+ * saa713x is not using an external ATV demod.
+ * Register the internal one
+ */
+ if (!decoder) {
+ dev->demod.name = "saa713x";
+ dev->demod_pad[SAA7134_PAD_IF_INPUT].flags = MEDIA_PAD_FL_SINK;
+ dev->demod_pad[SAA7134_PAD_IF_INPUT].sig_type = PAD_SIGNAL_ANALOG;
+ dev->demod_pad[SAA7134_PAD_VID_OUT].flags = MEDIA_PAD_FL_SOURCE;
+ dev->demod_pad[SAA7134_PAD_VID_OUT].sig_type = PAD_SIGNAL_DV;
+ dev->demod.function = MEDIA_ENT_F_ATV_DECODER;
+
+ ret = media_entity_pads_init(&dev->demod, SAA7134_NUM_PADS,
+ dev->demod_pad);
+ if (ret < 0)
+ pr_err("failed to initialize demod pad!\n");
+
+ ret = media_device_register_entity(dev->media_dev, &dev->demod);
+ if (ret < 0)
+ pr_err("failed to register demod entity!\n");
+
+ dev->decoder = &dev->demod;
+ } else {
+ dev->decoder = decoder;
+ }
+
+ /* Initialize Video, VBI and Radio pads */
+ dev->video_pad.flags = MEDIA_PAD_FL_SINK;
+ ret = media_entity_pads_init(&dev->video_dev->entity, 1,
+ &dev->video_pad);
+ if (ret < 0)
+ pr_err("failed to initialize video media entity!\n");
+
+ dev->vbi_pad.flags = MEDIA_PAD_FL_SINK;
+ ret = media_entity_pads_init(&dev->vbi_dev->entity, 1,
+ &dev->vbi_pad);
+ if (ret < 0)
+ pr_err("failed to initialize vbi media entity!\n");
+
+ /* Create entities for each input connector */
+ for (i = 0; i < SAA7134_INPUT_MAX; i++) {
+ struct media_entity *ent = &dev->input_ent[i];
+ struct saa7134_input *in = &card_in(dev, i);
+
+ if (in->type == SAA7134_NO_INPUT)
+ break;
+
+ /* This input uses the S-Video connector */
+ if (in->type == SAA7134_INPUT_COMPOSITE_OVER_SVIDEO)
+ continue;
+
+ ent->name = saa7134_input_name[in->type];
+ ent->flags = MEDIA_ENT_FL_CONNECTOR;
+ dev->input_pad[i].flags = MEDIA_PAD_FL_SOURCE;
+
+ switch (in->type) {
+ case SAA7134_INPUT_COMPOSITE:
+ case SAA7134_INPUT_COMPOSITE0:
+ case SAA7134_INPUT_COMPOSITE1:
+ case SAA7134_INPUT_COMPOSITE2:
+ case SAA7134_INPUT_COMPOSITE3:
+ case SAA7134_INPUT_COMPOSITE4:
+ ent->function = MEDIA_ENT_F_CONN_COMPOSITE;
+ break;
+ case SAA7134_INPUT_SVIDEO:
+ case SAA7134_INPUT_SVIDEO0:
+ case SAA7134_INPUT_SVIDEO1:
+ ent->function = MEDIA_ENT_F_CONN_SVIDEO;
+ break;
+ default:
+ /*
+ * SAA7134_INPUT_TV and SAA7134_INPUT_TV_MONO.
+ *
+ * Please notice that neither SAA7134_INPUT_MUTE or
+ * SAA7134_INPUT_RADIO are defined at
+ * saa7134_board.input.
+ */
+ ent->function = MEDIA_ENT_F_CONN_RF;
+ break;
+ }
+
+ ret = media_entity_pads_init(ent, 1, &dev->input_pad[i]);
+ if (ret < 0)
+ pr_err("failed to initialize input pad[%d]!\n", i);
+
+ ret = media_device_register_entity(dev->media_dev, ent);
+ if (ret < 0)
+ pr_err("failed to register input entity %d!\n", i);
+ }
+
+ /* Create input for Radio RF connector */
+ if (card_has_radio(dev)) {
+ struct saa7134_input *in = &saa7134_boards[dev->board].radio;
+ struct media_entity *ent = &dev->input_ent[i];
+
+ ent->name = saa7134_input_name[in->type];
+ ent->flags = MEDIA_ENT_FL_CONNECTOR;
+ dev->input_pad[i].flags = MEDIA_PAD_FL_SOURCE;
+ ent->function = MEDIA_ENT_F_CONN_RF;
+
+ ret = media_entity_pads_init(ent, 1, &dev->input_pad[i]);
+ if (ret < 0)
+ pr_err("failed to initialize input pad[%d]!\n", i);
+
+ ret = media_device_register_entity(dev->media_dev, ent);
+ if (ret < 0)
+ pr_err("failed to register input entity %d!\n", i);
+ }
+}
+#endif
+
+static struct video_device *vdev_init(struct saa7134_dev *dev,
+ struct video_device *template,
+ char *type)
+{
+ struct video_device *vfd;
+
+ vfd = video_device_alloc();
+ if (NULL == vfd)
+ return NULL;
+ *vfd = *template;
+ vfd->v4l2_dev = &dev->v4l2_dev;
+ vfd->release = video_device_release;
+ snprintf(vfd->name, sizeof(vfd->name), "%s %s (%s)",
+ dev->name, type, saa7134_boards[dev->board].name);
+ video_set_drvdata(vfd, dev);
+ return vfd;
+}
+
+static void saa7134_unregister_video(struct saa7134_dev *dev)
+{
+ saa7134_media_release(dev);
+
+ if (dev->video_dev) {
+ if (video_is_registered(dev->video_dev))
+ vb2_video_unregister_device(dev->video_dev);
+ else
+ video_device_release(dev->video_dev);
+ dev->video_dev = NULL;
+ }
+ if (dev->vbi_dev) {
+ if (video_is_registered(dev->vbi_dev))
+ vb2_video_unregister_device(dev->vbi_dev);
+ else
+ video_device_release(dev->vbi_dev);
+ dev->vbi_dev = NULL;
+ }
+ if (dev->radio_dev) {
+ if (video_is_registered(dev->radio_dev))
+ video_unregister_device(dev->radio_dev);
+ else
+ video_device_release(dev->radio_dev);
+ dev->radio_dev = NULL;
+ }
+}
+
+static void mpeg_ops_attach(struct saa7134_mpeg_ops *ops,
+ struct saa7134_dev *dev)
+{
+ int err;
+
+ if (NULL != dev->mops)
+ return;
+ if (saa7134_boards[dev->board].mpeg != ops->type)
+ return;
+ err = ops->init(dev);
+ if (0 != err)
+ return;
+ dev->mops = ops;
+}
+
+static void mpeg_ops_detach(struct saa7134_mpeg_ops *ops,
+ struct saa7134_dev *dev)
+{
+ if (NULL == dev->mops)
+ return;
+ if (dev->mops != ops)
+ return;
+ dev->mops->fini(dev);
+ dev->mops = NULL;
+}
+
+static int saa7134_initdev(struct pci_dev *pci_dev,
+ const struct pci_device_id *pci_id)
+{
+ struct saa7134_dev *dev;
+ struct saa7134_mpeg_ops *mops;
+ int err;
+
+ if (saa7134_devcount == SAA7134_MAXBOARDS)
+ return -ENOMEM;
+
+ dev = kzalloc(sizeof(*dev),GFP_KERNEL);
+ if (NULL == dev)
+ return -ENOMEM;
+
+ dev->nr = saa7134_devcount;
+ sprintf(dev->name, "saa%x[%d]", pci_dev->device, dev->nr);
+
+#ifdef CONFIG_MEDIA_CONTROLLER
+ dev->media_dev = kzalloc(sizeof(*dev->media_dev), GFP_KERNEL);
+ if (!dev->media_dev) {
+ err = -ENOMEM;
+ goto err_free_dev;
+ }
+ media_device_pci_init(dev->media_dev, pci_dev, dev->name);
+ dev->v4l2_dev.mdev = dev->media_dev;
+#endif
+
+ err = v4l2_device_register(&pci_dev->dev, &dev->v4l2_dev);
+ if (err)
+ goto err_free_dev;
+
+ /* pci init */
+ dev->pci = pci_dev;
+ if (pci_enable_device(pci_dev)) {
+ err = -EIO;
+ goto err_v4l2_unregister;
+ }
+
+ /* pci quirks */
+ if (pci_pci_problems) {
+ if (pci_pci_problems & PCIPCI_TRITON)
+ pr_info("%s: quirk: PCIPCI_TRITON\n", dev->name);
+ if (pci_pci_problems & PCIPCI_NATOMA)
+ pr_info("%s: quirk: PCIPCI_NATOMA\n", dev->name);
+ if (pci_pci_problems & PCIPCI_VIAETBF)
+ pr_info("%s: quirk: PCIPCI_VIAETBF\n", dev->name);
+ if (pci_pci_problems & PCIPCI_VSFX)
+ pr_info("%s: quirk: PCIPCI_VSFX\n", dev->name);
+#ifdef PCIPCI_ALIMAGIK
+ if (pci_pci_problems & PCIPCI_ALIMAGIK) {
+ pr_info("%s: quirk: PCIPCI_ALIMAGIK -- latency fixup\n",
+ dev->name);
+ latency = 0x0A;
+ }
+#endif
+ }
+ if (UNSET != latency) {
+ pr_info("%s: setting pci latency timer to %d\n",
+ dev->name,latency);
+ pci_write_config_byte(pci_dev, PCI_LATENCY_TIMER, latency);
+ }
+
+ /* print pci info */
+ dev->pci_rev = pci_dev->revision;
+ pci_read_config_byte(pci_dev, PCI_LATENCY_TIMER, &dev->pci_lat);
+ pr_info("%s: found at %s, rev: %d, irq: %d, latency: %d, mmio: 0x%llx\n",
+ dev->name, pci_name(pci_dev), dev->pci_rev, pci_dev->irq,
+ dev->pci_lat,
+ (unsigned long long)pci_resource_start(pci_dev, 0));
+ pci_set_master(pci_dev);
+ err = dma_set_mask(&pci_dev->dev, DMA_BIT_MASK(32));
+ if (err) {
+ pr_warn("%s: Oops: no 32bit PCI DMA ???\n", dev->name);
+ goto err_v4l2_unregister;
+ }
+
+ /* board config */
+ dev->board = pci_id->driver_data;
+ if ((unsigned)card[dev->nr] < saa7134_bcount)
+ dev->board = card[dev->nr];
+ if (SAA7134_BOARD_UNKNOWN == dev->board)
+ must_configure_manually(0);
+ else if (SAA7134_BOARD_NOAUTO == dev->board) {
+ must_configure_manually(1);
+ dev->board = SAA7134_BOARD_UNKNOWN;
+ }
+ dev->autodetected = card[dev->nr] != dev->board;
+ dev->tuner_type = saa7134_boards[dev->board].tuner_type;
+ dev->tuner_addr = saa7134_boards[dev->board].tuner_addr;
+ dev->radio_type = saa7134_boards[dev->board].radio_type;
+ dev->radio_addr = saa7134_boards[dev->board].radio_addr;
+ dev->tda9887_conf = saa7134_boards[dev->board].tda9887_conf;
+ if (UNSET != tuner[dev->nr])
+ dev->tuner_type = tuner[dev->nr];
+ pr_info("%s: subsystem: %04x:%04x, board: %s [card=%d,%s]\n",
+ dev->name,pci_dev->subsystem_vendor,
+ pci_dev->subsystem_device,saa7134_boards[dev->board].name,
+ dev->board, dev->autodetected ?
+ "autodetected" : "insmod option");
+
+ /* get mmio */
+ if (!request_mem_region(pci_resource_start(pci_dev,0),
+ pci_resource_len(pci_dev,0),
+ dev->name)) {
+ err = -EBUSY;
+ pr_err("%s: can't get MMIO memory @ 0x%llx\n",
+ dev->name,(unsigned long long)pci_resource_start(pci_dev,0));
+ goto err_v4l2_unregister;
+ }
+ dev->lmmio = ioremap(pci_resource_start(pci_dev, 0),
+ pci_resource_len(pci_dev, 0));
+ dev->bmmio = (__u8 __iomem *)dev->lmmio;
+ if (NULL == dev->lmmio) {
+ err = -EIO;
+ pr_err("%s: can't ioremap() MMIO memory\n",
+ dev->name);
+ goto err_release_mem_reg;
+ }
+
+ /* initialize hardware #1 */
+ saa7134_board_init1(dev);
+ saa7134_hwinit1(dev);
+
+ /* get irq */
+ err = request_irq(pci_dev->irq, saa7134_irq,
+ IRQF_SHARED, dev->name, dev);
+ if (err < 0) {
+ pr_err("%s: can't get IRQ %d\n",
+ dev->name,pci_dev->irq);
+ goto err_iounmap;
+ }
+
+ /* wait a bit, register i2c bus */
+ msleep(100);
+ saa7134_i2c_register(dev);
+ saa7134_board_init2(dev);
+
+ saa7134_hwinit2(dev);
+
+ /* load i2c helpers */
+ if (card_is_empress(dev)) {
+ dev->empress_sd =
+ v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap,
+ "saa6752hs",
+ saa7134_boards[dev->board].empress_addr, NULL);
+
+ if (dev->empress_sd)
+ dev->empress_sd->grp_id = GRP_EMPRESS;
+ }
+
+ if (saa7134_boards[dev->board].rds_addr) {
+ struct v4l2_subdev *sd;
+
+ sd = v4l2_i2c_new_subdev(&dev->v4l2_dev,
+ &dev->i2c_adap, "saa6588",
+ 0, I2C_ADDRS(saa7134_boards[dev->board].rds_addr));
+ if (sd) {
+ pr_info("%s: found RDS decoder\n", dev->name);
+ dev->has_rds = 1;
+ }
+ }
+
+ mutex_lock(&saa7134_devlist_lock);
+ list_for_each_entry(mops, &mops_list, next)
+ mpeg_ops_attach(mops, dev);
+ list_add_tail(&dev->devlist, &saa7134_devlist);
+ mutex_unlock(&saa7134_devlist_lock);
+
+ /* check for signal */
+ saa7134_irq_video_signalchange(dev);
+
+ if (TUNER_ABSENT != dev->tuner_type)
+ saa_call_all(dev, core, s_power, 0);
+
+ /* register v4l devices */
+ dev->video_dev = vdev_init(dev,&saa7134_video_template,"video");
+ dev->video_dev->ctrl_handler = &dev->ctrl_handler;
+ dev->video_dev->lock = &dev->lock;
+ dev->video_dev->queue = &dev->video_vbq;
+ dev->video_dev->device_caps = V4L2_CAP_READWRITE | V4L2_CAP_STREAMING |
+ V4L2_CAP_VIDEO_CAPTURE;
+ if (dev->tuner_type != TUNER_ABSENT && dev->tuner_type != UNSET)
+ dev->video_dev->device_caps |= V4L2_CAP_TUNER;
+
+ err = video_register_device(dev->video_dev,VFL_TYPE_VIDEO,
+ video_nr[dev->nr]);
+ if (err < 0) {
+ pr_info("%s: can't register video device\n",
+ dev->name);
+ goto err_unregister_video;
+ }
+ pr_info("%s: registered device %s [v4l2]\n",
+ dev->name, video_device_node_name(dev->video_dev));
+
+ dev->vbi_dev = vdev_init(dev, &saa7134_video_template, "vbi");
+ dev->vbi_dev->ctrl_handler = &dev->ctrl_handler;
+ dev->vbi_dev->lock = &dev->lock;
+ dev->vbi_dev->queue = &dev->vbi_vbq;
+ dev->vbi_dev->device_caps = V4L2_CAP_READWRITE | V4L2_CAP_STREAMING |
+ V4L2_CAP_VBI_CAPTURE;
+ if (dev->tuner_type != TUNER_ABSENT && dev->tuner_type != UNSET)
+ dev->vbi_dev->device_caps |= V4L2_CAP_TUNER;
+
+ err = video_register_device(dev->vbi_dev,VFL_TYPE_VBI,
+ vbi_nr[dev->nr]);
+ if (err < 0)
+ goto err_unregister_video;
+ pr_info("%s: registered device %s\n",
+ dev->name, video_device_node_name(dev->vbi_dev));
+
+ if (card_has_radio(dev)) {
+ dev->radio_dev = vdev_init(dev,&saa7134_radio_template,"radio");
+ dev->radio_dev->ctrl_handler = &dev->radio_ctrl_handler;
+ dev->radio_dev->lock = &dev->lock;
+ dev->radio_dev->device_caps = V4L2_CAP_RADIO | V4L2_CAP_TUNER;
+ if (dev->has_rds)
+ dev->radio_dev->device_caps |= V4L2_CAP_RDS_CAPTURE;
+ err = video_register_device(dev->radio_dev,VFL_TYPE_RADIO,
+ radio_nr[dev->nr]);
+ if (err < 0)
+ goto err_unregister_video;
+ pr_info("%s: registered device %s\n",
+ dev->name, video_device_node_name(dev->radio_dev));
+ }
+
+#ifdef CONFIG_MEDIA_CONTROLLER
+ saa7134_create_entities(dev);
+
+ err = v4l2_mc_create_media_graph(dev->media_dev);
+ if (err) {
+ pr_err("failed to create media graph\n");
+ goto err_unregister_video;
+ }
+#endif
+ /* everything worked */
+ saa7134_devcount++;
+
+ if (saa7134_dmasound_init && !dev->dmasound.priv_data)
+ saa7134_dmasound_init(dev);
+
+ request_submodules(dev);
+
+ /*
+ * Do it at the end, to reduce dynamic configuration changes during
+ * the device init. Yet, as request_modules() can be async, the
+ * topology will likely change after load the saa7134 subdrivers.
+ */
+#ifdef CONFIG_MEDIA_CONTROLLER
+ err = media_device_register(dev->media_dev);
+ if (err) {
+ media_device_cleanup(dev->media_dev);
+ goto err_unregister_video;
+ }
+#endif
+
+ return 0;
+
+err_unregister_video:
+ saa7134_unregister_video(dev);
+ list_del(&dev->devlist);
+ saa7134_i2c_unregister(dev);
+ free_irq(pci_dev->irq, dev);
+err_iounmap:
+ saa7134_hwfini(dev);
+ iounmap(dev->lmmio);
+err_release_mem_reg:
+ release_mem_region(pci_resource_start(pci_dev,0),
+ pci_resource_len(pci_dev,0));
+err_v4l2_unregister:
+ v4l2_device_unregister(&dev->v4l2_dev);
+err_free_dev:
+#ifdef CONFIG_MEDIA_CONTROLLER
+ kfree(dev->media_dev);
+#endif
+ kfree(dev);
+ return err;
+}
+
+static void saa7134_finidev(struct pci_dev *pci_dev)
+{
+ struct v4l2_device *v4l2_dev = pci_get_drvdata(pci_dev);
+ struct saa7134_dev *dev = container_of(v4l2_dev, struct saa7134_dev, v4l2_dev);
+ struct saa7134_mpeg_ops *mops;
+
+ flush_request_submodules(dev);
+
+ /* Release DMA sound modules if present */
+ if (saa7134_dmasound_exit && dev->dmasound.priv_data) {
+ saa7134_dmasound_exit(dev);
+ }
+
+ /* debugging ... */
+ if (irq_debug) {
+ u32 report = saa_readl(SAA7134_IRQ_REPORT);
+ u32 status = saa_readl(SAA7134_IRQ_STATUS);
+ print_irqstatus(dev,42,report,status);
+ }
+
+ /* disable peripheral devices */
+ saa_writeb(SAA7134_SPECIAL_MODE,0);
+
+ /* shutdown hardware */
+ saa_writel(SAA7134_IRQ1,0);
+ saa_writel(SAA7134_IRQ2,0);
+ saa_writel(SAA7134_MAIN_CTRL,0);
+
+ /* shutdown subsystems */
+ saa7134_hwfini(dev);
+
+ /* unregister */
+ mutex_lock(&saa7134_devlist_lock);
+ list_del(&dev->devlist);
+ list_for_each_entry(mops, &mops_list, next)
+ mpeg_ops_detach(mops, dev);
+ mutex_unlock(&saa7134_devlist_lock);
+ saa7134_devcount--;
+
+ saa7134_i2c_unregister(dev);
+ saa7134_unregister_video(dev);
+
+
+ /* the DMA sound modules should be unloaded before reaching
+ this, but just in case they are still present... */
+ if (dev->dmasound.priv_data != NULL) {
+ free_irq(pci_dev->irq, &dev->dmasound);
+ dev->dmasound.priv_data = NULL;
+ }
+
+
+ /* release resources */
+ free_irq(pci_dev->irq, dev);
+ iounmap(dev->lmmio);
+ release_mem_region(pci_resource_start(pci_dev,0),
+ pci_resource_len(pci_dev,0));
+
+ v4l2_device_unregister(&dev->v4l2_dev);
+
+ saa7134_unregister_media_device(dev);
+
+ /* free memory */
+ kfree(dev);
+}
+
+/* resends a current buffer in queue after resume */
+static int __maybe_unused saa7134_buffer_requeue(struct saa7134_dev *dev,
+ struct saa7134_dmaqueue *q)
+{
+ struct saa7134_buf *buf, *next;
+
+ assert_spin_locked(&dev->slock);
+
+ buf = q->curr;
+ next = buf;
+ core_dbg("buffer_requeue\n");
+
+ if (!buf)
+ return 0;
+
+ core_dbg("buffer_requeue : resending active buffer\n");
+
+ if (!list_empty(&q->queue))
+ next = list_entry(q->queue.next, struct saa7134_buf,
+ entry);
+ buf->activate(dev, buf, next);
+
+ return 0;
+}
+
+static int __maybe_unused saa7134_suspend(struct device *dev_d)
+{
+ struct pci_dev *pci_dev = to_pci_dev(dev_d);
+ struct v4l2_device *v4l2_dev = pci_get_drvdata(pci_dev);
+ struct saa7134_dev *dev = container_of(v4l2_dev, struct saa7134_dev, v4l2_dev);
+
+ /* Disable interrupts, DMA, and rest of the chip*/
+ saa_writel(SAA7134_IRQ1, 0);
+ saa_writel(SAA7134_IRQ2, 0);
+ saa_writel(SAA7134_MAIN_CTRL, 0);
+
+ dev->insuspend = 1;
+ synchronize_irq(pci_dev->irq);
+
+ /* ACK interrupts once more, just in case,
+ since the IRQ handler won't ack them anymore*/
+
+ saa_writel(SAA7134_IRQ_REPORT, saa_readl(SAA7134_IRQ_REPORT));
+
+ /* Disable timeout timers - if we have active buffers, we will
+ fill them on resume*/
+
+ del_timer(&dev->video_q.timeout);
+ del_timer(&dev->vbi_q.timeout);
+ del_timer(&dev->ts_q.timeout);
+
+ if (dev->remote && dev->remote->dev->users)
+ saa7134_ir_close(dev->remote->dev);
+
+ return 0;
+}
+
+static int __maybe_unused saa7134_resume(struct device *dev_d)
+{
+ struct v4l2_device *v4l2_dev = dev_get_drvdata(dev_d);
+ struct saa7134_dev *dev = container_of(v4l2_dev, struct saa7134_dev, v4l2_dev);
+ unsigned long flags;
+
+ /* Do things that are done in saa7134_initdev ,
+ except of initializing memory structures.*/
+
+ saa7134_board_init1(dev);
+
+ /* saa7134_hwinit1 */
+ if (saa7134_boards[dev->board].video_out)
+ saa7134_videoport_init(dev);
+ if (card_has_mpeg(dev))
+ saa7134_ts_init_hw(dev);
+ if (dev->remote && dev->remote->dev->users)
+ saa7134_ir_open(dev->remote->dev);
+ saa7134_hw_enable1(dev);
+
+ msleep(100);
+
+ saa7134_board_init2(dev);
+
+ /*saa7134_hwinit2*/
+ saa7134_set_tvnorm_hw(dev);
+ saa7134_tvaudio_setmute(dev);
+ saa7134_tvaudio_setvolume(dev, dev->ctl_volume);
+ saa7134_tvaudio_init(dev);
+ saa7134_enable_i2s(dev);
+ saa7134_hw_enable2(dev);
+
+ saa7134_irq_video_signalchange(dev);
+
+ /*resume unfinished buffer(s)*/
+ spin_lock_irqsave(&dev->slock, flags);
+ saa7134_buffer_requeue(dev, &dev->video_q);
+ saa7134_buffer_requeue(dev, &dev->vbi_q);
+ saa7134_buffer_requeue(dev, &dev->ts_q);
+
+ /* FIXME: Disable DMA audio sound - temporary till proper support
+ is implemented*/
+
+ dev->dmasound.dma_running = 0;
+
+ /* start DMA now*/
+ dev->insuspend = 0;
+ smp_wmb();
+ saa7134_set_dmabits(dev);
+ spin_unlock_irqrestore(&dev->slock, flags);
+
+ return 0;
+}
+
+/* ----------------------------------------------------------- */
+
+int saa7134_ts_register(struct saa7134_mpeg_ops *ops)
+{
+ struct saa7134_dev *dev;
+
+ mutex_lock(&saa7134_devlist_lock);
+ list_for_each_entry(dev, &saa7134_devlist, devlist)
+ mpeg_ops_attach(ops, dev);
+ list_add_tail(&ops->next,&mops_list);
+ mutex_unlock(&saa7134_devlist_lock);
+ return 0;
+}
+
+void saa7134_ts_unregister(struct saa7134_mpeg_ops *ops)
+{
+ struct saa7134_dev *dev;
+
+ mutex_lock(&saa7134_devlist_lock);
+ list_del(&ops->next);
+ list_for_each_entry(dev, &saa7134_devlist, devlist)
+ mpeg_ops_detach(ops, dev);
+ mutex_unlock(&saa7134_devlist_lock);
+}
+
+EXPORT_SYMBOL(saa7134_ts_register);
+EXPORT_SYMBOL(saa7134_ts_unregister);
+
+/* ----------------------------------------------------------- */
+
+static SIMPLE_DEV_PM_OPS(saa7134_pm_ops, saa7134_suspend, saa7134_resume);
+
+static struct pci_driver saa7134_pci_driver = {
+ .name = "saa7134",
+ .id_table = saa7134_pci_tbl,
+ .probe = saa7134_initdev,
+ .remove = saa7134_finidev,
+ .driver.pm = &saa7134_pm_ops,
+};
+
+static int __init saa7134_init(void)
+{
+ pr_info("saa7130/34: v4l2 driver version %s loaded\n",
+ SAA7134_VERSION);
+ return pci_register_driver(&saa7134_pci_driver);
+}
+
+static void __exit saa7134_fini(void)
+{
+ pci_unregister_driver(&saa7134_pci_driver);
+}
+
+module_init(saa7134_init);
+module_exit(saa7134_fini);
+
+/* ----------------------------------------------------------- */
+
+EXPORT_SYMBOL(saa7134_set_gpio);
+EXPORT_SYMBOL(saa7134_boards);
+
+/* ----------------- for the DMA sound modules --------------- */
+
+EXPORT_SYMBOL(saa7134_dmasound_init);
+EXPORT_SYMBOL(saa7134_dmasound_exit);
+EXPORT_SYMBOL(saa7134_pgtable_free);
+EXPORT_SYMBOL(saa7134_pgtable_build);
+EXPORT_SYMBOL(saa7134_pgtable_alloc);
+EXPORT_SYMBOL(saa7134_set_dmabits);
diff --git a/drivers/media/pci/saa7134/saa7134-dvb.c b/drivers/media/pci/saa7134/saa7134-dvb.c
new file mode 100644
index 0000000000..9c6cfef033
--- /dev/null
+++ b/drivers/media/pci/saa7134/saa7134-dvb.c
@@ -0,0 +1,2004 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ *
+ * (c) 2004 Gerd Knorr <kraxel@bytesex.org> [SuSE Labs]
+ *
+ * Extended 3 / 2005 by Hartmut Hackmann to support various
+ * cards with the tda10046 DVB-T channel decoder
+ */
+
+#include "saa7134.h"
+#include "saa7134-reg.h"
+
+#include <linux/init.h>
+#include <linux/list.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/kthread.h>
+#include <linux/suspend.h>
+
+#include <media/v4l2-common.h>
+#include "dvb-pll.h"
+#include <media/dvb_frontend.h>
+
+#include "mt352.h"
+#include "mt352_priv.h" /* FIXME */
+#include "tda1004x.h"
+#include "nxt200x.h"
+#include "xc2028.h"
+#include "xc5000.h"
+
+#include "tda10086.h"
+#include "tda826x.h"
+#include "tda827x.h"
+#include "isl6421.h"
+#include "isl6405.h"
+#include "lnbp21.h"
+#include "tuner-simple.h"
+#include "tda10048.h"
+#include "tda18271.h"
+#include "lgdt3305.h"
+#include "tda8290.h"
+#include "mb86a20s.h"
+#include "lgs8gxx.h"
+
+#include "zl10353.h"
+#include "qt1010.h"
+
+#include "zl10036.h"
+#include "zl10039.h"
+#include "mt312.h"
+#include "s5h1411.h"
+
+MODULE_AUTHOR("Gerd Knorr <kraxel@bytesex.org> [SuSE Labs]");
+MODULE_LICENSE("GPL");
+
+static unsigned int antenna_pwr;
+
+module_param(antenna_pwr, int, 0444);
+MODULE_PARM_DESC(antenna_pwr,"enable antenna power (Pinnacle 300i)");
+
+static int use_frontend;
+module_param(use_frontend, int, 0644);
+MODULE_PARM_DESC(use_frontend,"for cards with multiple frontends (0: terrestrial, 1: satellite)");
+
+DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
+
+/* ------------------------------------------------------------------
+ * mt352 based DVB-T cards
+ */
+
+static int pinnacle_antenna_pwr(struct saa7134_dev *dev, int on)
+{
+ u32 ok;
+
+ if (!on) {
+ saa_setl(SAA7134_GPIO_GPMODE0 >> 2, (1 << 26));
+ saa_clearl(SAA7134_GPIO_GPSTATUS0 >> 2, (1 << 26));
+ return 0;
+ }
+
+ saa_setl(SAA7134_GPIO_GPMODE0 >> 2, (1 << 26));
+ saa_setl(SAA7134_GPIO_GPSTATUS0 >> 2, (1 << 26));
+ udelay(10);
+
+ saa_setl(SAA7134_GPIO_GPMODE0 >> 2, (1 << 28));
+ saa_clearl(SAA7134_GPIO_GPSTATUS0 >> 2, (1 << 28));
+ udelay(10);
+ saa_setl(SAA7134_GPIO_GPSTATUS0 >> 2, (1 << 28));
+ udelay(10);
+ ok = saa_readl(SAA7134_GPIO_GPSTATUS0) & (1 << 27);
+ pr_debug("%s %s\n", __func__, ok ? "on" : "off");
+
+ if (!ok)
+ saa_clearl(SAA7134_GPIO_GPSTATUS0 >> 2, (1 << 26));
+ return ok;
+}
+
+static int mt352_pinnacle_init(struct dvb_frontend* fe)
+{
+ static u8 clock_config [] = { CLOCK_CTL, 0x3d, 0x28 };
+ static u8 reset [] = { RESET, 0x80 };
+ static u8 adc_ctl_1_cfg [] = { ADC_CTL_1, 0x40 };
+ static u8 agc_cfg [] = { AGC_TARGET, 0x28, 0xa0 };
+ static u8 capt_range_cfg[] = { CAPT_RANGE, 0x31 };
+ static u8 fsm_ctl_cfg[] = { 0x7b, 0x04 };
+ static u8 gpp_ctl_cfg [] = { GPP_CTL, 0x0f };
+ static u8 scan_ctl_cfg [] = { SCAN_CTL, 0x0d };
+ static u8 irq_cfg [] = { INTERRUPT_EN_0, 0x00, 0x00, 0x00, 0x00 };
+
+ pr_debug("%s called\n", __func__);
+
+ mt352_write(fe, clock_config, sizeof(clock_config));
+ udelay(200);
+ mt352_write(fe, reset, sizeof(reset));
+ mt352_write(fe, adc_ctl_1_cfg, sizeof(adc_ctl_1_cfg));
+ mt352_write(fe, agc_cfg, sizeof(agc_cfg));
+ mt352_write(fe, capt_range_cfg, sizeof(capt_range_cfg));
+ mt352_write(fe, gpp_ctl_cfg, sizeof(gpp_ctl_cfg));
+
+ mt352_write(fe, fsm_ctl_cfg, sizeof(fsm_ctl_cfg));
+ mt352_write(fe, scan_ctl_cfg, sizeof(scan_ctl_cfg));
+ mt352_write(fe, irq_cfg, sizeof(irq_cfg));
+
+ return 0;
+}
+
+static int mt352_aver777_init(struct dvb_frontend* fe)
+{
+ static u8 clock_config [] = { CLOCK_CTL, 0x38, 0x2d };
+ static u8 reset [] = { RESET, 0x80 };
+ static u8 adc_ctl_1_cfg [] = { ADC_CTL_1, 0x40 };
+ static u8 agc_cfg [] = { AGC_TARGET, 0x28, 0xa0 };
+ static u8 capt_range_cfg[] = { CAPT_RANGE, 0x33 };
+
+ mt352_write(fe, clock_config, sizeof(clock_config));
+ udelay(200);
+ mt352_write(fe, reset, sizeof(reset));
+ mt352_write(fe, adc_ctl_1_cfg, sizeof(adc_ctl_1_cfg));
+ mt352_write(fe, agc_cfg, sizeof(agc_cfg));
+ mt352_write(fe, capt_range_cfg, sizeof(capt_range_cfg));
+
+ return 0;
+}
+
+static int mt352_avermedia_xc3028_init(struct dvb_frontend *fe)
+{
+ static u8 clock_config [] = { CLOCK_CTL, 0x38, 0x2d };
+ static u8 reset [] = { RESET, 0x80 };
+ static u8 adc_ctl_1_cfg [] = { ADC_CTL_1, 0x40 };
+ static u8 agc_cfg [] = { AGC_TARGET, 0xe };
+ static u8 capt_range_cfg[] = { CAPT_RANGE, 0x33 };
+
+ mt352_write(fe, clock_config, sizeof(clock_config));
+ udelay(200);
+ mt352_write(fe, reset, sizeof(reset));
+ mt352_write(fe, adc_ctl_1_cfg, sizeof(adc_ctl_1_cfg));
+ mt352_write(fe, agc_cfg, sizeof(agc_cfg));
+ mt352_write(fe, capt_range_cfg, sizeof(capt_range_cfg));
+ return 0;
+}
+
+static int mt352_pinnacle_tuner_set_params(struct dvb_frontend *fe)
+{
+ struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+ u8 off[] = { 0x00, 0xf1};
+ u8 on[] = { 0x00, 0x71};
+ struct i2c_msg msg = {.addr=0x43, .flags=0, .buf=off, .len = sizeof(off)};
+
+ struct saa7134_dev *dev = fe->dvb->priv;
+ struct v4l2_frequency f;
+
+ /* set frequency (mt2050) */
+ f.tuner = 0;
+ f.type = V4L2_TUNER_DIGITAL_TV;
+ f.frequency = c->frequency / 1000 * 16 / 1000;
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
+ i2c_transfer(&dev->i2c_adap, &msg, 1);
+ saa_call_all(dev, tuner, s_frequency, &f);
+ msg.buf = on;
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
+ i2c_transfer(&dev->i2c_adap, &msg, 1);
+
+ pinnacle_antenna_pwr(dev, antenna_pwr);
+
+ /* mt352 setup */
+ return mt352_pinnacle_init(fe);
+}
+
+static struct mt352_config pinnacle_300i = {
+ .demod_address = 0x3c >> 1,
+ .adc_clock = 20333,
+ .if2 = 36150,
+ .no_tuner = 1,
+ .demod_init = mt352_pinnacle_init,
+};
+
+static struct mt352_config avermedia_777 = {
+ .demod_address = 0xf,
+ .demod_init = mt352_aver777_init,
+};
+
+static struct mt352_config avermedia_xc3028_mt352_dev = {
+ .demod_address = (0x1e >> 1),
+ .no_tuner = 1,
+ .demod_init = mt352_avermedia_xc3028_init,
+};
+
+static struct tda18271_std_map mb86a20s_tda18271_std_map = {
+ .dvbt_6 = { .if_freq = 3300, .agc_mode = 3, .std = 4,
+ .if_lvl = 7, .rfagc_top = 0x37, },
+};
+
+static struct tda18271_config kworld_tda18271_config = {
+ .std_map = &mb86a20s_tda18271_std_map,
+ .gate = TDA18271_GATE_DIGITAL,
+ .config = 3, /* Use tuner callback for AGC */
+
+};
+
+static const struct mb86a20s_config kworld_mb86a20s_config = {
+ .demod_address = 0x10,
+};
+
+static int kworld_sbtvd_gate_ctrl(struct dvb_frontend* fe, int enable)
+{
+ struct saa7134_dev *dev = fe->dvb->priv;
+
+ unsigned char initmsg[] = {0x45, 0x97};
+ unsigned char msg_enable[] = {0x45, 0xc1};
+ unsigned char msg_disable[] = {0x45, 0x81};
+ struct i2c_msg msg = {.addr = 0x4b, .flags = 0, .buf = initmsg, .len = 2};
+
+ if (i2c_transfer(&dev->i2c_adap, &msg, 1) != 1) {
+ pr_warn("could not access the I2C gate\n");
+ return -EIO;
+ }
+ if (enable)
+ msg.buf = msg_enable;
+ else
+ msg.buf = msg_disable;
+ if (i2c_transfer(&dev->i2c_adap, &msg, 1) != 1) {
+ pr_warn("could not access the I2C gate\n");
+ return -EIO;
+ }
+ msleep(20);
+ return 0;
+}
+
+/* ==================================================================
+ * tda1004x based DVB-T cards, helper functions
+ */
+
+static int philips_tda1004x_request_firmware(struct dvb_frontend *fe,
+ const struct firmware **fw, char *name)
+{
+ struct saa7134_dev *dev = fe->dvb->priv;
+ return request_firmware(fw, name, &dev->pci->dev);
+}
+
+/* ------------------------------------------------------------------
+ * these tuners are tu1216, td1316(a)
+ */
+
+static int philips_tda6651_pll_set(struct dvb_frontend *fe)
+{
+ struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+ struct saa7134_dev *dev = fe->dvb->priv;
+ struct tda1004x_state *state = fe->demodulator_priv;
+ u8 addr = state->config->tuner_address;
+ u8 tuner_buf[4];
+ struct i2c_msg tuner_msg = {.addr = addr,.flags = 0,.buf = tuner_buf,.len =
+ sizeof(tuner_buf) };
+ int tuner_frequency = 0;
+ u8 band, cp, filter;
+
+ /* determine charge pump */
+ tuner_frequency = c->frequency + 36166000;
+ if (tuner_frequency < 87000000)
+ return -EINVAL;
+ else if (tuner_frequency < 130000000)
+ cp = 3;
+ else if (tuner_frequency < 160000000)
+ cp = 5;
+ else if (tuner_frequency < 200000000)
+ cp = 6;
+ else if (tuner_frequency < 290000000)
+ cp = 3;
+ else if (tuner_frequency < 420000000)
+ cp = 5;
+ else if (tuner_frequency < 480000000)
+ cp = 6;
+ else if (tuner_frequency < 620000000)
+ cp = 3;
+ else if (tuner_frequency < 830000000)
+ cp = 5;
+ else if (tuner_frequency < 895000000)
+ cp = 7;
+ else
+ return -EINVAL;
+
+ /* determine band */
+ if (c->frequency < 49000000)
+ return -EINVAL;
+ else if (c->frequency < 161000000)
+ band = 1;
+ else if (c->frequency < 444000000)
+ band = 2;
+ else if (c->frequency < 861000000)
+ band = 4;
+ else
+ return -EINVAL;
+
+ /* setup PLL filter */
+ switch (c->bandwidth_hz) {
+ case 6000000:
+ filter = 0;
+ break;
+
+ case 7000000:
+ filter = 0;
+ break;
+
+ case 8000000:
+ filter = 1;
+ break;
+
+ default:
+ return -EINVAL;
+ }
+
+ /* calculate divisor
+ * ((36166000+((1000000/6)/2)) + Finput)/(1000000/6)
+ */
+ tuner_frequency = (((c->frequency / 1000) * 6) + 217496) / 1000;
+
+ /* setup tuner buffer */
+ tuner_buf[0] = (tuner_frequency >> 8) & 0x7f;
+ tuner_buf[1] = tuner_frequency & 0xff;
+ tuner_buf[2] = 0xca;
+ tuner_buf[3] = (cp << 5) | (filter << 3) | band;
+
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
+ if (i2c_transfer(&dev->i2c_adap, &tuner_msg, 1) != 1) {
+ pr_warn("could not write to tuner at addr: 0x%02x\n",
+ addr << 1);
+ return -EIO;
+ }
+ msleep(1);
+ return 0;
+}
+
+static int philips_tu1216_init(struct dvb_frontend *fe)
+{
+ struct saa7134_dev *dev = fe->dvb->priv;
+ struct tda1004x_state *state = fe->demodulator_priv;
+ u8 addr = state->config->tuner_address;
+ static u8 tu1216_init[] = { 0x0b, 0xf5, 0x85, 0xab };
+ struct i2c_msg tuner_msg = {.addr = addr,.flags = 0,.buf = tu1216_init,.len = sizeof(tu1216_init) };
+
+ /* setup PLL configuration */
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
+ if (i2c_transfer(&dev->i2c_adap, &tuner_msg, 1) != 1)
+ return -EIO;
+ msleep(1);
+
+ return 0;
+}
+
+/* ------------------------------------------------------------------ */
+
+static struct tda1004x_config philips_tu1216_60_config = {
+ .demod_address = 0x8,
+ .invert = 1,
+ .invert_oclk = 0,
+ .xtal_freq = TDA10046_XTAL_4M,
+ .agc_config = TDA10046_AGC_DEFAULT,
+ .if_freq = TDA10046_FREQ_3617,
+ .tuner_address = 0x60,
+ .request_firmware = philips_tda1004x_request_firmware
+};
+
+static struct tda1004x_config philips_tu1216_61_config = {
+
+ .demod_address = 0x8,
+ .invert = 1,
+ .invert_oclk = 0,
+ .xtal_freq = TDA10046_XTAL_4M,
+ .agc_config = TDA10046_AGC_DEFAULT,
+ .if_freq = TDA10046_FREQ_3617,
+ .tuner_address = 0x61,
+ .request_firmware = philips_tda1004x_request_firmware
+};
+
+/* ------------------------------------------------------------------ */
+
+static int philips_td1316_tuner_init(struct dvb_frontend *fe)
+{
+ struct saa7134_dev *dev = fe->dvb->priv;
+ struct tda1004x_state *state = fe->demodulator_priv;
+ u8 addr = state->config->tuner_address;
+ static u8 msg[] = { 0x0b, 0xf5, 0x86, 0xab };
+ struct i2c_msg init_msg = {.addr = addr,.flags = 0,.buf = msg,.len = sizeof(msg) };
+
+ /* setup PLL configuration */
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
+ if (i2c_transfer(&dev->i2c_adap, &init_msg, 1) != 1)
+ return -EIO;
+ return 0;
+}
+
+static int philips_td1316_tuner_set_params(struct dvb_frontend *fe)
+{
+ return philips_tda6651_pll_set(fe);
+}
+
+static int philips_td1316_tuner_sleep(struct dvb_frontend *fe)
+{
+ struct saa7134_dev *dev = fe->dvb->priv;
+ struct tda1004x_state *state = fe->demodulator_priv;
+ u8 addr = state->config->tuner_address;
+ static u8 msg[] = { 0x0b, 0xdc, 0x86, 0xa4 };
+ struct i2c_msg analog_msg = {.addr = addr,.flags = 0,.buf = msg,.len = sizeof(msg) };
+
+ /* switch the tuner to analog mode */
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
+ if (i2c_transfer(&dev->i2c_adap, &analog_msg, 1) != 1)
+ return -EIO;
+ return 0;
+}
+
+/* ------------------------------------------------------------------ */
+
+static int philips_europa_tuner_init(struct dvb_frontend *fe)
+{
+ struct saa7134_dev *dev = fe->dvb->priv;
+ static u8 msg[] = { 0x00, 0x40};
+ struct i2c_msg init_msg = {.addr = 0x43,.flags = 0,.buf = msg,.len = sizeof(msg) };
+
+
+ if (philips_td1316_tuner_init(fe))
+ return -EIO;
+ msleep(1);
+ if (i2c_transfer(&dev->i2c_adap, &init_msg, 1) != 1)
+ return -EIO;
+
+ return 0;
+}
+
+static int philips_europa_tuner_sleep(struct dvb_frontend *fe)
+{
+ struct saa7134_dev *dev = fe->dvb->priv;
+
+ static u8 msg[] = { 0x00, 0x14 };
+ struct i2c_msg analog_msg = {.addr = 0x43,.flags = 0,.buf = msg,.len = sizeof(msg) };
+
+ if (philips_td1316_tuner_sleep(fe))
+ return -EIO;
+
+ /* switch the board to analog mode */
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
+ i2c_transfer(&dev->i2c_adap, &analog_msg, 1);
+ return 0;
+}
+
+static int philips_europa_demod_sleep(struct dvb_frontend *fe)
+{
+ struct saa7134_dev *dev = fe->dvb->priv;
+
+ if (dev->original_demod_sleep)
+ dev->original_demod_sleep(fe);
+ fe->ops.i2c_gate_ctrl(fe, 1);
+ return 0;
+}
+
+static struct tda1004x_config philips_europa_config = {
+
+ .demod_address = 0x8,
+ .invert = 0,
+ .invert_oclk = 0,
+ .xtal_freq = TDA10046_XTAL_4M,
+ .agc_config = TDA10046_AGC_IFO_AUTO_POS,
+ .if_freq = TDA10046_FREQ_052,
+ .tuner_address = 0x61,
+ .request_firmware = philips_tda1004x_request_firmware
+};
+
+static struct tda1004x_config medion_cardbus = {
+ .demod_address = 0x08,
+ .invert = 1,
+ .invert_oclk = 0,
+ .xtal_freq = TDA10046_XTAL_16M,
+ .agc_config = TDA10046_AGC_IFO_AUTO_NEG,
+ .if_freq = TDA10046_FREQ_3613,
+ .tuner_address = 0x61,
+ .request_firmware = philips_tda1004x_request_firmware
+};
+
+static struct tda1004x_config technotrend_budget_t3000_config = {
+ .demod_address = 0x8,
+ .invert = 1,
+ .invert_oclk = 0,
+ .xtal_freq = TDA10046_XTAL_4M,
+ .agc_config = TDA10046_AGC_DEFAULT,
+ .if_freq = TDA10046_FREQ_3617,
+ .tuner_address = 0x63,
+ .request_firmware = philips_tda1004x_request_firmware
+};
+
+/* ------------------------------------------------------------------
+ * tda 1004x based cards with philips silicon tuner
+ */
+
+static int tda8290_i2c_gate_ctrl( struct dvb_frontend* fe, int enable)
+{
+ struct tda1004x_state *state = fe->demodulator_priv;
+
+ u8 addr = state->config->i2c_gate;
+ static u8 tda8290_close[] = { 0x21, 0xc0};
+ static u8 tda8290_open[] = { 0x21, 0x80};
+ struct i2c_msg tda8290_msg = {.addr = addr,.flags = 0, .len = 2};
+ if (enable) {
+ tda8290_msg.buf = tda8290_close;
+ } else {
+ tda8290_msg.buf = tda8290_open;
+ }
+ if (i2c_transfer(state->i2c, &tda8290_msg, 1) != 1) {
+ pr_warn("could not access tda8290 I2C gate\n");
+ return -EIO;
+ }
+ msleep(20);
+ return 0;
+}
+
+static int philips_tda827x_tuner_init(struct dvb_frontend *fe)
+{
+ struct saa7134_dev *dev = fe->dvb->priv;
+ struct tda1004x_state *state = fe->demodulator_priv;
+
+ switch (state->config->antenna_switch) {
+ case 0:
+ break;
+ case 1:
+ pr_debug("setting GPIO21 to 0 (TV antenna?)\n");
+ saa7134_set_gpio(dev, 21, 0);
+ break;
+ case 2:
+ pr_debug("setting GPIO21 to 1 (Radio antenna?)\n");
+ saa7134_set_gpio(dev, 21, 1);
+ break;
+ }
+ return 0;
+}
+
+static int philips_tda827x_tuner_sleep(struct dvb_frontend *fe)
+{
+ struct saa7134_dev *dev = fe->dvb->priv;
+ struct tda1004x_state *state = fe->demodulator_priv;
+
+ switch (state->config->antenna_switch) {
+ case 0:
+ break;
+ case 1:
+ pr_debug("setting GPIO21 to 1 (Radio antenna?)\n");
+ saa7134_set_gpio(dev, 21, 1);
+ break;
+ case 2:
+ pr_debug("setting GPIO21 to 0 (TV antenna?)\n");
+ saa7134_set_gpio(dev, 21, 0);
+ break;
+ }
+ return 0;
+}
+
+static int configure_tda827x_fe(struct saa7134_dev *dev,
+ struct tda1004x_config *cdec_conf,
+ struct tda827x_config *tuner_conf)
+{
+ struct vb2_dvb_frontend *fe0;
+
+ /* Get the first frontend */
+ fe0 = vb2_dvb_get_frontend(&dev->frontends, 1);
+
+ if (!fe0)
+ return -EINVAL;
+
+ fe0->dvb.frontend = dvb_attach(tda10046_attach, cdec_conf, &dev->i2c_adap);
+ if (fe0->dvb.frontend) {
+ if (cdec_conf->i2c_gate)
+ fe0->dvb.frontend->ops.i2c_gate_ctrl = tda8290_i2c_gate_ctrl;
+ if (dvb_attach(tda827x_attach, fe0->dvb.frontend,
+ cdec_conf->tuner_address,
+ &dev->i2c_adap, tuner_conf))
+ return 0;
+
+ pr_warn("no tda827x tuner found at addr: %02x\n",
+ cdec_conf->tuner_address);
+ }
+ return -EINVAL;
+}
+
+/* ------------------------------------------------------------------ */
+
+static struct tda827x_config tda827x_cfg_0 = {
+ .init = philips_tda827x_tuner_init,
+ .sleep = philips_tda827x_tuner_sleep,
+ .config = 0,
+ .switch_addr = 0
+};
+
+static struct tda827x_config tda827x_cfg_1 = {
+ .init = philips_tda827x_tuner_init,
+ .sleep = philips_tda827x_tuner_sleep,
+ .config = 1,
+ .switch_addr = 0x4b
+};
+
+static struct tda827x_config tda827x_cfg_2 = {
+ .init = philips_tda827x_tuner_init,
+ .sleep = philips_tda827x_tuner_sleep,
+ .config = 2,
+ .switch_addr = 0x4b
+};
+
+static struct tda827x_config tda827x_cfg_2_sw42 = {
+ .init = philips_tda827x_tuner_init,
+ .sleep = philips_tda827x_tuner_sleep,
+ .config = 2,
+ .switch_addr = 0x42
+};
+
+/* ------------------------------------------------------------------ */
+
+static struct tda1004x_config tda827x_lifeview_config = {
+ .demod_address = 0x08,
+ .invert = 1,
+ .invert_oclk = 0,
+ .xtal_freq = TDA10046_XTAL_16M,
+ .agc_config = TDA10046_AGC_TDA827X,
+ .gpio_config = TDA10046_GP11_I,
+ .if_freq = TDA10046_FREQ_045,
+ .tuner_address = 0x60,
+ .request_firmware = philips_tda1004x_request_firmware
+};
+
+static struct tda1004x_config philips_tiger_config = {
+ .demod_address = 0x08,
+ .invert = 1,
+ .invert_oclk = 0,
+ .xtal_freq = TDA10046_XTAL_16M,
+ .agc_config = TDA10046_AGC_TDA827X,
+ .gpio_config = TDA10046_GP11_I,
+ .if_freq = TDA10046_FREQ_045,
+ .i2c_gate = 0x4b,
+ .tuner_address = 0x61,
+ .antenna_switch= 1,
+ .request_firmware = philips_tda1004x_request_firmware
+};
+
+static struct tda1004x_config cinergy_ht_config = {
+ .demod_address = 0x08,
+ .invert = 1,
+ .invert_oclk = 0,
+ .xtal_freq = TDA10046_XTAL_16M,
+ .agc_config = TDA10046_AGC_TDA827X,
+ .gpio_config = TDA10046_GP01_I,
+ .if_freq = TDA10046_FREQ_045,
+ .i2c_gate = 0x4b,
+ .tuner_address = 0x61,
+ .request_firmware = philips_tda1004x_request_firmware
+};
+
+static struct tda1004x_config cinergy_ht_pci_config = {
+ .demod_address = 0x08,
+ .invert = 1,
+ .invert_oclk = 0,
+ .xtal_freq = TDA10046_XTAL_16M,
+ .agc_config = TDA10046_AGC_TDA827X,
+ .gpio_config = TDA10046_GP01_I,
+ .if_freq = TDA10046_FREQ_045,
+ .i2c_gate = 0x4b,
+ .tuner_address = 0x60,
+ .request_firmware = philips_tda1004x_request_firmware
+};
+
+static struct tda1004x_config philips_tiger_s_config = {
+ .demod_address = 0x08,
+ .invert = 1,
+ .invert_oclk = 0,
+ .xtal_freq = TDA10046_XTAL_16M,
+ .agc_config = TDA10046_AGC_TDA827X,
+ .gpio_config = TDA10046_GP01_I,
+ .if_freq = TDA10046_FREQ_045,
+ .i2c_gate = 0x4b,
+ .tuner_address = 0x61,
+ .antenna_switch= 1,
+ .request_firmware = philips_tda1004x_request_firmware
+};
+
+static struct tda1004x_config pinnacle_pctv_310i_config = {
+ .demod_address = 0x08,
+ .invert = 1,
+ .invert_oclk = 0,
+ .xtal_freq = TDA10046_XTAL_16M,
+ .agc_config = TDA10046_AGC_TDA827X,
+ .gpio_config = TDA10046_GP11_I,
+ .if_freq = TDA10046_FREQ_045,
+ .i2c_gate = 0x4b,
+ .tuner_address = 0x61,
+ .request_firmware = philips_tda1004x_request_firmware
+};
+
+static struct tda1004x_config hauppauge_hvr_1110_config = {
+ .demod_address = 0x08,
+ .invert = 1,
+ .invert_oclk = 0,
+ .xtal_freq = TDA10046_XTAL_16M,
+ .agc_config = TDA10046_AGC_TDA827X,
+ .gpio_config = TDA10046_GP11_I,
+ .if_freq = TDA10046_FREQ_045,
+ .i2c_gate = 0x4b,
+ .tuner_address = 0x61,
+ .request_firmware = philips_tda1004x_request_firmware
+};
+
+static struct tda1004x_config asus_p7131_dual_config = {
+ .demod_address = 0x08,
+ .invert = 1,
+ .invert_oclk = 0,
+ .xtal_freq = TDA10046_XTAL_16M,
+ .agc_config = TDA10046_AGC_TDA827X,
+ .gpio_config = TDA10046_GP11_I,
+ .if_freq = TDA10046_FREQ_045,
+ .i2c_gate = 0x4b,
+ .tuner_address = 0x61,
+ .antenna_switch= 2,
+ .request_firmware = philips_tda1004x_request_firmware
+};
+
+static struct tda1004x_config lifeview_trio_config = {
+ .demod_address = 0x09,
+ .invert = 1,
+ .invert_oclk = 0,
+ .xtal_freq = TDA10046_XTAL_16M,
+ .agc_config = TDA10046_AGC_TDA827X,
+ .gpio_config = TDA10046_GP00_I,
+ .if_freq = TDA10046_FREQ_045,
+ .tuner_address = 0x60,
+ .request_firmware = philips_tda1004x_request_firmware
+};
+
+static struct tda1004x_config tevion_dvbt220rf_config = {
+ .demod_address = 0x08,
+ .invert = 1,
+ .invert_oclk = 0,
+ .xtal_freq = TDA10046_XTAL_16M,
+ .agc_config = TDA10046_AGC_TDA827X,
+ .gpio_config = TDA10046_GP11_I,
+ .if_freq = TDA10046_FREQ_045,
+ .tuner_address = 0x60,
+ .request_firmware = philips_tda1004x_request_firmware
+};
+
+static struct tda1004x_config md8800_dvbt_config = {
+ .demod_address = 0x08,
+ .invert = 1,
+ .invert_oclk = 0,
+ .xtal_freq = TDA10046_XTAL_16M,
+ .agc_config = TDA10046_AGC_TDA827X,
+ .gpio_config = TDA10046_GP01_I,
+ .if_freq = TDA10046_FREQ_045,
+ .i2c_gate = 0x4b,
+ .tuner_address = 0x60,
+ .request_firmware = philips_tda1004x_request_firmware
+};
+
+static struct tda1004x_config asus_p7131_4871_config = {
+ .demod_address = 0x08,
+ .invert = 1,
+ .invert_oclk = 0,
+ .xtal_freq = TDA10046_XTAL_16M,
+ .agc_config = TDA10046_AGC_TDA827X,
+ .gpio_config = TDA10046_GP01_I,
+ .if_freq = TDA10046_FREQ_045,
+ .i2c_gate = 0x4b,
+ .tuner_address = 0x61,
+ .antenna_switch= 2,
+ .request_firmware = philips_tda1004x_request_firmware
+};
+
+static struct tda1004x_config asus_p7131_hybrid_lna_config = {
+ .demod_address = 0x08,
+ .invert = 1,
+ .invert_oclk = 0,
+ .xtal_freq = TDA10046_XTAL_16M,
+ .agc_config = TDA10046_AGC_TDA827X,
+ .gpio_config = TDA10046_GP11_I,
+ .if_freq = TDA10046_FREQ_045,
+ .i2c_gate = 0x4b,
+ .tuner_address = 0x61,
+ .antenna_switch= 2,
+ .request_firmware = philips_tda1004x_request_firmware
+};
+
+static struct tda1004x_config kworld_dvb_t_210_config = {
+ .demod_address = 0x08,
+ .invert = 1,
+ .invert_oclk = 0,
+ .xtal_freq = TDA10046_XTAL_16M,
+ .agc_config = TDA10046_AGC_TDA827X,
+ .gpio_config = TDA10046_GP11_I,
+ .if_freq = TDA10046_FREQ_045,
+ .i2c_gate = 0x4b,
+ .tuner_address = 0x61,
+ .antenna_switch= 1,
+ .request_firmware = philips_tda1004x_request_firmware
+};
+
+static struct tda1004x_config avermedia_super_007_config = {
+ .demod_address = 0x08,
+ .invert = 1,
+ .invert_oclk = 0,
+ .xtal_freq = TDA10046_XTAL_16M,
+ .agc_config = TDA10046_AGC_TDA827X,
+ .gpio_config = TDA10046_GP01_I,
+ .if_freq = TDA10046_FREQ_045,
+ .i2c_gate = 0x4b,
+ .tuner_address = 0x60,
+ .antenna_switch= 1,
+ .request_firmware = philips_tda1004x_request_firmware
+};
+
+static struct tda1004x_config twinhan_dtv_dvb_3056_config = {
+ .demod_address = 0x08,
+ .invert = 1,
+ .invert_oclk = 0,
+ .xtal_freq = TDA10046_XTAL_16M,
+ .agc_config = TDA10046_AGC_TDA827X,
+ .gpio_config = TDA10046_GP01_I,
+ .if_freq = TDA10046_FREQ_045,
+ .i2c_gate = 0x42,
+ .tuner_address = 0x61,
+ .antenna_switch = 1,
+ .request_firmware = philips_tda1004x_request_firmware
+};
+
+static struct tda1004x_config asus_tiger_3in1_config = {
+ .demod_address = 0x0b,
+ .invert = 1,
+ .invert_oclk = 0,
+ .xtal_freq = TDA10046_XTAL_16M,
+ .agc_config = TDA10046_AGC_TDA827X,
+ .gpio_config = TDA10046_GP11_I,
+ .if_freq = TDA10046_FREQ_045,
+ .i2c_gate = 0x4b,
+ .tuner_address = 0x61,
+ .antenna_switch = 1,
+ .request_firmware = philips_tda1004x_request_firmware
+};
+
+static struct tda1004x_config asus_ps3_100_config = {
+ .demod_address = 0x0b,
+ .invert = 1,
+ .invert_oclk = 0,
+ .xtal_freq = TDA10046_XTAL_16M,
+ .agc_config = TDA10046_AGC_TDA827X,
+ .gpio_config = TDA10046_GP11_I,
+ .if_freq = TDA10046_FREQ_045,
+ .i2c_gate = 0x4b,
+ .tuner_address = 0x61,
+ .antenna_switch = 1,
+ .request_firmware = philips_tda1004x_request_firmware
+};
+
+/* ------------------------------------------------------------------
+ * special case: this card uses saa713x GPIO22 for the mode switch
+ */
+
+static int ads_duo_tuner_init(struct dvb_frontend *fe)
+{
+ struct saa7134_dev *dev = fe->dvb->priv;
+ philips_tda827x_tuner_init(fe);
+ /* route TDA8275a AGC input to the channel decoder */
+ saa7134_set_gpio(dev, 22, 1);
+ return 0;
+}
+
+static int ads_duo_tuner_sleep(struct dvb_frontend *fe)
+{
+ struct saa7134_dev *dev = fe->dvb->priv;
+ /* route TDA8275a AGC input to the analog IF chip*/
+ saa7134_set_gpio(dev, 22, 0);
+ philips_tda827x_tuner_sleep(fe);
+ return 0;
+}
+
+static struct tda827x_config ads_duo_cfg = {
+ .init = ads_duo_tuner_init,
+ .sleep = ads_duo_tuner_sleep,
+ .config = 0
+};
+
+static struct tda1004x_config ads_tech_duo_config = {
+ .demod_address = 0x08,
+ .invert = 1,
+ .invert_oclk = 0,
+ .xtal_freq = TDA10046_XTAL_16M,
+ .agc_config = TDA10046_AGC_TDA827X,
+ .gpio_config = TDA10046_GP00_I,
+ .if_freq = TDA10046_FREQ_045,
+ .tuner_address = 0x61,
+ .request_firmware = philips_tda1004x_request_firmware
+};
+
+static struct zl10353_config behold_h6_config = {
+ .demod_address = 0x1e>>1,
+ .no_tuner = 1,
+ .parallel_ts = 1,
+ .disable_i2c_gate_ctrl = 1,
+};
+
+static struct xc5000_config behold_x7_tunerconfig = {
+ .i2c_address = 0xc2>>1,
+ .if_khz = 4560,
+ .radio_input = XC5000_RADIO_FM1,
+};
+
+static struct zl10353_config behold_x7_config = {
+ .demod_address = 0x1e>>1,
+ .if2 = 45600,
+ .no_tuner = 1,
+ .parallel_ts = 1,
+ .disable_i2c_gate_ctrl = 1,
+};
+
+static struct zl10353_config videomate_t750_zl10353_config = {
+ .demod_address = 0x0f,
+ .no_tuner = 1,
+ .parallel_ts = 1,
+ .disable_i2c_gate_ctrl = 1,
+};
+
+static struct qt1010_config videomate_t750_qt1010_config = {
+ .i2c_address = 0x62
+};
+
+
+/* ==================================================================
+ * tda10086 based DVB-S cards, helper functions
+ */
+
+static struct tda10086_config flydvbs = {
+ .demod_address = 0x0e,
+ .invert = 0,
+ .diseqc_tone = 0,
+ .xtal_freq = TDA10086_XTAL_16M,
+};
+
+static struct tda10086_config sd1878_4m = {
+ .demod_address = 0x0e,
+ .invert = 0,
+ .diseqc_tone = 0,
+ .xtal_freq = TDA10086_XTAL_4M,
+};
+
+/* ------------------------------------------------------------------
+ * special case: lnb supply is connected to the gated i2c
+ */
+
+static int md8800_set_voltage(struct dvb_frontend *fe,
+ enum fe_sec_voltage voltage)
+{
+ int res = -EIO;
+ struct saa7134_dev *dev = fe->dvb->priv;
+ if (fe->ops.i2c_gate_ctrl) {
+ fe->ops.i2c_gate_ctrl(fe, 1);
+ if (dev->original_set_voltage)
+ res = dev->original_set_voltage(fe, voltage);
+ fe->ops.i2c_gate_ctrl(fe, 0);
+ }
+ return res;
+};
+
+static int md8800_set_high_voltage(struct dvb_frontend *fe, long arg)
+{
+ int res = -EIO;
+ struct saa7134_dev *dev = fe->dvb->priv;
+ if (fe->ops.i2c_gate_ctrl) {
+ fe->ops.i2c_gate_ctrl(fe, 1);
+ if (dev->original_set_high_voltage)
+ res = dev->original_set_high_voltage(fe, arg);
+ fe->ops.i2c_gate_ctrl(fe, 0);
+ }
+ return res;
+};
+
+static int md8800_set_voltage2(struct dvb_frontend *fe,
+ enum fe_sec_voltage voltage)
+{
+ struct saa7134_dev *dev = fe->dvb->priv;
+ u8 wbuf[2] = { 0x1f, 00 };
+ u8 rbuf;
+ struct i2c_msg msg[] = { { .addr = 0x08, .flags = 0, .buf = wbuf, .len = 1 },
+ { .addr = 0x08, .flags = I2C_M_RD, .buf = &rbuf, .len = 1 } };
+
+ if (i2c_transfer(&dev->i2c_adap, msg, 2) != 2)
+ return -EIO;
+ /* NOTE: this assumes that gpo1 is used, it might be bit 5 (gpo2) */
+ if (voltage == SEC_VOLTAGE_18)
+ wbuf[1] = rbuf | 0x10;
+ else
+ wbuf[1] = rbuf & 0xef;
+ msg[0].len = 2;
+ i2c_transfer(&dev->i2c_adap, msg, 1);
+ return 0;
+}
+
+static int md8800_set_high_voltage2(struct dvb_frontend *fe, long arg)
+{
+ pr_warn("%s: sorry can't set high LNB supply voltage from here\n",
+ __func__);
+ return -EIO;
+}
+
+/* ==================================================================
+ * nxt200x based ATSC cards, helper functions
+ */
+
+static const struct nxt200x_config avertvhda180 = {
+ .demod_address = 0x0a,
+};
+
+static const struct nxt200x_config kworldatsc110 = {
+ .demod_address = 0x0a,
+};
+
+/* ------------------------------------------------------------------ */
+
+static struct mt312_config avertv_a700_mt312 = {
+ .demod_address = 0x0e,
+ .voltage_inverted = 1,
+};
+
+static struct zl10036_config avertv_a700_tuner = {
+ .tuner_address = 0x60,
+};
+
+static struct mt312_config zl10313_compro_s350_config = {
+ .demod_address = 0x0e,
+};
+
+static struct mt312_config zl10313_avermedia_a706_config = {
+ .demod_address = 0x0e,
+};
+
+static struct lgdt3305_config hcw_lgdt3305_config = {
+ .i2c_addr = 0x0e,
+ .mpeg_mode = LGDT3305_MPEG_SERIAL,
+ .tpclk_edge = LGDT3305_TPCLK_RISING_EDGE,
+ .tpvalid_polarity = LGDT3305_TP_VALID_HIGH,
+ .deny_i2c_rptr = 1,
+ .spectral_inversion = 1,
+ .qam_if_khz = 4000,
+ .vsb_if_khz = 3250,
+};
+
+static struct tda10048_config hcw_tda10048_config = {
+ .demod_address = 0x10 >> 1,
+ .output_mode = TDA10048_SERIAL_OUTPUT,
+ .fwbulkwritelen = TDA10048_BULKWRITE_200,
+ .inversion = TDA10048_INVERSION_ON,
+ .dtv6_if_freq_khz = TDA10048_IF_3300,
+ .dtv7_if_freq_khz = TDA10048_IF_3500,
+ .dtv8_if_freq_khz = TDA10048_IF_4000,
+ .clk_freq_khz = TDA10048_CLK_16000,
+ .disable_gate_access = 1,
+};
+
+static struct tda18271_std_map hauppauge_tda18271_std_map = {
+ .atsc_6 = { .if_freq = 3250, .agc_mode = 3, .std = 4,
+ .if_lvl = 1, .rfagc_top = 0x58, },
+ .qam_6 = { .if_freq = 4000, .agc_mode = 3, .std = 5,
+ .if_lvl = 1, .rfagc_top = 0x58, },
+};
+
+static struct tda18271_config hcw_tda18271_config = {
+ .std_map = &hauppauge_tda18271_std_map,
+ .gate = TDA18271_GATE_ANALOG,
+ .config = 3,
+ .output_opt = TDA18271_OUTPUT_LT_OFF,
+};
+
+static struct tda829x_config tda829x_no_probe = {
+ .probe_tuner = TDA829X_DONT_PROBE,
+};
+
+static struct tda10048_config zolid_tda10048_config = {
+ .demod_address = 0x10 >> 1,
+ .output_mode = TDA10048_PARALLEL_OUTPUT,
+ .fwbulkwritelen = TDA10048_BULKWRITE_200,
+ .inversion = TDA10048_INVERSION_ON,
+ .dtv6_if_freq_khz = TDA10048_IF_3300,
+ .dtv7_if_freq_khz = TDA10048_IF_3500,
+ .dtv8_if_freq_khz = TDA10048_IF_4000,
+ .clk_freq_khz = TDA10048_CLK_16000,
+ .disable_gate_access = 1,
+};
+
+static struct tda18271_config zolid_tda18271_config = {
+ .gate = TDA18271_GATE_ANALOG,
+};
+
+static struct tda10048_config dtv1000s_tda10048_config = {
+ .demod_address = 0x10 >> 1,
+ .output_mode = TDA10048_PARALLEL_OUTPUT,
+ .fwbulkwritelen = TDA10048_BULKWRITE_200,
+ .inversion = TDA10048_INVERSION_ON,
+ .dtv6_if_freq_khz = TDA10048_IF_3300,
+ .dtv7_if_freq_khz = TDA10048_IF_3800,
+ .dtv8_if_freq_khz = TDA10048_IF_4300,
+ .clk_freq_khz = TDA10048_CLK_16000,
+ .disable_gate_access = 1,
+};
+
+static struct tda18271_std_map dtv1000s_tda18271_std_map = {
+ .dvbt_6 = { .if_freq = 3300, .agc_mode = 3, .std = 4,
+ .if_lvl = 1, .rfagc_top = 0x37, },
+ .dvbt_7 = { .if_freq = 3800, .agc_mode = 3, .std = 5,
+ .if_lvl = 1, .rfagc_top = 0x37, },
+ .dvbt_8 = { .if_freq = 4300, .agc_mode = 3, .std = 6,
+ .if_lvl = 1, .rfagc_top = 0x37, },
+};
+
+static struct tda18271_config dtv1000s_tda18271_config = {
+ .std_map = &dtv1000s_tda18271_std_map,
+ .gate = TDA18271_GATE_ANALOG,
+};
+
+static struct lgs8gxx_config prohdtv_pro2_lgs8g75_config = {
+ .prod = LGS8GXX_PROD_LGS8G75,
+ .demod_address = 0x1d,
+ .serial_ts = 0,
+ .ts_clk_pol = 1,
+ .ts_clk_gated = 0,
+ .if_clk_freq = 30400, /* 30.4 MHz */
+ .if_freq = 4000, /* 4.00 MHz */
+ .if_neg_center = 0,
+ .ext_adc = 0,
+ .adc_signed = 1,
+ .adc_vpp = 3, /* 2.0 Vpp */
+ .if_neg_edge = 1,
+};
+
+static struct tda18271_config prohdtv_pro2_tda18271_config = {
+ .gate = TDA18271_GATE_ANALOG,
+ .output_opt = TDA18271_OUTPUT_LT_OFF,
+};
+
+static struct tda18271_std_map kworld_tda18271_std_map = {
+ .atsc_6 = { .if_freq = 3250, .agc_mode = 3, .std = 3,
+ .if_lvl = 6, .rfagc_top = 0x37 },
+ .qam_6 = { .if_freq = 4000, .agc_mode = 3, .std = 0,
+ .if_lvl = 6, .rfagc_top = 0x37 },
+};
+
+static struct tda18271_config kworld_pc150u_tda18271_config = {
+ .std_map = &kworld_tda18271_std_map,
+ .gate = TDA18271_GATE_ANALOG,
+ .output_opt = TDA18271_OUTPUT_LT_OFF,
+ .config = 3, /* Use tuner callback for AGC */
+ .rf_cal_on_startup = 1
+};
+
+static struct s5h1411_config kworld_s5h1411_config = {
+ .output_mode = S5H1411_PARALLEL_OUTPUT,
+ .gpio = S5H1411_GPIO_OFF,
+ .qam_if = S5H1411_IF_4000,
+ .vsb_if = S5H1411_IF_3250,
+ .inversion = S5H1411_INVERSION_ON,
+ .status_mode = S5H1411_DEMODLOCKING,
+ .mpeg_timing =
+ S5H1411_MPEGTIMING_CONTINUOUS_NONINVERTING_CLOCK,
+};
+
+static struct tda18271_config hdtv200h_tda18271_config = {
+ .gate = TDA18271_GATE_ANALOG,
+ .config = 3 /* Use tuner callback for AGC */
+};
+
+static struct s5h1411_config hdtv200h_s5h1411_config = {
+ .output_mode = S5H1411_PARALLEL_OUTPUT,
+ .gpio = S5H1411_GPIO_OFF,
+ .qam_if = S5H1411_IF_4000,
+ .vsb_if = S5H1411_IF_3250,
+ .inversion = S5H1411_INVERSION_ON,
+ .status_mode = S5H1411_DEMODLOCKING,
+ .mpeg_timing =
+ S5H1411_MPEGTIMING_CONTINUOUS_NONINVERTING_CLOCK,
+};
+
+
+/* ==================================================================
+ * Core code
+ */
+
+static int dvb_init(struct saa7134_dev *dev)
+{
+ int ret;
+ int attach_xc3028 = 0;
+ struct vb2_dvb_frontend *fe0;
+ struct vb2_queue *q;
+
+ /* FIXME: add support for multi-frontend */
+ mutex_init(&dev->frontends.lock);
+ INIT_LIST_HEAD(&dev->frontends.felist);
+
+ pr_info("%s() allocating 1 frontend\n", __func__);
+ fe0 = vb2_dvb_alloc_frontend(&dev->frontends, 1);
+ if (!fe0) {
+ pr_err("%s() failed to alloc\n", __func__);
+ return -ENOMEM;
+ }
+
+ /* init struct vb2_dvb */
+ dev->ts.nr_bufs = 32;
+ dev->ts.nr_packets = 32*4;
+ fe0->dvb.name = dev->name;
+ q = &fe0->dvb.dvbq;
+ q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ q->io_modes = VB2_MMAP | VB2_READ;
+ q->drv_priv = &dev->ts_q;
+ q->ops = &saa7134_ts_qops;
+ q->mem_ops = &vb2_dma_sg_memops;
+ q->buf_struct_size = sizeof(struct saa7134_buf);
+ q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
+ q->lock = &dev->lock;
+ q->dev = &dev->pci->dev;
+ ret = vb2_queue_init(q);
+ if (ret) {
+ vb2_dvb_dealloc_frontends(&dev->frontends);
+ return ret;
+ }
+
+ switch (dev->board) {
+ case SAA7134_BOARD_PINNACLE_300I_DVBT_PAL:
+ pr_debug("pinnacle 300i dvb setup\n");
+ fe0->dvb.frontend = dvb_attach(mt352_attach, &pinnacle_300i,
+ &dev->i2c_adap);
+ if (fe0->dvb.frontend) {
+ fe0->dvb.frontend->ops.tuner_ops.set_params = mt352_pinnacle_tuner_set_params;
+ }
+ break;
+ case SAA7134_BOARD_AVERMEDIA_777:
+ case SAA7134_BOARD_AVERMEDIA_A16AR:
+ pr_debug("avertv 777 dvb setup\n");
+ fe0->dvb.frontend = dvb_attach(mt352_attach, &avermedia_777,
+ &dev->i2c_adap);
+ if (fe0->dvb.frontend) {
+ dvb_attach(simple_tuner_attach, fe0->dvb.frontend,
+ &dev->i2c_adap, 0x61,
+ TUNER_PHILIPS_TD1316);
+ }
+ break;
+ case SAA7134_BOARD_AVERMEDIA_A16D:
+ pr_debug("AverMedia A16D dvb setup\n");
+ fe0->dvb.frontend = dvb_attach(mt352_attach,
+ &avermedia_xc3028_mt352_dev,
+ &dev->i2c_adap);
+ attach_xc3028 = 1;
+ break;
+ case SAA7134_BOARD_MD7134:
+ fe0->dvb.frontend = dvb_attach(tda10046_attach,
+ &medion_cardbus,
+ &dev->i2c_adap);
+ if (fe0->dvb.frontend) {
+ /*
+ * The TV tuner on this board is actually NOT
+ * behind the demod i2c gate.
+ * However, the demod EEPROM is indeed there and it
+ * conflicts with the SAA7134 chip config EEPROM
+ * if the i2c gate is open (since they have same
+ * bus addresses) resulting in card PCI SVID / SSID
+ * being garbage after a reboot from time to time.
+ *
+ * Let's just leave the gate permanently closed -
+ * saa7134_i2c_eeprom_md7134_gate() will close it for
+ * us at probe time if it was open for some reason.
+ */
+ fe0->dvb.frontend->ops.i2c_gate_ctrl = NULL;
+ dvb_attach(simple_tuner_attach, fe0->dvb.frontend,
+ &dev->i2c_adap, medion_cardbus.tuner_address,
+ TUNER_PHILIPS_FMD1216ME_MK3);
+ }
+ break;
+ case SAA7134_BOARD_PHILIPS_TOUGH:
+ fe0->dvb.frontend = dvb_attach(tda10046_attach,
+ &philips_tu1216_60_config,
+ &dev->i2c_adap);
+ if (fe0->dvb.frontend) {
+ fe0->dvb.frontend->ops.tuner_ops.init = philips_tu1216_init;
+ fe0->dvb.frontend->ops.tuner_ops.set_params = philips_tda6651_pll_set;
+ }
+ break;
+ case SAA7134_BOARD_FLYDVBTDUO:
+ case SAA7134_BOARD_FLYDVBT_DUO_CARDBUS:
+ if (configure_tda827x_fe(dev, &tda827x_lifeview_config,
+ &tda827x_cfg_0) < 0)
+ goto detach_frontend;
+ break;
+ case SAA7134_BOARD_PHILIPS_EUROPA:
+ case SAA7134_BOARD_VIDEOMATE_DVBT_300:
+ case SAA7134_BOARD_ASUS_EUROPA_HYBRID:
+ fe0->dvb.frontend = dvb_attach(tda10046_attach,
+ &philips_europa_config,
+ &dev->i2c_adap);
+ if (fe0->dvb.frontend) {
+ dev->original_demod_sleep = fe0->dvb.frontend->ops.sleep;
+ fe0->dvb.frontend->ops.sleep = philips_europa_demod_sleep;
+ fe0->dvb.frontend->ops.tuner_ops.init = philips_europa_tuner_init;
+ fe0->dvb.frontend->ops.tuner_ops.sleep = philips_europa_tuner_sleep;
+ fe0->dvb.frontend->ops.tuner_ops.set_params = philips_td1316_tuner_set_params;
+ }
+ break;
+ case SAA7134_BOARD_TECHNOTREND_BUDGET_T3000:
+ fe0->dvb.frontend = dvb_attach(tda10046_attach,
+ &technotrend_budget_t3000_config,
+ &dev->i2c_adap);
+ if (fe0->dvb.frontend) {
+ dev->original_demod_sleep = fe0->dvb.frontend->ops.sleep;
+ fe0->dvb.frontend->ops.sleep = philips_europa_demod_sleep;
+ fe0->dvb.frontend->ops.tuner_ops.init = philips_europa_tuner_init;
+ fe0->dvb.frontend->ops.tuner_ops.sleep = philips_europa_tuner_sleep;
+ fe0->dvb.frontend->ops.tuner_ops.set_params = philips_td1316_tuner_set_params;
+ }
+ break;
+ case SAA7134_BOARD_VIDEOMATE_DVBT_200:
+ fe0->dvb.frontend = dvb_attach(tda10046_attach,
+ &philips_tu1216_61_config,
+ &dev->i2c_adap);
+ if (fe0->dvb.frontend) {
+ fe0->dvb.frontend->ops.tuner_ops.init = philips_tu1216_init;
+ fe0->dvb.frontend->ops.tuner_ops.set_params = philips_tda6651_pll_set;
+ }
+ break;
+ case SAA7134_BOARD_KWORLD_DVBT_210:
+ if (configure_tda827x_fe(dev, &kworld_dvb_t_210_config,
+ &tda827x_cfg_2) < 0)
+ goto detach_frontend;
+ break;
+ case SAA7134_BOARD_HAUPPAUGE_HVR1120:
+ fe0->dvb.frontend = dvb_attach(tda10048_attach,
+ &hcw_tda10048_config,
+ &dev->i2c_adap);
+ if (fe0->dvb.frontend != NULL) {
+ dvb_attach(tda829x_attach, fe0->dvb.frontend,
+ &dev->i2c_adap, 0x4b,
+ &tda829x_no_probe);
+ dvb_attach(tda18271_attach, fe0->dvb.frontend,
+ 0x60, &dev->i2c_adap,
+ &hcw_tda18271_config);
+ }
+ break;
+ case SAA7134_BOARD_PHILIPS_TIGER:
+ if (configure_tda827x_fe(dev, &philips_tiger_config,
+ &tda827x_cfg_0) < 0)
+ goto detach_frontend;
+ break;
+ case SAA7134_BOARD_PINNACLE_PCTV_310i:
+ if (configure_tda827x_fe(dev, &pinnacle_pctv_310i_config,
+ &tda827x_cfg_1) < 0)
+ goto detach_frontend;
+ break;
+ case SAA7134_BOARD_HAUPPAUGE_HVR1110:
+ if (configure_tda827x_fe(dev, &hauppauge_hvr_1110_config,
+ &tda827x_cfg_1) < 0)
+ goto detach_frontend;
+ break;
+ case SAA7134_BOARD_HAUPPAUGE_HVR1150:
+ fe0->dvb.frontend = dvb_attach(lgdt3305_attach,
+ &hcw_lgdt3305_config,
+ &dev->i2c_adap);
+ if (fe0->dvb.frontend) {
+ dvb_attach(tda829x_attach, fe0->dvb.frontend,
+ &dev->i2c_adap, 0x4b,
+ &tda829x_no_probe);
+ dvb_attach(tda18271_attach, fe0->dvb.frontend,
+ 0x60, &dev->i2c_adap,
+ &hcw_tda18271_config);
+ }
+ break;
+ case SAA7134_BOARD_ASUSTeK_P7131_DUAL:
+ if (configure_tda827x_fe(dev, &asus_p7131_dual_config,
+ &tda827x_cfg_0) < 0)
+ goto detach_frontend;
+ break;
+ case SAA7134_BOARD_FLYDVBT_LR301:
+ if (configure_tda827x_fe(dev, &tda827x_lifeview_config,
+ &tda827x_cfg_0) < 0)
+ goto detach_frontend;
+ break;
+ case SAA7134_BOARD_FLYDVB_TRIO:
+ if (!use_frontend) { /* terrestrial */
+ if (configure_tda827x_fe(dev, &lifeview_trio_config,
+ &tda827x_cfg_0) < 0)
+ goto detach_frontend;
+ } else { /* satellite */
+ fe0->dvb.frontend = dvb_attach(tda10086_attach, &flydvbs, &dev->i2c_adap);
+ if (fe0->dvb.frontend) {
+ if (dvb_attach(tda826x_attach, fe0->dvb.frontend, 0x63,
+ &dev->i2c_adap, 0) == NULL) {
+ pr_warn("%s: Lifeview Trio, No tda826x found!\n",
+ __func__);
+ goto detach_frontend;
+ }
+ if (dvb_attach(isl6421_attach, fe0->dvb.frontend,
+ &dev->i2c_adap,
+ 0x08, 0, 0, false) == NULL) {
+ pr_warn("%s: Lifeview Trio, No ISL6421 found!\n",
+ __func__);
+ goto detach_frontend;
+ }
+ }
+ }
+ break;
+ case SAA7134_BOARD_ADS_DUO_CARDBUS_PTV331:
+ case SAA7134_BOARD_FLYDVBT_HYBRID_CARDBUS:
+ fe0->dvb.frontend = dvb_attach(tda10046_attach,
+ &ads_tech_duo_config,
+ &dev->i2c_adap);
+ if (fe0->dvb.frontend) {
+ if (dvb_attach(tda827x_attach,fe0->dvb.frontend,
+ ads_tech_duo_config.tuner_address, &dev->i2c_adap,
+ &ads_duo_cfg) == NULL) {
+ pr_warn("no tda827x tuner found at addr: %02x\n",
+ ads_tech_duo_config.tuner_address);
+ goto detach_frontend;
+ }
+ } else
+ pr_warn("failed to attach tda10046\n");
+ break;
+ case SAA7134_BOARD_TEVION_DVBT_220RF:
+ if (configure_tda827x_fe(dev, &tevion_dvbt220rf_config,
+ &tda827x_cfg_0) < 0)
+ goto detach_frontend;
+ break;
+ case SAA7134_BOARD_MEDION_MD8800_QUADRO:
+ if (!use_frontend) { /* terrestrial */
+ if (configure_tda827x_fe(dev, &md8800_dvbt_config,
+ &tda827x_cfg_0) < 0)
+ goto detach_frontend;
+ } else { /* satellite */
+ fe0->dvb.frontend = dvb_attach(tda10086_attach,
+ &flydvbs, &dev->i2c_adap);
+ if (fe0->dvb.frontend) {
+ struct dvb_frontend *fe = fe0->dvb.frontend;
+ u8 dev_id = dev->eedata[2];
+ u8 data = 0xc4;
+ struct i2c_msg msg = {.addr = 0x08, .flags = 0, .len = 1};
+
+ if (dvb_attach(tda826x_attach, fe0->dvb.frontend,
+ 0x60, &dev->i2c_adap, 0) == NULL) {
+ pr_warn("%s: Medion Quadro, no tda826x found !\n",
+ __func__);
+ goto detach_frontend;
+ }
+ if (dev_id != 0x08) {
+ /* we need to open the i2c gate (we know it exists) */
+ fe->ops.i2c_gate_ctrl(fe, 1);
+ if (dvb_attach(isl6405_attach, fe,
+ &dev->i2c_adap, 0x08, 0, 0) == NULL) {
+ pr_warn("%s: Medion Quadro, no ISL6405 found !\n",
+ __func__);
+ goto detach_frontend;
+ }
+ if (dev_id == 0x07) {
+ /* fire up the 2nd section of the LNB supply since
+ we can't do this from the other section */
+ msg.buf = &data;
+ i2c_transfer(&dev->i2c_adap, &msg, 1);
+ }
+ fe->ops.i2c_gate_ctrl(fe, 0);
+ dev->original_set_voltage = fe->ops.set_voltage;
+ fe->ops.set_voltage = md8800_set_voltage;
+ dev->original_set_high_voltage = fe->ops.enable_high_lnb_voltage;
+ fe->ops.enable_high_lnb_voltage = md8800_set_high_voltage;
+ } else {
+ fe->ops.set_voltage = md8800_set_voltage2;
+ fe->ops.enable_high_lnb_voltage = md8800_set_high_voltage2;
+ }
+ }
+ }
+ break;
+ case SAA7134_BOARD_AVERMEDIA_AVERTVHD_A180:
+ fe0->dvb.frontend = dvb_attach(nxt200x_attach, &avertvhda180,
+ &dev->i2c_adap);
+ if (fe0->dvb.frontend)
+ dvb_attach(dvb_pll_attach, fe0->dvb.frontend, 0x61,
+ NULL, DVB_PLL_TDHU2);
+ break;
+ case SAA7134_BOARD_ADS_INSTANT_HDTV_PCI:
+ case SAA7134_BOARD_KWORLD_ATSC110:
+ fe0->dvb.frontend = dvb_attach(nxt200x_attach, &kworldatsc110,
+ &dev->i2c_adap);
+ if (fe0->dvb.frontend)
+ dvb_attach(simple_tuner_attach, fe0->dvb.frontend,
+ &dev->i2c_adap, 0x61,
+ TUNER_PHILIPS_TUV1236D);
+ break;
+ case SAA7134_BOARD_KWORLD_PC150U:
+ saa7134_set_gpio(dev, 18, 1); /* Switch to digital mode */
+ saa7134_tuner_callback(dev, 0,
+ TDA18271_CALLBACK_CMD_AGC_ENABLE, 1);
+ fe0->dvb.frontend = dvb_attach(s5h1411_attach,
+ &kworld_s5h1411_config,
+ &dev->i2c_adap);
+ if (fe0->dvb.frontend != NULL) {
+ dvb_attach(tda829x_attach, fe0->dvb.frontend,
+ &dev->i2c_adap, 0x4b,
+ &tda829x_no_probe);
+ dvb_attach(tda18271_attach, fe0->dvb.frontend,
+ 0x60, &dev->i2c_adap,
+ &kworld_pc150u_tda18271_config);
+ }
+ break;
+ case SAA7134_BOARD_FLYDVBS_LR300:
+ fe0->dvb.frontend = dvb_attach(tda10086_attach, &flydvbs,
+ &dev->i2c_adap);
+ if (fe0->dvb.frontend) {
+ if (dvb_attach(tda826x_attach, fe0->dvb.frontend, 0x60,
+ &dev->i2c_adap, 0) == NULL) {
+ pr_warn("%s: No tda826x found!\n", __func__);
+ goto detach_frontend;
+ }
+ if (dvb_attach(isl6421_attach, fe0->dvb.frontend,
+ &dev->i2c_adap,
+ 0x08, 0, 0, false) == NULL) {
+ pr_warn("%s: No ISL6421 found!\n", __func__);
+ goto detach_frontend;
+ }
+ }
+ break;
+ case SAA7134_BOARD_ASUS_EUROPA2_HYBRID:
+ fe0->dvb.frontend = dvb_attach(tda10046_attach,
+ &medion_cardbus,
+ &dev->i2c_adap);
+ if (fe0->dvb.frontend) {
+ dev->original_demod_sleep = fe0->dvb.frontend->ops.sleep;
+ fe0->dvb.frontend->ops.sleep = philips_europa_demod_sleep;
+
+ dvb_attach(simple_tuner_attach, fe0->dvb.frontend,
+ &dev->i2c_adap, medion_cardbus.tuner_address,
+ TUNER_PHILIPS_FMD1216ME_MK3);
+ }
+ break;
+ case SAA7134_BOARD_VIDEOMATE_DVBT_200A:
+ fe0->dvb.frontend = dvb_attach(tda10046_attach,
+ &philips_europa_config,
+ &dev->i2c_adap);
+ if (fe0->dvb.frontend) {
+ fe0->dvb.frontend->ops.tuner_ops.init = philips_td1316_tuner_init;
+ fe0->dvb.frontend->ops.tuner_ops.set_params = philips_td1316_tuner_set_params;
+ }
+ break;
+ case SAA7134_BOARD_CINERGY_HT_PCMCIA:
+ if (configure_tda827x_fe(dev, &cinergy_ht_config,
+ &tda827x_cfg_0) < 0)
+ goto detach_frontend;
+ break;
+ case SAA7134_BOARD_CINERGY_HT_PCI:
+ if (configure_tda827x_fe(dev, &cinergy_ht_pci_config,
+ &tda827x_cfg_0) < 0)
+ goto detach_frontend;
+ break;
+ case SAA7134_BOARD_PHILIPS_TIGER_S:
+ if (configure_tda827x_fe(dev, &philips_tiger_s_config,
+ &tda827x_cfg_2) < 0)
+ goto detach_frontend;
+ break;
+ case SAA7134_BOARD_ASUS_P7131_4871:
+ if (configure_tda827x_fe(dev, &asus_p7131_4871_config,
+ &tda827x_cfg_2) < 0)
+ goto detach_frontend;
+ break;
+ case SAA7134_BOARD_ASUSTeK_P7131_HYBRID_LNA:
+ if (configure_tda827x_fe(dev, &asus_p7131_hybrid_lna_config,
+ &tda827x_cfg_2) < 0)
+ goto detach_frontend;
+ break;
+ case SAA7134_BOARD_AVERMEDIA_SUPER_007:
+ if (configure_tda827x_fe(dev, &avermedia_super_007_config,
+ &tda827x_cfg_0) < 0)
+ goto detach_frontend;
+ break;
+ case SAA7134_BOARD_TWINHAN_DTV_DVB_3056:
+ if (configure_tda827x_fe(dev, &twinhan_dtv_dvb_3056_config,
+ &tda827x_cfg_2_sw42) < 0)
+ goto detach_frontend;
+ break;
+ case SAA7134_BOARD_PHILIPS_SNAKE:
+ fe0->dvb.frontend = dvb_attach(tda10086_attach, &flydvbs,
+ &dev->i2c_adap);
+ if (fe0->dvb.frontend) {
+ if (dvb_attach(tda826x_attach, fe0->dvb.frontend, 0x60,
+ &dev->i2c_adap, 0) == NULL) {
+ pr_warn("%s: No tda826x found!\n", __func__);
+ goto detach_frontend;
+ }
+ if (dvb_attach(lnbp21_attach, fe0->dvb.frontend,
+ &dev->i2c_adap, 0, 0) == NULL) {
+ pr_warn("%s: No lnbp21 found!\n", __func__);
+ goto detach_frontend;
+ }
+ }
+ break;
+ case SAA7134_BOARD_CREATIX_CTX953:
+ if (configure_tda827x_fe(dev, &md8800_dvbt_config,
+ &tda827x_cfg_0) < 0)
+ goto detach_frontend;
+ break;
+ case SAA7134_BOARD_MSI_TVANYWHERE_AD11:
+ if (configure_tda827x_fe(dev, &philips_tiger_s_config,
+ &tda827x_cfg_2) < 0)
+ goto detach_frontend;
+ break;
+ case SAA7134_BOARD_AVERMEDIA_CARDBUS_506:
+ pr_debug("AverMedia E506R dvb setup\n");
+ saa7134_set_gpio(dev, 25, 0);
+ msleep(10);
+ saa7134_set_gpio(dev, 25, 1);
+ fe0->dvb.frontend = dvb_attach(mt352_attach,
+ &avermedia_xc3028_mt352_dev,
+ &dev->i2c_adap);
+ attach_xc3028 = 1;
+ break;
+ case SAA7134_BOARD_MD7134_BRIDGE_2:
+ fe0->dvb.frontend = dvb_attach(tda10086_attach,
+ &sd1878_4m, &dev->i2c_adap);
+ if (fe0->dvb.frontend) {
+ struct dvb_frontend *fe;
+ if (dvb_attach(dvb_pll_attach, fe0->dvb.frontend, 0x60,
+ &dev->i2c_adap, DVB_PLL_PHILIPS_SD1878_TDA8261) == NULL) {
+ pr_warn("%s: MD7134 DVB-S, no SD1878 found !\n",
+ __func__);
+ goto detach_frontend;
+ }
+ /* we need to open the i2c gate (we know it exists) */
+ fe = fe0->dvb.frontend;
+ fe->ops.i2c_gate_ctrl(fe, 1);
+ if (dvb_attach(isl6405_attach, fe,
+ &dev->i2c_adap, 0x08, 0, 0) == NULL) {
+ pr_warn("%s: MD7134 DVB-S, no ISL6405 found !\n",
+ __func__);
+ goto detach_frontend;
+ }
+ fe->ops.i2c_gate_ctrl(fe, 0);
+ dev->original_set_voltage = fe->ops.set_voltage;
+ fe->ops.set_voltage = md8800_set_voltage;
+ dev->original_set_high_voltage = fe->ops.enable_high_lnb_voltage;
+ fe->ops.enable_high_lnb_voltage = md8800_set_high_voltage;
+ }
+ break;
+ case SAA7134_BOARD_AVERMEDIA_M103:
+ saa7134_set_gpio(dev, 25, 0);
+ msleep(10);
+ saa7134_set_gpio(dev, 25, 1);
+ fe0->dvb.frontend = dvb_attach(mt352_attach,
+ &avermedia_xc3028_mt352_dev,
+ &dev->i2c_adap);
+ attach_xc3028 = 1;
+ break;
+ case SAA7134_BOARD_ASUSTeK_TIGER_3IN1:
+ if (!use_frontend) { /* terrestrial */
+ if (configure_tda827x_fe(dev, &asus_tiger_3in1_config,
+ &tda827x_cfg_2) < 0)
+ goto detach_frontend;
+ } else { /* satellite */
+ fe0->dvb.frontend = dvb_attach(tda10086_attach,
+ &flydvbs, &dev->i2c_adap);
+ if (fe0->dvb.frontend) {
+ if (dvb_attach(tda826x_attach,
+ fe0->dvb.frontend, 0x60,
+ &dev->i2c_adap, 0) == NULL) {
+ pr_warn("%s: Asus Tiger 3in1, no tda826x found!\n",
+ __func__);
+ goto detach_frontend;
+ }
+ if (dvb_attach(lnbp21_attach, fe0->dvb.frontend,
+ &dev->i2c_adap, 0, 0) == NULL) {
+ pr_warn("%s: Asus Tiger 3in1, no lnbp21 found!\n",
+ __func__);
+ goto detach_frontend;
+ }
+ }
+ }
+ break;
+ case SAA7134_BOARD_ASUSTeK_PS3_100:
+ if (!use_frontend) { /* terrestrial */
+ if (configure_tda827x_fe(dev, &asus_ps3_100_config,
+ &tda827x_cfg_2) < 0)
+ goto detach_frontend;
+ } else { /* satellite */
+ fe0->dvb.frontend = dvb_attach(tda10086_attach,
+ &flydvbs, &dev->i2c_adap);
+ if (fe0->dvb.frontend) {
+ if (dvb_attach(tda826x_attach,
+ fe0->dvb.frontend, 0x60,
+ &dev->i2c_adap, 0) == NULL) {
+ pr_warn("%s: Asus My Cinema PS3-100, no tda826x found!\n",
+ __func__);
+ goto detach_frontend;
+ }
+ if (dvb_attach(lnbp21_attach, fe0->dvb.frontend,
+ &dev->i2c_adap, 0, 0) == NULL) {
+ pr_warn("%s: Asus My Cinema PS3-100, no lnbp21 found!\n",
+ __func__);
+ goto detach_frontend;
+ }
+ }
+ }
+ break;
+ case SAA7134_BOARD_ASUSTeK_TIGER:
+ if (configure_tda827x_fe(dev, &philips_tiger_config,
+ &tda827x_cfg_0) < 0)
+ goto detach_frontend;
+ break;
+ case SAA7134_BOARD_BEHOLD_H6:
+ fe0->dvb.frontend = dvb_attach(zl10353_attach,
+ &behold_h6_config,
+ &dev->i2c_adap);
+ if (fe0->dvb.frontend) {
+ dvb_attach(simple_tuner_attach, fe0->dvb.frontend,
+ &dev->i2c_adap, 0x61,
+ TUNER_PHILIPS_FMD1216MEX_MK3);
+ }
+ break;
+ case SAA7134_BOARD_BEHOLD_X7:
+ fe0->dvb.frontend = dvb_attach(zl10353_attach,
+ &behold_x7_config,
+ &dev->i2c_adap);
+ if (fe0->dvb.frontend) {
+ dvb_attach(xc5000_attach, fe0->dvb.frontend,
+ &dev->i2c_adap, &behold_x7_tunerconfig);
+ }
+ break;
+ case SAA7134_BOARD_BEHOLD_H7:
+ fe0->dvb.frontend = dvb_attach(zl10353_attach,
+ &behold_x7_config,
+ &dev->i2c_adap);
+ if (fe0->dvb.frontend) {
+ dvb_attach(xc5000_attach, fe0->dvb.frontend,
+ &dev->i2c_adap, &behold_x7_tunerconfig);
+ }
+ break;
+ case SAA7134_BOARD_AVERMEDIA_A700_PRO:
+ case SAA7134_BOARD_AVERMEDIA_A700_HYBRID:
+ /* Zarlink ZL10313 */
+ fe0->dvb.frontend = dvb_attach(mt312_attach,
+ &avertv_a700_mt312, &dev->i2c_adap);
+ if (fe0->dvb.frontend) {
+ if (dvb_attach(zl10036_attach, fe0->dvb.frontend,
+ &avertv_a700_tuner, &dev->i2c_adap) == NULL) {
+ pr_warn("%s: No zl10036 found!\n",
+ __func__);
+ }
+ }
+ break;
+ case SAA7134_BOARD_VIDEOMATE_S350:
+ fe0->dvb.frontend = dvb_attach(mt312_attach,
+ &zl10313_compro_s350_config, &dev->i2c_adap);
+ if (fe0->dvb.frontend)
+ if (dvb_attach(zl10039_attach, fe0->dvb.frontend,
+ 0x60, &dev->i2c_adap) == NULL)
+ pr_warn("%s: No zl10039 found!\n",
+ __func__);
+
+ break;
+ case SAA7134_BOARD_VIDEOMATE_T750:
+ fe0->dvb.frontend = dvb_attach(zl10353_attach,
+ &videomate_t750_zl10353_config,
+ &dev->i2c_adap);
+ if (fe0->dvb.frontend != NULL) {
+ if (dvb_attach(qt1010_attach,
+ fe0->dvb.frontend,
+ &dev->i2c_adap,
+ &videomate_t750_qt1010_config) == NULL)
+ pr_warn("error attaching QT1010\n");
+ }
+ break;
+ case SAA7134_BOARD_ZOLID_HYBRID_PCI:
+ fe0->dvb.frontend = dvb_attach(tda10048_attach,
+ &zolid_tda10048_config,
+ &dev->i2c_adap);
+ if (fe0->dvb.frontend != NULL) {
+ dvb_attach(tda829x_attach, fe0->dvb.frontend,
+ &dev->i2c_adap, 0x4b,
+ &tda829x_no_probe);
+ dvb_attach(tda18271_attach, fe0->dvb.frontend,
+ 0x60, &dev->i2c_adap,
+ &zolid_tda18271_config);
+ }
+ break;
+ case SAA7134_BOARD_LEADTEK_WINFAST_DTV1000S:
+ fe0->dvb.frontend = dvb_attach(tda10048_attach,
+ &dtv1000s_tda10048_config,
+ &dev->i2c_adap);
+ if (fe0->dvb.frontend != NULL) {
+ dvb_attach(tda829x_attach, fe0->dvb.frontend,
+ &dev->i2c_adap, 0x4b,
+ &tda829x_no_probe);
+ dvb_attach(tda18271_attach, fe0->dvb.frontend,
+ 0x60, &dev->i2c_adap,
+ &dtv1000s_tda18271_config);
+ }
+ break;
+ case SAA7134_BOARD_KWORLD_PCI_SBTVD_FULLSEG:
+ /* Switch to digital mode */
+ saa7134_tuner_callback(dev, 0,
+ TDA18271_CALLBACK_CMD_AGC_ENABLE, 1);
+ fe0->dvb.frontend = dvb_attach(mb86a20s_attach,
+ &kworld_mb86a20s_config,
+ &dev->i2c_adap);
+ if (fe0->dvb.frontend != NULL) {
+ dvb_attach(tda829x_attach, fe0->dvb.frontend,
+ &dev->i2c_adap, 0x4b,
+ &tda829x_no_probe);
+ fe0->dvb.frontend->ops.i2c_gate_ctrl = kworld_sbtvd_gate_ctrl;
+ dvb_attach(tda18271_attach, fe0->dvb.frontend,
+ 0x60, &dev->i2c_adap,
+ &kworld_tda18271_config);
+ }
+
+ /* mb86a20s need to use the I2C gateway */
+ break;
+ case SAA7134_BOARD_MAGICPRO_PROHDTV_PRO2:
+ fe0->dvb.frontend = dvb_attach(lgs8gxx_attach,
+ &prohdtv_pro2_lgs8g75_config,
+ &dev->i2c_adap);
+ if (fe0->dvb.frontend != NULL) {
+ dvb_attach(tda829x_attach, fe0->dvb.frontend,
+ &dev->i2c_adap, 0x4b,
+ &tda829x_no_probe);
+ dvb_attach(tda18271_attach, fe0->dvb.frontend,
+ 0x60, &dev->i2c_adap,
+ &prohdtv_pro2_tda18271_config);
+ }
+ break;
+ case SAA7134_BOARD_AVERMEDIA_A706:
+ /* Enable all DVB-S devices now */
+ /* CE5039 DVB-S tuner SLEEP pin low */
+ saa7134_set_gpio(dev, 23, 0);
+ /* CE6313 DVB-S demod SLEEP pin low */
+ saa7134_set_gpio(dev, 9, 0);
+ /* CE6313 DVB-S demod RESET# pin high */
+ saa7134_set_gpio(dev, 25, 1);
+ msleep(1);
+ fe0->dvb.frontend = dvb_attach(mt312_attach,
+ &zl10313_avermedia_a706_config, &dev->i2c_adap);
+ if (fe0->dvb.frontend) {
+ fe0->dvb.frontend->ops.i2c_gate_ctrl = NULL;
+ if (dvb_attach(zl10039_attach, fe0->dvb.frontend,
+ 0x60, &dev->i2c_adap) == NULL)
+ pr_warn("%s: No zl10039 found!\n",
+ __func__);
+ }
+ break;
+ case SAA7134_BOARD_LEADTEK_WINFAST_HDTV200_H:
+ fe0->dvb.frontend = dvb_attach(s5h1411_attach,
+ &hdtv200h_s5h1411_config,
+ &dev->i2c_adap);
+ if (fe0->dvb.frontend) {
+ dvb_attach(tda829x_attach, fe0->dvb.frontend,
+ &dev->i2c_adap, 0x4b,
+ &tda829x_no_probe);
+ dvb_attach(tda18271_attach, fe0->dvb.frontend,
+ 0x60, &dev->i2c_adap,
+ &hdtv200h_tda18271_config);
+ }
+ break;
+ default:
+ pr_warn("Huh? unknown DVB card?\n");
+ break;
+ }
+
+ if (attach_xc3028) {
+ struct dvb_frontend *fe;
+ struct xc2028_config cfg = {
+ .i2c_adap = &dev->i2c_adap,
+ .i2c_addr = 0x61,
+ };
+
+ if (!fe0->dvb.frontend)
+ goto detach_frontend;
+
+ fe = dvb_attach(xc2028_attach, fe0->dvb.frontend, &cfg);
+ if (!fe) {
+ pr_err("%s/2: xc3028 attach failed\n",
+ dev->name);
+ goto detach_frontend;
+ }
+ }
+
+ if (NULL == fe0->dvb.frontend) {
+ pr_err("%s/dvb: frontend initialization failed\n", dev->name);
+ goto detach_frontend;
+ }
+ /* define general-purpose callback pointer */
+ fe0->dvb.frontend->callback = saa7134_tuner_callback;
+
+ /* register everything else */
+#ifndef CONFIG_MEDIA_CONTROLLER_DVB
+ ret = vb2_dvb_register_bus(&dev->frontends, THIS_MODULE, dev,
+ &dev->pci->dev, NULL,
+ adapter_nr, 0);
+#else
+ ret = vb2_dvb_register_bus(&dev->frontends, THIS_MODULE, dev,
+ &dev->pci->dev, dev->media_dev,
+ adapter_nr, 0);
+#endif
+
+ /* this sequence is necessary to make the tda1004x load its firmware
+ * and to enter analog mode of hybrid boards
+ */
+ if (!ret) {
+ if (fe0->dvb.frontend->ops.init)
+ fe0->dvb.frontend->ops.init(fe0->dvb.frontend);
+ if (fe0->dvb.frontend->ops.sleep)
+ fe0->dvb.frontend->ops.sleep(fe0->dvb.frontend);
+ if (fe0->dvb.frontend->ops.tuner_ops.sleep)
+ fe0->dvb.frontend->ops.tuner_ops.sleep(fe0->dvb.frontend);
+ }
+ return ret;
+
+detach_frontend:
+ vb2_dvb_dealloc_frontends(&dev->frontends);
+ vb2_queue_release(&fe0->dvb.dvbq);
+ return -EINVAL;
+}
+
+static int dvb_fini(struct saa7134_dev *dev)
+{
+ struct vb2_dvb_frontend *fe0;
+
+ /* Get the first frontend */
+ fe0 = vb2_dvb_get_frontend(&dev->frontends, 1);
+ if (!fe0)
+ return -EINVAL;
+
+ /* FIXME: I suspect that this code is bogus, since the entry for
+ Pinnacle 300I DVB-T PAL already defines the proper init to allow
+ the detection of mt2032 (TDA9887_PORT2_INACTIVE)
+ */
+ if (dev->board == SAA7134_BOARD_PINNACLE_300I_DVBT_PAL) {
+ struct v4l2_priv_tun_config tda9887_cfg;
+ static int on = TDA9887_PRESENT | TDA9887_PORT2_INACTIVE;
+
+ tda9887_cfg.tuner = TUNER_TDA9887;
+ tda9887_cfg.priv = &on;
+
+ /* otherwise we don't detect the tuner on next insmod */
+ saa_call_all(dev, tuner, s_config, &tda9887_cfg);
+ } else if (dev->board == SAA7134_BOARD_MEDION_MD8800_QUADRO) {
+ if ((dev->eedata[2] == 0x07) && use_frontend) {
+ /* turn off the 2nd lnb supply */
+ u8 data = 0x80;
+ struct i2c_msg msg = {.addr = 0x08, .buf = &data, .flags = 0, .len = 1};
+ struct dvb_frontend *fe;
+ fe = fe0->dvb.frontend;
+ if (fe->ops.i2c_gate_ctrl) {
+ fe->ops.i2c_gate_ctrl(fe, 1);
+ i2c_transfer(&dev->i2c_adap, &msg, 1);
+ fe->ops.i2c_gate_ctrl(fe, 0);
+ }
+ }
+ }
+ vb2_dvb_unregister_bus(&dev->frontends);
+ vb2_queue_release(&fe0->dvb.dvbq);
+ return 0;
+}
+
+static struct saa7134_mpeg_ops dvb_ops = {
+ .type = SAA7134_MPEG_DVB,
+ .init = dvb_init,
+ .fini = dvb_fini,
+};
+
+static int __init dvb_register(void)
+{
+ return saa7134_ts_register(&dvb_ops);
+}
+
+static void __exit dvb_unregister(void)
+{
+ saa7134_ts_unregister(&dvb_ops);
+}
+
+module_init(dvb_register);
+module_exit(dvb_unregister);
diff --git a/drivers/media/pci/saa7134/saa7134-empress.c b/drivers/media/pci/saa7134/saa7134-empress.c
new file mode 100644
index 0000000000..434fa1ee1c
--- /dev/null
+++ b/drivers/media/pci/saa7134/saa7134-empress.c
@@ -0,0 +1,347 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ *
+ * (c) 2004 Gerd Knorr <kraxel@bytesex.org> [SuSE Labs]
+ */
+
+#include "saa7134.h"
+#include "saa7134-reg.h"
+
+#include <linux/init.h>
+#include <linux/list.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+
+#include <media/v4l2-common.h>
+#include <media/v4l2-event.h>
+
+/* ------------------------------------------------------------------ */
+
+MODULE_AUTHOR("Gerd Knorr <kraxel@bytesex.org> [SuSE Labs]");
+MODULE_LICENSE("GPL");
+
+static unsigned int empress_nr[] = {[0 ... (SAA7134_MAXBOARDS - 1)] = UNSET };
+
+module_param_array(empress_nr, int, NULL, 0444);
+MODULE_PARM_DESC(empress_nr,"ts device number");
+
+/* ------------------------------------------------------------------ */
+
+static int start_streaming(struct vb2_queue *vq, unsigned int count)
+{
+ struct saa7134_dmaqueue *dmaq = vq->drv_priv;
+ struct saa7134_dev *dev = dmaq->dev;
+ u32 leading_null_bytes = 0;
+ int err;
+
+ err = saa7134_ts_start_streaming(vq, count);
+ if (err)
+ return err;
+
+ /* If more cards start to need this, then this
+ should probably be added to the card definitions. */
+ switch (dev->board) {
+ case SAA7134_BOARD_BEHOLD_M6:
+ case SAA7134_BOARD_BEHOLD_M63:
+ case SAA7134_BOARD_BEHOLD_M6_EXTRA:
+ leading_null_bytes = 1;
+ break;
+ }
+ saa_call_all(dev, core, init, leading_null_bytes);
+ /* Unmute audio */
+ saa_writeb(SAA7134_AUDIO_MUTE_CTRL,
+ saa_readb(SAA7134_AUDIO_MUTE_CTRL) & ~(1 << 6));
+ dev->empress_started = 1;
+ return 0;
+}
+
+static void stop_streaming(struct vb2_queue *vq)
+{
+ struct saa7134_dmaqueue *dmaq = vq->drv_priv;
+ struct saa7134_dev *dev = dmaq->dev;
+
+ saa7134_ts_stop_streaming(vq);
+ saa_writeb(SAA7134_SPECIAL_MODE, 0x00);
+ msleep(20);
+ saa_writeb(SAA7134_SPECIAL_MODE, 0x01);
+ msleep(100);
+ /* Mute audio */
+ saa_writeb(SAA7134_AUDIO_MUTE_CTRL,
+ saa_readb(SAA7134_AUDIO_MUTE_CTRL) | (1 << 6));
+ dev->empress_started = 0;
+}
+
+static const struct vb2_ops saa7134_empress_qops = {
+ .queue_setup = saa7134_ts_queue_setup,
+ .buf_init = saa7134_ts_buffer_init,
+ .buf_prepare = saa7134_ts_buffer_prepare,
+ .buf_queue = saa7134_vb2_buffer_queue,
+ .wait_prepare = vb2_ops_wait_prepare,
+ .wait_finish = vb2_ops_wait_finish,
+ .start_streaming = start_streaming,
+ .stop_streaming = stop_streaming,
+};
+
+/* ------------------------------------------------------------------ */
+
+static int empress_enum_fmt_vid_cap(struct file *file, void *priv,
+ struct v4l2_fmtdesc *f)
+{
+ if (f->index != 0)
+ return -EINVAL;
+
+ f->pixelformat = V4L2_PIX_FMT_MPEG;
+ return 0;
+}
+
+static int empress_g_fmt_vid_cap(struct file *file, void *priv,
+ struct v4l2_format *f)
+{
+ struct saa7134_dev *dev = video_drvdata(file);
+ struct v4l2_subdev_format fmt = {
+ .which = V4L2_SUBDEV_FORMAT_ACTIVE,
+ };
+ struct v4l2_mbus_framefmt *mbus_fmt = &fmt.format;
+
+ saa_call_all(dev, pad, get_fmt, NULL, &fmt);
+
+ v4l2_fill_pix_format(&f->fmt.pix, mbus_fmt);
+ f->fmt.pix.pixelformat = V4L2_PIX_FMT_MPEG;
+ f->fmt.pix.sizeimage = TS_PACKET_SIZE * dev->ts.nr_packets;
+ f->fmt.pix.bytesperline = 0;
+
+ return 0;
+}
+
+static int empress_s_fmt_vid_cap(struct file *file, void *priv,
+ struct v4l2_format *f)
+{
+ struct saa7134_dev *dev = video_drvdata(file);
+ struct v4l2_subdev_format format = {
+ .which = V4L2_SUBDEV_FORMAT_ACTIVE,
+ };
+
+ v4l2_fill_mbus_format(&format.format, &f->fmt.pix, MEDIA_BUS_FMT_FIXED);
+ saa_call_all(dev, pad, set_fmt, NULL, &format);
+ v4l2_fill_pix_format(&f->fmt.pix, &format.format);
+
+ f->fmt.pix.pixelformat = V4L2_PIX_FMT_MPEG;
+ f->fmt.pix.sizeimage = TS_PACKET_SIZE * dev->ts.nr_packets;
+ f->fmt.pix.bytesperline = 0;
+
+ return 0;
+}
+
+static int empress_try_fmt_vid_cap(struct file *file, void *priv,
+ struct v4l2_format *f)
+{
+ struct saa7134_dev *dev = video_drvdata(file);
+ struct v4l2_subdev_pad_config pad_cfg;
+ struct v4l2_subdev_state pad_state = {
+ .pads = &pad_cfg,
+ };
+ struct v4l2_subdev_format format = {
+ .which = V4L2_SUBDEV_FORMAT_TRY,
+ };
+
+ v4l2_fill_mbus_format(&format.format, &f->fmt.pix, MEDIA_BUS_FMT_FIXED);
+ saa_call_all(dev, pad, set_fmt, &pad_state, &format);
+ v4l2_fill_pix_format(&f->fmt.pix, &format.format);
+
+ f->fmt.pix.pixelformat = V4L2_PIX_FMT_MPEG;
+ f->fmt.pix.sizeimage = TS_PACKET_SIZE * dev->ts.nr_packets;
+ f->fmt.pix.bytesperline = 0;
+
+ return 0;
+}
+
+static const struct v4l2_file_operations ts_fops =
+{
+ .owner = THIS_MODULE,
+ .open = v4l2_fh_open,
+ .release = vb2_fop_release,
+ .read = vb2_fop_read,
+ .poll = vb2_fop_poll,
+ .mmap = vb2_fop_mmap,
+ .unlocked_ioctl = video_ioctl2,
+};
+
+static const struct v4l2_ioctl_ops ts_ioctl_ops = {
+ .vidioc_querycap = saa7134_querycap,
+ .vidioc_enum_fmt_vid_cap = empress_enum_fmt_vid_cap,
+ .vidioc_try_fmt_vid_cap = empress_try_fmt_vid_cap,
+ .vidioc_s_fmt_vid_cap = empress_s_fmt_vid_cap,
+ .vidioc_g_fmt_vid_cap = empress_g_fmt_vid_cap,
+ .vidioc_reqbufs = vb2_ioctl_reqbufs,
+ .vidioc_querybuf = vb2_ioctl_querybuf,
+ .vidioc_qbuf = vb2_ioctl_qbuf,
+ .vidioc_dqbuf = vb2_ioctl_dqbuf,
+ .vidioc_expbuf = vb2_ioctl_expbuf,
+ .vidioc_streamon = vb2_ioctl_streamon,
+ .vidioc_streamoff = vb2_ioctl_streamoff,
+ .vidioc_g_frequency = saa7134_g_frequency,
+ .vidioc_s_frequency = saa7134_s_frequency,
+ .vidioc_g_tuner = saa7134_g_tuner,
+ .vidioc_s_tuner = saa7134_s_tuner,
+ .vidioc_enum_input = saa7134_enum_input,
+ .vidioc_g_input = saa7134_g_input,
+ .vidioc_s_input = saa7134_s_input,
+ .vidioc_s_std = saa7134_s_std,
+ .vidioc_g_std = saa7134_g_std,
+ .vidioc_querystd = saa7134_querystd,
+ .vidioc_log_status = v4l2_ctrl_log_status,
+ .vidioc_subscribe_event = v4l2_ctrl_subscribe_event,
+ .vidioc_unsubscribe_event = v4l2_event_unsubscribe,
+};
+
+/* ----------------------------------------------------------- */
+
+static const struct video_device saa7134_empress_template = {
+ .name = "saa7134-empress",
+ .fops = &ts_fops,
+ .ioctl_ops = &ts_ioctl_ops,
+
+ .tvnorms = SAA7134_NORMS,
+};
+
+static void empress_signal_update(struct work_struct *work)
+{
+ struct saa7134_dev* dev =
+ container_of(work, struct saa7134_dev, empress_workqueue);
+
+ if (dev->nosignal) {
+ pr_debug("no video signal\n");
+ } else {
+ pr_debug("video signal acquired\n");
+ }
+}
+
+static void empress_signal_change(struct saa7134_dev *dev)
+{
+ schedule_work(&dev->empress_workqueue);
+}
+
+static bool empress_ctrl_filter(const struct v4l2_ctrl *ctrl)
+{
+ switch (ctrl->id) {
+ case V4L2_CID_BRIGHTNESS:
+ case V4L2_CID_HUE:
+ case V4L2_CID_CONTRAST:
+ case V4L2_CID_SATURATION:
+ case V4L2_CID_AUDIO_MUTE:
+ case V4L2_CID_AUDIO_VOLUME:
+ case V4L2_CID_PRIVATE_INVERT:
+ case V4L2_CID_PRIVATE_AUTOMUTE:
+ return true;
+ default:
+ return false;
+ }
+}
+
+static int empress_init(struct saa7134_dev *dev)
+{
+ struct v4l2_ctrl_handler *hdl = &dev->empress_ctrl_handler;
+ struct vb2_queue *q;
+ int err;
+
+ pr_debug("%s: %s\n", dev->name, __func__);
+ dev->empress_dev = video_device_alloc();
+ if (NULL == dev->empress_dev)
+ return -ENOMEM;
+ *(dev->empress_dev) = saa7134_empress_template;
+ dev->empress_dev->v4l2_dev = &dev->v4l2_dev;
+ dev->empress_dev->release = video_device_release;
+ dev->empress_dev->lock = &dev->lock;
+ snprintf(dev->empress_dev->name, sizeof(dev->empress_dev->name),
+ "%s empress (%s)", dev->name,
+ saa7134_boards[dev->board].name);
+ v4l2_ctrl_handler_init(hdl, 21);
+ v4l2_ctrl_add_handler(hdl, &dev->ctrl_handler, empress_ctrl_filter, false);
+ if (dev->empress_sd)
+ v4l2_ctrl_add_handler(hdl, dev->empress_sd->ctrl_handler, NULL, true);
+ if (hdl->error) {
+ video_device_release(dev->empress_dev);
+ return hdl->error;
+ }
+ dev->empress_dev->ctrl_handler = hdl;
+
+ INIT_WORK(&dev->empress_workqueue, empress_signal_update);
+
+ q = &dev->empress_vbq;
+ q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ /*
+ * Do not add VB2_USERPTR: the saa7134 DMA engine cannot handle
+ * transfers that do not start at the beginning of a page. A USERPTR
+ * can start anywhere in a page, so USERPTR support is a no-go.
+ */
+ q->io_modes = VB2_MMAP | VB2_DMABUF | VB2_READ;
+ q->drv_priv = &dev->ts_q;
+ q->ops = &saa7134_empress_qops;
+ q->gfp_flags = GFP_DMA32;
+ q->mem_ops = &vb2_dma_sg_memops;
+ q->buf_struct_size = sizeof(struct saa7134_buf);
+ q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
+ q->lock = &dev->lock;
+ q->dev = &dev->pci->dev;
+ err = vb2_queue_init(q);
+ if (err) {
+ video_device_release(dev->empress_dev);
+ dev->empress_dev = NULL;
+ return err;
+ }
+ dev->empress_dev->queue = q;
+ dev->empress_dev->device_caps = V4L2_CAP_READWRITE | V4L2_CAP_STREAMING |
+ V4L2_CAP_VIDEO_CAPTURE;
+ if (dev->tuner_type != TUNER_ABSENT && dev->tuner_type != UNSET)
+ dev->empress_dev->device_caps |= V4L2_CAP_TUNER;
+
+ video_set_drvdata(dev->empress_dev, dev);
+ err = video_register_device(dev->empress_dev,VFL_TYPE_VIDEO,
+ empress_nr[dev->nr]);
+ if (err < 0) {
+ pr_info("%s: can't register video device\n",
+ dev->name);
+ video_device_release(dev->empress_dev);
+ dev->empress_dev = NULL;
+ return err;
+ }
+ pr_info("%s: registered device %s [mpeg]\n",
+ dev->name, video_device_node_name(dev->empress_dev));
+
+ empress_signal_update(&dev->empress_workqueue);
+ return 0;
+}
+
+static int empress_fini(struct saa7134_dev *dev)
+{
+ pr_debug("%s: %s\n", dev->name, __func__);
+
+ if (NULL == dev->empress_dev)
+ return 0;
+ flush_work(&dev->empress_workqueue);
+ vb2_video_unregister_device(dev->empress_dev);
+ v4l2_ctrl_handler_free(&dev->empress_ctrl_handler);
+ dev->empress_dev = NULL;
+ return 0;
+}
+
+static struct saa7134_mpeg_ops empress_ops = {
+ .type = SAA7134_MPEG_EMPRESS,
+ .init = empress_init,
+ .fini = empress_fini,
+ .signal_change = empress_signal_change,
+};
+
+static int __init empress_register(void)
+{
+ return saa7134_ts_register(&empress_ops);
+}
+
+static void __exit empress_unregister(void)
+{
+ saa7134_ts_unregister(&empress_ops);
+}
+
+module_init(empress_register);
+module_exit(empress_unregister);
diff --git a/drivers/media/pci/saa7134/saa7134-go7007.c b/drivers/media/pci/saa7134/saa7134-go7007.c
new file mode 100644
index 0000000000..da83893ffe
--- /dev/null
+++ b/drivers/media/pci/saa7134/saa7134-go7007.c
@@ -0,0 +1,519 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (C) 2005-2006 Micronas USA Inc.
+ */
+
+#include "saa7134.h"
+#include "saa7134-reg.h"
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/spinlock.h>
+#include <linux/wait.h>
+#include <linux/list.h>
+#include <linux/slab.h>
+#include <linux/time.h>
+#include <linux/mm.h>
+#include <linux/usb.h>
+#include <linux/i2c.h>
+#include <asm/byteorder.h>
+#include <media/v4l2-common.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-subdev.h>
+
+#include "go7007-priv.h"
+
+/*#define GO7007_HPI_DEBUG*/
+
+enum hpi_address {
+ HPI_ADDR_VIDEO_BUFFER = 0xe4,
+ HPI_ADDR_INIT_BUFFER = 0xea,
+ HPI_ADDR_INTR_RET_VALUE = 0xee,
+ HPI_ADDR_INTR_RET_DATA = 0xec,
+ HPI_ADDR_INTR_STATUS = 0xf4,
+ HPI_ADDR_INTR_WR_PARAM = 0xf6,
+ HPI_ADDR_INTR_WR_INDEX = 0xf8,
+};
+
+enum gpio_command {
+ GPIO_COMMAND_RESET = 0x00, /* 000b */
+ GPIO_COMMAND_REQ1 = 0x04, /* 001b */
+ GPIO_COMMAND_WRITE = 0x20, /* 010b */
+ GPIO_COMMAND_REQ2 = 0x24, /* 011b */
+ GPIO_COMMAND_READ = 0x80, /* 100b */
+ GPIO_COMMAND_VIDEO = 0x84, /* 101b */
+ GPIO_COMMAND_IDLE = 0xA0, /* 110b */
+ GPIO_COMMAND_ADDR = 0xA4, /* 111b */
+};
+
+struct saa7134_go7007 {
+ struct v4l2_subdev sd;
+ struct saa7134_dev *dev;
+ u8 *top;
+ u8 *bottom;
+ dma_addr_t top_dma;
+ dma_addr_t bottom_dma;
+};
+
+static const struct go7007_board_info board_voyager = {
+ .flags = 0,
+ .sensor_flags = GO7007_SENSOR_656 |
+ GO7007_SENSOR_VALID_ENABLE |
+ GO7007_SENSOR_TV |
+ GO7007_SENSOR_VBI,
+ .audio_flags = GO7007_AUDIO_I2S_MODE_1 |
+ GO7007_AUDIO_WORD_16,
+ .audio_rate = 48000,
+ .audio_bclk_div = 8,
+ .audio_main_div = 2,
+ .hpi_buffer_cap = 7,
+ .num_inputs = 1,
+ .inputs = {
+ {
+ .name = "SAA7134",
+ },
+ },
+};
+
+/********************* Driver for GPIO HPI interface *********************/
+
+static int gpio_write(struct saa7134_dev *dev, u8 addr, u16 data)
+{
+ saa_writeb(SAA7134_GPIO_GPMODE0, 0xff);
+
+ /* Write HPI address */
+ saa_writeb(SAA7134_GPIO_GPSTATUS0, addr);
+ saa_writeb(SAA7134_GPIO_GPSTATUS2, GPIO_COMMAND_ADDR);
+ saa_writeb(SAA7134_GPIO_GPSTATUS2, GPIO_COMMAND_IDLE);
+
+ /* Write low byte */
+ saa_writeb(SAA7134_GPIO_GPSTATUS0, data & 0xff);
+ saa_writeb(SAA7134_GPIO_GPSTATUS2, GPIO_COMMAND_WRITE);
+ saa_writeb(SAA7134_GPIO_GPSTATUS2, GPIO_COMMAND_IDLE);
+
+ /* Write high byte */
+ saa_writeb(SAA7134_GPIO_GPSTATUS0, data >> 8);
+ saa_writeb(SAA7134_GPIO_GPSTATUS2, GPIO_COMMAND_WRITE);
+ saa_writeb(SAA7134_GPIO_GPSTATUS2, GPIO_COMMAND_IDLE);
+
+ return 0;
+}
+
+static int gpio_read(struct saa7134_dev *dev, u8 addr, u16 *data)
+{
+ saa_writeb(SAA7134_GPIO_GPMODE0, 0xff);
+
+ /* Write HPI address */
+ saa_writeb(SAA7134_GPIO_GPSTATUS0, addr);
+ saa_writeb(SAA7134_GPIO_GPSTATUS2, GPIO_COMMAND_ADDR);
+ saa_writeb(SAA7134_GPIO_GPSTATUS2, GPIO_COMMAND_IDLE);
+
+ saa_writeb(SAA7134_GPIO_GPMODE0, 0x00);
+
+ /* Read low byte */
+ saa_writeb(SAA7134_GPIO_GPSTATUS2, GPIO_COMMAND_READ);
+ saa_clearb(SAA7134_GPIO_GPMODE3, SAA7134_GPIO_GPRESCAN);
+ saa_setb(SAA7134_GPIO_GPMODE3, SAA7134_GPIO_GPRESCAN);
+ *data = saa_readb(SAA7134_GPIO_GPSTATUS0);
+ saa_writeb(SAA7134_GPIO_GPSTATUS2, GPIO_COMMAND_IDLE);
+
+ /* Read high byte */
+ saa_writeb(SAA7134_GPIO_GPSTATUS2, GPIO_COMMAND_READ);
+ saa_clearb(SAA7134_GPIO_GPMODE3, SAA7134_GPIO_GPRESCAN);
+ saa_setb(SAA7134_GPIO_GPMODE3, SAA7134_GPIO_GPRESCAN);
+ *data |= saa_readb(SAA7134_GPIO_GPSTATUS0) << 8;
+ saa_writeb(SAA7134_GPIO_GPSTATUS2, GPIO_COMMAND_IDLE);
+
+ return 0;
+}
+
+static int saa7134_go7007_interface_reset(struct go7007 *go)
+{
+ struct saa7134_go7007 *saa = go->hpi_context;
+ struct saa7134_dev *dev = saa->dev;
+ u16 intr_val, intr_data;
+ int count = 20;
+
+ saa_clearb(SAA7134_TS_PARALLEL, 0x80); /* Disable TS interface */
+ saa_writeb(SAA7134_GPIO_GPMODE2, 0xa4);
+ saa_writeb(SAA7134_GPIO_GPMODE0, 0xff);
+
+ saa_writeb(SAA7134_GPIO_GPSTATUS2, GPIO_COMMAND_REQ1);
+ saa_writeb(SAA7134_GPIO_GPSTATUS2, GPIO_COMMAND_RESET);
+ msleep(1);
+ saa_writeb(SAA7134_GPIO_GPSTATUS2, GPIO_COMMAND_REQ1);
+ saa_writeb(SAA7134_GPIO_GPSTATUS2, GPIO_COMMAND_REQ2);
+ msleep(10);
+
+ saa_clearb(SAA7134_GPIO_GPMODE3, SAA7134_GPIO_GPRESCAN);
+ saa_setb(SAA7134_GPIO_GPMODE3, SAA7134_GPIO_GPRESCAN);
+
+ saa_readb(SAA7134_GPIO_GPSTATUS2);
+ /*pr_debug("status is %s\n", saa_readb(SAA7134_GPIO_GPSTATUS2) & 0x40 ? "OK" : "not OK"); */
+
+ /* enter command mode...(?) */
+ saa_writeb(SAA7134_GPIO_GPSTATUS2, GPIO_COMMAND_REQ1);
+ saa_writeb(SAA7134_GPIO_GPSTATUS2, GPIO_COMMAND_REQ2);
+
+ do {
+ saa_clearb(SAA7134_GPIO_GPMODE3, SAA7134_GPIO_GPRESCAN);
+ saa_setb(SAA7134_GPIO_GPMODE3, SAA7134_GPIO_GPRESCAN);
+ saa_readb(SAA7134_GPIO_GPSTATUS2);
+ /*pr_info("gpio is %08x\n", saa_readl(SAA7134_GPIO_GPSTATUS0 >> 2)); */
+ } while (--count > 0);
+
+ /* Wait for an interrupt to indicate successful hardware reset */
+ if (go7007_read_interrupt(go, &intr_val, &intr_data) < 0 ||
+ (intr_val & ~0x1) != 0x55aa) {
+ pr_err("saa7134-go7007: unable to reset the GO7007\n");
+ return -1;
+ }
+ return 0;
+}
+
+static int saa7134_go7007_write_interrupt(struct go7007 *go, int addr, int data)
+{
+ struct saa7134_go7007 *saa = go->hpi_context;
+ struct saa7134_dev *dev = saa->dev;
+ int i;
+ u16 status_reg;
+
+#ifdef GO7007_HPI_DEBUG
+ pr_debug("saa7134-go7007: WriteInterrupt: %04x %04x\n", addr, data);
+#endif
+
+ for (i = 0; i < 100; ++i) {
+ gpio_read(dev, HPI_ADDR_INTR_STATUS, &status_reg);
+ if (!(status_reg & 0x0010))
+ break;
+ msleep(10);
+ }
+ if (i == 100) {
+ pr_err("saa7134-go7007: device is hung, status reg = 0x%04x\n",
+ status_reg);
+ return -1;
+ }
+ gpio_write(dev, HPI_ADDR_INTR_WR_PARAM, data);
+ gpio_write(dev, HPI_ADDR_INTR_WR_INDEX, addr);
+
+ return 0;
+}
+
+static int saa7134_go7007_read_interrupt(struct go7007 *go)
+{
+ struct saa7134_go7007 *saa = go->hpi_context;
+ struct saa7134_dev *dev = saa->dev;
+
+ /* XXX we need to wait if there is no interrupt available */
+ go->interrupt_available = 1;
+ gpio_read(dev, HPI_ADDR_INTR_RET_VALUE, &go->interrupt_value);
+ gpio_read(dev, HPI_ADDR_INTR_RET_DATA, &go->interrupt_data);
+#ifdef GO7007_HPI_DEBUG
+ pr_debug("saa7134-go7007: ReadInterrupt: %04x %04x\n",
+ go->interrupt_value, go->interrupt_data);
+#endif
+ return 0;
+}
+
+static void saa7134_go7007_irq_ts_done(struct saa7134_dev *dev,
+ unsigned long status)
+{
+ struct go7007 *go = video_get_drvdata(dev->empress_dev);
+ struct saa7134_go7007 *saa = go->hpi_context;
+
+ if (!vb2_is_streaming(&go->vidq))
+ return;
+ if (0 != (status & 0x000f0000))
+ pr_debug("saa7134-go7007: irq: lost %ld\n",
+ (status >> 16) & 0x0f);
+ if (status & 0x100000) {
+ dma_sync_single_for_cpu(&dev->pci->dev,
+ saa->bottom_dma, PAGE_SIZE, DMA_FROM_DEVICE);
+ go7007_parse_video_stream(go, saa->bottom, PAGE_SIZE);
+ saa_writel(SAA7134_RS_BA2(5), saa->bottom_dma);
+ } else {
+ dma_sync_single_for_cpu(&dev->pci->dev,
+ saa->top_dma, PAGE_SIZE, DMA_FROM_DEVICE);
+ go7007_parse_video_stream(go, saa->top, PAGE_SIZE);
+ saa_writel(SAA7134_RS_BA1(5), saa->top_dma);
+ }
+}
+
+static int saa7134_go7007_stream_start(struct go7007 *go)
+{
+ struct saa7134_go7007 *saa = go->hpi_context;
+ struct saa7134_dev *dev = saa->dev;
+
+ saa->top_dma = dma_map_page(&dev->pci->dev, virt_to_page(saa->top),
+ 0, PAGE_SIZE, DMA_FROM_DEVICE);
+ if (dma_mapping_error(&dev->pci->dev, saa->top_dma))
+ return -ENOMEM;
+ saa->bottom_dma = dma_map_page(&dev->pci->dev,
+ virt_to_page(saa->bottom),
+ 0, PAGE_SIZE, DMA_FROM_DEVICE);
+ if (dma_mapping_error(&dev->pci->dev, saa->bottom_dma)) {
+ dma_unmap_page(&dev->pci->dev, saa->top_dma, PAGE_SIZE,
+ DMA_FROM_DEVICE);
+ return -ENOMEM;
+ }
+
+ saa_writel(SAA7134_VIDEO_PORT_CTRL0 >> 2, 0xA300B000);
+ saa_writel(SAA7134_VIDEO_PORT_CTRL4 >> 2, 0x40000200);
+
+ /* Set HPI interface for video */
+ saa_writeb(SAA7134_GPIO_GPMODE0, 0xff);
+ saa_writeb(SAA7134_GPIO_GPSTATUS0, HPI_ADDR_VIDEO_BUFFER);
+ saa_writeb(SAA7134_GPIO_GPSTATUS2, GPIO_COMMAND_ADDR);
+ saa_writeb(SAA7134_GPIO_GPMODE0, 0x00);
+
+ /* Enable TS interface */
+ saa_writeb(SAA7134_TS_PARALLEL, 0xe6);
+
+ /* Reset TS interface */
+ saa_setb(SAA7134_TS_SERIAL1, 0x01);
+ saa_clearb(SAA7134_TS_SERIAL1, 0x01);
+
+ /* Set up transfer block size */
+ saa_writeb(SAA7134_TS_PARALLEL_SERIAL, 128 - 1);
+ saa_writeb(SAA7134_TS_DMA0, ((PAGE_SIZE >> 7) - 1) & 0xff);
+ saa_writeb(SAA7134_TS_DMA1, (PAGE_SIZE >> 15) & 0xff);
+ saa_writeb(SAA7134_TS_DMA2, (PAGE_SIZE >> 31) & 0x3f);
+
+ /* Enable video streaming mode */
+ saa_writeb(SAA7134_GPIO_GPSTATUS2, GPIO_COMMAND_VIDEO);
+
+ saa_writel(SAA7134_RS_BA1(5), saa->top_dma);
+ saa_writel(SAA7134_RS_BA2(5), saa->bottom_dma);
+ saa_writel(SAA7134_RS_PITCH(5), 128);
+ saa_writel(SAA7134_RS_CONTROL(5), SAA7134_RS_CONTROL_BURST_MAX);
+
+ /* Enable TS FIFO */
+ saa_setl(SAA7134_MAIN_CTRL, SAA7134_MAIN_CTRL_TE5);
+
+ /* Enable DMA IRQ */
+ saa_setl(SAA7134_IRQ1,
+ SAA7134_IRQ1_INTE_RA2_1 | SAA7134_IRQ1_INTE_RA2_0);
+
+ return 0;
+}
+
+static int saa7134_go7007_stream_stop(struct go7007 *go)
+{
+ struct saa7134_go7007 *saa = go->hpi_context;
+ struct saa7134_dev *dev;
+
+ if (!saa)
+ return -EINVAL;
+ dev = saa->dev;
+ if (!dev)
+ return -EINVAL;
+
+ /* Shut down TS FIFO */
+ saa_clearl(SAA7134_MAIN_CTRL, SAA7134_MAIN_CTRL_TE5);
+
+ /* Disable DMA IRQ */
+ saa_clearl(SAA7134_IRQ1,
+ SAA7134_IRQ1_INTE_RA2_1 | SAA7134_IRQ1_INTE_RA2_0);
+
+ /* Disable TS interface */
+ saa_clearb(SAA7134_TS_PARALLEL, 0x80);
+
+ dma_unmap_page(&dev->pci->dev, saa->top_dma, PAGE_SIZE,
+ DMA_FROM_DEVICE);
+ dma_unmap_page(&dev->pci->dev, saa->bottom_dma, PAGE_SIZE,
+ DMA_FROM_DEVICE);
+
+ return 0;
+}
+
+static int saa7134_go7007_send_firmware(struct go7007 *go, u8 *data, int len)
+{
+ struct saa7134_go7007 *saa = go->hpi_context;
+ struct saa7134_dev *dev = saa->dev;
+ u16 status_reg;
+ int i;
+
+#ifdef GO7007_HPI_DEBUG
+ pr_debug("saa7134-go7007: DownloadBuffer sending %d bytes\n", len);
+#endif
+
+ while (len > 0) {
+ i = len > 64 ? 64 : len;
+ saa_writeb(SAA7134_GPIO_GPMODE0, 0xff);
+ saa_writeb(SAA7134_GPIO_GPSTATUS0, HPI_ADDR_INIT_BUFFER);
+ saa_writeb(SAA7134_GPIO_GPSTATUS2, GPIO_COMMAND_ADDR);
+ saa_writeb(SAA7134_GPIO_GPSTATUS2, GPIO_COMMAND_IDLE);
+ while (i-- > 0) {
+ saa_writeb(SAA7134_GPIO_GPSTATUS0, *data);
+ saa_writeb(SAA7134_GPIO_GPSTATUS2, GPIO_COMMAND_WRITE);
+ saa_writeb(SAA7134_GPIO_GPSTATUS2, GPIO_COMMAND_IDLE);
+ ++data;
+ --len;
+ }
+ for (i = 0; i < 100; ++i) {
+ gpio_read(dev, HPI_ADDR_INTR_STATUS, &status_reg);
+ if (!(status_reg & 0x0002))
+ break;
+ }
+ if (i == 100) {
+ pr_err("saa7134-go7007: device is hung, status reg = 0x%04x\n",
+ status_reg);
+ return -1;
+ }
+ }
+ return 0;
+}
+
+static const struct go7007_hpi_ops saa7134_go7007_hpi_ops = {
+ .interface_reset = saa7134_go7007_interface_reset,
+ .write_interrupt = saa7134_go7007_write_interrupt,
+ .read_interrupt = saa7134_go7007_read_interrupt,
+ .stream_start = saa7134_go7007_stream_start,
+ .stream_stop = saa7134_go7007_stream_stop,
+ .send_firmware = saa7134_go7007_send_firmware,
+};
+MODULE_FIRMWARE("go7007/go7007tv.bin");
+
+/* --------------------------------------------------------------------------*/
+
+static int saa7134_go7007_s_std(struct v4l2_subdev *sd, v4l2_std_id norm)
+{
+#if 0
+ struct saa7134_go7007 *saa = container_of(sd, struct saa7134_go7007, sd);
+ struct saa7134_dev *dev = saa->dev;
+
+ return saa7134_s_std_internal(dev, NULL, norm);
+#else
+ return 0;
+#endif
+}
+
+static const struct v4l2_subdev_video_ops saa7134_go7007_video_ops = {
+ .s_std = saa7134_go7007_s_std,
+};
+
+static const struct v4l2_subdev_ops saa7134_go7007_sd_ops = {
+ .video = &saa7134_go7007_video_ops,
+};
+
+/* --------------------------------------------------------------------------*/
+
+
+/********************* Add/remove functions *********************/
+
+static int saa7134_go7007_init(struct saa7134_dev *dev)
+{
+ struct go7007 *go;
+ struct saa7134_go7007 *saa;
+ struct v4l2_subdev *sd;
+
+ pr_debug("saa7134-go7007: probing new SAA713X board\n");
+
+ go = go7007_alloc(&board_voyager, &dev->pci->dev);
+ if (go == NULL)
+ return -ENOMEM;
+
+ saa = kzalloc(sizeof(struct saa7134_go7007), GFP_KERNEL);
+ if (saa == NULL) {
+ kfree(go);
+ return -ENOMEM;
+ }
+
+ go->board_id = GO7007_BOARDID_PCI_VOYAGER;
+ snprintf(go->bus_info, sizeof(go->bus_info), "PCI:%s", pci_name(dev->pci));
+ strscpy(go->name, saa7134_boards[dev->board].name, sizeof(go->name));
+ go->hpi_ops = &saa7134_go7007_hpi_ops;
+ go->hpi_context = saa;
+ saa->dev = dev;
+
+ /* Init the subdevice interface */
+ sd = &saa->sd;
+ v4l2_subdev_init(sd, &saa7134_go7007_sd_ops);
+ v4l2_set_subdevdata(sd, saa);
+ strscpy(sd->name, "saa7134-go7007", sizeof(sd->name));
+
+ /* Allocate a couple pages for receiving the compressed stream */
+ saa->top = (u8 *)get_zeroed_page(GFP_KERNEL);
+ if (!saa->top)
+ goto allocfail;
+ saa->bottom = (u8 *)get_zeroed_page(GFP_KERNEL);
+ if (!saa->bottom)
+ goto allocfail;
+
+ /* Boot the GO7007 */
+ if (go7007_boot_encoder(go, go->board_info->flags &
+ GO7007_BOARD_USE_ONBOARD_I2C) < 0)
+ goto allocfail;
+
+ /* Do any final GO7007 initialization, then register the
+ * V4L2 and ALSA interfaces */
+ if (go7007_register_encoder(go, go->board_info->num_i2c_devs) < 0)
+ goto allocfail;
+
+ /* Register the subdevice interface with the go7007 device */
+ if (v4l2_device_register_subdev(&go->v4l2_dev, sd) < 0)
+ pr_info("saa7134-go7007: register subdev failed\n");
+
+ dev->empress_dev = &go->vdev;
+
+ go->status = STATUS_ONLINE;
+ return 0;
+
+allocfail:
+ if (saa->top)
+ free_page((unsigned long)saa->top);
+ if (saa->bottom)
+ free_page((unsigned long)saa->bottom);
+ kfree(saa);
+ kfree(go);
+ return -ENOMEM;
+}
+
+static int saa7134_go7007_fini(struct saa7134_dev *dev)
+{
+ struct go7007 *go;
+ struct saa7134_go7007 *saa;
+
+ if (NULL == dev->empress_dev)
+ return 0;
+
+ go = video_get_drvdata(dev->empress_dev);
+ if (go->audio_enabled)
+ go7007_snd_remove(go);
+
+ saa = go->hpi_context;
+ go->status = STATUS_SHUTDOWN;
+ free_page((unsigned long)saa->top);
+ free_page((unsigned long)saa->bottom);
+ v4l2_device_unregister_subdev(&saa->sd);
+ kfree(saa);
+ vb2_video_unregister_device(&go->vdev);
+
+ v4l2_device_put(&go->v4l2_dev);
+ dev->empress_dev = NULL;
+
+ return 0;
+}
+
+static struct saa7134_mpeg_ops saa7134_go7007_ops = {
+ .type = SAA7134_MPEG_GO7007,
+ .init = saa7134_go7007_init,
+ .fini = saa7134_go7007_fini,
+ .irq_ts_done = saa7134_go7007_irq_ts_done,
+};
+
+static int __init saa7134_go7007_mod_init(void)
+{
+ return saa7134_ts_register(&saa7134_go7007_ops);
+}
+
+static void __exit saa7134_go7007_mod_cleanup(void)
+{
+ saa7134_ts_unregister(&saa7134_go7007_ops);
+}
+
+module_init(saa7134_go7007_mod_init);
+module_exit(saa7134_go7007_mod_cleanup);
+
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/media/pci/saa7134/saa7134-i2c.c b/drivers/media/pci/saa7134/saa7134-i2c.c
new file mode 100644
index 0000000000..04e8576537
--- /dev/null
+++ b/drivers/media/pci/saa7134/saa7134-i2c.c
@@ -0,0 +1,456 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ *
+ * device driver for philips saa7134 based TV cards
+ * i2c interface support
+ *
+ * (c) 2001,02 Gerd Knorr <kraxel@bytesex.org> [SuSE Labs]
+ */
+
+#include "saa7134.h"
+#include "saa7134-reg.h"
+
+#include <linux/init.h>
+#include <linux/list.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+
+#include <media/v4l2-common.h>
+
+/* ----------------------------------------------------------- */
+
+static unsigned int i2c_debug;
+module_param(i2c_debug, int, 0644);
+MODULE_PARM_DESC(i2c_debug,"enable debug messages [i2c]");
+
+static unsigned int i2c_scan;
+module_param(i2c_scan, int, 0444);
+MODULE_PARM_DESC(i2c_scan,"scan i2c bus at insmod time");
+
+#define i2c_dbg(level, fmt, arg...) do { \
+ if (i2c_debug == level) \
+ printk(KERN_DEBUG pr_fmt("i2c: " fmt), ## arg); \
+ } while (0)
+
+#define i2c_cont(level, fmt, arg...) do { \
+ if (i2c_debug == level) \
+ pr_cont(fmt, ## arg); \
+ } while (0)
+
+#define I2C_WAIT_DELAY 32
+#define I2C_WAIT_RETRY 16
+
+/* ----------------------------------------------------------- */
+
+static char *str_i2c_status[] = {
+ "IDLE", "DONE_STOP", "BUSY", "TO_SCL", "TO_ARB", "DONE_WRITE",
+ "DONE_READ", "DONE_WRITE_TO", "DONE_READ_TO", "NO_DEVICE",
+ "NO_ACKN", "BUS_ERR", "ARB_LOST", "SEQ_ERR", "ST_ERR", "SW_ERR"
+};
+
+enum i2c_status {
+ IDLE = 0, // no I2C command pending
+ DONE_STOP = 1, // I2C command done and STOP executed
+ BUSY = 2, // executing I2C command
+ TO_SCL = 3, // executing I2C command, time out on clock stretching
+ TO_ARB = 4, // time out on arbitration trial, still trying
+ DONE_WRITE = 5, // I2C command done and awaiting next write command
+ DONE_READ = 6, // I2C command done and awaiting next read command
+ DONE_WRITE_TO = 7, // see 5, and time out on status echo
+ DONE_READ_TO = 8, // see 6, and time out on status echo
+ NO_DEVICE = 9, // no acknowledge on device slave address
+ NO_ACKN = 10, // no acknowledge after data byte transfer
+ BUS_ERR = 11, // bus error
+ ARB_LOST = 12, // arbitration lost during transfer
+ SEQ_ERR = 13, // erroneous programming sequence
+ ST_ERR = 14, // wrong status echoing
+ SW_ERR = 15 // software error
+};
+
+static char *str_i2c_attr[] = {
+ "NOP", "STOP", "CONTINUE", "START"
+};
+
+enum i2c_attr {
+ NOP = 0, // no operation on I2C bus
+ STOP = 1, // stop condition, no associated byte transfer
+ CONTINUE = 2, // continue with byte transfer
+ START = 3 // start condition with byte transfer
+};
+
+static inline enum i2c_status i2c_get_status(struct saa7134_dev *dev)
+{
+ enum i2c_status status;
+
+ status = saa_readb(SAA7134_I2C_ATTR_STATUS) & 0x0f;
+ i2c_dbg(2, "i2c stat <= %s\n", str_i2c_status[status]);
+ return status;
+}
+
+static inline void i2c_set_status(struct saa7134_dev *dev,
+ enum i2c_status status)
+{
+ i2c_dbg(2, "i2c stat => %s\n", str_i2c_status[status]);
+ saa_andorb(SAA7134_I2C_ATTR_STATUS,0x0f,status);
+}
+
+static inline void i2c_set_attr(struct saa7134_dev *dev, enum i2c_attr attr)
+{
+ i2c_dbg(2, "i2c attr => %s\n", str_i2c_attr[attr]);
+ saa_andorb(SAA7134_I2C_ATTR_STATUS,0xc0,attr << 6);
+}
+
+static inline int i2c_is_error(enum i2c_status status)
+{
+ switch (status) {
+ case NO_DEVICE:
+ case NO_ACKN:
+ case BUS_ERR:
+ case ARB_LOST:
+ case SEQ_ERR:
+ case ST_ERR:
+ return true;
+ default:
+ return false;
+ }
+}
+
+static inline int i2c_is_idle(enum i2c_status status)
+{
+ switch (status) {
+ case IDLE:
+ case DONE_STOP:
+ return true;
+ default:
+ return false;
+ }
+}
+
+static inline int i2c_is_busy(enum i2c_status status)
+{
+ switch (status) {
+ case BUSY:
+ case TO_SCL:
+ case TO_ARB:
+ return true;
+ default:
+ return false;
+ }
+}
+
+static int i2c_is_busy_wait(struct saa7134_dev *dev)
+{
+ enum i2c_status status;
+ int count;
+
+ for (count = 0; count < I2C_WAIT_RETRY; count++) {
+ status = i2c_get_status(dev);
+ if (!i2c_is_busy(status))
+ break;
+ saa_wait(I2C_WAIT_DELAY);
+ }
+ if (I2C_WAIT_RETRY == count)
+ return false;
+ return true;
+}
+
+static int i2c_reset(struct saa7134_dev *dev)
+{
+ enum i2c_status status;
+ int count;
+
+ i2c_dbg(2, "i2c reset\n");
+ status = i2c_get_status(dev);
+ if (!i2c_is_error(status))
+ return true;
+ i2c_set_status(dev,status);
+
+ for (count = 0; count < I2C_WAIT_RETRY; count++) {
+ status = i2c_get_status(dev);
+ if (!i2c_is_error(status))
+ break;
+ udelay(I2C_WAIT_DELAY);
+ }
+ if (I2C_WAIT_RETRY == count)
+ return false;
+
+ if (!i2c_is_idle(status))
+ return false;
+
+ i2c_set_attr(dev,NOP);
+ return true;
+}
+
+static inline int i2c_send_byte(struct saa7134_dev *dev,
+ enum i2c_attr attr,
+ unsigned char data)
+{
+ enum i2c_status status;
+ __u32 dword;
+
+ /* have to write both attr + data in one 32bit word */
+ dword = saa_readl(SAA7134_I2C_ATTR_STATUS >> 2);
+ dword &= 0x0f;
+ dword |= (attr << 6);
+ dword |= ((__u32)data << 8);
+ dword |= 0x00 << 16; /* 100 kHz */
+// dword |= 0x40 << 16; /* 400 kHz */
+ dword |= 0xf0 << 24;
+ saa_writel(SAA7134_I2C_ATTR_STATUS >> 2, dword);
+ i2c_dbg(2, "i2c data => 0x%x\n", data);
+
+ if (!i2c_is_busy_wait(dev))
+ return -EIO;
+ status = i2c_get_status(dev);
+ if (i2c_is_error(status))
+ return -EIO;
+ return 0;
+}
+
+static inline int i2c_recv_byte(struct saa7134_dev *dev)
+{
+ enum i2c_status status;
+ unsigned char data;
+
+ i2c_set_attr(dev,CONTINUE);
+ if (!i2c_is_busy_wait(dev))
+ return -EIO;
+ status = i2c_get_status(dev);
+ if (i2c_is_error(status))
+ return -EIO;
+ data = saa_readb(SAA7134_I2C_DATA);
+ i2c_dbg(2, "i2c data <= 0x%x\n", data);
+ return data;
+}
+
+static int saa7134_i2c_xfer(struct i2c_adapter *i2c_adap,
+ struct i2c_msg *msgs, int num)
+{
+ struct saa7134_dev *dev = i2c_adap->algo_data;
+ enum i2c_status status;
+ unsigned char data;
+ int addr,rc,i,byte;
+
+ status = i2c_get_status(dev);
+ if (!i2c_is_idle(status))
+ if (!i2c_reset(dev))
+ return -EIO;
+
+ i2c_dbg(2, "start xfer\n");
+ i2c_dbg(1, "i2c xfer:");
+ for (i = 0; i < num; i++) {
+ if (!(msgs[i].flags & I2C_M_NOSTART) || 0 == i) {
+ /* send address */
+ i2c_dbg(2, "send address\n");
+ addr = msgs[i].addr << 1;
+ if (msgs[i].flags & I2C_M_RD)
+ addr |= 1;
+ if (i > 0 && msgs[i].flags &
+ I2C_M_RD && msgs[i].addr != 0x40 &&
+ msgs[i].addr != 0x41 &&
+ msgs[i].addr != 0x19) {
+ /* workaround for a saa7134 i2c bug
+ * needed to talk to the mt352 demux
+ * thanks to pinnacle for the hint */
+ int quirk = 0xfe;
+ i2c_cont(1, " [%02x quirk]", quirk);
+ i2c_send_byte(dev,START,quirk);
+ i2c_recv_byte(dev);
+ }
+ i2c_cont(1, " < %02x", addr);
+ rc = i2c_send_byte(dev,START,addr);
+ if (rc < 0)
+ goto err;
+ }
+ if (msgs[i].flags & I2C_M_RD) {
+ /* read bytes */
+ i2c_dbg(2, "read bytes\n");
+ for (byte = 0; byte < msgs[i].len; byte++) {
+ i2c_cont(1, " =");
+ rc = i2c_recv_byte(dev);
+ if (rc < 0)
+ goto err;
+ i2c_cont(1, "%02x", rc);
+ msgs[i].buf[byte] = rc;
+ }
+ /* discard mysterious extra byte when reading
+ from Samsung S5H1411. i2c bus gets error
+ if we do not. */
+ if (0x19 == msgs[i].addr) {
+ i2c_cont(1, " ?");
+ rc = i2c_recv_byte(dev);
+ if (rc < 0)
+ goto err;
+ i2c_cont(1, "%02x", rc);
+ }
+ } else {
+ /* write bytes */
+ i2c_dbg(2, "write bytes\n");
+ for (byte = 0; byte < msgs[i].len; byte++) {
+ data = msgs[i].buf[byte];
+ i2c_cont(1, " %02x", data);
+ rc = i2c_send_byte(dev,CONTINUE,data);
+ if (rc < 0)
+ goto err;
+ }
+ }
+ }
+ i2c_dbg(2, "xfer done\n");
+ i2c_cont(1, " >");
+ i2c_set_attr(dev,STOP);
+ rc = -EIO;
+ if (!i2c_is_busy_wait(dev))
+ goto err;
+ status = i2c_get_status(dev);
+ if (i2c_is_error(status))
+ goto err;
+ /* ensure that the bus is idle for at least one bit slot */
+ msleep(1);
+
+ i2c_cont(1, "\n");
+ return num;
+ err:
+ if (1 == i2c_debug) {
+ status = i2c_get_status(dev);
+ i2c_cont(1, " ERROR: %s\n", str_i2c_status[status]);
+ }
+ return rc;
+}
+
+/* ----------------------------------------------------------- */
+
+static u32 functionality(struct i2c_adapter *adap)
+{
+ return I2C_FUNC_SMBUS_EMUL;
+}
+
+static const struct i2c_algorithm saa7134_algo = {
+ .master_xfer = saa7134_i2c_xfer,
+ .functionality = functionality,
+};
+
+static const struct i2c_adapter saa7134_adap_template = {
+ .owner = THIS_MODULE,
+ .name = "saa7134",
+ .algo = &saa7134_algo,
+};
+
+static const struct i2c_client saa7134_client_template = {
+ .name = "saa7134 internal",
+};
+
+/* ----------------------------------------------------------- */
+
+/*
+ * On Medion 7134 reading the SAA7134 chip config EEPROM needs DVB-T
+ * demod i2c gate closed due to an address clash between this EEPROM
+ * and the demod one.
+ */
+static void saa7134_i2c_eeprom_md7134_gate(struct saa7134_dev *dev)
+{
+ u8 subaddr = 0x7, dmdregval;
+ u8 data[2];
+ int ret;
+ struct i2c_msg i2cgatemsg_r[] = { {.addr = 0x08, .flags = 0,
+ .buf = &subaddr, .len = 1},
+ {.addr = 0x08,
+ .flags = I2C_M_RD,
+ .buf = &dmdregval, .len = 1}
+ };
+ struct i2c_msg i2cgatemsg_w[] = { {.addr = 0x08, .flags = 0,
+ .buf = data, .len = 2} };
+
+ ret = i2c_transfer(&dev->i2c_adap, i2cgatemsg_r, 2);
+ if ((ret == 2) && (dmdregval & 0x2)) {
+ pr_debug("%s: DVB-T demod i2c gate was left open\n",
+ dev->name);
+
+ data[0] = subaddr;
+ data[1] = (dmdregval & ~0x2);
+ if (i2c_transfer(&dev->i2c_adap, i2cgatemsg_w, 1) != 1)
+ pr_err("%s: EEPROM i2c gate close failure\n",
+ dev->name);
+ }
+}
+
+static int
+saa7134_i2c_eeprom(struct saa7134_dev *dev, unsigned char *eedata, int len)
+{
+ unsigned char buf;
+ int i,err;
+
+ if (dev->board == SAA7134_BOARD_MD7134)
+ saa7134_i2c_eeprom_md7134_gate(dev);
+
+ dev->i2c_client.addr = 0xa0 >> 1;
+ buf = 0;
+ if (1 != (err = i2c_master_send(&dev->i2c_client,&buf,1))) {
+ pr_info("%s: Huh, no eeprom present (err=%d)?\n",
+ dev->name,err);
+ return -1;
+ }
+ if (len != (err = i2c_master_recv(&dev->i2c_client,eedata,len))) {
+ pr_warn("%s: i2c eeprom read error (err=%d)\n",
+ dev->name,err);
+ return -1;
+ }
+
+ for (i = 0; i < len; i += 16) {
+ int size = (len - i) > 16 ? 16 : len - i;
+
+ pr_info("i2c eeprom %02x: %*ph\n", i, size, &eedata[i]);
+ }
+
+ return 0;
+}
+
+static char *i2c_devs[128] = {
+ [ 0x20 ] = "mpeg encoder (saa6752hs)",
+ [ 0xa0 >> 1 ] = "eeprom",
+ [ 0xc0 >> 1 ] = "tuner (analog)",
+ [ 0x86 >> 1 ] = "tda9887",
+ [ 0x5a >> 1 ] = "remote control",
+};
+
+static void do_i2c_scan(struct i2c_client *c)
+{
+ unsigned char buf;
+ int i,rc;
+
+ for (i = 0; i < ARRAY_SIZE(i2c_devs); i++) {
+ c->addr = i;
+ rc = i2c_master_recv(c,&buf,0);
+ if (rc < 0)
+ continue;
+ pr_info("i2c scan: found device @ 0x%x [%s]\n",
+ i << 1, i2c_devs[i] ? i2c_devs[i] : "???");
+ }
+}
+
+int saa7134_i2c_register(struct saa7134_dev *dev)
+{
+ dev->i2c_adap = saa7134_adap_template;
+ dev->i2c_adap.dev.parent = &dev->pci->dev;
+ strscpy(dev->i2c_adap.name, dev->name, sizeof(dev->i2c_adap.name));
+ dev->i2c_adap.algo_data = dev;
+ i2c_set_adapdata(&dev->i2c_adap, &dev->v4l2_dev);
+ i2c_add_adapter(&dev->i2c_adap);
+
+ dev->i2c_client = saa7134_client_template;
+ dev->i2c_client.adapter = &dev->i2c_adap;
+
+ saa7134_i2c_eeprom(dev,dev->eedata,sizeof(dev->eedata));
+ if (i2c_scan)
+ do_i2c_scan(&dev->i2c_client);
+
+ /* Instantiate the IR receiver device, if present */
+ saa7134_probe_i2c_ir(dev);
+ return 0;
+}
+
+int saa7134_i2c_unregister(struct saa7134_dev *dev)
+{
+ i2c_del_adapter(&dev->i2c_adap);
+ return 0;
+}
diff --git a/drivers/media/pci/saa7134/saa7134-input.c b/drivers/media/pci/saa7134/saa7134-input.c
new file mode 100644
index 0000000000..8610eb473b
--- /dev/null
+++ b/drivers/media/pci/saa7134/saa7134-input.c
@@ -0,0 +1,1000 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ *
+ * handle saa7134 IR remotes via linux kernel input layer.
+ */
+
+#include "saa7134.h"
+#include "saa7134-reg.h"
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/slab.h>
+
+#define MODULE_NAME "saa7134"
+
+static unsigned int disable_ir;
+module_param(disable_ir, int, 0444);
+MODULE_PARM_DESC(disable_ir,"disable infrared remote support");
+
+static unsigned int ir_debug;
+module_param(ir_debug, int, 0644);
+MODULE_PARM_DESC(ir_debug,"enable debug messages [IR]");
+
+static int pinnacle_remote;
+module_param(pinnacle_remote, int, 0644); /* Choose Pinnacle PCTV remote */
+MODULE_PARM_DESC(pinnacle_remote, "Specify Pinnacle PCTV remote: 0=coloured, 1=grey (defaults to 0)");
+
+#define input_dbg(fmt, arg...) do { \
+ if (ir_debug) \
+ printk(KERN_DEBUG pr_fmt("input: " fmt), ## arg); \
+ } while (0)
+#define ir_dbg(ir, fmt, arg...) do { \
+ if (ir_debug) \
+ printk(KERN_DEBUG pr_fmt("ir %s: " fmt), ir->rc->device_name, \
+ ## arg); \
+ } while (0)
+
+/* Helper function for raw decoding at GPIO16 or GPIO18 */
+static int saa7134_raw_decode_irq(struct saa7134_dev *dev);
+
+/* -------------------- GPIO generic keycode builder -------------------- */
+
+static int build_key(struct saa7134_dev *dev)
+{
+ struct saa7134_card_ir *ir = dev->remote;
+ u32 gpio, data;
+
+ /* here comes the additional handshake steps for some cards */
+ switch (dev->board) {
+ case SAA7134_BOARD_GOTVIEW_7135:
+ saa_setb(SAA7134_GPIO_GPSTATUS1, 0x80);
+ saa_clearb(SAA7134_GPIO_GPSTATUS1, 0x80);
+ break;
+ }
+ /* rising SAA7134_GPIO_GPRESCAN reads the status */
+ saa_clearb(SAA7134_GPIO_GPMODE3,SAA7134_GPIO_GPRESCAN);
+ saa_setb(SAA7134_GPIO_GPMODE3,SAA7134_GPIO_GPRESCAN);
+
+ gpio = saa_readl(SAA7134_GPIO_GPSTATUS0 >> 2);
+ if (ir->polling) {
+ if (ir->last_gpio == gpio)
+ return 0;
+ ir->last_gpio = gpio;
+ }
+
+ data = ir_extract_bits(gpio, ir->mask_keycode);
+ input_dbg("build_key gpio=0x%x mask=0x%x data=%d\n",
+ gpio, ir->mask_keycode, data);
+
+ switch (dev->board) {
+ case SAA7134_BOARD_KWORLD_PLUS_TV_ANALOG:
+ if (data == ir->mask_keycode)
+ rc_keyup(ir->dev);
+ else
+ rc_keydown_notimeout(ir->dev, RC_PROTO_UNKNOWN, data,
+ 0);
+ return 0;
+ }
+
+ if (ir->polling) {
+ if ((ir->mask_keydown && (0 != (gpio & ir->mask_keydown))) ||
+ (ir->mask_keyup && (0 == (gpio & ir->mask_keyup)))) {
+ rc_keydown_notimeout(ir->dev, RC_PROTO_UNKNOWN, data,
+ 0);
+ } else {
+ rc_keyup(ir->dev);
+ }
+ }
+ else { /* IRQ driven mode - handle key press and release in one go */
+ if ((ir->mask_keydown && (0 != (gpio & ir->mask_keydown))) ||
+ (ir->mask_keyup && (0 == (gpio & ir->mask_keyup)))) {
+ rc_keydown_notimeout(ir->dev, RC_PROTO_UNKNOWN, data,
+ 0);
+ rc_keyup(ir->dev);
+ }
+ }
+
+ return 0;
+}
+
+/* --------------------- Chip specific I2C key builders ----------------- */
+
+static int get_key_flydvb_trio(struct IR_i2c *ir, enum rc_proto *protocol,
+ u32 *scancode, u8 *toggle)
+{
+ int gpio, rc;
+ int attempt = 0;
+ unsigned char b;
+
+ /* We need this to access GPI Used by the saa_readl macro. */
+ struct saa7134_dev *dev = ir->c->adapter->algo_data;
+
+ if (dev == NULL) {
+ ir_dbg(ir, "get_key_flydvb_trio: ir->c->adapter->algo_data is NULL!\n");
+ return -EIO;
+ }
+
+ /* rising SAA7134_GPIGPRESCAN reads the status */
+ saa_clearb(SAA7134_GPIO_GPMODE3, SAA7134_GPIO_GPRESCAN);
+ saa_setb(SAA7134_GPIO_GPMODE3, SAA7134_GPIO_GPRESCAN);
+
+ gpio = saa_readl(SAA7134_GPIO_GPSTATUS0 >> 2);
+
+ if (0x40000 & ~gpio)
+ return 0; /* No button press */
+
+ /* poll IR chip */
+ /* weak up the IR chip */
+ b = 0;
+
+ while (1 != i2c_master_send(ir->c, &b, 1)) {
+ if ((attempt++) < 10) {
+ /*
+ * wait a bit for next attempt -
+ * I don't know how make it better
+ */
+ msleep(10);
+ continue;
+ }
+ ir_dbg(ir, "send wake up byte to pic16C505 (IR chip)failed %dx\n",
+ attempt);
+ return -EIO;
+ }
+ rc = i2c_master_recv(ir->c, &b, 1);
+ if (rc != 1) {
+ ir_dbg(ir, "read error\n");
+ if (rc < 0)
+ return rc;
+ return -EIO;
+ }
+
+ *protocol = RC_PROTO_UNKNOWN;
+ *scancode = b;
+ *toggle = 0;
+ return 1;
+}
+
+static int get_key_msi_tvanywhere_plus(struct IR_i2c *ir,
+ enum rc_proto *protocol,
+ u32 *scancode, u8 *toggle)
+{
+ unsigned char b;
+ int gpio, rc;
+
+ /* <dev> is needed to access GPIO. Used by the saa_readl macro. */
+ struct saa7134_dev *dev = ir->c->adapter->algo_data;
+ if (dev == NULL) {
+ ir_dbg(ir, "get_key_msi_tvanywhere_plus: ir->c->adapter->algo_data is NULL!\n");
+ return -EIO;
+ }
+
+ /* rising SAA7134_GPIO_GPRESCAN reads the status */
+
+ saa_clearb(SAA7134_GPIO_GPMODE3, SAA7134_GPIO_GPRESCAN);
+ saa_setb(SAA7134_GPIO_GPMODE3, SAA7134_GPIO_GPRESCAN);
+
+ gpio = saa_readl(SAA7134_GPIO_GPSTATUS0 >> 2);
+
+ /* GPIO&0x40 is pulsed low when a button is pressed. Don't do
+ I2C receive if gpio&0x40 is not low. */
+
+ if (gpio & 0x40)
+ return 0; /* No button press */
+
+ /* GPIO says there is a button press. Get it. */
+
+ rc = i2c_master_recv(ir->c, &b, 1);
+ if (rc != 1) {
+ ir_dbg(ir, "read error\n");
+ if (rc < 0)
+ return rc;
+ return -EIO;
+ }
+
+ /* No button press */
+
+ if (b == 0xff)
+ return 0;
+
+ /* Button pressed */
+
+ input_dbg("get_key_msi_tvanywhere_plus: Key = 0x%02X\n", b);
+ *protocol = RC_PROTO_UNKNOWN;
+ *scancode = b;
+ *toggle = 0;
+ return 1;
+}
+
+/* copied and modified from get_key_msi_tvanywhere_plus() */
+static int get_key_kworld_pc150u(struct IR_i2c *ir, enum rc_proto *protocol,
+ u32 *scancode, u8 *toggle)
+{
+ unsigned char b;
+ unsigned int gpio;
+ int rc;
+
+ /* <dev> is needed to access GPIO. Used by the saa_readl macro. */
+ struct saa7134_dev *dev = ir->c->adapter->algo_data;
+ if (dev == NULL) {
+ ir_dbg(ir, "get_key_kworld_pc150u: ir->c->adapter->algo_data is NULL!\n");
+ return -EIO;
+ }
+
+ /* rising SAA7134_GPIO_GPRESCAN reads the status */
+
+ saa_clearb(SAA7134_GPIO_GPMODE3, SAA7134_GPIO_GPRESCAN);
+ saa_setb(SAA7134_GPIO_GPMODE3, SAA7134_GPIO_GPRESCAN);
+
+ gpio = saa_readl(SAA7134_GPIO_GPSTATUS0 >> 2);
+
+ /* GPIO&0x100 is pulsed low when a button is pressed. Don't do
+ I2C receive if gpio&0x100 is not low. */
+
+ if (gpio & 0x100)
+ return 0; /* No button press */
+
+ /* GPIO says there is a button press. Get it. */
+
+ rc = i2c_master_recv(ir->c, &b, 1);
+ if (rc != 1) {
+ ir_dbg(ir, "read error\n");
+ if (rc < 0)
+ return rc;
+ return -EIO;
+ }
+
+ /* No button press */
+
+ if (b == 0xff)
+ return 0;
+
+ /* Button pressed */
+
+ input_dbg("get_key_kworld_pc150u: Key = 0x%02X\n", b);
+ *protocol = RC_PROTO_UNKNOWN;
+ *scancode = b;
+ *toggle = 0;
+ return 1;
+}
+
+static int get_key_purpletv(struct IR_i2c *ir, enum rc_proto *protocol,
+ u32 *scancode, u8 *toggle)
+{
+ int rc;
+ unsigned char b;
+
+ /* poll IR chip */
+ rc = i2c_master_recv(ir->c, &b, 1);
+ if (rc != 1) {
+ ir_dbg(ir, "read error\n");
+ if (rc < 0)
+ return rc;
+ return -EIO;
+ }
+
+ /* no button press */
+ if (b==0)
+ return 0;
+
+ /* repeating */
+ if (b & 0x80)
+ return 1;
+
+ *protocol = RC_PROTO_UNKNOWN;
+ *scancode = b;
+ *toggle = 0;
+ return 1;
+}
+
+static int get_key_beholdm6xx(struct IR_i2c *ir, enum rc_proto *protocol,
+ u32 *scancode, u8 *toggle)
+{
+ int rc;
+ unsigned char data[12];
+ u32 gpio;
+
+ struct saa7134_dev *dev = ir->c->adapter->algo_data;
+
+ /* rising SAA7134_GPIO_GPRESCAN reads the status */
+ saa_clearb(SAA7134_GPIO_GPMODE3, SAA7134_GPIO_GPRESCAN);
+ saa_setb(SAA7134_GPIO_GPMODE3, SAA7134_GPIO_GPRESCAN);
+
+ gpio = saa_readl(SAA7134_GPIO_GPSTATUS0 >> 2);
+
+ if (0x400000 & ~gpio)
+ return 0; /* No button press */
+
+ ir->c->addr = 0x5a >> 1;
+
+ rc = i2c_master_recv(ir->c, data, 12);
+ if (rc != 12) {
+ ir_dbg(ir, "read error\n");
+ if (rc < 0)
+ return rc;
+ return -EIO;
+ }
+
+ if (data[9] != (unsigned char)(~data[8]))
+ return 0;
+
+ *protocol = RC_PROTO_NECX;
+ *scancode = RC_SCANCODE_NECX(data[11] << 8 | data[10], data[9]);
+ *toggle = 0;
+ return 1;
+}
+
+/* Common (grey or coloured) pinnacle PCTV remote handling
+ *
+ */
+static int get_key_pinnacle(struct IR_i2c *ir, enum rc_proto *protocol,
+ u32 *scancode, u8 *toggle, int parity_offset,
+ int marker, int code_modulo)
+{
+ int rc;
+ unsigned char b[4];
+ unsigned int start = 0,parity = 0,code = 0;
+
+ /* poll IR chip */
+ rc = i2c_master_recv(ir->c, b, 4);
+ if (rc != 4) {
+ ir_dbg(ir, "read error\n");
+ if (rc < 0)
+ return rc;
+ return -EIO;
+ }
+
+ for (start = 0; start < ARRAY_SIZE(b); start++) {
+ if (b[start] == marker) {
+ code=b[(start+parity_offset + 1) % 4];
+ parity=b[(start+parity_offset) % 4];
+ }
+ }
+
+ /* Empty Request */
+ if (parity == 0)
+ return 0;
+
+ /* Repeating... */
+ if (ir->old == parity)
+ return 0;
+
+ ir->old = parity;
+
+ /* drop special codes when a key is held down a long time for the grey controller
+ In this case, the second bit of the code is asserted */
+ if (marker == 0xfe && (code & 0x40))
+ return 0;
+
+ code %= code_modulo;
+
+ *protocol = RC_PROTO_UNKNOWN;
+ *scancode = code;
+ *toggle = 0;
+
+ ir_dbg(ir, "Pinnacle PCTV key %02x\n", code);
+ return 1;
+}
+
+/* The grey pinnacle PCTV remote
+ *
+ * There are one issue with this remote:
+ * - I2c packet does not change when the same key is pressed quickly. The workaround
+ * is to hold down each key for about half a second, so that another code is generated
+ * in the i2c packet, and the function can distinguish key presses.
+ *
+ * Sylvain Pasche <sylvain.pasche@gmail.com>
+ */
+static int get_key_pinnacle_grey(struct IR_i2c *ir, enum rc_proto *protocol,
+ u32 *scancode, u8 *toggle)
+{
+
+ return get_key_pinnacle(ir, protocol, scancode, toggle, 1, 0xfe, 0xff);
+}
+
+
+/* The new pinnacle PCTV remote (with the colored buttons)
+ *
+ * Ricardo Cerqueira <v4l@cerqueira.org>
+ */
+static int get_key_pinnacle_color(struct IR_i2c *ir, enum rc_proto *protocol,
+ u32 *scancode, u8 *toggle)
+{
+ /* code_modulo parameter (0x88) is used to reduce code value to fit inside IR_KEYTAB_SIZE
+ *
+ * this is the only value that results in 42 unique
+ * codes < 128
+ */
+
+ return get_key_pinnacle(ir, protocol, scancode, toggle, 2, 0x80, 0x88);
+}
+
+void saa7134_input_irq(struct saa7134_dev *dev)
+{
+ struct saa7134_card_ir *ir;
+
+ if (!dev || !dev->remote)
+ return;
+
+ ir = dev->remote;
+ if (!ir->running)
+ return;
+
+ if (!ir->polling && !ir->raw_decode) {
+ build_key(dev);
+ } else if (ir->raw_decode) {
+ saa7134_raw_decode_irq(dev);
+ }
+}
+
+static void saa7134_input_timer(struct timer_list *t)
+{
+ struct saa7134_card_ir *ir = from_timer(ir, t, timer);
+ struct saa7134_dev *dev = ir->dev->priv;
+
+ build_key(dev);
+ mod_timer(&ir->timer, jiffies + msecs_to_jiffies(ir->polling));
+}
+
+int saa7134_ir_open(struct rc_dev *rc)
+{
+ struct saa7134_dev *dev = rc->priv;
+ struct saa7134_card_ir *ir = dev->remote;
+
+ /* Moved here from saa7134_input_init1() because the latter
+ * is not called on device resume */
+ switch (dev->board) {
+ case SAA7134_BOARD_MD2819:
+ case SAA7134_BOARD_KWORLD_VSTREAM_XPERT:
+ case SAA7134_BOARD_AVERMEDIA_305:
+ case SAA7134_BOARD_AVERMEDIA_307:
+ case SAA7134_BOARD_AVERMEDIA_505:
+ case SAA7134_BOARD_AVERMEDIA_STUDIO_305:
+ case SAA7134_BOARD_AVERMEDIA_STUDIO_505:
+ case SAA7134_BOARD_AVERMEDIA_STUDIO_307:
+ case SAA7134_BOARD_AVERMEDIA_STUDIO_507:
+ case SAA7134_BOARD_AVERMEDIA_STUDIO_507UA:
+ case SAA7134_BOARD_AVERMEDIA_GO_007_FM:
+ case SAA7134_BOARD_AVERMEDIA_M102:
+ case SAA7134_BOARD_AVERMEDIA_GO_007_FM_PLUS:
+ /* Without this we won't receive key up events */
+ saa_setb(SAA7134_GPIO_GPMODE0, 0x4);
+ saa_setb(SAA7134_GPIO_GPSTATUS0, 0x4);
+ break;
+ case SAA7134_BOARD_AVERMEDIA_777:
+ case SAA7134_BOARD_AVERMEDIA_A16AR:
+ /* Without this we won't receive key up events */
+ saa_setb(SAA7134_GPIO_GPMODE1, 0x1);
+ saa_setb(SAA7134_GPIO_GPSTATUS1, 0x1);
+ break;
+ case SAA7134_BOARD_AVERMEDIA_A16D:
+ /* Without this we won't receive key up events */
+ saa_setb(SAA7134_GPIO_GPMODE1, 0x1);
+ saa_setb(SAA7134_GPIO_GPSTATUS1, 0x1);
+ break;
+ case SAA7134_BOARD_GOTVIEW_7135:
+ saa_setb(SAA7134_GPIO_GPMODE1, 0x80);
+ break;
+ }
+
+ ir->running = true;
+
+ if (ir->polling) {
+ timer_setup(&ir->timer, saa7134_input_timer, 0);
+ ir->timer.expires = jiffies + HZ;
+ add_timer(&ir->timer);
+ }
+
+ return 0;
+}
+
+void saa7134_ir_close(struct rc_dev *rc)
+{
+ struct saa7134_dev *dev = rc->priv;
+ struct saa7134_card_ir *ir = dev->remote;
+
+ if (ir->polling)
+ del_timer_sync(&ir->timer);
+
+ ir->running = false;
+}
+
+int saa7134_input_init1(struct saa7134_dev *dev)
+{
+ struct saa7134_card_ir *ir;
+ struct rc_dev *rc;
+ char *ir_codes = NULL;
+ u32 mask_keycode = 0;
+ u32 mask_keydown = 0;
+ u32 mask_keyup = 0;
+ unsigned polling = 0;
+ bool raw_decode = false;
+ int err;
+
+ if (dev->has_remote != SAA7134_REMOTE_GPIO)
+ return -ENODEV;
+ if (disable_ir)
+ return -ENODEV;
+
+ /* detect & configure */
+ switch (dev->board) {
+ case SAA7134_BOARD_FLYVIDEO2000:
+ case SAA7134_BOARD_FLYVIDEO3000:
+ case SAA7134_BOARD_FLYTVPLATINUM_FM:
+ case SAA7134_BOARD_FLYTVPLATINUM_MINI2:
+ case SAA7134_BOARD_ROVERMEDIA_LINK_PRO_FM:
+ ir_codes = RC_MAP_FLYVIDEO;
+ mask_keycode = 0xEC00000;
+ mask_keydown = 0x0040000;
+ break;
+ case SAA7134_BOARD_CINERGY400:
+ case SAA7134_BOARD_CINERGY600:
+ case SAA7134_BOARD_CINERGY600_MK3:
+ ir_codes = RC_MAP_CINERGY;
+ mask_keycode = 0x00003f;
+ mask_keyup = 0x040000;
+ break;
+ case SAA7134_BOARD_ECS_TVP3XP:
+ case SAA7134_BOARD_ECS_TVP3XP_4CB5:
+ ir_codes = RC_MAP_EZTV;
+ mask_keycode = 0x00017c;
+ mask_keyup = 0x000002;
+ polling = 50; // ms
+ break;
+ case SAA7134_BOARD_KWORLD_XPERT:
+ case SAA7134_BOARD_AVACSSMARTTV:
+ ir_codes = RC_MAP_PIXELVIEW;
+ mask_keycode = 0x00001F;
+ mask_keyup = 0x000020;
+ polling = 50; // ms
+ break;
+ case SAA7134_BOARD_MD2819:
+ case SAA7134_BOARD_KWORLD_VSTREAM_XPERT:
+ case SAA7134_BOARD_AVERMEDIA_305:
+ case SAA7134_BOARD_AVERMEDIA_307:
+ case SAA7134_BOARD_AVERMEDIA_505:
+ case SAA7134_BOARD_AVERMEDIA_STUDIO_305:
+ case SAA7134_BOARD_AVERMEDIA_STUDIO_505:
+ case SAA7134_BOARD_AVERMEDIA_STUDIO_307:
+ case SAA7134_BOARD_AVERMEDIA_STUDIO_507:
+ case SAA7134_BOARD_AVERMEDIA_STUDIO_507UA:
+ case SAA7134_BOARD_AVERMEDIA_GO_007_FM:
+ case SAA7134_BOARD_AVERMEDIA_M102:
+ case SAA7134_BOARD_AVERMEDIA_GO_007_FM_PLUS:
+ ir_codes = RC_MAP_AVERMEDIA;
+ mask_keycode = 0x0007C8;
+ mask_keydown = 0x000010;
+ polling = 50; // ms
+ /* GPIO stuff moved to saa7134_ir_open() */
+ break;
+ case SAA7134_BOARD_AVERMEDIA_M135A:
+ ir_codes = RC_MAP_AVERMEDIA_M135A;
+ mask_keydown = 0x0040000; /* Enable GPIO18 line on both edges */
+ mask_keyup = 0x0040000;
+ mask_keycode = 0xffff;
+ raw_decode = true;
+ break;
+ case SAA7134_BOARD_AVERMEDIA_M733A:
+ ir_codes = RC_MAP_AVERMEDIA_M733A_RM_K6;
+ mask_keydown = 0x0040000;
+ mask_keyup = 0x0040000;
+ mask_keycode = 0xffff;
+ raw_decode = true;
+ break;
+ case SAA7134_BOARD_AVERMEDIA_777:
+ case SAA7134_BOARD_AVERMEDIA_A16AR:
+ ir_codes = RC_MAP_AVERMEDIA;
+ mask_keycode = 0x02F200;
+ mask_keydown = 0x000400;
+ polling = 50; // ms
+ /* GPIO stuff moved to saa7134_ir_open() */
+ break;
+ case SAA7134_BOARD_AVERMEDIA_A16D:
+ ir_codes = RC_MAP_AVERMEDIA_A16D;
+ mask_keycode = 0x02F200;
+ mask_keydown = 0x000400;
+ polling = 50; /* ms */
+ /* GPIO stuff moved to saa7134_ir_open() */
+ break;
+ case SAA7134_BOARD_KWORLD_TERMINATOR:
+ ir_codes = RC_MAP_PIXELVIEW;
+ mask_keycode = 0x00001f;
+ mask_keyup = 0x000060;
+ polling = 50; // ms
+ break;
+ case SAA7134_BOARD_MANLI_MTV001:
+ case SAA7134_BOARD_MANLI_MTV002:
+ ir_codes = RC_MAP_MANLI;
+ mask_keycode = 0x001f00;
+ mask_keyup = 0x004000;
+ polling = 50; /* ms */
+ break;
+ case SAA7134_BOARD_BEHOLD_409FM:
+ case SAA7134_BOARD_BEHOLD_401:
+ case SAA7134_BOARD_BEHOLD_403:
+ case SAA7134_BOARD_BEHOLD_403FM:
+ case SAA7134_BOARD_BEHOLD_405:
+ case SAA7134_BOARD_BEHOLD_405FM:
+ case SAA7134_BOARD_BEHOLD_407:
+ case SAA7134_BOARD_BEHOLD_407FM:
+ case SAA7134_BOARD_BEHOLD_409:
+ case SAA7134_BOARD_BEHOLD_505FM:
+ case SAA7134_BOARD_BEHOLD_505RDS_MK5:
+ case SAA7134_BOARD_BEHOLD_505RDS_MK3:
+ case SAA7134_BOARD_BEHOLD_507_9FM:
+ case SAA7134_BOARD_BEHOLD_507RDS_MK3:
+ case SAA7134_BOARD_BEHOLD_507RDS_MK5:
+ ir_codes = RC_MAP_MANLI;
+ mask_keycode = 0x003f00;
+ mask_keyup = 0x004000;
+ polling = 50; /* ms */
+ break;
+ case SAA7134_BOARD_BEHOLD_COLUMBUS_TVFM:
+ ir_codes = RC_MAP_BEHOLD_COLUMBUS;
+ mask_keycode = 0x003f00;
+ mask_keyup = 0x004000;
+ polling = 50; // ms
+ break;
+ case SAA7134_BOARD_SEDNA_PC_TV_CARDBUS:
+ ir_codes = RC_MAP_PCTV_SEDNA;
+ mask_keycode = 0x001f00;
+ mask_keyup = 0x004000;
+ polling = 50; // ms
+ break;
+ case SAA7134_BOARD_GOTVIEW_7135:
+ ir_codes = RC_MAP_GOTVIEW7135;
+ mask_keycode = 0x0003CC;
+ mask_keydown = 0x000010;
+ polling = 5; /* ms */
+ /* GPIO stuff moved to saa7134_ir_open() */
+ break;
+ case SAA7134_BOARD_VIDEOMATE_TV_PVR:
+ case SAA7134_BOARD_VIDEOMATE_GOLD_PLUS:
+ case SAA7134_BOARD_VIDEOMATE_TV_GOLD_PLUSII:
+ ir_codes = RC_MAP_VIDEOMATE_TV_PVR;
+ mask_keycode = 0x00003F;
+ mask_keyup = 0x400000;
+ polling = 50; // ms
+ break;
+ case SAA7134_BOARD_PROTEUS_2309:
+ ir_codes = RC_MAP_PROTEUS_2309;
+ mask_keycode = 0x00007F;
+ mask_keyup = 0x000080;
+ polling = 50; // ms
+ break;
+ case SAA7134_BOARD_VIDEOMATE_DVBT_300:
+ case SAA7134_BOARD_VIDEOMATE_DVBT_200:
+ ir_codes = RC_MAP_VIDEOMATE_TV_PVR;
+ mask_keycode = 0x003F00;
+ mask_keyup = 0x040000;
+ break;
+ case SAA7134_BOARD_FLYDVBS_LR300:
+ case SAA7134_BOARD_FLYDVBT_LR301:
+ case SAA7134_BOARD_FLYDVBTDUO:
+ ir_codes = RC_MAP_FLYDVB;
+ mask_keycode = 0x0001F00;
+ mask_keydown = 0x0040000;
+ break;
+ case SAA7134_BOARD_ASUSTeK_P7131_DUAL:
+ case SAA7134_BOARD_ASUSTeK_P7131_HYBRID_LNA:
+ case SAA7134_BOARD_ASUSTeK_P7131_ANALOG:
+ ir_codes = RC_MAP_ASUS_PC39;
+ mask_keydown = 0x0040000; /* Enable GPIO18 line on both edges */
+ mask_keyup = 0x0040000;
+ mask_keycode = 0xffff;
+ raw_decode = true;
+ break;
+ case SAA7134_BOARD_ASUSTeK_PS3_100:
+ ir_codes = RC_MAP_ASUS_PS3_100;
+ mask_keydown = 0x0040000;
+ mask_keyup = 0x0040000;
+ mask_keycode = 0xffff;
+ raw_decode = true;
+ break;
+ case SAA7134_BOARD_ENCORE_ENLTV:
+ case SAA7134_BOARD_ENCORE_ENLTV_FM:
+ ir_codes = RC_MAP_ENCORE_ENLTV;
+ mask_keycode = 0x00007f;
+ mask_keyup = 0x040000;
+ polling = 50; // ms
+ break;
+ case SAA7134_BOARD_ENCORE_ENLTV_FM53:
+ case SAA7134_BOARD_ENCORE_ENLTV_FM3:
+ ir_codes = RC_MAP_ENCORE_ENLTV_FM53;
+ mask_keydown = 0x0040000; /* Enable GPIO18 line on both edges */
+ mask_keyup = 0x0040000;
+ mask_keycode = 0xffff;
+ raw_decode = true;
+ break;
+ case SAA7134_BOARD_10MOONSTVMASTER3:
+ ir_codes = RC_MAP_ENCORE_ENLTV;
+ mask_keycode = 0x5f80000;
+ mask_keyup = 0x8000000;
+ polling = 50; //ms
+ break;
+ case SAA7134_BOARD_GENIUS_TVGO_A11MCE:
+ ir_codes = RC_MAP_GENIUS_TVGO_A11MCE;
+ mask_keycode = 0xff;
+ mask_keydown = 0xf00000;
+ polling = 50; /* ms */
+ break;
+ case SAA7134_BOARD_REAL_ANGEL_220:
+ ir_codes = RC_MAP_REAL_AUDIO_220_32_KEYS;
+ mask_keycode = 0x3f00;
+ mask_keyup = 0x4000;
+ polling = 50; /* ms */
+ break;
+ case SAA7134_BOARD_KWORLD_PLUS_TV_ANALOG:
+ ir_codes = RC_MAP_KWORLD_PLUS_TV_ANALOG;
+ mask_keycode = 0x7f;
+ polling = 40; /* ms */
+ break;
+ case SAA7134_BOARD_VIDEOMATE_S350:
+ ir_codes = RC_MAP_VIDEOMATE_S350;
+ mask_keycode = 0x003f00;
+ mask_keydown = 0x040000;
+ break;
+ case SAA7134_BOARD_LEADTEK_WINFAST_DTV1000S:
+ ir_codes = RC_MAP_WINFAST;
+ mask_keycode = 0x5f00;
+ mask_keyup = 0x020000;
+ polling = 50; /* ms */
+ break;
+ case SAA7134_BOARD_VIDEOMATE_M1F:
+ ir_codes = RC_MAP_VIDEOMATE_K100;
+ mask_keycode = 0x0ff00;
+ mask_keyup = 0x040000;
+ break;
+ case SAA7134_BOARD_HAUPPAUGE_HVR1150:
+ case SAA7134_BOARD_HAUPPAUGE_HVR1120:
+ ir_codes = RC_MAP_HAUPPAUGE;
+ mask_keydown = 0x0040000; /* Enable GPIO18 line on both edges */
+ mask_keyup = 0x0040000;
+ mask_keycode = 0xffff;
+ raw_decode = true;
+ break;
+ case SAA7134_BOARD_LEADTEK_WINFAST_TV2100_FM:
+ ir_codes = RC_MAP_LEADTEK_Y04G0051;
+ mask_keydown = 0x0040000; /* Enable GPIO18 line on both edges */
+ mask_keyup = 0x0040000;
+ mask_keycode = 0xffff;
+ raw_decode = true;
+ break;
+ }
+ if (NULL == ir_codes) {
+ pr_err("Oops: IR config error [card=%d]\n", dev->board);
+ return -ENODEV;
+ }
+
+ ir = kzalloc(sizeof(*ir), GFP_KERNEL);
+ rc = rc_allocate_device(RC_DRIVER_SCANCODE);
+ if (!ir || !rc) {
+ err = -ENOMEM;
+ goto err_out_free;
+ }
+
+ ir->dev = rc;
+ dev->remote = ir;
+
+ /* init hardware-specific stuff */
+ ir->mask_keycode = mask_keycode;
+ ir->mask_keydown = mask_keydown;
+ ir->mask_keyup = mask_keyup;
+ ir->polling = polling;
+ ir->raw_decode = raw_decode;
+
+ /* init input device */
+ snprintf(ir->phys, sizeof(ir->phys), "pci-%s/ir0",
+ pci_name(dev->pci));
+
+ rc->priv = dev;
+ rc->open = saa7134_ir_open;
+ rc->close = saa7134_ir_close;
+ if (raw_decode) {
+ rc->driver_type = RC_DRIVER_IR_RAW;
+ rc->allowed_protocols = RC_PROTO_BIT_ALL_IR_DECODER;
+ }
+
+ rc->device_name = saa7134_boards[dev->board].name;
+ rc->input_phys = ir->phys;
+ rc->input_id.bustype = BUS_PCI;
+ rc->input_id.version = 1;
+ if (dev->pci->subsystem_vendor) {
+ rc->input_id.vendor = dev->pci->subsystem_vendor;
+ rc->input_id.product = dev->pci->subsystem_device;
+ } else {
+ rc->input_id.vendor = dev->pci->vendor;
+ rc->input_id.product = dev->pci->device;
+ }
+ rc->dev.parent = &dev->pci->dev;
+ rc->map_name = ir_codes;
+ rc->driver_name = MODULE_NAME;
+ rc->min_timeout = 1;
+ rc->timeout = IR_DEFAULT_TIMEOUT;
+ rc->max_timeout = 10 * IR_DEFAULT_TIMEOUT;
+
+ err = rc_register_device(rc);
+ if (err)
+ goto err_out_free;
+
+ return 0;
+
+err_out_free:
+ rc_free_device(rc);
+ dev->remote = NULL;
+ kfree(ir);
+ return err;
+}
+
+void saa7134_input_fini(struct saa7134_dev *dev)
+{
+ if (NULL == dev->remote)
+ return;
+
+ rc_unregister_device(dev->remote->dev);
+ kfree(dev->remote);
+ dev->remote = NULL;
+}
+
+void saa7134_probe_i2c_ir(struct saa7134_dev *dev)
+{
+ struct i2c_board_info info;
+ struct i2c_msg msg_msi = {
+ .addr = 0x50,
+ .flags = I2C_M_RD,
+ .len = 0,
+ .buf = NULL,
+ };
+ int rc;
+
+ if (disable_ir) {
+ input_dbg("IR has been disabled, not probing for i2c remote\n");
+ return;
+ }
+
+ memset(&info, 0, sizeof(struct i2c_board_info));
+ memset(&dev->init_data, 0, sizeof(dev->init_data));
+ strscpy(info.type, "ir_video", I2C_NAME_SIZE);
+
+ switch (dev->board) {
+ case SAA7134_BOARD_PINNACLE_PCTV_110i:
+ case SAA7134_BOARD_PINNACLE_PCTV_310i:
+ dev->init_data.name = "Pinnacle PCTV";
+ if (pinnacle_remote == 0) {
+ dev->init_data.get_key = get_key_pinnacle_color;
+ dev->init_data.ir_codes = RC_MAP_PINNACLE_COLOR;
+ info.addr = 0x47;
+ } else {
+ dev->init_data.get_key = get_key_pinnacle_grey;
+ dev->init_data.ir_codes = RC_MAP_PINNACLE_GREY;
+ info.addr = 0x47;
+ }
+ break;
+ case SAA7134_BOARD_UPMOST_PURPLE_TV:
+ dev->init_data.name = "Purple TV";
+ dev->init_data.get_key = get_key_purpletv;
+ dev->init_data.ir_codes = RC_MAP_PURPLETV;
+ info.addr = 0x7a;
+ break;
+ case SAA7134_BOARD_MSI_TVATANYWHERE_PLUS:
+ dev->init_data.name = "MSI TV@nywhere Plus";
+ dev->init_data.get_key = get_key_msi_tvanywhere_plus;
+ dev->init_data.ir_codes = RC_MAP_MSI_TVANYWHERE_PLUS;
+ /*
+ * MSI TV@nyware Plus requires more frequent polling
+ * otherwise it will miss some keypresses
+ */
+ dev->init_data.polling_interval = 50;
+ info.addr = 0x30;
+ /* MSI TV@nywhere Plus controller doesn't seem to
+ respond to probes unless we read something from
+ an existing device. Weird...
+ REVISIT: might no longer be needed */
+ rc = i2c_transfer(&dev->i2c_adap, &msg_msi, 1);
+ input_dbg("probe 0x%02x @ %s: %s\n",
+ msg_msi.addr, dev->i2c_adap.name,
+ (1 == rc) ? "yes" : "no");
+ break;
+ case SAA7134_BOARD_SNAZIO_TVPVR_PRO:
+ dev->init_data.name = "SnaZio* TVPVR PRO";
+ dev->init_data.get_key = get_key_msi_tvanywhere_plus;
+ dev->init_data.ir_codes = RC_MAP_MSI_TVANYWHERE_PLUS;
+ /*
+ * MSI TV@nyware Plus requires more frequent polling
+ * otherwise it will miss some keypresses
+ */
+ dev->init_data.polling_interval = 50;
+ info.addr = 0x30;
+ /*
+ * MSI TV@nywhere Plus controller doesn't seem to
+ * respond to probes unless we read something from
+ * an existing device. Weird...
+ * REVISIT: might no longer be needed
+ */
+ rc = i2c_transfer(&dev->i2c_adap, &msg_msi, 1);
+ input_dbg("probe 0x%02x @ %s: %s\n",
+ msg_msi.addr, dev->i2c_adap.name,
+ (rc == 1) ? "yes" : "no");
+ break;
+ case SAA7134_BOARD_KWORLD_PC150U:
+ /* copied and modified from MSI TV@nywhere Plus */
+ dev->init_data.name = "Kworld PC150-U";
+ dev->init_data.get_key = get_key_kworld_pc150u;
+ dev->init_data.ir_codes = RC_MAP_KWORLD_PC150U;
+ info.addr = 0x30;
+ /* MSI TV@nywhere Plus controller doesn't seem to
+ respond to probes unless we read something from
+ an existing device. Weird...
+ REVISIT: might no longer be needed */
+ rc = i2c_transfer(&dev->i2c_adap, &msg_msi, 1);
+ input_dbg("probe 0x%02x @ %s: %s\n",
+ msg_msi.addr, dev->i2c_adap.name,
+ (1 == rc) ? "yes" : "no");
+ break;
+ case SAA7134_BOARD_HAUPPAUGE_HVR1110:
+ dev->init_data.name = saa7134_boards[dev->board].name;
+ dev->init_data.ir_codes = RC_MAP_HAUPPAUGE;
+ dev->init_data.type = RC_PROTO_BIT_RC5 |
+ RC_PROTO_BIT_RC6_MCE | RC_PROTO_BIT_RC6_6A_32;
+ dev->init_data.internal_get_key_func = IR_KBD_GET_KEY_HAUP_XVR;
+ info.addr = 0x71;
+ break;
+ case SAA7134_BOARD_BEHOLD_607FM_MK3:
+ case SAA7134_BOARD_BEHOLD_607FM_MK5:
+ case SAA7134_BOARD_BEHOLD_609FM_MK3:
+ case SAA7134_BOARD_BEHOLD_609FM_MK5:
+ case SAA7134_BOARD_BEHOLD_607RDS_MK3:
+ case SAA7134_BOARD_BEHOLD_607RDS_MK5:
+ case SAA7134_BOARD_BEHOLD_609RDS_MK3:
+ case SAA7134_BOARD_BEHOLD_609RDS_MK5:
+ case SAA7134_BOARD_BEHOLD_M6:
+ case SAA7134_BOARD_BEHOLD_M63:
+ case SAA7134_BOARD_BEHOLD_M6_EXTRA:
+ case SAA7134_BOARD_BEHOLD_H6:
+ case SAA7134_BOARD_BEHOLD_X7:
+ case SAA7134_BOARD_BEHOLD_H7:
+ case SAA7134_BOARD_BEHOLD_A7:
+ dev->init_data.name = "BeholdTV";
+ dev->init_data.get_key = get_key_beholdm6xx;
+ dev->init_data.ir_codes = RC_MAP_BEHOLD;
+ dev->init_data.type = RC_PROTO_BIT_NECX;
+ info.addr = 0x2d;
+ break;
+ case SAA7134_BOARD_AVERMEDIA_CARDBUS_501:
+ case SAA7134_BOARD_AVERMEDIA_CARDBUS_506:
+ info.addr = 0x40;
+ break;
+ case SAA7134_BOARD_AVERMEDIA_A706:
+ info.addr = 0x41;
+ break;
+ case SAA7134_BOARD_FLYDVB_TRIO:
+ dev->init_data.name = "FlyDVB Trio";
+ dev->init_data.get_key = get_key_flydvb_trio;
+ dev->init_data.ir_codes = RC_MAP_FLYDVB;
+ info.addr = 0x0b;
+ break;
+ default:
+ input_dbg("No I2C IR support for board %x\n", dev->board);
+ return;
+ }
+
+ if (dev->init_data.name)
+ info.platform_data = &dev->init_data;
+ i2c_new_client_device(&dev->i2c_adap, &info);
+}
+
+static int saa7134_raw_decode_irq(struct saa7134_dev *dev)
+{
+ struct saa7134_card_ir *ir = dev->remote;
+ int space;
+
+ /* Generate initial event */
+ saa_clearb(SAA7134_GPIO_GPMODE3, SAA7134_GPIO_GPRESCAN);
+ saa_setb(SAA7134_GPIO_GPMODE3, SAA7134_GPIO_GPRESCAN);
+ space = saa_readl(SAA7134_GPIO_GPSTATUS0 >> 2) & ir->mask_keydown;
+ ir_raw_event_store_edge(dev->remote->dev, !space);
+
+ return 1;
+}
diff --git a/drivers/media/pci/saa7134/saa7134-reg.h b/drivers/media/pci/saa7134/saa7134-reg.h
new file mode 100644
index 0000000000..56b12641d7
--- /dev/null
+++ b/drivers/media/pci/saa7134/saa7134-reg.h
@@ -0,0 +1,377 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ *
+ * philips saa7134 registers
+ */
+
+/* ------------------------------------------------------------------ */
+/*
+ * PCI ID's
+ */
+#ifndef PCI_DEVICE_ID_PHILIPS_SAA7130
+# define PCI_DEVICE_ID_PHILIPS_SAA7130 0x7130
+#endif
+#ifndef PCI_DEVICE_ID_PHILIPS_SAA7133
+# define PCI_DEVICE_ID_PHILIPS_SAA7133 0x7133
+#endif
+#ifndef PCI_DEVICE_ID_PHILIPS_SAA7134
+# define PCI_DEVICE_ID_PHILIPS_SAA7134 0x7134
+#endif
+#ifndef PCI_DEVICE_ID_PHILIPS_SAA7135
+# define PCI_DEVICE_ID_PHILIPS_SAA7135 0x7135
+#endif
+
+/* ------------------------------------------------------------------ */
+/*
+ * registers -- 32 bit
+ */
+
+/* DMA channels, n = 0 ... 6 */
+#define SAA7134_RS_BA1(n) ((0x200 >> 2) + 4*n)
+#define SAA7134_RS_BA2(n) ((0x204 >> 2) + 4*n)
+#define SAA7134_RS_PITCH(n) ((0x208 >> 2) + 4*n)
+#define SAA7134_RS_CONTROL(n) ((0x20c >> 2) + 4*n)
+#define SAA7134_RS_CONTROL_WSWAP (0x01 << 25)
+#define SAA7134_RS_CONTROL_BSWAP (0x01 << 24)
+#define SAA7134_RS_CONTROL_BURST_2 (0x01 << 21)
+#define SAA7134_RS_CONTROL_BURST_4 (0x02 << 21)
+#define SAA7134_RS_CONTROL_BURST_8 (0x03 << 21)
+#define SAA7134_RS_CONTROL_BURST_16 (0x04 << 21)
+#define SAA7134_RS_CONTROL_BURST_32 (0x05 << 21)
+#define SAA7134_RS_CONTROL_BURST_64 (0x06 << 21)
+#define SAA7134_RS_CONTROL_BURST_MAX (0x07 << 21)
+#define SAA7134_RS_CONTROL_ME (0x01 << 20)
+#define SAA7134_FIFO_SIZE (0x2a0 >> 2)
+#define SAA7134_THRESHOULD (0x2a4 >> 2)
+
+#define SAA7133_NUM_SAMPLES (0x588 >> 2)
+#define SAA7133_AUDIO_CHANNEL (0x58c >> 2)
+#define SAA7133_AUDIO_FORMAT (0x58f >> 2)
+#define SAA7133_DIGITAL_OUTPUT_SEL1 (0x46c >> 2)
+#define SAA7133_DIGITAL_OUTPUT_SEL2 (0x470 >> 2)
+#define SAA7133_DIGITAL_INPUT_XBAR1 (0x464 >> 2)
+#define SAA7133_ANALOG_IO_SELECT (0x594 >> 2)
+
+/* main control */
+#define SAA7134_MAIN_CTRL (0x2a8 >> 2)
+#define SAA7134_MAIN_CTRL_VPLLE (1 << 15)
+#define SAA7134_MAIN_CTRL_APLLE (1 << 14)
+#define SAA7134_MAIN_CTRL_EXOSC (1 << 13)
+#define SAA7134_MAIN_CTRL_EVFE1 (1 << 12)
+#define SAA7134_MAIN_CTRL_EVFE2 (1 << 11)
+#define SAA7134_MAIN_CTRL_ESFE (1 << 10)
+#define SAA7134_MAIN_CTRL_EBADC (1 << 9)
+#define SAA7134_MAIN_CTRL_EBDAC (1 << 8)
+#define SAA7134_MAIN_CTRL_TE6 (1 << 6)
+#define SAA7134_MAIN_CTRL_TE5 (1 << 5)
+#define SAA7134_MAIN_CTRL_TE4 (1 << 4)
+#define SAA7134_MAIN_CTRL_TE3 (1 << 3)
+#define SAA7134_MAIN_CTRL_TE2 (1 << 2)
+#define SAA7134_MAIN_CTRL_TE1 (1 << 1)
+#define SAA7134_MAIN_CTRL_TE0 (1 << 0)
+
+/* DMA status */
+#define SAA7134_DMA_STATUS (0x2ac >> 2)
+
+/* audio / video status */
+#define SAA7134_AV_STATUS (0x2c0 >> 2)
+#define SAA7134_AV_STATUS_STEREO (1 << 17)
+#define SAA7134_AV_STATUS_DUAL (1 << 16)
+#define SAA7134_AV_STATUS_PILOT (1 << 15)
+#define SAA7134_AV_STATUS_SMB (1 << 14)
+#define SAA7134_AV_STATUS_DMB (1 << 13)
+#define SAA7134_AV_STATUS_VDSP (1 << 12)
+#define SAA7134_AV_STATUS_IIC_STATUS (3 << 10)
+#define SAA7134_AV_STATUS_MVM (7 << 7)
+#define SAA7134_AV_STATUS_FIDT (1 << 6)
+#define SAA7134_AV_STATUS_INTL (1 << 5)
+#define SAA7134_AV_STATUS_RDCAP (1 << 4)
+#define SAA7134_AV_STATUS_PWR_ON (1 << 3)
+#define SAA7134_AV_STATUS_LOAD_ERR (1 << 2)
+#define SAA7134_AV_STATUS_TRIG_ERR (1 << 1)
+#define SAA7134_AV_STATUS_CONF_ERR (1 << 0)
+
+/* interrupt */
+#define SAA7134_IRQ1 (0x2c4 >> 2)
+#define SAA7134_IRQ1_INTE_RA3_1 (1 << 25)
+#define SAA7134_IRQ1_INTE_RA3_0 (1 << 24)
+#define SAA7134_IRQ1_INTE_RA2_3 (1 << 19)
+#define SAA7134_IRQ1_INTE_RA2_2 (1 << 18)
+#define SAA7134_IRQ1_INTE_RA2_1 (1 << 17)
+#define SAA7134_IRQ1_INTE_RA2_0 (1 << 16)
+#define SAA7134_IRQ1_INTE_RA1_3 (1 << 11)
+#define SAA7134_IRQ1_INTE_RA1_2 (1 << 10)
+#define SAA7134_IRQ1_INTE_RA1_1 (1 << 9)
+#define SAA7134_IRQ1_INTE_RA1_0 (1 << 8)
+#define SAA7134_IRQ1_INTE_RA0_7 (1 << 7)
+#define SAA7134_IRQ1_INTE_RA0_6 (1 << 6)
+#define SAA7134_IRQ1_INTE_RA0_5 (1 << 5)
+#define SAA7134_IRQ1_INTE_RA0_4 (1 << 4)
+#define SAA7134_IRQ1_INTE_RA0_3 (1 << 3)
+#define SAA7134_IRQ1_INTE_RA0_2 (1 << 2)
+#define SAA7134_IRQ1_INTE_RA0_1 (1 << 1)
+#define SAA7134_IRQ1_INTE_RA0_0 (1 << 0)
+
+#define SAA7134_IRQ2 (0x2c8 >> 2)
+#define SAA7134_IRQ2_INTE_GPIO23_N (1 << 17) /* negative edge */
+#define SAA7134_IRQ2_INTE_GPIO23_P (1 << 16) /* positive edge */
+#define SAA7134_IRQ2_INTE_GPIO22_N (1 << 15) /* negative edge */
+#define SAA7134_IRQ2_INTE_GPIO22_P (1 << 14) /* positive edge */
+#define SAA7134_IRQ2_INTE_GPIO18_N (1 << 13) /* negative edge */
+#define SAA7134_IRQ2_INTE_GPIO18_P (1 << 12) /* positive edge */
+#define SAA7134_IRQ2_INTE_GPIO16_N (1 << 11) /* negative edge */
+#define SAA7134_IRQ2_INTE_GPIO16_P (1 << 10) /* positive edge */
+#define SAA7134_IRQ2_INTE_SC2 (1 << 9)
+#define SAA7134_IRQ2_INTE_SC1 (1 << 8)
+#define SAA7134_IRQ2_INTE_SC0 (1 << 7)
+#define SAA7134_IRQ2_INTE_DEC4 (1 << 6)
+#define SAA7134_IRQ2_INTE_DEC3 (1 << 5)
+#define SAA7134_IRQ2_INTE_DEC2 (1 << 4)
+#define SAA7134_IRQ2_INTE_DEC1 (1 << 3)
+#define SAA7134_IRQ2_INTE_DEC0 (1 << 2)
+#define SAA7134_IRQ2_INTE_PE (1 << 1)
+#define SAA7134_IRQ2_INTE_AR (1 << 0)
+
+#define SAA7134_IRQ_REPORT (0x2cc >> 2)
+#define SAA7134_IRQ_REPORT_GPIO23 (1 << 17)
+#define SAA7134_IRQ_REPORT_GPIO22 (1 << 16)
+#define SAA7134_IRQ_REPORT_GPIO18 (1 << 15)
+#define SAA7134_IRQ_REPORT_GPIO16 (1 << 14)
+#define SAA7134_IRQ_REPORT_LOAD_ERR (1 << 13)
+#define SAA7134_IRQ_REPORT_CONF_ERR (1 << 12)
+#define SAA7134_IRQ_REPORT_TRIG_ERR (1 << 11)
+#define SAA7134_IRQ_REPORT_MMC (1 << 10)
+#define SAA7134_IRQ_REPORT_FIDT (1 << 9)
+#define SAA7134_IRQ_REPORT_INTL (1 << 8)
+#define SAA7134_IRQ_REPORT_RDCAP (1 << 7)
+#define SAA7134_IRQ_REPORT_PWR_ON (1 << 6)
+#define SAA7134_IRQ_REPORT_PE (1 << 5)
+#define SAA7134_IRQ_REPORT_AR (1 << 4)
+#define SAA7134_IRQ_REPORT_DONE_RA3 (1 << 3)
+#define SAA7134_IRQ_REPORT_DONE_RA2 (1 << 2)
+#define SAA7134_IRQ_REPORT_DONE_RA1 (1 << 1)
+#define SAA7134_IRQ_REPORT_DONE_RA0 (1 << 0)
+#define SAA7134_IRQ_STATUS (0x2d0 >> 2)
+
+
+/* ------------------------------------------------------------------ */
+/*
+ * registers -- 8 bit
+ */
+
+/* video decoder */
+#define SAA7134_INCR_DELAY 0x101
+#define SAA7134_ANALOG_IN_CTRL1 0x102
+#define SAA7134_ANALOG_IN_CTRL2 0x103
+#define SAA7134_ANALOG_IN_CTRL3 0x104
+#define SAA7134_ANALOG_IN_CTRL4 0x105
+#define SAA7134_HSYNC_START 0x106
+#define SAA7134_HSYNC_STOP 0x107
+#define SAA7134_SYNC_CTRL 0x108
+#define SAA7134_SYNC_CTRL_AUFD (1 << 7)
+#define SAA7134_LUMA_CTRL 0x109
+#define SAA7134_LUMA_CTRL_LDEL (1 << 5)
+#define SAA7134_DEC_LUMA_BRIGHT 0x10a
+#define SAA7134_DEC_LUMA_CONTRAST 0x10b
+#define SAA7134_DEC_CHROMA_SATURATION 0x10c
+#define SAA7134_DEC_CHROMA_HUE 0x10d
+#define SAA7134_CHROMA_CTRL1 0x10e
+#define SAA7134_CHROMA_CTRL1_AUTO0 (1 << 1)
+#define SAA7134_CHROMA_CTRL1_FCTC (1 << 2)
+#define SAA7134_CHROMA_GAIN 0x10f
+#define SAA7134_CHROMA_CTRL2 0x110
+#define SAA7134_MODE_DELAY_CTRL 0x111
+
+#define SAA7134_ANALOG_ADC 0x114
+#define SAA7134_ANALOG_ADC_AUTO1 (1 << 2)
+#define SAA7134_VGATE_START 0x115
+#define SAA7134_VGATE_STOP 0x116
+#define SAA7134_MISC_VGATE_MSB 0x117
+#define SAA7134_RAW_DATA_GAIN 0x118
+#define SAA7134_RAW_DATA_OFFSET 0x119
+#define SAA7134_STATUS_VIDEO1 0x11e
+#define SAA7134_STATUS_VIDEO2 0x11f
+
+/* video scaler */
+#define SAA7134_SOURCE_TIMING1 0x000
+#define SAA7134_SOURCE_TIMING2 0x001
+#define SAA7134_REGION_ENABLE 0x004
+#define SAA7134_SCALER_STATUS0 0x006
+#define SAA7134_SCALER_STATUS1 0x007
+#define SAA7134_START_GREEN 0x00c
+#define SAA7134_START_BLUE 0x00d
+#define SAA7134_START_RED 0x00e
+#define SAA7134_GREEN_PATH(x) (0x010 +x)
+#define SAA7134_BLUE_PATH(x) (0x020 +x)
+#define SAA7134_RED_PATH(x) (0x030 +x)
+
+#define TASK_A 0x040
+#define TASK_B 0x080
+#define SAA7134_TASK_CONDITIONS(t) (0x000 +t)
+#define SAA7134_FIELD_HANDLING(t) (0x001 +t)
+#define SAA7134_DATA_PATH(t) (0x002 +t)
+#define SAA7134_VBI_H_START1(t) (0x004 +t)
+#define SAA7134_VBI_H_START2(t) (0x005 +t)
+#define SAA7134_VBI_H_STOP1(t) (0x006 +t)
+#define SAA7134_VBI_H_STOP2(t) (0x007 +t)
+#define SAA7134_VBI_V_START1(t) (0x008 +t)
+#define SAA7134_VBI_V_START2(t) (0x009 +t)
+#define SAA7134_VBI_V_STOP1(t) (0x00a +t)
+#define SAA7134_VBI_V_STOP2(t) (0x00b +t)
+#define SAA7134_VBI_H_LEN1(t) (0x00c +t)
+#define SAA7134_VBI_H_LEN2(t) (0x00d +t)
+#define SAA7134_VBI_V_LEN1(t) (0x00e +t)
+#define SAA7134_VBI_V_LEN2(t) (0x00f +t)
+
+#define SAA7134_VIDEO_H_START1(t) (0x014 +t)
+#define SAA7134_VIDEO_H_START2(t) (0x015 +t)
+#define SAA7134_VIDEO_H_STOP1(t) (0x016 +t)
+#define SAA7134_VIDEO_H_STOP2(t) (0x017 +t)
+#define SAA7134_VIDEO_V_START1(t) (0x018 +t)
+#define SAA7134_VIDEO_V_START2(t) (0x019 +t)
+#define SAA7134_VIDEO_V_STOP1(t) (0x01a +t)
+#define SAA7134_VIDEO_V_STOP2(t) (0x01b +t)
+#define SAA7134_VIDEO_PIXELS1(t) (0x01c +t)
+#define SAA7134_VIDEO_PIXELS2(t) (0x01d +t)
+#define SAA7134_VIDEO_LINES1(t) (0x01e +t)
+#define SAA7134_VIDEO_LINES2(t) (0x01f +t)
+
+#define SAA7134_H_PRESCALE(t) (0x020 +t)
+#define SAA7134_ACC_LENGTH(t) (0x021 +t)
+#define SAA7134_LEVEL_CTRL(t) (0x022 +t)
+#define SAA7134_FIR_PREFILTER_CTRL(t) (0x023 +t)
+#define SAA7134_LUMA_BRIGHT(t) (0x024 +t)
+#define SAA7134_LUMA_CONTRAST(t) (0x025 +t)
+#define SAA7134_CHROMA_SATURATION(t) (0x026 +t)
+#define SAA7134_VBI_H_SCALE_INC1(t) (0x028 +t)
+#define SAA7134_VBI_H_SCALE_INC2(t) (0x029 +t)
+#define SAA7134_VBI_PHASE_OFFSET_LUMA(t) (0x02a +t)
+#define SAA7134_VBI_PHASE_OFFSET_CHROMA(t) (0x02b +t)
+#define SAA7134_H_SCALE_INC1(t) (0x02c +t)
+#define SAA7134_H_SCALE_INC2(t) (0x02d +t)
+#define SAA7134_H_PHASE_OFF_LUMA(t) (0x02e +t)
+#define SAA7134_H_PHASE_OFF_CHROMA(t) (0x02f +t)
+#define SAA7134_V_SCALE_RATIO1(t) (0x030 +t)
+#define SAA7134_V_SCALE_RATIO2(t) (0x031 +t)
+#define SAA7134_V_FILTER(t) (0x032 +t)
+#define SAA7134_V_PHASE_OFFSET0(t) (0x034 +t)
+#define SAA7134_V_PHASE_OFFSET1(t) (0x035 +t)
+#define SAA7134_V_PHASE_OFFSET2(t) (0x036 +t)
+#define SAA7134_V_PHASE_OFFSET3(t) (0x037 +t)
+
+/* clipping & dma */
+#define SAA7134_OFMT_VIDEO_A 0x300
+#define SAA7134_OFMT_DATA_A 0x301
+#define SAA7134_OFMT_VIDEO_B 0x302
+#define SAA7134_OFMT_DATA_B 0x303
+#define SAA7134_ALPHA_NOCLIP 0x304
+#define SAA7134_ALPHA_CLIP 0x305
+#define SAA7134_UV_PIXEL 0x308
+#define SAA7134_CLIP_RED 0x309
+#define SAA7134_CLIP_GREEN 0x30a
+#define SAA7134_CLIP_BLUE 0x30b
+
+/* i2c bus */
+#define SAA7134_I2C_ATTR_STATUS 0x180
+#define SAA7134_I2C_DATA 0x181
+#define SAA7134_I2C_CLOCK_SELECT 0x182
+#define SAA7134_I2C_TIMER 0x183
+
+/* audio */
+#define SAA7134_NICAM_ADD_DATA1 0x140
+#define SAA7134_NICAM_ADD_DATA2 0x141
+#define SAA7134_NICAM_STATUS 0x142
+#define SAA7134_AUDIO_STATUS 0x143
+#define SAA7134_NICAM_ERROR_COUNT 0x144
+#define SAA7134_IDENT_SIF 0x145
+#define SAA7134_LEVEL_READOUT1 0x146
+#define SAA7134_LEVEL_READOUT2 0x147
+#define SAA7134_NICAM_ERROR_LOW 0x148
+#define SAA7134_NICAM_ERROR_HIGH 0x149
+#define SAA7134_DCXO_IDENT_CTRL 0x14a
+#define SAA7134_DEMODULATOR 0x14b
+#define SAA7134_AGC_GAIN_SELECT 0x14c
+#define SAA7134_CARRIER1_FREQ0 0x150
+#define SAA7134_CARRIER1_FREQ1 0x151
+#define SAA7134_CARRIER1_FREQ2 0x152
+#define SAA7134_CARRIER2_FREQ0 0x154
+#define SAA7134_CARRIER2_FREQ1 0x155
+#define SAA7134_CARRIER2_FREQ2 0x156
+#define SAA7134_NUM_SAMPLES0 0x158
+#define SAA7134_NUM_SAMPLES1 0x159
+#define SAA7134_NUM_SAMPLES2 0x15a
+#define SAA7134_AUDIO_FORMAT_CTRL 0x15b
+#define SAA7134_MONITOR_SELECT 0x160
+#define SAA7134_FM_DEEMPHASIS 0x161
+#define SAA7134_FM_DEMATRIX 0x162
+#define SAA7134_CHANNEL1_LEVEL 0x163
+#define SAA7134_CHANNEL2_LEVEL 0x164
+#define SAA7134_NICAM_CONFIG 0x165
+#define SAA7134_NICAM_LEVEL_ADJUST 0x166
+#define SAA7134_STEREO_DAC_OUTPUT_SELECT 0x167
+#define SAA7134_I2S_OUTPUT_FORMAT 0x168
+#define SAA7134_I2S_OUTPUT_SELECT 0x169
+#define SAA7134_I2S_OUTPUT_LEVEL 0x16a
+#define SAA7134_DSP_OUTPUT_SELECT 0x16b
+#define SAA7134_AUDIO_MUTE_CTRL 0x16c
+#define SAA7134_SIF_SAMPLE_FREQ 0x16d
+#define SAA7134_ANALOG_IO_SELECT 0x16e
+#define SAA7134_AUDIO_CLOCK0 0x170
+#define SAA7134_AUDIO_CLOCK1 0x171
+#define SAA7134_AUDIO_CLOCK2 0x172
+#define SAA7134_AUDIO_PLL_CTRL 0x173
+#define SAA7134_AUDIO_CLOCKS_PER_FIELD0 0x174
+#define SAA7134_AUDIO_CLOCKS_PER_FIELD1 0x175
+#define SAA7134_AUDIO_CLOCKS_PER_FIELD2 0x176
+
+/* video port output */
+#define SAA7134_VIDEO_PORT_CTRL0 0x190
+#define SAA7134_VIDEO_PORT_CTRL1 0x191
+#define SAA7134_VIDEO_PORT_CTRL2 0x192
+#define SAA7134_VIDEO_PORT_CTRL3 0x193
+#define SAA7134_VIDEO_PORT_CTRL4 0x194
+#define SAA7134_VIDEO_PORT_CTRL5 0x195
+#define SAA7134_VIDEO_PORT_CTRL6 0x196
+#define SAA7134_VIDEO_PORT_CTRL7 0x197
+#define SAA7134_VIDEO_PORT_CTRL8 0x198
+
+/* transport stream interface */
+#define SAA7134_TS_PARALLEL 0x1a0
+#define SAA7134_TS_PARALLEL_SERIAL 0x1a1
+#define SAA7134_TS_SERIAL0 0x1a2
+#define SAA7134_TS_SERIAL1 0x1a3
+#define SAA7134_TS_DMA0 0x1a4
+#define SAA7134_TS_DMA1 0x1a5
+#define SAA7134_TS_DMA2 0x1a6
+
+/* GPIO Controls */
+#define SAA7134_GPIO_GPRESCAN 0x80
+#define SAA7134_GPIO_27_25 0x0E
+
+#define SAA7134_GPIO_GPMODE0 0x1B0
+#define SAA7134_GPIO_GPMODE1 0x1B1
+#define SAA7134_GPIO_GPMODE2 0x1B2
+#define SAA7134_GPIO_GPMODE3 0x1B3
+#define SAA7134_GPIO_GPSTATUS0 0x1B4
+#define SAA7134_GPIO_GPSTATUS1 0x1B5
+#define SAA7134_GPIO_GPSTATUS2 0x1B6
+#define SAA7134_GPIO_GPSTATUS3 0x1B7
+
+/* I2S output */
+#define SAA7134_I2S_AUDIO_OUTPUT 0x1c0
+
+/* test modes */
+#define SAA7134_SPECIAL_MODE 0x1d0
+#define SAA7134_PRODUCTION_TEST_MODE 0x1d1
+
+/* audio -- saa7133 + saa7135 only */
+#define SAA7135_DSP_RWSTATE 0x580
+#define SAA7135_DSP_RWSTATE_ERR (1 << 3)
+#define SAA7135_DSP_RWSTATE_IDA (1 << 2)
+#define SAA7135_DSP_RWSTATE_RDB (1 << 1)
+#define SAA7135_DSP_RWSTATE_WRR (1 << 0)
+
+#define SAA7135_DSP_RWCLEAR 0x586
+#define SAA7135_DSP_RWCLEAR_RERR 1
+
+#define SAA7133_I2S_AUDIO_CONTROL 0x591
diff --git a/drivers/media/pci/saa7134/saa7134-ts.c b/drivers/media/pci/saa7134/saa7134-ts.c
new file mode 100644
index 0000000000..437dbe5e75
--- /dev/null
+++ b/drivers/media/pci/saa7134/saa7134-ts.c
@@ -0,0 +1,328 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ *
+ * device driver for philips saa7134 based TV cards
+ * video4linux video interface
+ *
+ * (c) 2001,02 Gerd Knorr <kraxel@bytesex.org> [SuSE Labs]
+ */
+
+#include "saa7134.h"
+#include "saa7134-reg.h"
+
+#include <linux/init.h>
+#include <linux/list.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+
+/* ------------------------------------------------------------------ */
+
+static unsigned int ts_debug;
+module_param(ts_debug, int, 0644);
+MODULE_PARM_DESC(ts_debug,"enable debug messages [ts]");
+
+#define ts_dbg(fmt, arg...) do { \
+ if (ts_debug) \
+ printk(KERN_DEBUG pr_fmt("ts: " fmt), ## arg); \
+ } while (0)
+
+/* ------------------------------------------------------------------ */
+static int buffer_activate(struct saa7134_dev *dev,
+ struct saa7134_buf *buf,
+ struct saa7134_buf *next)
+{
+
+ ts_dbg("buffer_activate [%p]", buf);
+ buf->top_seen = 0;
+
+ if (!dev->ts_started)
+ dev->ts_field = V4L2_FIELD_TOP;
+
+ if (NULL == next)
+ next = buf;
+ if (V4L2_FIELD_TOP == dev->ts_field) {
+ ts_dbg("- [top] buf=%p next=%p\n", buf, next);
+ saa_writel(SAA7134_RS_BA1(5),saa7134_buffer_base(buf));
+ saa_writel(SAA7134_RS_BA2(5),saa7134_buffer_base(next));
+ dev->ts_field = V4L2_FIELD_BOTTOM;
+ } else {
+ ts_dbg("- [bottom] buf=%p next=%p\n", buf, next);
+ saa_writel(SAA7134_RS_BA1(5),saa7134_buffer_base(next));
+ saa_writel(SAA7134_RS_BA2(5),saa7134_buffer_base(buf));
+ dev->ts_field = V4L2_FIELD_TOP;
+ }
+
+ /* start DMA */
+ saa7134_set_dmabits(dev);
+
+ mod_timer(&dev->ts_q.timeout, jiffies+TS_BUFFER_TIMEOUT);
+
+ if (!dev->ts_started)
+ saa7134_ts_start(dev);
+
+ return 0;
+}
+
+int saa7134_ts_buffer_init(struct vb2_buffer *vb2)
+{
+ struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb2);
+ struct saa7134_dmaqueue *dmaq = vb2->vb2_queue->drv_priv;
+ struct saa7134_buf *buf = container_of(vbuf, struct saa7134_buf, vb2);
+
+ dmaq->curr = NULL;
+ buf->activate = buffer_activate;
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(saa7134_ts_buffer_init);
+
+int saa7134_ts_buffer_prepare(struct vb2_buffer *vb2)
+{
+ struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb2);
+ struct saa7134_dmaqueue *dmaq = vb2->vb2_queue->drv_priv;
+ struct saa7134_dev *dev = dmaq->dev;
+ struct saa7134_buf *buf = container_of(vbuf, struct saa7134_buf, vb2);
+ struct sg_table *dma = vb2_dma_sg_plane_desc(vb2, 0);
+ unsigned int lines, llength, size;
+
+ ts_dbg("buffer_prepare [%p]\n", buf);
+
+ llength = TS_PACKET_SIZE;
+ lines = dev->ts.nr_packets;
+
+ size = lines * llength;
+ if (vb2_plane_size(vb2, 0) < size)
+ return -EINVAL;
+
+ vb2_set_plane_payload(vb2, 0, size);
+ vbuf->field = dev->field;
+
+ return saa7134_pgtable_build(dev->pci, &dmaq->pt, dma->sgl, dma->nents,
+ saa7134_buffer_startpage(buf));
+}
+EXPORT_SYMBOL_GPL(saa7134_ts_buffer_prepare);
+
+int saa7134_ts_queue_setup(struct vb2_queue *q,
+ unsigned int *nbuffers, unsigned int *nplanes,
+ unsigned int sizes[], struct device *alloc_devs[])
+{
+ struct saa7134_dmaqueue *dmaq = q->drv_priv;
+ struct saa7134_dev *dev = dmaq->dev;
+ int size = TS_PACKET_SIZE * dev->ts.nr_packets;
+
+ if (0 == *nbuffers)
+ *nbuffers = dev->ts.nr_bufs;
+ *nbuffers = saa7134_buffer_count(size, *nbuffers);
+ if (*nbuffers < 3)
+ *nbuffers = 3;
+ *nplanes = 1;
+ sizes[0] = size;
+ return 0;
+}
+EXPORT_SYMBOL_GPL(saa7134_ts_queue_setup);
+
+int saa7134_ts_start_streaming(struct vb2_queue *vq, unsigned int count)
+{
+ struct saa7134_dmaqueue *dmaq = vq->drv_priv;
+ struct saa7134_dev *dev = dmaq->dev;
+
+ /*
+ * Planar video capture and TS share the same DMA channel,
+ * so only one can be active at a time.
+ */
+ if (vb2_is_busy(&dev->video_vbq) && dev->fmt->planar) {
+ struct saa7134_buf *buf, *tmp;
+
+ list_for_each_entry_safe(buf, tmp, &dmaq->queue, entry) {
+ list_del(&buf->entry);
+ vb2_buffer_done(&buf->vb2.vb2_buf,
+ VB2_BUF_STATE_QUEUED);
+ }
+ if (dmaq->curr) {
+ vb2_buffer_done(&dmaq->curr->vb2.vb2_buf,
+ VB2_BUF_STATE_QUEUED);
+ dmaq->curr = NULL;
+ }
+ return -EBUSY;
+ }
+ dmaq->seq_nr = 0;
+ return 0;
+}
+EXPORT_SYMBOL_GPL(saa7134_ts_start_streaming);
+
+void saa7134_ts_stop_streaming(struct vb2_queue *vq)
+{
+ struct saa7134_dmaqueue *dmaq = vq->drv_priv;
+ struct saa7134_dev *dev = dmaq->dev;
+
+ saa7134_ts_stop(dev);
+ saa7134_stop_streaming(dev, dmaq);
+}
+EXPORT_SYMBOL_GPL(saa7134_ts_stop_streaming);
+
+struct vb2_ops saa7134_ts_qops = {
+ .queue_setup = saa7134_ts_queue_setup,
+ .buf_init = saa7134_ts_buffer_init,
+ .buf_prepare = saa7134_ts_buffer_prepare,
+ .buf_queue = saa7134_vb2_buffer_queue,
+ .wait_prepare = vb2_ops_wait_prepare,
+ .wait_finish = vb2_ops_wait_finish,
+ .stop_streaming = saa7134_ts_stop_streaming,
+};
+EXPORT_SYMBOL_GPL(saa7134_ts_qops);
+
+/* ----------------------------------------------------------- */
+/* exported stuff */
+
+static unsigned int tsbufs = 8;
+module_param(tsbufs, int, 0444);
+MODULE_PARM_DESC(tsbufs, "number of ts buffers for read/write IO, range 2-32");
+
+static unsigned int ts_nr_packets = 64;
+module_param(ts_nr_packets, int, 0444);
+MODULE_PARM_DESC(ts_nr_packets,"size of a ts buffers (in ts packets)");
+
+int saa7134_ts_init_hw(struct saa7134_dev *dev)
+{
+ /* deactivate TS softreset */
+ saa_writeb(SAA7134_TS_SERIAL1, 0x00);
+ /* TSSOP high active, TSVAL high active, TSLOCK ignored */
+ saa_writeb(SAA7134_TS_PARALLEL, 0x6c);
+ saa_writeb(SAA7134_TS_PARALLEL_SERIAL, (TS_PACKET_SIZE-1));
+ saa_writeb(SAA7134_TS_DMA0, ((dev->ts.nr_packets-1)&0xff));
+ saa_writeb(SAA7134_TS_DMA1, (((dev->ts.nr_packets-1)>>8)&0xff));
+ /* TSNOPIT=0, TSCOLAP=0 */
+ saa_writeb(SAA7134_TS_DMA2,
+ ((((dev->ts.nr_packets-1)>>16)&0x3f) | 0x00));
+
+ return 0;
+}
+
+int saa7134_ts_init1(struct saa7134_dev *dev)
+{
+ /* sanitycheck insmod options */
+ if (tsbufs < 2)
+ tsbufs = 2;
+ if (tsbufs > VIDEO_MAX_FRAME)
+ tsbufs = VIDEO_MAX_FRAME;
+ if (ts_nr_packets < 4)
+ ts_nr_packets = 4;
+ if (ts_nr_packets > 312)
+ ts_nr_packets = 312;
+ dev->ts.nr_bufs = tsbufs;
+ dev->ts.nr_packets = ts_nr_packets;
+
+ INIT_LIST_HEAD(&dev->ts_q.queue);
+ timer_setup(&dev->ts_q.timeout, saa7134_buffer_timeout, 0);
+ dev->ts_q.dev = dev;
+ dev->ts_q.need_two = 1;
+ dev->ts_started = 0;
+ saa7134_pgtable_alloc(dev->pci, &dev->ts_q.pt);
+
+ /* init TS hw */
+ saa7134_ts_init_hw(dev);
+
+ return 0;
+}
+
+/* Function for stop TS */
+int saa7134_ts_stop(struct saa7134_dev *dev)
+{
+ ts_dbg("TS stop\n");
+
+ if (!dev->ts_started)
+ return 0;
+
+ /* Stop TS stream */
+ switch (saa7134_boards[dev->board].ts_type) {
+ case SAA7134_MPEG_TS_PARALLEL:
+ saa_writeb(SAA7134_TS_PARALLEL, 0x6c);
+ dev->ts_started = 0;
+ break;
+ case SAA7134_MPEG_TS_SERIAL:
+ saa_writeb(SAA7134_TS_SERIAL0, 0x40);
+ dev->ts_started = 0;
+ break;
+ }
+ return 0;
+}
+
+/* Function for start TS */
+int saa7134_ts_start(struct saa7134_dev *dev)
+{
+ ts_dbg("TS start\n");
+
+ if (WARN_ON(dev->ts_started))
+ return 0;
+
+ /* dma: setup channel 5 (= TS) */
+ saa_writeb(SAA7134_TS_DMA0, (dev->ts.nr_packets - 1) & 0xff);
+ saa_writeb(SAA7134_TS_DMA1,
+ ((dev->ts.nr_packets - 1) >> 8) & 0xff);
+ /* TSNOPIT=0, TSCOLAP=0 */
+ saa_writeb(SAA7134_TS_DMA2,
+ (((dev->ts.nr_packets - 1) >> 16) & 0x3f) | 0x00);
+ saa_writel(SAA7134_RS_PITCH(5), TS_PACKET_SIZE);
+ saa_writel(SAA7134_RS_CONTROL(5), SAA7134_RS_CONTROL_BURST_16 |
+ SAA7134_RS_CONTROL_ME |
+ (dev->ts_q.pt.dma >> 12));
+
+ /* reset hardware TS buffers */
+ saa_writeb(SAA7134_TS_SERIAL1, 0x00);
+ saa_writeb(SAA7134_TS_SERIAL1, 0x03);
+ saa_writeb(SAA7134_TS_SERIAL1, 0x00);
+ saa_writeb(SAA7134_TS_SERIAL1, 0x01);
+
+ /* TS clock non-inverted */
+ saa_writeb(SAA7134_TS_SERIAL1, 0x00);
+
+ /* Start TS stream */
+ switch (saa7134_boards[dev->board].ts_type) {
+ case SAA7134_MPEG_TS_PARALLEL:
+ saa_writeb(SAA7134_TS_SERIAL0, 0x40);
+ saa_writeb(SAA7134_TS_PARALLEL, 0xec |
+ (saa7134_boards[dev->board].ts_force_val << 4));
+ break;
+ case SAA7134_MPEG_TS_SERIAL:
+ saa_writeb(SAA7134_TS_SERIAL0, 0xd8);
+ saa_writeb(SAA7134_TS_PARALLEL, 0x6c |
+ (saa7134_boards[dev->board].ts_force_val << 4));
+ saa_writeb(SAA7134_TS_PARALLEL_SERIAL, 0xbc);
+ saa_writeb(SAA7134_TS_SERIAL1, 0x02);
+ break;
+ }
+
+ dev->ts_started = 1;
+
+ return 0;
+}
+
+int saa7134_ts_fini(struct saa7134_dev *dev)
+{
+ del_timer_sync(&dev->ts_q.timeout);
+ saa7134_pgtable_free(dev->pci, &dev->ts_q.pt);
+ return 0;
+}
+
+void saa7134_irq_ts_done(struct saa7134_dev *dev, unsigned long status)
+{
+ enum v4l2_field field;
+
+ spin_lock(&dev->slock);
+ if (dev->ts_q.curr) {
+ field = dev->ts_field;
+ if (field != V4L2_FIELD_TOP) {
+ if ((status & 0x100000) != 0x000000)
+ goto done;
+ } else {
+ if ((status & 0x100000) != 0x100000)
+ goto done;
+ }
+ saa7134_buffer_finish(dev, &dev->ts_q, VB2_BUF_STATE_DONE);
+ }
+ saa7134_buffer_next(dev,&dev->ts_q);
+
+ done:
+ spin_unlock(&dev->slock);
+}
diff --git a/drivers/media/pci/saa7134/saa7134-tvaudio.c b/drivers/media/pci/saa7134/saa7134-tvaudio.c
new file mode 100644
index 0000000000..9e0c442abc
--- /dev/null
+++ b/drivers/media/pci/saa7134/saa7134-tvaudio.c
@@ -0,0 +1,1068 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ *
+ * device driver for philips saa7134 based TV cards
+ * tv audio decoder (fm stereo, nicam, ...)
+ *
+ * (c) 2001-03 Gerd Knorr <kraxel@bytesex.org> [SuSE Labs]
+ */
+
+#include "saa7134.h"
+#include "saa7134-reg.h"
+
+#include <linux/init.h>
+#include <linux/list.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/kthread.h>
+#include <linux/delay.h>
+#include <linux/freezer.h>
+#include <asm/div64.h>
+
+/* ------------------------------------------------------------------ */
+
+static unsigned int audio_debug;
+module_param(audio_debug, int, 0644);
+MODULE_PARM_DESC(audio_debug,"enable debug messages [tv audio]");
+
+static unsigned int audio_ddep;
+module_param(audio_ddep, int, 0644);
+MODULE_PARM_DESC(audio_ddep,"audio ddep overwrite");
+
+static int audio_clock_override = UNSET;
+module_param(audio_clock_override, int, 0644);
+
+static int audio_clock_tweak;
+module_param(audio_clock_tweak, int, 0644);
+MODULE_PARM_DESC(audio_clock_tweak, "Audio clock tick fine tuning for cards with audio crystal that's slightly off (range [-1024 .. 1024])");
+
+#define audio_dbg(level, fmt, arg...) do { \
+ if (audio_debug >= level) \
+ printk(KERN_DEBUG pr_fmt("audio: " fmt), ## arg); \
+ } while (0)
+
+/* msecs */
+#define SCAN_INITIAL_DELAY 1000
+#define SCAN_SAMPLE_DELAY 200
+#define SCAN_SUBCARRIER_DELAY 2000
+
+/* ------------------------------------------------------------------ */
+/* saa7134 code */
+
+static struct mainscan {
+ char *name;
+ v4l2_std_id std;
+ int carr;
+} mainscan[] = {
+ {
+ .name = "MN",
+ .std = V4L2_STD_MN,
+ .carr = 4500,
+ },{
+ .name = "BGH",
+ .std = V4L2_STD_B | V4L2_STD_GH,
+ .carr = 5500,
+ },{
+ .name = "I",
+ .std = V4L2_STD_PAL_I,
+ .carr = 6000,
+ },{
+ .name = "DKL",
+ .std = V4L2_STD_DK | V4L2_STD_SECAM_L | V4L2_STD_SECAM_LC,
+ .carr = 6500,
+ }
+};
+
+static struct saa7134_tvaudio tvaudio[] = {
+ {
+ .name = "PAL-B/G FM-stereo",
+ .std = V4L2_STD_PAL_BG,
+ .mode = TVAUDIO_FM_BG_STEREO,
+ .carr1 = 5500,
+ .carr2 = 5742,
+ },{
+ .name = "PAL-D/K1 FM-stereo",
+ .std = V4L2_STD_PAL_DK,
+ .carr1 = 6500,
+ .carr2 = 6258,
+ .mode = TVAUDIO_FM_BG_STEREO,
+ },{
+ .name = "PAL-D/K2 FM-stereo",
+ .std = V4L2_STD_PAL_DK,
+ .carr1 = 6500,
+ .carr2 = 6742,
+ .mode = TVAUDIO_FM_BG_STEREO,
+ },{
+ .name = "PAL-D/K3 FM-stereo",
+ .std = V4L2_STD_PAL_DK,
+ .carr1 = 6500,
+ .carr2 = 5742,
+ .mode = TVAUDIO_FM_BG_STEREO,
+ },{
+ .name = "PAL-B/G NICAM",
+ .std = V4L2_STD_PAL_BG,
+ .carr1 = 5500,
+ .carr2 = 5850,
+ .mode = TVAUDIO_NICAM_FM,
+ },{
+ .name = "PAL-I NICAM",
+ .std = V4L2_STD_PAL_I,
+ .carr1 = 6000,
+ .carr2 = 6552,
+ .mode = TVAUDIO_NICAM_FM,
+ },{
+ .name = "PAL-D/K NICAM",
+ .std = V4L2_STD_PAL_DK,
+ .carr1 = 6500,
+ .carr2 = 5850,
+ .mode = TVAUDIO_NICAM_FM,
+ },{
+ .name = "SECAM-L NICAM",
+ .std = V4L2_STD_SECAM_L,
+ .carr1 = 6500,
+ .carr2 = 5850,
+ .mode = TVAUDIO_NICAM_AM,
+ },{
+ .name = "SECAM-D/K NICAM",
+ .std = V4L2_STD_SECAM_DK,
+ .carr1 = 6500,
+ .carr2 = 5850,
+ .mode = TVAUDIO_NICAM_FM,
+ },{
+ .name = "NTSC-A2 FM-stereo",
+ .std = V4L2_STD_NTSC,
+ .carr1 = 4500,
+ .carr2 = 4724,
+ .mode = TVAUDIO_FM_K_STEREO,
+ },{
+ .name = "NTSC-M",
+ .std = V4L2_STD_NTSC,
+ .carr1 = 4500,
+ .carr2 = -1,
+ .mode = TVAUDIO_FM_MONO,
+ }
+};
+#define TVAUDIO ARRAY_SIZE(tvaudio)
+
+/* ------------------------------------------------------------------ */
+
+static u32 tvaudio_carr2reg(u32 carrier)
+{
+ u64 a = carrier;
+
+ a <<= 24;
+ do_div(a,12288);
+ return a;
+}
+
+static void tvaudio_setcarrier(struct saa7134_dev *dev,
+ int primary, int secondary)
+{
+ if (-1 == secondary)
+ secondary = primary;
+ saa_writel(SAA7134_CARRIER1_FREQ0 >> 2, tvaudio_carr2reg(primary));
+ saa_writel(SAA7134_CARRIER2_FREQ0 >> 2, tvaudio_carr2reg(secondary));
+}
+
+#define SAA7134_MUTE_MASK 0xbb
+#define SAA7134_MUTE_ANALOG 0x04
+#define SAA7134_MUTE_I2S 0x40
+
+static void mute_input_7134(struct saa7134_dev *dev)
+{
+ unsigned int mute;
+ struct saa7134_input *in;
+ int ausel=0, ics=0, ocs=0;
+ int mask;
+
+ /* look what is to do ... */
+ in = dev->input;
+ mute = (dev->ctl_mute ||
+ (dev->automute && (&card(dev).radio) != in));
+ if (card(dev).mute.type) {
+ /*
+ * 7130 - we'll mute using some unconnected audio input
+ * 7134 - we'll probably should switch external mux with gpio
+ */
+ if (mute)
+ in = &card(dev).mute;
+ }
+
+ if (dev->hw_mute == mute &&
+ dev->hw_input == in && !dev->insuspend) {
+ audio_dbg(1, "mute/input: nothing to do [mute=%d,input=%s]\n",
+ mute, saa7134_input_name[in->type]);
+ return;
+ }
+
+ audio_dbg(1, "ctl_mute=%d automute=%d input=%s => mute=%d input=%s\n",
+ dev->ctl_mute, dev->automute,
+ saa7134_input_name[dev->input->type], mute,
+ saa7134_input_name[in->type]);
+ dev->hw_mute = mute;
+ dev->hw_input = in;
+
+ if (PCI_DEVICE_ID_PHILIPS_SAA7134 == dev->pci->device)
+ /* 7134 mute */
+ saa_writeb(SAA7134_AUDIO_MUTE_CTRL, mute ?
+ SAA7134_MUTE_MASK |
+ SAA7134_MUTE_ANALOG |
+ SAA7134_MUTE_I2S :
+ SAA7134_MUTE_MASK);
+
+ /* switch internal audio mux */
+ switch (in->amux) {
+ case TV: ausel=0xc0; ics=0x00; ocs=0x02; break;
+ case LINE1: ausel=0x80; ics=0x00; ocs=0x00; break;
+ case LINE2: ausel=0x80; ics=0x08; ocs=0x01; break;
+ case LINE2_LEFT: ausel=0x80; ics=0x08; ocs=0x05; break;
+ }
+ saa_andorb(SAA7134_AUDIO_FORMAT_CTRL, 0xc0, ausel);
+ saa_andorb(SAA7134_ANALOG_IO_SELECT, 0x08, ics);
+ saa_andorb(SAA7134_ANALOG_IO_SELECT, 0x07, ocs);
+ // for oss, we need to change the clock configuration
+ if (in->amux == TV)
+ saa_andorb(SAA7134_SIF_SAMPLE_FREQ, 0x03, 0x00);
+ else
+ saa_andorb(SAA7134_SIF_SAMPLE_FREQ, 0x03, 0x01);
+
+ /* switch gpio-connected external audio mux */
+ if (0 == card(dev).gpiomask)
+ return;
+
+ mask = card(dev).gpiomask;
+ saa_andorl(SAA7134_GPIO_GPMODE0 >> 2, mask, mask);
+ saa_andorl(SAA7134_GPIO_GPSTATUS0 >> 2, mask, in->gpio);
+ saa7134_track_gpio(dev, saa7134_input_name[in->type]);
+}
+
+static void tvaudio_setmode(struct saa7134_dev *dev,
+ struct saa7134_tvaudio *audio,
+ char *note)
+{
+ int acpf, tweak = 0;
+
+ if (dev->tvnorm->id == V4L2_STD_NTSC) {
+ acpf = 0x19066;
+ } else {
+ acpf = 0x1e000;
+ }
+ if (audio_clock_tweak > -1024 && audio_clock_tweak < 1024)
+ tweak = audio_clock_tweak;
+
+ if (note)
+ audio_dbg(1, "tvaudio_setmode: %s %s [%d.%03d/%d.%03d MHz] acpf=%d%+d\n",
+ note, audio->name,
+ audio->carr1 / 1000, audio->carr1 % 1000,
+ audio->carr2 / 1000, audio->carr2 % 1000,
+ acpf, tweak);
+
+ acpf += tweak;
+ saa_writeb(SAA7134_AUDIO_CLOCKS_PER_FIELD0, (acpf & 0x0000ff) >> 0);
+ saa_writeb(SAA7134_AUDIO_CLOCKS_PER_FIELD1, (acpf & 0x00ff00) >> 8);
+ saa_writeb(SAA7134_AUDIO_CLOCKS_PER_FIELD2, (acpf & 0x030000) >> 16);
+ tvaudio_setcarrier(dev,audio->carr1,audio->carr2);
+
+ switch (audio->mode) {
+ case TVAUDIO_FM_MONO:
+ case TVAUDIO_FM_BG_STEREO:
+ saa_writeb(SAA7134_DEMODULATOR, 0x00);
+ saa_writeb(SAA7134_DCXO_IDENT_CTRL, 0x00);
+ saa_writeb(SAA7134_FM_DEEMPHASIS, 0x22);
+ saa_writeb(SAA7134_FM_DEMATRIX, 0x80);
+ saa_writeb(SAA7134_STEREO_DAC_OUTPUT_SELECT, 0xa0);
+ break;
+ case TVAUDIO_FM_K_STEREO:
+ saa_writeb(SAA7134_DEMODULATOR, 0x00);
+ saa_writeb(SAA7134_DCXO_IDENT_CTRL, 0x01);
+ saa_writeb(SAA7134_FM_DEEMPHASIS, 0x22);
+ saa_writeb(SAA7134_FM_DEMATRIX, 0x80);
+ saa_writeb(SAA7134_STEREO_DAC_OUTPUT_SELECT, 0xa0);
+ break;
+ case TVAUDIO_NICAM_FM:
+ saa_writeb(SAA7134_DEMODULATOR, 0x10);
+ saa_writeb(SAA7134_DCXO_IDENT_CTRL, 0x00);
+ saa_writeb(SAA7134_FM_DEEMPHASIS, 0x44);
+ saa_writeb(SAA7134_STEREO_DAC_OUTPUT_SELECT, 0xa1);
+ saa_writeb(SAA7134_NICAM_CONFIG, 0x00);
+ break;
+ case TVAUDIO_NICAM_AM:
+ saa_writeb(SAA7134_DEMODULATOR, 0x12);
+ saa_writeb(SAA7134_DCXO_IDENT_CTRL, 0x00);
+ saa_writeb(SAA7134_FM_DEEMPHASIS, 0x44);
+ saa_writeb(SAA7134_STEREO_DAC_OUTPUT_SELECT, 0xa1);
+ saa_writeb(SAA7134_NICAM_CONFIG, 0x00);
+ break;
+ case TVAUDIO_FM_SAT_STEREO:
+ /* not implemented (yet) */
+ break;
+ }
+}
+
+static int tvaudio_sleep(struct saa7134_dev *dev, int timeout)
+{
+ if (dev->thread.scan1 == dev->thread.scan2 &&
+ !kthread_should_stop()) {
+ if (timeout < 0) {
+ set_current_state(TASK_INTERRUPTIBLE);
+ schedule();
+ } else {
+ schedule_timeout_interruptible
+ (msecs_to_jiffies(timeout));
+ }
+ }
+ return dev->thread.scan1 != dev->thread.scan2;
+}
+
+static int tvaudio_checkcarrier(struct saa7134_dev *dev, struct mainscan *scan)
+{
+ __s32 left,right,value;
+
+ if (!(dev->tvnorm->id & scan->std)) {
+ audio_dbg(1, "skipping %d.%03d MHz [%4s]\n",
+ scan->carr / 1000, scan->carr % 1000, scan->name);
+ return 0;
+ }
+
+ if (audio_debug > 1) {
+ int i;
+ audio_dbg(1, "debug %d:", scan->carr);
+ for (i = -150; i <= 150; i += 30) {
+ tvaudio_setcarrier(dev,scan->carr+i,scan->carr+i);
+ saa_readl(SAA7134_LEVEL_READOUT1 >> 2);
+ if (tvaudio_sleep(dev,SCAN_SAMPLE_DELAY))
+ return -1;
+ value = saa_readl(SAA7134_LEVEL_READOUT1 >> 2);
+ if (0 == i)
+ pr_cont(" # %6d # ", value >> 16);
+ else
+ pr_cont(" %6d", value >> 16);
+ }
+ pr_cont("\n");
+ }
+
+ tvaudio_setcarrier(dev,scan->carr-90,scan->carr-90);
+ saa_readl(SAA7134_LEVEL_READOUT1 >> 2);
+ if (tvaudio_sleep(dev,SCAN_SAMPLE_DELAY))
+ return -1;
+ left = saa_readl(SAA7134_LEVEL_READOUT1 >> 2);
+
+ tvaudio_setcarrier(dev,scan->carr+90,scan->carr+90);
+ saa_readl(SAA7134_LEVEL_READOUT1 >> 2);
+ if (tvaudio_sleep(dev,SCAN_SAMPLE_DELAY))
+ return -1;
+ right = saa_readl(SAA7134_LEVEL_READOUT1 >> 2);
+
+ left >>= 16;
+ right >>= 16;
+ value = left > right ? left - right : right - left;
+ audio_dbg(1, "scanning %d.%03d MHz [%4s] => dc is %5d [%d/%d]\n",
+ scan->carr / 1000, scan->carr % 1000,
+ scan->name, value, left, right);
+ return value;
+}
+
+
+static int tvaudio_getstereo(struct saa7134_dev *dev, struct saa7134_tvaudio *audio)
+{
+ __u32 idp, nicam, nicam_status;
+ int retval = -1;
+
+ switch (audio->mode) {
+ case TVAUDIO_FM_MONO:
+ return V4L2_TUNER_SUB_MONO;
+ case TVAUDIO_FM_K_STEREO:
+ case TVAUDIO_FM_BG_STEREO:
+ idp = (saa_readb(SAA7134_IDENT_SIF) & 0xe0) >> 5;
+ audio_dbg(1, "getstereo: fm/stereo: idp=0x%x\n", idp);
+ if (0x03 == (idp & 0x03))
+ retval = V4L2_TUNER_SUB_LANG1 | V4L2_TUNER_SUB_LANG2;
+ else if (0x05 == (idp & 0x05))
+ retval = V4L2_TUNER_SUB_MONO | V4L2_TUNER_SUB_STEREO;
+ else if (0x01 == (idp & 0x01))
+ retval = V4L2_TUNER_SUB_MONO;
+ break;
+ case TVAUDIO_FM_SAT_STEREO:
+ /* not implemented (yet) */
+ break;
+ case TVAUDIO_NICAM_FM:
+ case TVAUDIO_NICAM_AM:
+ nicam = saa_readb(SAA7134_AUDIO_STATUS);
+ audio_dbg(1, "getstereo: nicam=0x%x\n", nicam);
+ if (nicam & 0x1) {
+ nicam_status = saa_readb(SAA7134_NICAM_STATUS);
+ audio_dbg(1, "getstereo: nicam_status=0x%x\n",
+ nicam_status);
+
+ switch (nicam_status & 0x03) {
+ case 0x01:
+ retval = V4L2_TUNER_SUB_LANG1 | V4L2_TUNER_SUB_LANG2;
+ break;
+ case 0x02:
+ retval = V4L2_TUNER_SUB_MONO | V4L2_TUNER_SUB_STEREO;
+ break;
+ default:
+ retval = V4L2_TUNER_SUB_MONO;
+ }
+ } else {
+ /* No nicam detected */
+ }
+ break;
+ }
+ if (retval != -1)
+ audio_dbg(1, "found audio subchannels:%s%s%s%s\n",
+ (retval & V4L2_TUNER_SUB_MONO) ? " mono" : "",
+ (retval & V4L2_TUNER_SUB_STEREO) ? " stereo" : "",
+ (retval & V4L2_TUNER_SUB_LANG1) ? " lang1" : "",
+ (retval & V4L2_TUNER_SUB_LANG2) ? " lang2" : "");
+ return retval;
+}
+
+static int tvaudio_setstereo(struct saa7134_dev *dev, struct saa7134_tvaudio *audio,
+ u32 mode)
+{
+ static char *name[] = {
+ [ V4L2_TUNER_MODE_MONO ] = "mono",
+ [ V4L2_TUNER_MODE_STEREO ] = "stereo",
+ [ V4L2_TUNER_MODE_LANG1 ] = "lang1",
+ [ V4L2_TUNER_MODE_LANG2 ] = "lang2",
+ [ V4L2_TUNER_MODE_LANG1_LANG2 ] = "lang1+lang2",
+ };
+ static u32 fm[] = {
+ [ V4L2_TUNER_MODE_MONO ] = 0x00, /* ch1 */
+ [ V4L2_TUNER_MODE_STEREO ] = 0x80, /* auto */
+ [ V4L2_TUNER_MODE_LANG1 ] = 0x00, /* ch1 */
+ [ V4L2_TUNER_MODE_LANG2 ] = 0x01, /* ch2 */
+ [ V4L2_TUNER_MODE_LANG1_LANG2 ] = 0x80, /* auto */
+ };
+ u32 reg;
+
+ switch (audio->mode) {
+ case TVAUDIO_FM_MONO:
+ /* nothing to do ... */
+ break;
+ case TVAUDIO_FM_K_STEREO:
+ case TVAUDIO_FM_BG_STEREO:
+ case TVAUDIO_NICAM_AM:
+ case TVAUDIO_NICAM_FM:
+ audio_dbg(1, "setstereo [fm] => %s\n",
+ name[mode % ARRAY_SIZE(name)]);
+ reg = fm[ mode % ARRAY_SIZE(fm) ];
+ saa_writeb(SAA7134_FM_DEMATRIX, reg);
+ break;
+ case TVAUDIO_FM_SAT_STEREO:
+ /* Not implemented */
+ break;
+ }
+ return 0;
+}
+
+static int tvaudio_thread(void *data)
+{
+ struct saa7134_dev *dev = data;
+ int carr_vals[ARRAY_SIZE(mainscan)];
+ unsigned int i, audio, nscan;
+ int max1,max2,carrier,rx,mode,lastmode,default_carrier;
+
+ set_freezable();
+
+ for (;;) {
+ tvaudio_sleep(dev,-1);
+ if (kthread_should_stop())
+ goto done;
+
+ restart:
+ try_to_freeze();
+
+ dev->thread.scan1 = dev->thread.scan2;
+ audio_dbg(1, "tvaudio thread scan start [%d]\n",
+ dev->thread.scan1);
+ dev->tvaudio = NULL;
+
+ saa_writeb(SAA7134_MONITOR_SELECT, 0xa0);
+ saa_writeb(SAA7134_FM_DEMATRIX, 0x80);
+
+ if (dev->ctl_automute)
+ dev->automute = 1;
+
+ mute_input_7134(dev);
+
+ /* give the tuner some time */
+ if (tvaudio_sleep(dev,SCAN_INITIAL_DELAY))
+ goto restart;
+
+ max1 = 0;
+ max2 = 0;
+ nscan = 0;
+ carrier = 0;
+ default_carrier = 0;
+ for (i = 0; i < ARRAY_SIZE(mainscan); i++) {
+ if (!(dev->tvnorm->id & mainscan[i].std))
+ continue;
+ if (!default_carrier)
+ default_carrier = mainscan[i].carr;
+ nscan++;
+ }
+
+ if (1 == nscan) {
+ /* only one candidate -- skip scan ;) */
+ audio_dbg(1, "only one main carrier candidate - skipping scan\n");
+ max1 = 12345;
+ carrier = default_carrier;
+ } else {
+ /* scan for the main carrier */
+ saa_writeb(SAA7134_MONITOR_SELECT,0x00);
+ tvaudio_setmode(dev,&tvaudio[0],NULL);
+ for (i = 0; i < ARRAY_SIZE(mainscan); i++) {
+ carr_vals[i] = tvaudio_checkcarrier(dev, mainscan+i);
+ if (dev->thread.scan1 != dev->thread.scan2)
+ goto restart;
+ }
+ for (max1 = 0, max2 = 0, i = 0; i < ARRAY_SIZE(mainscan); i++) {
+ if (max1 < carr_vals[i]) {
+ max2 = max1;
+ max1 = carr_vals[i];
+ carrier = mainscan[i].carr;
+ } else if (max2 < carr_vals[i]) {
+ max2 = carr_vals[i];
+ }
+ }
+ }
+
+ if (0 != carrier && max1 > 2000 && max1 > max2*3) {
+ /* found good carrier */
+ audio_dbg(1, "found %s main sound carrier @ %d.%03d MHz [%d/%d]\n",
+ dev->tvnorm->name, carrier/1000, carrier%1000,
+ max1, max2);
+ dev->last_carrier = carrier;
+ dev->automute = 0;
+
+ } else if (0 != dev->last_carrier) {
+ /* no carrier -- try last detected one as fallback */
+ carrier = dev->last_carrier;
+ audio_dbg(1, "audio carrier scan failed, using %d.%03d MHz [last detected]\n",
+ carrier/1000, carrier%1000);
+ dev->automute = 1;
+
+ } else {
+ /* no carrier + no fallback -- use default */
+ carrier = default_carrier;
+ audio_dbg(1, "audio carrier scan failed, using %d.%03d MHz [default]\n",
+ carrier/1000, carrier%1000);
+ dev->automute = 1;
+ }
+ tvaudio_setcarrier(dev,carrier,carrier);
+ saa_andorb(SAA7134_STEREO_DAC_OUTPUT_SELECT, 0x30, 0x00);
+ saa7134_tvaudio_setmute(dev);
+ /* find the exact tv audio norm */
+ for (audio = UNSET, i = 0; i < TVAUDIO; i++) {
+ if (dev->tvnorm->id != UNSET &&
+ !(dev->tvnorm->id & tvaudio[i].std))
+ continue;
+ if (tvaudio[i].carr1 != carrier)
+ continue;
+ /* Note: at least the primary carrier is right here */
+ if (UNSET == audio)
+ audio = i;
+ tvaudio_setmode(dev,&tvaudio[i],"trying");
+ if (tvaudio_sleep(dev,SCAN_SUBCARRIER_DELAY))
+ goto restart;
+ if (-1 != tvaudio_getstereo(dev,&tvaudio[i])) {
+ audio = i;
+ break;
+ }
+ }
+ saa_andorb(SAA7134_STEREO_DAC_OUTPUT_SELECT, 0x30, 0x30);
+ if (UNSET == audio)
+ continue;
+ tvaudio_setmode(dev,&tvaudio[audio],"using");
+
+ tvaudio_setstereo(dev,&tvaudio[audio],V4L2_TUNER_MODE_MONO);
+ dev->tvaudio = &tvaudio[audio];
+
+ lastmode = 42;
+ for (;;) {
+
+ try_to_freeze();
+
+ if (tvaudio_sleep(dev,5000))
+ goto restart;
+ if (kthread_should_stop())
+ break;
+ if (UNSET == dev->thread.mode) {
+ rx = tvaudio_getstereo(dev, &tvaudio[audio]);
+ mode = saa7134_tvaudio_rx2mode(rx);
+ } else {
+ mode = dev->thread.mode;
+ }
+ if (lastmode != mode) {
+ tvaudio_setstereo(dev,&tvaudio[audio],mode);
+ lastmode = mode;
+ }
+ }
+ }
+
+ done:
+ dev->thread.stopped = 1;
+ return 0;
+}
+
+/* ------------------------------------------------------------------ */
+/* saa7133 / saa7135 code */
+
+static char *stdres[0x20] = {
+ [0x00] = "no standard detected",
+ [0x01] = "B/G (in progress)",
+ [0x02] = "D/K (in progress)",
+ [0x03] = "M (in progress)",
+
+ [0x04] = "B/G A2",
+ [0x05] = "B/G NICAM",
+ [0x06] = "D/K A2 (1)",
+ [0x07] = "D/K A2 (2)",
+ [0x08] = "D/K A2 (3)",
+ [0x09] = "D/K NICAM",
+ [0x0a] = "L NICAM",
+ [0x0b] = "I NICAM",
+
+ [0x0c] = "M Korea",
+ [0x0d] = "M BTSC ",
+ [0x0e] = "M EIAJ",
+
+ [0x0f] = "FM radio / IF 10.7 / 50 deemp",
+ [0x10] = "FM radio / IF 10.7 / 75 deemp",
+ [0x11] = "FM radio / IF sel / 50 deemp",
+ [0x12] = "FM radio / IF sel / 75 deemp",
+
+ [0x13 ... 0x1e ] = "unknown",
+ [0x1f] = "??? [in progress]",
+};
+
+#define DSP_RETRY 32
+#define DSP_DELAY 16
+#define SAA7135_DSP_RWCLEAR_RERR 1
+
+static inline int saa_dsp_reset_error_bit(struct saa7134_dev *dev)
+{
+ int state = saa_readb(SAA7135_DSP_RWSTATE);
+ if (unlikely(state & SAA7135_DSP_RWSTATE_ERR)) {
+ audio_dbg(2, "%s: resetting error bit\n", dev->name);
+ saa_writeb(SAA7135_DSP_RWCLEAR, SAA7135_DSP_RWCLEAR_RERR);
+ }
+ return 0;
+}
+
+static inline int saa_dsp_wait_bit(struct saa7134_dev *dev, int bit)
+{
+ int state, count = DSP_RETRY;
+
+ state = saa_readb(SAA7135_DSP_RWSTATE);
+ if (unlikely(state & SAA7135_DSP_RWSTATE_ERR)) {
+ pr_warn("%s: dsp access error\n", dev->name);
+ saa_dsp_reset_error_bit(dev);
+ return -EIO;
+ }
+ while (0 == (state & bit)) {
+ if (unlikely(0 == count)) {
+ pr_err("dsp access wait timeout [bit=%s]\n",
+ (bit & SAA7135_DSP_RWSTATE_WRR) ? "WRR" :
+ (bit & SAA7135_DSP_RWSTATE_RDB) ? "RDB" :
+ (bit & SAA7135_DSP_RWSTATE_IDA) ? "IDA" :
+ "???");
+ return -EIO;
+ }
+ saa_wait(DSP_DELAY);
+ state = saa_readb(SAA7135_DSP_RWSTATE);
+ count--;
+ }
+ return 0;
+}
+
+
+int saa_dsp_writel(struct saa7134_dev *dev, int reg, u32 value)
+{
+ int err;
+
+ audio_dbg(2, "dsp write reg 0x%x = 0x%06x\n",
+ (reg << 2) & 0xffffffff, value);
+ err = saa_dsp_wait_bit(dev,SAA7135_DSP_RWSTATE_WRR);
+ if (err < 0)
+ return err;
+ saa_writel(reg,value);
+ err = saa_dsp_wait_bit(dev,SAA7135_DSP_RWSTATE_WRR);
+ if (err < 0)
+ return err;
+ return 0;
+}
+
+static int getstereo_7133(struct saa7134_dev *dev)
+{
+ int retval = V4L2_TUNER_SUB_MONO;
+ u32 value;
+
+ value = saa_readl(0x528 >> 2);
+ if (value & 0x20)
+ retval = V4L2_TUNER_SUB_MONO | V4L2_TUNER_SUB_STEREO;
+ if (value & 0x40)
+ retval = V4L2_TUNER_SUB_LANG1 | V4L2_TUNER_SUB_LANG2;
+ return retval;
+}
+
+static int mute_input_7133(struct saa7134_dev *dev)
+{
+ u32 reg = 0;
+ u32 xbarin, xbarout;
+ int mask;
+ struct saa7134_input *in;
+
+ xbarin = 0x03;
+ switch (dev->input->amux) {
+ case TV:
+ reg = 0x02;
+ xbarin = 0;
+ break;
+ case LINE1:
+ reg = 0x00;
+ break;
+ case LINE2:
+ case LINE2_LEFT:
+ reg = 0x09;
+ break;
+ }
+ saa_dsp_writel(dev, 0x464 >> 2, xbarin);
+ if (dev->ctl_mute) {
+ reg = 0x07;
+ xbarout = 0xbbbbbb;
+ } else
+ xbarout = 0xbbbb10;
+ saa_dsp_writel(dev, 0x46c >> 2, xbarout);
+
+ saa_writel(0x594 >> 2, reg);
+
+
+ /* switch gpio-connected external audio mux */
+ if (0 != card(dev).gpiomask) {
+ mask = card(dev).gpiomask;
+
+ if (card(dev).mute.type && dev->ctl_mute)
+ in = &card(dev).mute;
+ else
+ in = dev->input;
+
+ saa_andorl(SAA7134_GPIO_GPMODE0 >> 2, mask, mask);
+ saa_andorl(SAA7134_GPIO_GPSTATUS0 >> 2, mask, in->gpio);
+ saa7134_track_gpio(dev, saa7134_input_name[in->type]);
+ }
+
+ return 0;
+}
+
+static int tvaudio_thread_ddep(void *data)
+{
+ struct saa7134_dev *dev = data;
+ u32 value, norms;
+
+ set_freezable();
+ for (;;) {
+ tvaudio_sleep(dev,-1);
+ if (kthread_should_stop())
+ goto done;
+ restart:
+ try_to_freeze();
+
+ dev->thread.scan1 = dev->thread.scan2;
+ audio_dbg(1, "tvaudio thread scan start [%d]\n",
+ dev->thread.scan1);
+
+ if (audio_ddep >= 0x04 && audio_ddep <= 0x0e) {
+ /* insmod option override */
+ norms = (audio_ddep << 2) | 0x01;
+ audio_dbg(1, "ddep override: %s\n",
+ stdres[audio_ddep]);
+ } else if (&card(dev).radio == dev->input) {
+ audio_dbg(1, "FM Radio\n");
+ if (dev->tuner_type == TUNER_PHILIPS_TDA8290) {
+ norms = (0x11 << 2) | 0x01;
+ /* set IF frequency to 5.5 MHz */
+ saa_dsp_writel(dev, 0x42c >> 2, 0x729555);
+ } else {
+ norms = (0x0f << 2) | 0x01;
+ }
+ } else {
+ /* (let chip) scan for sound carrier */
+ norms = 0;
+ if (dev->tvnorm->id & (V4L2_STD_B | V4L2_STD_GH))
+ norms |= 0x04;
+ if (dev->tvnorm->id & V4L2_STD_PAL_I)
+ norms |= 0x20;
+ if (dev->tvnorm->id & V4L2_STD_DK)
+ norms |= 0x08;
+ if (dev->tvnorm->id & V4L2_STD_MN)
+ norms |= 0x40;
+ if (dev->tvnorm->id & (V4L2_STD_SECAM_L | V4L2_STD_SECAM_LC))
+ norms |= 0x10;
+ if (0 == norms)
+ norms = 0x7c; /* all */
+ audio_dbg(1, "scanning:%s%s%s%s%s\n",
+ (norms & 0x04) ? " B/G" : "",
+ (norms & 0x08) ? " D/K" : "",
+ (norms & 0x10) ? " L/L'" : "",
+ (norms & 0x20) ? " I" : "",
+ (norms & 0x40) ? " M" : "");
+ }
+
+ /* kick automatic standard detection */
+ saa_dsp_writel(dev, 0x454 >> 2, 0);
+ saa_dsp_writel(dev, 0x454 >> 2, norms | 0x80);
+
+ /* setup crossbars */
+ saa_dsp_writel(dev, 0x464 >> 2, 0x000000);
+ saa_dsp_writel(dev, 0x470 >> 2, 0x101010);
+
+ if (tvaudio_sleep(dev,3000))
+ goto restart;
+ value = saa_readl(0x528 >> 2) & 0xffffff;
+
+ audio_dbg(1, "tvaudio thread status: 0x%x [%s%s%s]\n",
+ value, stdres[value & 0x1f],
+ (value & 0x000020) ? ",stereo" : "",
+ (value & 0x000040) ? ",dual" : "");
+ audio_dbg(1, "detailed status: %s#%s#%s#%s#%s#%s#%s#%s#%s#%s#%s#%s#%s#%s\n",
+ (value & 0x000080) ? " A2/EIAJ pilot tone " : "",
+ (value & 0x000100) ? " A2/EIAJ dual " : "",
+ (value & 0x000200) ? " A2/EIAJ stereo " : "",
+ (value & 0x000400) ? " A2/EIAJ noise mute " : "",
+
+ (value & 0x000800) ? " BTSC/FM radio pilot " : "",
+ (value & 0x001000) ? " SAP carrier " : "",
+ (value & 0x002000) ? " BTSC stereo noise mute " : "",
+ (value & 0x004000) ? " SAP noise mute " : "",
+ (value & 0x008000) ? " VDSP " : "",
+
+ (value & 0x010000) ? " NICST " : "",
+ (value & 0x020000) ? " NICDU " : "",
+ (value & 0x040000) ? " NICAM muted " : "",
+ (value & 0x080000) ? " NICAM reserve sound " : "",
+
+ (value & 0x100000) ? " init done " : "");
+ }
+
+ done:
+ dev->thread.stopped = 1;
+ return 0;
+}
+
+/* ------------------------------------------------------------------ */
+/* common stuff + external entry points */
+
+void saa7134_enable_i2s(struct saa7134_dev *dev)
+{
+ int i2s_format;
+
+ if (!card_is_empress(dev))
+ return;
+
+ if (dev->pci->device == PCI_DEVICE_ID_PHILIPS_SAA7130)
+ return;
+
+ /* configure GPIO for out */
+ saa_andorl(SAA7134_GPIO_GPMODE0 >> 2, 0x0E000000, 0x00000000);
+
+ switch (dev->pci->device) {
+ case PCI_DEVICE_ID_PHILIPS_SAA7133:
+ case PCI_DEVICE_ID_PHILIPS_SAA7135:
+ /* Set I2S format (SONY) */
+ saa_writeb(SAA7133_I2S_AUDIO_CONTROL, 0x00);
+ /* Start I2S */
+ saa_writeb(SAA7134_I2S_AUDIO_OUTPUT, 0x11);
+ break;
+
+ case PCI_DEVICE_ID_PHILIPS_SAA7134:
+ i2s_format = (dev->input->amux == TV) ? 0x00 : 0x01;
+
+ /* enable I2S audio output for the mpeg encoder */
+ saa_writeb(SAA7134_I2S_OUTPUT_SELECT, 0x80);
+ saa_writeb(SAA7134_I2S_OUTPUT_FORMAT, i2s_format);
+ saa_writeb(SAA7134_I2S_OUTPUT_LEVEL, 0x0F);
+ saa_writeb(SAA7134_I2S_AUDIO_OUTPUT, 0x01);
+ break;
+
+ default:
+ break;
+ }
+}
+
+int saa7134_tvaudio_rx2mode(u32 rx)
+{
+ u32 mode;
+
+ mode = V4L2_TUNER_MODE_MONO;
+ if (rx & V4L2_TUNER_SUB_STEREO)
+ mode = V4L2_TUNER_MODE_STEREO;
+ else if (rx & V4L2_TUNER_SUB_LANG1)
+ mode = V4L2_TUNER_MODE_LANG1;
+ else if (rx & V4L2_TUNER_SUB_LANG2)
+ mode = V4L2_TUNER_MODE_LANG2;
+ return mode;
+}
+
+void saa7134_tvaudio_setmute(struct saa7134_dev *dev)
+{
+ switch (dev->pci->device) {
+ case PCI_DEVICE_ID_PHILIPS_SAA7130:
+ case PCI_DEVICE_ID_PHILIPS_SAA7134:
+ mute_input_7134(dev);
+ break;
+ case PCI_DEVICE_ID_PHILIPS_SAA7133:
+ case PCI_DEVICE_ID_PHILIPS_SAA7135:
+ mute_input_7133(dev);
+ break;
+ }
+}
+
+void saa7134_tvaudio_setinput(struct saa7134_dev *dev,
+ struct saa7134_input *in)
+{
+ dev->input = in;
+ switch (dev->pci->device) {
+ case PCI_DEVICE_ID_PHILIPS_SAA7130:
+ case PCI_DEVICE_ID_PHILIPS_SAA7134:
+ mute_input_7134(dev);
+ break;
+ case PCI_DEVICE_ID_PHILIPS_SAA7133:
+ case PCI_DEVICE_ID_PHILIPS_SAA7135:
+ mute_input_7133(dev);
+ break;
+ }
+ saa7134_enable_i2s(dev);
+}
+
+void saa7134_tvaudio_setvolume(struct saa7134_dev *dev, int level)
+{
+ switch (dev->pci->device) {
+ case PCI_DEVICE_ID_PHILIPS_SAA7134:
+ saa_writeb(SAA7134_CHANNEL1_LEVEL, level & 0x1f);
+ saa_writeb(SAA7134_CHANNEL2_LEVEL, level & 0x1f);
+ saa_writeb(SAA7134_NICAM_LEVEL_ADJUST, level & 0x1f);
+ break;
+ }
+}
+
+int saa7134_tvaudio_getstereo(struct saa7134_dev *dev)
+{
+ int retval = V4L2_TUNER_SUB_MONO;
+
+ switch (dev->pci->device) {
+ case PCI_DEVICE_ID_PHILIPS_SAA7134:
+ if (dev->tvaudio)
+ retval = tvaudio_getstereo(dev,dev->tvaudio);
+ break;
+ case PCI_DEVICE_ID_PHILIPS_SAA7133:
+ case PCI_DEVICE_ID_PHILIPS_SAA7135:
+ retval = getstereo_7133(dev);
+ break;
+ }
+ return retval;
+}
+
+void saa7134_tvaudio_init(struct saa7134_dev *dev)
+{
+ int clock = saa7134_boards[dev->board].audio_clock;
+
+ if (UNSET != audio_clock_override)
+ clock = audio_clock_override;
+
+ switch (dev->pci->device) {
+ case PCI_DEVICE_ID_PHILIPS_SAA7134:
+ /* init all audio registers */
+ saa_writeb(SAA7134_AUDIO_PLL_CTRL, 0x00);
+ if (need_resched())
+ schedule();
+ else
+ udelay(10);
+
+ saa_writeb(SAA7134_AUDIO_CLOCK0, clock & 0xff);
+ saa_writeb(SAA7134_AUDIO_CLOCK1, (clock >> 8) & 0xff);
+ saa_writeb(SAA7134_AUDIO_CLOCK2, (clock >> 16) & 0xff);
+ /* frame locked audio is mandatory for NICAM */
+ saa_writeb(SAA7134_AUDIO_PLL_CTRL, 0x01);
+ saa_writeb(SAA7134_NICAM_ERROR_LOW, 0x14);
+ saa_writeb(SAA7134_NICAM_ERROR_HIGH, 0x50);
+ break;
+ case PCI_DEVICE_ID_PHILIPS_SAA7133:
+ case PCI_DEVICE_ID_PHILIPS_SAA7135:
+ saa_writel(0x598 >> 2, clock);
+ saa_dsp_writel(dev, 0x474 >> 2, 0x00);
+ saa_dsp_writel(dev, 0x450 >> 2, 0x00);
+ }
+}
+
+int saa7134_tvaudio_init2(struct saa7134_dev *dev)
+{
+ int (*my_thread)(void *data) = NULL;
+
+ switch (dev->pci->device) {
+ case PCI_DEVICE_ID_PHILIPS_SAA7134:
+ my_thread = tvaudio_thread;
+ break;
+ case PCI_DEVICE_ID_PHILIPS_SAA7133:
+ case PCI_DEVICE_ID_PHILIPS_SAA7135:
+ my_thread = tvaudio_thread_ddep;
+ break;
+ }
+
+ dev->thread.thread = NULL;
+ dev->thread.scan1 = dev->thread.scan2 = 0;
+ if (my_thread) {
+ saa7134_tvaudio_init(dev);
+ /* start tvaudio thread */
+ dev->thread.thread = kthread_run(my_thread, dev, "%s", dev->name);
+ if (IS_ERR(dev->thread.thread)) {
+ pr_warn("%s: kernel_thread() failed\n",
+ dev->name);
+ /* XXX: missing error handling here */
+ }
+ }
+
+ saa7134_enable_i2s(dev);
+ return 0;
+}
+
+int saa7134_tvaudio_close(struct saa7134_dev *dev)
+{
+ dev->automute = 1;
+ /* anything else to undo? */
+ return 0;
+}
+
+int saa7134_tvaudio_fini(struct saa7134_dev *dev)
+{
+ /* shutdown tvaudio thread */
+ if (dev->thread.thread && !dev->thread.stopped)
+ kthread_stop(dev->thread.thread);
+
+ saa_andorb(SAA7134_ANALOG_IO_SELECT, 0x07, 0x00); /* LINE1 */
+ return 0;
+}
+
+int saa7134_tvaudio_do_scan(struct saa7134_dev *dev)
+{
+ if (dev->input->amux != TV) {
+ audio_dbg(1, "sound IF not in use, skipping scan\n");
+ dev->automute = 0;
+ saa7134_tvaudio_setmute(dev);
+ } else if (dev->thread.thread) {
+ dev->thread.mode = UNSET;
+ dev->thread.scan2++;
+
+ if (!dev->insuspend && !dev->thread.stopped)
+ wake_up_process(dev->thread.thread);
+ } else {
+ dev->automute = 0;
+ saa7134_tvaudio_setmute(dev);
+ }
+ return 0;
+}
+
+EXPORT_SYMBOL(saa_dsp_writel);
+EXPORT_SYMBOL(saa7134_tvaudio_setmute);
diff --git a/drivers/media/pci/saa7134/saa7134-vbi.c b/drivers/media/pci/saa7134/saa7134-vbi.c
new file mode 100644
index 0000000000..3e77369046
--- /dev/null
+++ b/drivers/media/pci/saa7134/saa7134-vbi.c
@@ -0,0 +1,210 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ *
+ * device driver for philips saa7134 based TV cards
+ * video4linux video interface
+ *
+ * (c) 2001,02 Gerd Knorr <kraxel@bytesex.org> [SuSE Labs]
+ */
+
+#include "saa7134.h"
+#include "saa7134-reg.h"
+
+#include <linux/init.h>
+#include <linux/list.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+
+/* ------------------------------------------------------------------ */
+
+static unsigned int vbi_debug;
+module_param(vbi_debug, int, 0644);
+MODULE_PARM_DESC(vbi_debug,"enable debug messages [vbi]");
+
+static unsigned int vbibufs = 4;
+module_param(vbibufs, int, 0444);
+MODULE_PARM_DESC(vbibufs,"number of vbi buffers, range 2-32");
+
+#define vbi_dbg(fmt, arg...) do { \
+ if (vbi_debug) \
+ printk(KERN_DEBUG pr_fmt("vbi: " fmt), ## arg); \
+ } while (0)
+
+/* ------------------------------------------------------------------ */
+
+#define VBI_LINE_COUNT 17
+#define VBI_LINE_LENGTH 2048
+#define VBI_SCALE 0x200
+
+static void task_init(struct saa7134_dev *dev, struct saa7134_buf *buf,
+ int task)
+{
+ struct saa7134_tvnorm *norm = dev->tvnorm;
+
+ /* setup video scaler */
+ saa_writeb(SAA7134_VBI_H_START1(task), norm->h_start & 0xff);
+ saa_writeb(SAA7134_VBI_H_START2(task), norm->h_start >> 8);
+ saa_writeb(SAA7134_VBI_H_STOP1(task), norm->h_stop & 0xff);
+ saa_writeb(SAA7134_VBI_H_STOP2(task), norm->h_stop >> 8);
+ saa_writeb(SAA7134_VBI_V_START1(task), norm->vbi_v_start_0 & 0xff);
+ saa_writeb(SAA7134_VBI_V_START2(task), norm->vbi_v_start_0 >> 8);
+ saa_writeb(SAA7134_VBI_V_STOP1(task), norm->vbi_v_stop_0 & 0xff);
+ saa_writeb(SAA7134_VBI_V_STOP2(task), norm->vbi_v_stop_0 >> 8);
+
+ saa_writeb(SAA7134_VBI_H_SCALE_INC1(task), VBI_SCALE & 0xff);
+ saa_writeb(SAA7134_VBI_H_SCALE_INC2(task), VBI_SCALE >> 8);
+ saa_writeb(SAA7134_VBI_PHASE_OFFSET_LUMA(task), 0x00);
+ saa_writeb(SAA7134_VBI_PHASE_OFFSET_CHROMA(task), 0x00);
+
+ saa_writeb(SAA7134_VBI_H_LEN1(task), dev->vbi_hlen & 0xff);
+ saa_writeb(SAA7134_VBI_H_LEN2(task), dev->vbi_hlen >> 8);
+ saa_writeb(SAA7134_VBI_V_LEN1(task), dev->vbi_vlen & 0xff);
+ saa_writeb(SAA7134_VBI_V_LEN2(task), dev->vbi_vlen >> 8);
+
+ saa_andorb(SAA7134_DATA_PATH(task), 0xc0, 0x00);
+}
+
+/* ------------------------------------------------------------------ */
+
+static int buffer_activate(struct saa7134_dev *dev,
+ struct saa7134_buf *buf,
+ struct saa7134_buf *next)
+{
+ struct saa7134_dmaqueue *dmaq = buf->vb2.vb2_buf.vb2_queue->drv_priv;
+ unsigned long control, base;
+
+ vbi_dbg("buffer_activate [%p]\n", buf);
+ buf->top_seen = 0;
+
+ task_init(dev, buf, TASK_A);
+ task_init(dev, buf, TASK_B);
+ saa_writeb(SAA7134_OFMT_DATA_A, 0x06);
+ saa_writeb(SAA7134_OFMT_DATA_B, 0x06);
+
+ /* DMA: setup channel 2+3 (= VBI Task A+B) */
+ base = saa7134_buffer_base(buf);
+ control = SAA7134_RS_CONTROL_BURST_16 |
+ SAA7134_RS_CONTROL_ME |
+ (dmaq->pt.dma >> 12);
+ saa_writel(SAA7134_RS_BA1(2), base);
+ saa_writel(SAA7134_RS_BA2(2), base + dev->vbi_hlen * dev->vbi_vlen);
+ saa_writel(SAA7134_RS_PITCH(2), dev->vbi_hlen);
+ saa_writel(SAA7134_RS_CONTROL(2), control);
+ saa_writel(SAA7134_RS_BA1(3), base);
+ saa_writel(SAA7134_RS_BA2(3), base + dev->vbi_hlen * dev->vbi_vlen);
+ saa_writel(SAA7134_RS_PITCH(3), dev->vbi_hlen);
+ saa_writel(SAA7134_RS_CONTROL(3), control);
+
+ /* start DMA */
+ saa7134_set_dmabits(dev);
+ mod_timer(&dmaq->timeout, jiffies + BUFFER_TIMEOUT);
+
+ return 0;
+}
+
+static int buffer_prepare(struct vb2_buffer *vb2)
+{
+ struct saa7134_dmaqueue *dmaq = vb2->vb2_queue->drv_priv;
+ struct saa7134_dev *dev = dmaq->dev;
+ struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb2);
+ struct saa7134_buf *buf = container_of(vbuf, struct saa7134_buf, vb2);
+ struct sg_table *dma = vb2_dma_sg_plane_desc(vb2, 0);
+ unsigned int size;
+
+ if (dma->sgl->offset) {
+ pr_err("The buffer is not page-aligned\n");
+ return -EINVAL;
+ }
+ size = dev->vbi_hlen * dev->vbi_vlen * 2;
+ if (vb2_plane_size(vb2, 0) < size)
+ return -EINVAL;
+
+ vb2_set_plane_payload(vb2, 0, size);
+
+ return saa7134_pgtable_build(dev->pci, &dmaq->pt, dma->sgl, dma->nents,
+ saa7134_buffer_startpage(buf));
+}
+
+static int queue_setup(struct vb2_queue *q,
+ unsigned int *nbuffers, unsigned int *nplanes,
+ unsigned int sizes[], struct device *alloc_devs[])
+{
+ struct saa7134_dmaqueue *dmaq = q->drv_priv;
+ struct saa7134_dev *dev = dmaq->dev;
+ unsigned int size;
+
+ dev->vbi_vlen = dev->tvnorm->vbi_v_stop_0 - dev->tvnorm->vbi_v_start_0 + 1;
+ if (dev->vbi_vlen > VBI_LINE_COUNT)
+ dev->vbi_vlen = VBI_LINE_COUNT;
+ dev->vbi_hlen = VBI_LINE_LENGTH;
+ size = dev->vbi_hlen * dev->vbi_vlen * 2;
+
+ *nbuffers = saa7134_buffer_count(size, *nbuffers);
+ *nplanes = 1;
+ sizes[0] = size;
+ return 0;
+}
+
+static int buffer_init(struct vb2_buffer *vb2)
+{
+ struct saa7134_dmaqueue *dmaq = vb2->vb2_queue->drv_priv;
+ struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb2);
+ struct saa7134_buf *buf = container_of(vbuf, struct saa7134_buf, vb2);
+
+ dmaq->curr = NULL;
+ buf->activate = buffer_activate;
+ return 0;
+}
+
+const struct vb2_ops saa7134_vbi_qops = {
+ .queue_setup = queue_setup,
+ .buf_init = buffer_init,
+ .buf_prepare = buffer_prepare,
+ .buf_queue = saa7134_vb2_buffer_queue,
+ .wait_prepare = vb2_ops_wait_prepare,
+ .wait_finish = vb2_ops_wait_finish,
+ .start_streaming = saa7134_vb2_start_streaming,
+ .stop_streaming = saa7134_vb2_stop_streaming,
+};
+
+/* ------------------------------------------------------------------ */
+
+int saa7134_vbi_init1(struct saa7134_dev *dev)
+{
+ INIT_LIST_HEAD(&dev->vbi_q.queue);
+ timer_setup(&dev->vbi_q.timeout, saa7134_buffer_timeout, 0);
+ dev->vbi_q.dev = dev;
+
+ if (vbibufs < 2)
+ vbibufs = 2;
+ if (vbibufs > VIDEO_MAX_FRAME)
+ vbibufs = VIDEO_MAX_FRAME;
+ return 0;
+}
+
+int saa7134_vbi_fini(struct saa7134_dev *dev)
+{
+ /* nothing */
+ del_timer_sync(&dev->vbi_q.timeout);
+ return 0;
+}
+
+void saa7134_irq_vbi_done(struct saa7134_dev *dev, unsigned long status)
+{
+ spin_lock(&dev->slock);
+ if (dev->vbi_q.curr) {
+ /* make sure we have seen both fields */
+ if ((status & 0x10) == 0x00) {
+ dev->vbi_q.curr->top_seen = 1;
+ goto done;
+ }
+ if (!dev->vbi_q.curr->top_seen)
+ goto done;
+
+ saa7134_buffer_finish(dev, &dev->vbi_q, VB2_BUF_STATE_DONE);
+ }
+ saa7134_buffer_next(dev, &dev->vbi_q);
+
+ done:
+ spin_unlock(&dev->slock);
+}
diff --git a/drivers/media/pci/saa7134/saa7134-video.c b/drivers/media/pci/saa7134/saa7134-video.c
new file mode 100644
index 0000000000..56b4481a40
--- /dev/null
+++ b/drivers/media/pci/saa7134/saa7134-video.c
@@ -0,0 +1,1864 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ *
+ * device driver for philips saa7134 based TV cards
+ * video4linux video interface
+ *
+ * (c) 2001-03 Gerd Knorr <kraxel@bytesex.org> [SuSE Labs]
+ */
+
+#include "saa7134.h"
+#include "saa7134-reg.h"
+
+#include <linux/init.h>
+#include <linux/list.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/sort.h>
+
+#include <media/v4l2-common.h>
+#include <media/v4l2-event.h>
+#include <media/i2c/saa6588.h>
+
+/* ------------------------------------------------------------------ */
+
+unsigned int video_debug;
+static unsigned int gbuffers = 8;
+static unsigned int noninterlaced; /* 0 */
+static unsigned int gbufsize = 720*576*4;
+static unsigned int gbufsize_max = 720*576*4;
+static char secam[] = "--";
+module_param(video_debug, int, 0644);
+MODULE_PARM_DESC(video_debug,"enable debug messages [video]");
+module_param(gbuffers, int, 0444);
+MODULE_PARM_DESC(gbuffers,"number of capture buffers, range 2-32");
+module_param(noninterlaced, int, 0644);
+MODULE_PARM_DESC(noninterlaced,"capture non interlaced video");
+module_param_string(secam, secam, sizeof(secam), 0644);
+MODULE_PARM_DESC(secam, "force SECAM variant, either DK,L or Lc");
+
+
+#define video_dbg(fmt, arg...) do { \
+ if (video_debug & 0x04) \
+ printk(KERN_DEBUG pr_fmt("video: " fmt), ## arg); \
+ } while (0)
+
+/* ------------------------------------------------------------------ */
+/* Defines for Video Output Port Register at address 0x191 */
+
+/* Bit 0: VIP code T bit polarity */
+
+#define VP_T_CODE_P_NON_INVERTED 0x00
+#define VP_T_CODE_P_INVERTED 0x01
+
+/* ------------------------------------------------------------------ */
+/* Defines for Video Output Port Register at address 0x195 */
+
+/* Bit 2: Video output clock delay control */
+
+#define VP_CLK_CTRL2_NOT_DELAYED 0x00
+#define VP_CLK_CTRL2_DELAYED 0x04
+
+/* Bit 1: Video output clock invert control */
+
+#define VP_CLK_CTRL1_NON_INVERTED 0x00
+#define VP_CLK_CTRL1_INVERTED 0x02
+
+/* ------------------------------------------------------------------ */
+/* Defines for Video Output Port Register at address 0x196 */
+
+/* Bits 2 to 0: VSYNC pin video vertical sync type */
+
+#define VP_VS_TYPE_MASK 0x07
+
+#define VP_VS_TYPE_OFF 0x00
+#define VP_VS_TYPE_V123 0x01
+#define VP_VS_TYPE_V_ITU 0x02
+#define VP_VS_TYPE_VGATE_L 0x03
+#define VP_VS_TYPE_RESERVED1 0x04
+#define VP_VS_TYPE_RESERVED2 0x05
+#define VP_VS_TYPE_F_ITU 0x06
+#define VP_VS_TYPE_SC_FID 0x07
+
+/* ------------------------------------------------------------------ */
+/* data structs for video */
+
+static int video_out[][9] = {
+ [CCIR656] = { 0x00, 0xb1, 0x00, 0xa1, 0x00, 0x04, 0x06, 0x00, 0x00 },
+};
+
+static struct saa7134_format formats[] = {
+ {
+ .fourcc = V4L2_PIX_FMT_GREY,
+ .depth = 8,
+ .pm = 0x06,
+ },{
+ .fourcc = V4L2_PIX_FMT_RGB555,
+ .depth = 16,
+ .pm = 0x13 | 0x80,
+ },{
+ .fourcc = V4L2_PIX_FMT_RGB555X,
+ .depth = 16,
+ .pm = 0x13 | 0x80,
+ .bswap = 1,
+ },{
+ .fourcc = V4L2_PIX_FMT_RGB565,
+ .depth = 16,
+ .pm = 0x10 | 0x80,
+ },{
+ .fourcc = V4L2_PIX_FMT_RGB565X,
+ .depth = 16,
+ .pm = 0x10 | 0x80,
+ .bswap = 1,
+ },{
+ .fourcc = V4L2_PIX_FMT_BGR24,
+ .depth = 24,
+ .pm = 0x11,
+ },{
+ .fourcc = V4L2_PIX_FMT_RGB24,
+ .depth = 24,
+ .pm = 0x11,
+ .bswap = 1,
+ },{
+ .fourcc = V4L2_PIX_FMT_BGR32,
+ .depth = 32,
+ .pm = 0x12,
+ },{
+ .fourcc = V4L2_PIX_FMT_RGB32,
+ .depth = 32,
+ .pm = 0x12,
+ .bswap = 1,
+ .wswap = 1,
+ },{
+ .fourcc = V4L2_PIX_FMT_YUYV,
+ .depth = 16,
+ .pm = 0x00,
+ .bswap = 1,
+ .yuv = 1,
+ },{
+ .fourcc = V4L2_PIX_FMT_UYVY,
+ .depth = 16,
+ .pm = 0x00,
+ .yuv = 1,
+ },{
+ .fourcc = V4L2_PIX_FMT_YUV422P,
+ .depth = 16,
+ .pm = 0x09,
+ .yuv = 1,
+ .planar = 1,
+ .hshift = 1,
+ .vshift = 0,
+ },{
+ .fourcc = V4L2_PIX_FMT_YUV420,
+ .depth = 12,
+ .pm = 0x0a,
+ .yuv = 1,
+ .planar = 1,
+ .hshift = 1,
+ .vshift = 1,
+ },{
+ .fourcc = V4L2_PIX_FMT_YVU420,
+ .depth = 12,
+ .pm = 0x0a,
+ .yuv = 1,
+ .planar = 1,
+ .uvswap = 1,
+ .hshift = 1,
+ .vshift = 1,
+ }
+};
+#define FORMATS ARRAY_SIZE(formats)
+
+#define NORM_625_50 \
+ .h_start = 0, \
+ .h_stop = 719, \
+ .video_v_start = 24, \
+ .video_v_stop = 311, \
+ .vbi_v_start_0 = 7, \
+ .vbi_v_stop_0 = 23, \
+ .vbi_v_start_1 = 319, \
+ .src_timing = 4
+
+#define NORM_525_60 \
+ .h_start = 0, \
+ .h_stop = 719, \
+ .video_v_start = 23, \
+ .video_v_stop = 262, \
+ .vbi_v_start_0 = 10, \
+ .vbi_v_stop_0 = 21, \
+ .vbi_v_start_1 = 273, \
+ .src_timing = 7
+
+static struct saa7134_tvnorm tvnorms[] = {
+ {
+ .name = "PAL", /* autodetect */
+ .id = V4L2_STD_PAL,
+ NORM_625_50,
+
+ .sync_control = 0x18,
+ .luma_control = 0x40,
+ .chroma_ctrl1 = 0x81,
+ .chroma_gain = 0x2a,
+ .chroma_ctrl2 = 0x06,
+ .vgate_misc = 0x1c,
+
+ },{
+ .name = "PAL-BG",
+ .id = V4L2_STD_PAL_BG,
+ NORM_625_50,
+
+ .sync_control = 0x18,
+ .luma_control = 0x40,
+ .chroma_ctrl1 = 0x81,
+ .chroma_gain = 0x2a,
+ .chroma_ctrl2 = 0x06,
+ .vgate_misc = 0x1c,
+
+ },{
+ .name = "PAL-I",
+ .id = V4L2_STD_PAL_I,
+ NORM_625_50,
+
+ .sync_control = 0x18,
+ .luma_control = 0x40,
+ .chroma_ctrl1 = 0x81,
+ .chroma_gain = 0x2a,
+ .chroma_ctrl2 = 0x06,
+ .vgate_misc = 0x1c,
+
+ },{
+ .name = "PAL-DK",
+ .id = V4L2_STD_PAL_DK,
+ NORM_625_50,
+
+ .sync_control = 0x18,
+ .luma_control = 0x40,
+ .chroma_ctrl1 = 0x81,
+ .chroma_gain = 0x2a,
+ .chroma_ctrl2 = 0x06,
+ .vgate_misc = 0x1c,
+
+ },{
+ .name = "NTSC",
+ .id = V4L2_STD_NTSC,
+ NORM_525_60,
+
+ .sync_control = 0x59,
+ .luma_control = 0x40,
+ .chroma_ctrl1 = 0x89,
+ .chroma_gain = 0x2a,
+ .chroma_ctrl2 = 0x0e,
+ .vgate_misc = 0x18,
+
+ },{
+ .name = "SECAM",
+ .id = V4L2_STD_SECAM,
+ NORM_625_50,
+
+ .sync_control = 0x18,
+ .luma_control = 0x1b,
+ .chroma_ctrl1 = 0xd1,
+ .chroma_gain = 0x80,
+ .chroma_ctrl2 = 0x00,
+ .vgate_misc = 0x1c,
+
+ },{
+ .name = "SECAM-DK",
+ .id = V4L2_STD_SECAM_DK,
+ NORM_625_50,
+
+ .sync_control = 0x18,
+ .luma_control = 0x1b,
+ .chroma_ctrl1 = 0xd1,
+ .chroma_gain = 0x80,
+ .chroma_ctrl2 = 0x00,
+ .vgate_misc = 0x1c,
+
+ },{
+ .name = "SECAM-L",
+ .id = V4L2_STD_SECAM_L,
+ NORM_625_50,
+
+ .sync_control = 0x18,
+ .luma_control = 0x1b,
+ .chroma_ctrl1 = 0xd1,
+ .chroma_gain = 0x80,
+ .chroma_ctrl2 = 0x00,
+ .vgate_misc = 0x1c,
+
+ },{
+ .name = "SECAM-Lc",
+ .id = V4L2_STD_SECAM_LC,
+ NORM_625_50,
+
+ .sync_control = 0x18,
+ .luma_control = 0x1b,
+ .chroma_ctrl1 = 0xd1,
+ .chroma_gain = 0x80,
+ .chroma_ctrl2 = 0x00,
+ .vgate_misc = 0x1c,
+
+ },{
+ .name = "PAL-M",
+ .id = V4L2_STD_PAL_M,
+ NORM_525_60,
+
+ .sync_control = 0x59,
+ .luma_control = 0x40,
+ .chroma_ctrl1 = 0xb9,
+ .chroma_gain = 0x2a,
+ .chroma_ctrl2 = 0x0e,
+ .vgate_misc = 0x18,
+
+ },{
+ .name = "PAL-Nc",
+ .id = V4L2_STD_PAL_Nc,
+ NORM_625_50,
+
+ .sync_control = 0x18,
+ .luma_control = 0x40,
+ .chroma_ctrl1 = 0xa1,
+ .chroma_gain = 0x2a,
+ .chroma_ctrl2 = 0x06,
+ .vgate_misc = 0x1c,
+
+ },{
+ .name = "PAL-60",
+ .id = V4L2_STD_PAL_60,
+
+ .h_start = 0,
+ .h_stop = 719,
+ .video_v_start = 23,
+ .video_v_stop = 262,
+ .vbi_v_start_0 = 10,
+ .vbi_v_stop_0 = 21,
+ .vbi_v_start_1 = 273,
+ .src_timing = 7,
+
+ .sync_control = 0x18,
+ .luma_control = 0x40,
+ .chroma_ctrl1 = 0x81,
+ .chroma_gain = 0x2a,
+ .chroma_ctrl2 = 0x06,
+ .vgate_misc = 0x1c,
+ }
+};
+#define TVNORMS ARRAY_SIZE(tvnorms)
+
+static struct saa7134_format* format_by_fourcc(unsigned int fourcc)
+{
+ unsigned int i;
+
+ for (i = 0; i < FORMATS; i++)
+ if (formats[i].fourcc == fourcc)
+ return formats+i;
+ return NULL;
+}
+
+/* ------------------------------------------------------------------ */
+
+static void set_tvnorm(struct saa7134_dev *dev, struct saa7134_tvnorm *norm)
+{
+ video_dbg("set tv norm = %s\n", norm->name);
+ dev->tvnorm = norm;
+
+ /* setup cropping */
+ dev->crop_bounds.left = norm->h_start;
+ dev->crop_defrect.left = norm->h_start;
+ dev->crop_bounds.width = norm->h_stop - norm->h_start +1;
+ dev->crop_defrect.width = norm->h_stop - norm->h_start +1;
+
+ dev->crop_bounds.top = (norm->vbi_v_stop_0+1)*2;
+ dev->crop_defrect.top = norm->video_v_start*2;
+ dev->crop_bounds.height = ((norm->id & V4L2_STD_525_60) ? 524 : 624)
+ - dev->crop_bounds.top;
+ dev->crop_defrect.height = (norm->video_v_stop - norm->video_v_start +1)*2;
+
+ dev->crop_current = dev->crop_defrect;
+
+ saa7134_set_tvnorm_hw(dev);
+}
+
+static void video_mux(struct saa7134_dev *dev, int input)
+{
+ video_dbg("video input = %d [%s]\n",
+ input, saa7134_input_name[card_in(dev, input).type]);
+ dev->ctl_input = input;
+ set_tvnorm(dev, dev->tvnorm);
+ saa7134_tvaudio_setinput(dev, &card_in(dev, input));
+}
+
+
+static void saa7134_set_decoder(struct saa7134_dev *dev)
+{
+ int luma_control, sync_control, chroma_ctrl1, mux;
+
+ struct saa7134_tvnorm *norm = dev->tvnorm;
+ mux = card_in(dev, dev->ctl_input).vmux;
+
+ luma_control = norm->luma_control;
+ sync_control = norm->sync_control;
+ chroma_ctrl1 = norm->chroma_ctrl1;
+
+ if (mux > 5)
+ luma_control |= 0x80; /* svideo */
+ if (noninterlaced || dev->nosignal)
+ sync_control |= 0x20;
+
+ /* switch on auto standard detection */
+ sync_control |= SAA7134_SYNC_CTRL_AUFD;
+ chroma_ctrl1 |= SAA7134_CHROMA_CTRL1_AUTO0;
+ chroma_ctrl1 &= ~SAA7134_CHROMA_CTRL1_FCTC;
+ luma_control &= ~SAA7134_LUMA_CTRL_LDEL;
+
+ /* setup video decoder */
+ saa_writeb(SAA7134_INCR_DELAY, 0x08);
+ saa_writeb(SAA7134_ANALOG_IN_CTRL1, 0xc0 | mux);
+ saa_writeb(SAA7134_ANALOG_IN_CTRL2, 0x00);
+
+ saa_writeb(SAA7134_ANALOG_IN_CTRL3, 0x90);
+ saa_writeb(SAA7134_ANALOG_IN_CTRL4, 0x90);
+ saa_writeb(SAA7134_HSYNC_START, 0xeb);
+ saa_writeb(SAA7134_HSYNC_STOP, 0xe0);
+ saa_writeb(SAA7134_SOURCE_TIMING1, norm->src_timing);
+
+ saa_writeb(SAA7134_SYNC_CTRL, sync_control);
+ saa_writeb(SAA7134_LUMA_CTRL, luma_control);
+ saa_writeb(SAA7134_DEC_LUMA_BRIGHT, dev->ctl_bright);
+
+ saa_writeb(SAA7134_DEC_LUMA_CONTRAST,
+ dev->ctl_invert ? -dev->ctl_contrast : dev->ctl_contrast);
+
+ saa_writeb(SAA7134_DEC_CHROMA_SATURATION,
+ dev->ctl_invert ? -dev->ctl_saturation : dev->ctl_saturation);
+
+ saa_writeb(SAA7134_DEC_CHROMA_HUE, dev->ctl_hue);
+ saa_writeb(SAA7134_CHROMA_CTRL1, chroma_ctrl1);
+ saa_writeb(SAA7134_CHROMA_GAIN, norm->chroma_gain);
+
+ saa_writeb(SAA7134_CHROMA_CTRL2, norm->chroma_ctrl2);
+ saa_writeb(SAA7134_MODE_DELAY_CTRL, 0x00);
+
+ saa_writeb(SAA7134_ANALOG_ADC, 0x01);
+ saa_writeb(SAA7134_VGATE_START, 0x11);
+ saa_writeb(SAA7134_VGATE_STOP, 0xfe);
+ saa_writeb(SAA7134_MISC_VGATE_MSB, norm->vgate_misc);
+ saa_writeb(SAA7134_RAW_DATA_GAIN, 0x40);
+ saa_writeb(SAA7134_RAW_DATA_OFFSET, 0x80);
+}
+
+void saa7134_set_tvnorm_hw(struct saa7134_dev *dev)
+{
+ saa7134_set_decoder(dev);
+
+ saa_call_all(dev, video, s_std, dev->tvnorm->id);
+ /* Set the correct norm for the saa6752hs. This function
+ does nothing if there is no saa6752hs. */
+ saa_call_empress(dev, video, s_std, dev->tvnorm->id);
+}
+
+static void set_h_prescale(struct saa7134_dev *dev, int task, int prescale)
+{
+ static const struct {
+ int xpsc;
+ int xacl;
+ int xc2_1;
+ int xdcg;
+ int vpfy;
+ } vals[] = {
+ /* XPSC XACL XC2_1 XDCG VPFY */
+ { 1, 0, 0, 0, 0 },
+ { 2, 2, 1, 2, 2 },
+ { 3, 4, 1, 3, 2 },
+ { 4, 8, 1, 4, 2 },
+ { 5, 8, 1, 4, 2 },
+ { 6, 8, 1, 4, 3 },
+ { 7, 8, 1, 4, 3 },
+ { 8, 15, 0, 4, 3 },
+ { 9, 15, 0, 4, 3 },
+ { 10, 16, 1, 5, 3 },
+ };
+ static const int count = ARRAY_SIZE(vals);
+ int i;
+
+ for (i = 0; i < count; i++)
+ if (vals[i].xpsc == prescale)
+ break;
+ if (i == count)
+ return;
+
+ saa_writeb(SAA7134_H_PRESCALE(task), vals[i].xpsc);
+ saa_writeb(SAA7134_ACC_LENGTH(task), vals[i].xacl);
+ saa_writeb(SAA7134_LEVEL_CTRL(task),
+ (vals[i].xc2_1 << 3) | (vals[i].xdcg));
+ saa_andorb(SAA7134_FIR_PREFILTER_CTRL(task), 0x0f,
+ (vals[i].vpfy << 2) | vals[i].vpfy);
+}
+
+static void set_v_scale(struct saa7134_dev *dev, int task, int yscale)
+{
+ int val,mirror;
+
+ saa_writeb(SAA7134_V_SCALE_RATIO1(task), yscale & 0xff);
+ saa_writeb(SAA7134_V_SCALE_RATIO2(task), yscale >> 8);
+
+ mirror = (dev->ctl_mirror) ? 0x02 : 0x00;
+ if (yscale < 2048) {
+ /* LPI */
+ video_dbg("yscale LPI yscale=%d\n", yscale);
+ saa_writeb(SAA7134_V_FILTER(task), 0x00 | mirror);
+ saa_writeb(SAA7134_LUMA_CONTRAST(task), 0x40);
+ saa_writeb(SAA7134_CHROMA_SATURATION(task), 0x40);
+ } else {
+ /* ACM */
+ val = 0x40 * 1024 / yscale;
+ video_dbg("yscale ACM yscale=%d val=0x%x\n", yscale, val);
+ saa_writeb(SAA7134_V_FILTER(task), 0x01 | mirror);
+ saa_writeb(SAA7134_LUMA_CONTRAST(task), val);
+ saa_writeb(SAA7134_CHROMA_SATURATION(task), val);
+ }
+ saa_writeb(SAA7134_LUMA_BRIGHT(task), 0x80);
+}
+
+static void set_size(struct saa7134_dev *dev, int task,
+ int width, int height, int interlace)
+{
+ int prescale,xscale,yscale,y_even,y_odd;
+ int h_start, h_stop, v_start, v_stop;
+ int div = interlace ? 2 : 1;
+
+ /* setup video scaler */
+ h_start = dev->crop_current.left;
+ v_start = dev->crop_current.top/2;
+ h_stop = (dev->crop_current.left + dev->crop_current.width -1);
+ v_stop = (dev->crop_current.top + dev->crop_current.height -1)/2;
+
+ saa_writeb(SAA7134_VIDEO_H_START1(task), h_start & 0xff);
+ saa_writeb(SAA7134_VIDEO_H_START2(task), h_start >> 8);
+ saa_writeb(SAA7134_VIDEO_H_STOP1(task), h_stop & 0xff);
+ saa_writeb(SAA7134_VIDEO_H_STOP2(task), h_stop >> 8);
+ saa_writeb(SAA7134_VIDEO_V_START1(task), v_start & 0xff);
+ saa_writeb(SAA7134_VIDEO_V_START2(task), v_start >> 8);
+ saa_writeb(SAA7134_VIDEO_V_STOP1(task), v_stop & 0xff);
+ saa_writeb(SAA7134_VIDEO_V_STOP2(task), v_stop >> 8);
+
+ prescale = dev->crop_current.width / width;
+ if (0 == prescale)
+ prescale = 1;
+ xscale = 1024 * dev->crop_current.width / prescale / width;
+ yscale = 512 * div * dev->crop_current.height / height;
+ video_dbg("prescale=%d xscale=%d yscale=%d\n",
+ prescale, xscale, yscale);
+ set_h_prescale(dev,task,prescale);
+ saa_writeb(SAA7134_H_SCALE_INC1(task), xscale & 0xff);
+ saa_writeb(SAA7134_H_SCALE_INC2(task), xscale >> 8);
+ set_v_scale(dev,task,yscale);
+
+ saa_writeb(SAA7134_VIDEO_PIXELS1(task), width & 0xff);
+ saa_writeb(SAA7134_VIDEO_PIXELS2(task), width >> 8);
+ saa_writeb(SAA7134_VIDEO_LINES1(task), height/div & 0xff);
+ saa_writeb(SAA7134_VIDEO_LINES2(task), height/div >> 8);
+
+ /* deinterlace y offsets */
+ y_odd = dev->ctl_y_odd;
+ y_even = dev->ctl_y_even;
+ saa_writeb(SAA7134_V_PHASE_OFFSET0(task), y_odd);
+ saa_writeb(SAA7134_V_PHASE_OFFSET1(task), y_even);
+ saa_writeb(SAA7134_V_PHASE_OFFSET2(task), y_odd);
+ saa_writeb(SAA7134_V_PHASE_OFFSET3(task), y_even);
+}
+
+/* ------------------------------------------------------------------ */
+
+/*
+ * Media Controller helper functions
+ */
+
+static int saa7134_enable_analog_tuner(struct saa7134_dev *dev)
+{
+#ifdef CONFIG_MEDIA_CONTROLLER
+ struct media_device *mdev = dev->media_dev;
+ struct media_entity *source;
+ struct media_link *link, *found_link = NULL;
+ int ret, active_links = 0;
+
+ if (!mdev || !dev->decoder)
+ return 0;
+
+ /*
+ * This will find the tuner that is connected into the decoder.
+ * Technically, this is not 100% correct, as the device may be
+ * using an analog input instead of the tuner. However, as we can't
+ * do DVB streaming while the DMA engine is being used for V4L2,
+ * this should be enough for the actual needs.
+ */
+ list_for_each_entry(link, &dev->decoder->links, list) {
+ if (link->sink->entity == dev->decoder) {
+ found_link = link;
+ if (link->flags & MEDIA_LNK_FL_ENABLED)
+ active_links++;
+ break;
+ }
+ }
+
+ if (active_links == 1 || !found_link)
+ return 0;
+
+ source = found_link->source->entity;
+ list_for_each_entry(link, &source->links, list) {
+ struct media_entity *sink;
+ int flags = 0;
+
+ sink = link->sink->entity;
+
+ if (sink == dev->decoder)
+ flags = MEDIA_LNK_FL_ENABLED;
+
+ ret = media_entity_setup_link(link, flags);
+ if (ret) {
+ pr_err("Couldn't change link %s->%s to %s. Error %d\n",
+ source->name, sink->name,
+ flags ? "enabled" : "disabled",
+ ret);
+ return ret;
+ }
+ }
+#endif
+ return 0;
+}
+
+/* ------------------------------------------------------------------ */
+
+static int buffer_activate(struct saa7134_dev *dev,
+ struct saa7134_buf *buf,
+ struct saa7134_buf *next)
+{
+ struct saa7134_dmaqueue *dmaq = buf->vb2.vb2_buf.vb2_queue->drv_priv;
+ unsigned long base,control,bpl;
+ unsigned long bpl_uv, lines_uv, base2, base3; /* planar */
+
+ video_dbg("buffer_activate buf=%p\n", buf);
+ buf->top_seen = 0;
+
+ set_size(dev, TASK_A, dev->width, dev->height,
+ V4L2_FIELD_HAS_BOTH(dev->field));
+ if (dev->fmt->yuv)
+ saa_andorb(SAA7134_DATA_PATH(TASK_A), 0x3f, 0x03);
+ else
+ saa_andorb(SAA7134_DATA_PATH(TASK_A), 0x3f, 0x01);
+ saa_writeb(SAA7134_OFMT_VIDEO_A, dev->fmt->pm);
+
+ /* DMA: setup channel 0 (= Video Task A0) */
+ base = saa7134_buffer_base(buf);
+ if (dev->fmt->planar)
+ bpl = dev->width;
+ else
+ bpl = (dev->width * dev->fmt->depth) / 8;
+ control = SAA7134_RS_CONTROL_BURST_16 |
+ SAA7134_RS_CONTROL_ME |
+ (dmaq->pt.dma >> 12);
+ if (dev->fmt->bswap)
+ control |= SAA7134_RS_CONTROL_BSWAP;
+ if (dev->fmt->wswap)
+ control |= SAA7134_RS_CONTROL_WSWAP;
+ if (V4L2_FIELD_HAS_BOTH(dev->field)) {
+ /* interlaced */
+ saa_writel(SAA7134_RS_BA1(0),base);
+ saa_writel(SAA7134_RS_BA2(0),base+bpl);
+ saa_writel(SAA7134_RS_PITCH(0),bpl*2);
+ } else {
+ /* non-interlaced */
+ saa_writel(SAA7134_RS_BA1(0),base);
+ saa_writel(SAA7134_RS_BA2(0),base);
+ saa_writel(SAA7134_RS_PITCH(0),bpl);
+ }
+ saa_writel(SAA7134_RS_CONTROL(0),control);
+
+ if (dev->fmt->planar) {
+ /* DMA: setup channel 4+5 (= planar task A) */
+ bpl_uv = bpl >> dev->fmt->hshift;
+ lines_uv = dev->height >> dev->fmt->vshift;
+ base2 = base + bpl * dev->height;
+ base3 = base2 + bpl_uv * lines_uv;
+ if (dev->fmt->uvswap)
+ swap(base2, base3);
+ video_dbg("uv: bpl=%ld lines=%ld base2/3=%ld/%ld\n",
+ bpl_uv,lines_uv,base2,base3);
+ if (V4L2_FIELD_HAS_BOTH(dev->field)) {
+ /* interlaced */
+ saa_writel(SAA7134_RS_BA1(4),base2);
+ saa_writel(SAA7134_RS_BA2(4),base2+bpl_uv);
+ saa_writel(SAA7134_RS_PITCH(4),bpl_uv*2);
+ saa_writel(SAA7134_RS_BA1(5),base3);
+ saa_writel(SAA7134_RS_BA2(5),base3+bpl_uv);
+ saa_writel(SAA7134_RS_PITCH(5),bpl_uv*2);
+ } else {
+ /* non-interlaced */
+ saa_writel(SAA7134_RS_BA1(4),base2);
+ saa_writel(SAA7134_RS_BA2(4),base2);
+ saa_writel(SAA7134_RS_PITCH(4),bpl_uv);
+ saa_writel(SAA7134_RS_BA1(5),base3);
+ saa_writel(SAA7134_RS_BA2(5),base3);
+ saa_writel(SAA7134_RS_PITCH(5),bpl_uv);
+ }
+ saa_writel(SAA7134_RS_CONTROL(4),control);
+ saa_writel(SAA7134_RS_CONTROL(5),control);
+ }
+
+ /* start DMA */
+ saa7134_set_dmabits(dev);
+ mod_timer(&dmaq->timeout, jiffies + BUFFER_TIMEOUT);
+ return 0;
+}
+
+static int buffer_init(struct vb2_buffer *vb2)
+{
+ struct saa7134_dmaqueue *dmaq = vb2->vb2_queue->drv_priv;
+ struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb2);
+ struct saa7134_buf *buf = container_of(vbuf, struct saa7134_buf, vb2);
+
+ dmaq->curr = NULL;
+ buf->activate = buffer_activate;
+ return 0;
+}
+
+static int buffer_prepare(struct vb2_buffer *vb2)
+{
+ struct saa7134_dmaqueue *dmaq = vb2->vb2_queue->drv_priv;
+ struct saa7134_dev *dev = dmaq->dev;
+ struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb2);
+ struct saa7134_buf *buf = container_of(vbuf, struct saa7134_buf, vb2);
+ struct sg_table *dma = vb2_dma_sg_plane_desc(vb2, 0);
+ unsigned int size;
+
+ if (dma->sgl->offset) {
+ pr_err("The buffer is not page-aligned\n");
+ return -EINVAL;
+ }
+ size = (dev->width * dev->height * dev->fmt->depth) >> 3;
+ if (vb2_plane_size(vb2, 0) < size)
+ return -EINVAL;
+
+ vb2_set_plane_payload(vb2, 0, size);
+ vbuf->field = dev->field;
+
+ return saa7134_pgtable_build(dev->pci, &dmaq->pt, dma->sgl, dma->nents,
+ saa7134_buffer_startpage(buf));
+}
+
+static int queue_setup(struct vb2_queue *q,
+ unsigned int *nbuffers, unsigned int *nplanes,
+ unsigned int sizes[], struct device *alloc_devs[])
+{
+ struct saa7134_dmaqueue *dmaq = q->drv_priv;
+ struct saa7134_dev *dev = dmaq->dev;
+ int size = dev->fmt->depth * dev->width * dev->height >> 3;
+
+ if (dev->width < 48 ||
+ dev->height < 32 ||
+ dev->width/4 > dev->crop_current.width ||
+ dev->height/4 > dev->crop_current.height ||
+ dev->width > dev->crop_bounds.width ||
+ dev->height > dev->crop_bounds.height)
+ return -EINVAL;
+
+ *nbuffers = saa7134_buffer_count(size, *nbuffers);
+ *nplanes = 1;
+ sizes[0] = size;
+
+ saa7134_enable_analog_tuner(dev);
+
+ return 0;
+}
+
+/*
+ * move buffer to hardware queue
+ */
+void saa7134_vb2_buffer_queue(struct vb2_buffer *vb)
+{
+ struct saa7134_dmaqueue *dmaq = vb->vb2_queue->drv_priv;
+ struct saa7134_dev *dev = dmaq->dev;
+ struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
+ struct saa7134_buf *buf = container_of(vbuf, struct saa7134_buf, vb2);
+
+ saa7134_buffer_queue(dev, dmaq, buf);
+}
+EXPORT_SYMBOL_GPL(saa7134_vb2_buffer_queue);
+
+int saa7134_vb2_start_streaming(struct vb2_queue *vq, unsigned int count)
+{
+ struct saa7134_dmaqueue *dmaq = vq->drv_priv;
+ struct saa7134_dev *dev = dmaq->dev;
+
+ /*
+ * Planar video capture and TS share the same DMA channel,
+ * so only one can be active at a time.
+ */
+ if (card_is_empress(dev) && vb2_is_busy(&dev->empress_vbq) &&
+ dmaq == &dev->video_q && dev->fmt->planar) {
+ struct saa7134_buf *buf, *tmp;
+
+ list_for_each_entry_safe(buf, tmp, &dmaq->queue, entry) {
+ list_del(&buf->entry);
+ vb2_buffer_done(&buf->vb2.vb2_buf,
+ VB2_BUF_STATE_QUEUED);
+ }
+ if (dmaq->curr) {
+ vb2_buffer_done(&dmaq->curr->vb2.vb2_buf,
+ VB2_BUF_STATE_QUEUED);
+ dmaq->curr = NULL;
+ }
+ return -EBUSY;
+ }
+
+ /* The SAA7134 has a 1K FIFO; the datasheet suggests that when
+ * configured conservatively, there's 22 usec of buffering for video.
+ * We therefore request a DMA latency of 20 usec, giving us 2 usec of
+ * margin in case the FIFO is configured differently to the datasheet.
+ * Unfortunately, I lack register-level documentation to check the
+ * Linux FIFO setup and confirm the perfect value.
+ */
+ if ((dmaq == &dev->video_q && !vb2_is_streaming(&dev->vbi_vbq)) ||
+ (dmaq == &dev->vbi_q && !vb2_is_streaming(&dev->video_vbq)))
+ cpu_latency_qos_add_request(&dev->qos_request, 20);
+ dmaq->seq_nr = 0;
+
+ return 0;
+}
+
+void saa7134_vb2_stop_streaming(struct vb2_queue *vq)
+{
+ struct saa7134_dmaqueue *dmaq = vq->drv_priv;
+ struct saa7134_dev *dev = dmaq->dev;
+
+ saa7134_stop_streaming(dev, dmaq);
+
+ if ((dmaq == &dev->video_q && !vb2_is_streaming(&dev->vbi_vbq)) ||
+ (dmaq == &dev->vbi_q && !vb2_is_streaming(&dev->video_vbq)))
+ cpu_latency_qos_remove_request(&dev->qos_request);
+}
+
+static const struct vb2_ops vb2_qops = {
+ .queue_setup = queue_setup,
+ .buf_init = buffer_init,
+ .buf_prepare = buffer_prepare,
+ .buf_queue = saa7134_vb2_buffer_queue,
+ .wait_prepare = vb2_ops_wait_prepare,
+ .wait_finish = vb2_ops_wait_finish,
+ .start_streaming = saa7134_vb2_start_streaming,
+ .stop_streaming = saa7134_vb2_stop_streaming,
+};
+
+/* ------------------------------------------------------------------ */
+
+static int saa7134_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+ struct saa7134_dev *dev = container_of(ctrl->handler, struct saa7134_dev, ctrl_handler);
+
+ switch (ctrl->id) {
+ case V4L2_CID_BRIGHTNESS:
+ dev->ctl_bright = ctrl->val;
+ saa_writeb(SAA7134_DEC_LUMA_BRIGHT, ctrl->val);
+ break;
+ case V4L2_CID_HUE:
+ dev->ctl_hue = ctrl->val;
+ saa_writeb(SAA7134_DEC_CHROMA_HUE, ctrl->val);
+ break;
+ case V4L2_CID_CONTRAST:
+ dev->ctl_contrast = ctrl->val;
+ saa_writeb(SAA7134_DEC_LUMA_CONTRAST,
+ dev->ctl_invert ? -dev->ctl_contrast : dev->ctl_contrast);
+ break;
+ case V4L2_CID_SATURATION:
+ dev->ctl_saturation = ctrl->val;
+ saa_writeb(SAA7134_DEC_CHROMA_SATURATION,
+ dev->ctl_invert ? -dev->ctl_saturation : dev->ctl_saturation);
+ break;
+ case V4L2_CID_AUDIO_MUTE:
+ dev->ctl_mute = ctrl->val;
+ saa7134_tvaudio_setmute(dev);
+ break;
+ case V4L2_CID_AUDIO_VOLUME:
+ dev->ctl_volume = ctrl->val;
+ saa7134_tvaudio_setvolume(dev,dev->ctl_volume);
+ break;
+ case V4L2_CID_PRIVATE_INVERT:
+ dev->ctl_invert = ctrl->val;
+ saa_writeb(SAA7134_DEC_LUMA_CONTRAST,
+ dev->ctl_invert ? -dev->ctl_contrast : dev->ctl_contrast);
+ saa_writeb(SAA7134_DEC_CHROMA_SATURATION,
+ dev->ctl_invert ? -dev->ctl_saturation : dev->ctl_saturation);
+ break;
+ case V4L2_CID_HFLIP:
+ dev->ctl_mirror = ctrl->val;
+ break;
+ case V4L2_CID_PRIVATE_Y_EVEN:
+ dev->ctl_y_even = ctrl->val;
+ break;
+ case V4L2_CID_PRIVATE_Y_ODD:
+ dev->ctl_y_odd = ctrl->val;
+ break;
+ case V4L2_CID_PRIVATE_AUTOMUTE:
+ {
+ struct v4l2_priv_tun_config tda9887_cfg;
+
+ tda9887_cfg.tuner = TUNER_TDA9887;
+ tda9887_cfg.priv = &dev->tda9887_conf;
+
+ dev->ctl_automute = ctrl->val;
+ if (dev->tda9887_conf) {
+ if (dev->ctl_automute)
+ dev->tda9887_conf |= TDA9887_AUTOMUTE;
+ else
+ dev->tda9887_conf &= ~TDA9887_AUTOMUTE;
+
+ saa_call_all(dev, tuner, s_config, &tda9887_cfg);
+ }
+ break;
+ }
+ default:
+ return -EINVAL;
+ }
+ return 0;
+}
+
+/* ------------------------------------------------------------------ */
+
+static int video_open(struct file *file)
+{
+ struct video_device *vdev = video_devdata(file);
+ struct saa7134_dev *dev = video_drvdata(file);
+ int ret = v4l2_fh_open(file);
+
+ if (ret < 0)
+ return ret;
+
+ mutex_lock(&dev->lock);
+ if (vdev->vfl_type == VFL_TYPE_RADIO) {
+ /* switch to radio mode */
+ saa7134_tvaudio_setinput(dev, &card(dev).radio);
+ saa_call_all(dev, tuner, s_radio);
+ } else {
+ /* switch to video/vbi mode */
+ video_mux(dev, dev->ctl_input);
+ }
+ mutex_unlock(&dev->lock);
+
+ return 0;
+}
+
+static int video_release(struct file *file)
+{
+ struct video_device *vdev = video_devdata(file);
+ struct saa7134_dev *dev = video_drvdata(file);
+ struct saa6588_command cmd;
+
+ mutex_lock(&dev->lock);
+ saa7134_tvaudio_close(dev);
+
+ if (vdev->vfl_type == VFL_TYPE_RADIO)
+ v4l2_fh_release(file);
+ else
+ _vb2_fop_release(file, NULL);
+
+ /* ts-capture will not work in planar mode, so turn it off Hac: 04.05*/
+ saa_andorb(SAA7134_OFMT_VIDEO_A, 0x1f, 0);
+ saa_andorb(SAA7134_OFMT_VIDEO_B, 0x1f, 0);
+ saa_andorb(SAA7134_OFMT_DATA_A, 0x1f, 0);
+ saa_andorb(SAA7134_OFMT_DATA_B, 0x1f, 0);
+
+ saa_call_all(dev, tuner, standby);
+ if (vdev->vfl_type == VFL_TYPE_RADIO)
+ saa_call_all(dev, core, command, SAA6588_CMD_CLOSE, &cmd);
+ mutex_unlock(&dev->lock);
+
+ return 0;
+}
+
+static ssize_t radio_read(struct file *file, char __user *data,
+ size_t count, loff_t *ppos)
+{
+ struct saa7134_dev *dev = video_drvdata(file);
+ struct saa6588_command cmd;
+
+ cmd.block_count = count/3;
+ cmd.nonblocking = file->f_flags & O_NONBLOCK;
+ cmd.buffer = data;
+ cmd.instance = file;
+ cmd.result = -ENODEV;
+
+ mutex_lock(&dev->lock);
+ saa_call_all(dev, core, command, SAA6588_CMD_READ, &cmd);
+ mutex_unlock(&dev->lock);
+
+ return cmd.result;
+}
+
+static __poll_t radio_poll(struct file *file, poll_table *wait)
+{
+ struct saa7134_dev *dev = video_drvdata(file);
+ struct saa6588_command cmd;
+ __poll_t rc = v4l2_ctrl_poll(file, wait);
+
+ cmd.instance = file;
+ cmd.event_list = wait;
+ cmd.poll_mask = 0;
+ mutex_lock(&dev->lock);
+ saa_call_all(dev, core, command, SAA6588_CMD_POLL, &cmd);
+ mutex_unlock(&dev->lock);
+
+ return rc | cmd.poll_mask;
+}
+
+/* ------------------------------------------------------------------ */
+
+static int saa7134_try_get_set_fmt_vbi_cap(struct file *file, void *priv,
+ struct v4l2_format *f)
+{
+ struct saa7134_dev *dev = video_drvdata(file);
+ struct saa7134_tvnorm *norm = dev->tvnorm;
+
+ memset(&f->fmt.vbi.reserved, 0, sizeof(f->fmt.vbi.reserved));
+ f->fmt.vbi.sampling_rate = 6750000 * 4;
+ f->fmt.vbi.samples_per_line = 2048 /* VBI_LINE_LENGTH */;
+ f->fmt.vbi.sample_format = V4L2_PIX_FMT_GREY;
+ f->fmt.vbi.offset = 64 * 4;
+ f->fmt.vbi.start[0] = norm->vbi_v_start_0;
+ f->fmt.vbi.count[0] = norm->vbi_v_stop_0 - norm->vbi_v_start_0 +1;
+ f->fmt.vbi.start[1] = norm->vbi_v_start_1;
+ f->fmt.vbi.count[1] = f->fmt.vbi.count[0];
+ f->fmt.vbi.flags = 0; /* VBI_UNSYNC VBI_INTERLACED */
+
+ return 0;
+}
+
+static int saa7134_g_fmt_vid_cap(struct file *file, void *priv,
+ struct v4l2_format *f)
+{
+ struct saa7134_dev *dev = video_drvdata(file);
+
+ f->fmt.pix.width = dev->width;
+ f->fmt.pix.height = dev->height;
+ f->fmt.pix.field = dev->field;
+ f->fmt.pix.pixelformat = dev->fmt->fourcc;
+ if (dev->fmt->planar)
+ f->fmt.pix.bytesperline = f->fmt.pix.width;
+ else
+ f->fmt.pix.bytesperline =
+ (f->fmt.pix.width * dev->fmt->depth) / 8;
+ f->fmt.pix.sizeimage =
+ (f->fmt.pix.height * f->fmt.pix.width * dev->fmt->depth) / 8;
+ f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M;
+ return 0;
+}
+
+static int saa7134_try_fmt_vid_cap(struct file *file, void *priv,
+ struct v4l2_format *f)
+{
+ struct saa7134_dev *dev = video_drvdata(file);
+ struct saa7134_format *fmt;
+ enum v4l2_field field;
+ unsigned int maxw, maxh;
+
+ fmt = format_by_fourcc(f->fmt.pix.pixelformat);
+ if (NULL == fmt)
+ return -EINVAL;
+
+ field = f->fmt.pix.field;
+ maxw = min(dev->crop_current.width*4, dev->crop_bounds.width);
+ maxh = min(dev->crop_current.height*4, dev->crop_bounds.height);
+
+ if (V4L2_FIELD_ANY == field) {
+ field = (f->fmt.pix.height > maxh/2)
+ ? V4L2_FIELD_INTERLACED
+ : V4L2_FIELD_BOTTOM;
+ }
+ switch (field) {
+ case V4L2_FIELD_TOP:
+ case V4L2_FIELD_BOTTOM:
+ maxh = maxh / 2;
+ break;
+ default:
+ field = V4L2_FIELD_INTERLACED;
+ break;
+ }
+
+ f->fmt.pix.field = field;
+ if (f->fmt.pix.width < 48)
+ f->fmt.pix.width = 48;
+ if (f->fmt.pix.height < 32)
+ f->fmt.pix.height = 32;
+ if (f->fmt.pix.width > maxw)
+ f->fmt.pix.width = maxw;
+ if (f->fmt.pix.height > maxh)
+ f->fmt.pix.height = maxh;
+ f->fmt.pix.width &= ~0x03;
+ if (fmt->planar)
+ f->fmt.pix.bytesperline = f->fmt.pix.width;
+ else
+ f->fmt.pix.bytesperline =
+ (f->fmt.pix.width * fmt->depth) / 8;
+ f->fmt.pix.sizeimage =
+ (f->fmt.pix.height * f->fmt.pix.width * fmt->depth) / 8;
+ f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M;
+
+ return 0;
+}
+
+static int saa7134_s_fmt_vid_cap(struct file *file, void *priv,
+ struct v4l2_format *f)
+{
+ struct saa7134_dev *dev = video_drvdata(file);
+ int err;
+
+ err = saa7134_try_fmt_vid_cap(file, priv, f);
+ if (0 != err)
+ return err;
+
+ dev->fmt = format_by_fourcc(f->fmt.pix.pixelformat);
+ dev->width = f->fmt.pix.width;
+ dev->height = f->fmt.pix.height;
+ dev->field = f->fmt.pix.field;
+ return 0;
+}
+
+int saa7134_enum_input(struct file *file, void *priv, struct v4l2_input *i)
+{
+ struct saa7134_dev *dev = video_drvdata(file);
+ unsigned int n;
+
+ n = i->index;
+ if (n >= SAA7134_INPUT_MAX)
+ return -EINVAL;
+ if (card_in(dev, i->index).type == SAA7134_NO_INPUT)
+ return -EINVAL;
+ i->index = n;
+ strscpy(i->name, saa7134_input_name[card_in(dev, n).type],
+ sizeof(i->name));
+ switch (card_in(dev, n).type) {
+ case SAA7134_INPUT_TV:
+ case SAA7134_INPUT_TV_MONO:
+ i->type = V4L2_INPUT_TYPE_TUNER;
+ break;
+ default:
+ i->type = V4L2_INPUT_TYPE_CAMERA;
+ break;
+ }
+ if (n == dev->ctl_input) {
+ int v1 = saa_readb(SAA7134_STATUS_VIDEO1);
+ int v2 = saa_readb(SAA7134_STATUS_VIDEO2);
+
+ if (0 != (v1 & 0x40))
+ i->status |= V4L2_IN_ST_NO_H_LOCK;
+ if (0 != (v2 & 0x40))
+ i->status |= V4L2_IN_ST_NO_SIGNAL;
+ if (0 != (v2 & 0x0e))
+ i->status |= V4L2_IN_ST_MACROVISION;
+ }
+ i->std = SAA7134_NORMS;
+ return 0;
+}
+EXPORT_SYMBOL_GPL(saa7134_enum_input);
+
+int saa7134_g_input(struct file *file, void *priv, unsigned int *i)
+{
+ struct saa7134_dev *dev = video_drvdata(file);
+
+ *i = dev->ctl_input;
+ return 0;
+}
+EXPORT_SYMBOL_GPL(saa7134_g_input);
+
+int saa7134_s_input(struct file *file, void *priv, unsigned int i)
+{
+ struct saa7134_dev *dev = video_drvdata(file);
+
+ if (i >= SAA7134_INPUT_MAX)
+ return -EINVAL;
+ if (card_in(dev, i).type == SAA7134_NO_INPUT)
+ return -EINVAL;
+ video_mux(dev, i);
+ return 0;
+}
+EXPORT_SYMBOL_GPL(saa7134_s_input);
+
+int saa7134_querycap(struct file *file, void *priv,
+ struct v4l2_capability *cap)
+{
+ struct saa7134_dev *dev = video_drvdata(file);
+
+ strscpy(cap->driver, "saa7134", sizeof(cap->driver));
+ strscpy(cap->card, saa7134_boards[dev->board].name,
+ sizeof(cap->card));
+ cap->capabilities = V4L2_CAP_READWRITE | V4L2_CAP_STREAMING |
+ V4L2_CAP_RADIO | V4L2_CAP_VIDEO_CAPTURE |
+ V4L2_CAP_VBI_CAPTURE | V4L2_CAP_DEVICE_CAPS;
+ if (dev->tuner_type != TUNER_ABSENT && dev->tuner_type != UNSET)
+ cap->capabilities |= V4L2_CAP_TUNER;
+ if (dev->has_rds)
+ cap->capabilities |= V4L2_CAP_RDS_CAPTURE;
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(saa7134_querycap);
+
+int saa7134_s_std(struct file *file, void *priv, v4l2_std_id id)
+{
+ struct saa7134_dev *dev = video_drvdata(file);
+ unsigned int i;
+ v4l2_std_id fixup;
+
+ for (i = 0; i < TVNORMS; i++)
+ if (id == tvnorms[i].id)
+ break;
+
+ if (i == TVNORMS)
+ for (i = 0; i < TVNORMS; i++)
+ if (id & tvnorms[i].id)
+ break;
+ if (i == TVNORMS)
+ return -EINVAL;
+
+ if ((id & V4L2_STD_SECAM) && (secam[0] != '-')) {
+ if (secam[0] == 'L' || secam[0] == 'l') {
+ if (secam[1] == 'C' || secam[1] == 'c')
+ fixup = V4L2_STD_SECAM_LC;
+ else
+ fixup = V4L2_STD_SECAM_L;
+ } else {
+ if (secam[0] == 'D' || secam[0] == 'd')
+ fixup = V4L2_STD_SECAM_DK;
+ else
+ fixup = V4L2_STD_SECAM;
+ }
+ for (i = 0; i < TVNORMS; i++) {
+ if (fixup == tvnorms[i].id)
+ break;
+ }
+ if (i == TVNORMS)
+ return -EINVAL;
+ }
+
+ set_tvnorm(dev, &tvnorms[i]);
+
+ saa7134_tvaudio_do_scan(dev);
+ return 0;
+}
+EXPORT_SYMBOL_GPL(saa7134_s_std);
+
+int saa7134_g_std(struct file *file, void *priv, v4l2_std_id *id)
+{
+ struct saa7134_dev *dev = video_drvdata(file);
+
+ *id = dev->tvnorm->id;
+ return 0;
+}
+EXPORT_SYMBOL_GPL(saa7134_g_std);
+
+static v4l2_std_id saa7134_read_std(struct saa7134_dev *dev)
+{
+ static v4l2_std_id stds[] = {
+ V4L2_STD_UNKNOWN,
+ V4L2_STD_NTSC,
+ V4L2_STD_PAL,
+ V4L2_STD_SECAM };
+
+ v4l2_std_id result = 0;
+
+ u8 st1 = saa_readb(SAA7134_STATUS_VIDEO1);
+ u8 st2 = saa_readb(SAA7134_STATUS_VIDEO2);
+
+ if (!(st2 & 0x1)) /* RDCAP == 0 */
+ result = V4L2_STD_UNKNOWN;
+ else
+ result = stds[st1 & 0x03];
+
+ return result;
+}
+
+int saa7134_querystd(struct file *file, void *priv, v4l2_std_id *std)
+{
+ struct saa7134_dev *dev = video_drvdata(file);
+ *std &= saa7134_read_std(dev);
+ return 0;
+}
+EXPORT_SYMBOL_GPL(saa7134_querystd);
+
+static int saa7134_g_pixelaspect(struct file *file, void *priv,
+ int type, struct v4l2_fract *f)
+{
+ struct saa7134_dev *dev = video_drvdata(file);
+
+ if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ return -EINVAL;
+
+ if (dev->tvnorm->id & V4L2_STD_525_60) {
+ f->numerator = 11;
+ f->denominator = 10;
+ }
+ if (dev->tvnorm->id & V4L2_STD_625_50) {
+ f->numerator = 54;
+ f->denominator = 59;
+ }
+ return 0;
+}
+
+static int saa7134_g_selection(struct file *file, void *f, struct v4l2_selection *sel)
+{
+ struct saa7134_dev *dev = video_drvdata(file);
+
+ if (sel->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ return -EINVAL;
+
+ switch (sel->target) {
+ case V4L2_SEL_TGT_CROP:
+ sel->r = dev->crop_current;
+ break;
+ case V4L2_SEL_TGT_CROP_DEFAULT:
+ sel->r = dev->crop_defrect;
+ break;
+ case V4L2_SEL_TGT_CROP_BOUNDS:
+ sel->r = dev->crop_bounds;
+ break;
+ default:
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static int saa7134_s_selection(struct file *file, void *f, struct v4l2_selection *sel)
+{
+ struct saa7134_dev *dev = video_drvdata(file);
+ struct v4l2_rect *b = &dev->crop_bounds;
+ struct v4l2_rect *c = &dev->crop_current;
+
+ if (sel->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ return -EINVAL;
+
+ if (sel->target != V4L2_SEL_TGT_CROP)
+ return -EINVAL;
+
+ if (vb2_is_streaming(&dev->video_vbq))
+ return -EBUSY;
+
+ *c = sel->r;
+ if (c->top < b->top)
+ c->top = b->top;
+ if (c->top > b->top + b->height)
+ c->top = b->top + b->height;
+ if (c->height > b->top - c->top + b->height)
+ c->height = b->top - c->top + b->height;
+
+ if (c->left < b->left)
+ c->left = b->left;
+ if (c->left > b->left + b->width)
+ c->left = b->left + b->width;
+ if (c->width > b->left - c->left + b->width)
+ c->width = b->left - c->left + b->width;
+ sel->r = *c;
+ return 0;
+}
+
+int saa7134_g_tuner(struct file *file, void *priv,
+ struct v4l2_tuner *t)
+{
+ struct saa7134_dev *dev = video_drvdata(file);
+ int n;
+
+ if (0 != t->index)
+ return -EINVAL;
+ memset(t, 0, sizeof(*t));
+ for (n = 0; n < SAA7134_INPUT_MAX; n++) {
+ if (card_in(dev, n).type == SAA7134_INPUT_TV ||
+ card_in(dev, n).type == SAA7134_INPUT_TV_MONO)
+ break;
+ }
+ if (n == SAA7134_INPUT_MAX)
+ return -EINVAL;
+ if (card_in(dev, n).type != SAA7134_NO_INPUT) {
+ strscpy(t->name, "Television", sizeof(t->name));
+ t->type = V4L2_TUNER_ANALOG_TV;
+ saa_call_all(dev, tuner, g_tuner, t);
+ t->capability = V4L2_TUNER_CAP_NORM |
+ V4L2_TUNER_CAP_STEREO |
+ V4L2_TUNER_CAP_LANG1 |
+ V4L2_TUNER_CAP_LANG2;
+ t->rxsubchans = saa7134_tvaudio_getstereo(dev);
+ t->audmode = saa7134_tvaudio_rx2mode(t->rxsubchans);
+ }
+ if (0 != (saa_readb(SAA7134_STATUS_VIDEO1) & 0x03))
+ t->signal = 0xffff;
+ return 0;
+}
+EXPORT_SYMBOL_GPL(saa7134_g_tuner);
+
+int saa7134_s_tuner(struct file *file, void *priv,
+ const struct v4l2_tuner *t)
+{
+ struct saa7134_dev *dev = video_drvdata(file);
+ int rx, mode;
+
+ if (0 != t->index)
+ return -EINVAL;
+
+ mode = dev->thread.mode;
+ if (UNSET == mode) {
+ rx = saa7134_tvaudio_getstereo(dev);
+ mode = saa7134_tvaudio_rx2mode(rx);
+ }
+ if (mode != t->audmode)
+ dev->thread.mode = t->audmode;
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(saa7134_s_tuner);
+
+int saa7134_g_frequency(struct file *file, void *priv,
+ struct v4l2_frequency *f)
+{
+ struct saa7134_dev *dev = video_drvdata(file);
+
+ if (0 != f->tuner)
+ return -EINVAL;
+
+ saa_call_all(dev, tuner, g_frequency, f);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(saa7134_g_frequency);
+
+int saa7134_s_frequency(struct file *file, void *priv,
+ const struct v4l2_frequency *f)
+{
+ struct saa7134_dev *dev = video_drvdata(file);
+
+ if (0 != f->tuner)
+ return -EINVAL;
+
+ saa_call_all(dev, tuner, s_frequency, f);
+
+ saa7134_tvaudio_do_scan(dev);
+ return 0;
+}
+EXPORT_SYMBOL_GPL(saa7134_s_frequency);
+
+static int saa7134_enum_fmt_vid_cap(struct file *file, void *priv,
+ struct v4l2_fmtdesc *f)
+{
+ if (f->index >= FORMATS)
+ return -EINVAL;
+
+ f->pixelformat = formats[f->index].fourcc;
+
+ return 0;
+}
+
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+static int vidioc_g_register (struct file *file, void *priv,
+ struct v4l2_dbg_register *reg)
+{
+ struct saa7134_dev *dev = video_drvdata(file);
+
+ reg->val = saa_readb(reg->reg & 0xffffff);
+ reg->size = 1;
+ return 0;
+}
+
+static int vidioc_s_register (struct file *file, void *priv,
+ const struct v4l2_dbg_register *reg)
+{
+ struct saa7134_dev *dev = video_drvdata(file);
+
+ saa_writeb(reg->reg & 0xffffff, reg->val);
+ return 0;
+}
+#endif
+
+static int radio_g_tuner(struct file *file, void *priv,
+ struct v4l2_tuner *t)
+{
+ struct saa7134_dev *dev = video_drvdata(file);
+
+ if (0 != t->index)
+ return -EINVAL;
+
+ strscpy(t->name, "Radio", sizeof(t->name));
+
+ saa_call_all(dev, tuner, g_tuner, t);
+ t->audmode &= V4L2_TUNER_MODE_MONO | V4L2_TUNER_MODE_STEREO;
+ if (dev->input->amux == TV) {
+ t->signal = 0xf800 - ((saa_readb(0x581) & 0x1f) << 11);
+ t->rxsubchans = (saa_readb(0x529) & 0x08) ?
+ V4L2_TUNER_SUB_STEREO : V4L2_TUNER_SUB_MONO;
+ }
+ return 0;
+}
+static int radio_s_tuner(struct file *file, void *priv,
+ const struct v4l2_tuner *t)
+{
+ struct saa7134_dev *dev = video_drvdata(file);
+
+ if (0 != t->index)
+ return -EINVAL;
+
+ saa_call_all(dev, tuner, s_tuner, t);
+ return 0;
+}
+
+static const struct v4l2_file_operations video_fops =
+{
+ .owner = THIS_MODULE,
+ .open = video_open,
+ .release = video_release,
+ .read = vb2_fop_read,
+ .poll = vb2_fop_poll,
+ .mmap = vb2_fop_mmap,
+ .unlocked_ioctl = video_ioctl2,
+};
+
+static const struct v4l2_ioctl_ops video_ioctl_ops = {
+ .vidioc_querycap = saa7134_querycap,
+ .vidioc_enum_fmt_vid_cap = saa7134_enum_fmt_vid_cap,
+ .vidioc_g_fmt_vid_cap = saa7134_g_fmt_vid_cap,
+ .vidioc_try_fmt_vid_cap = saa7134_try_fmt_vid_cap,
+ .vidioc_s_fmt_vid_cap = saa7134_s_fmt_vid_cap,
+ .vidioc_g_fmt_vbi_cap = saa7134_try_get_set_fmt_vbi_cap,
+ .vidioc_try_fmt_vbi_cap = saa7134_try_get_set_fmt_vbi_cap,
+ .vidioc_s_fmt_vbi_cap = saa7134_try_get_set_fmt_vbi_cap,
+ .vidioc_g_pixelaspect = saa7134_g_pixelaspect,
+ .vidioc_reqbufs = vb2_ioctl_reqbufs,
+ .vidioc_querybuf = vb2_ioctl_querybuf,
+ .vidioc_qbuf = vb2_ioctl_qbuf,
+ .vidioc_dqbuf = vb2_ioctl_dqbuf,
+ .vidioc_expbuf = vb2_ioctl_expbuf,
+ .vidioc_s_std = saa7134_s_std,
+ .vidioc_g_std = saa7134_g_std,
+ .vidioc_querystd = saa7134_querystd,
+ .vidioc_enum_input = saa7134_enum_input,
+ .vidioc_g_input = saa7134_g_input,
+ .vidioc_s_input = saa7134_s_input,
+ .vidioc_streamon = vb2_ioctl_streamon,
+ .vidioc_streamoff = vb2_ioctl_streamoff,
+ .vidioc_g_tuner = saa7134_g_tuner,
+ .vidioc_s_tuner = saa7134_s_tuner,
+ .vidioc_g_selection = saa7134_g_selection,
+ .vidioc_s_selection = saa7134_s_selection,
+ .vidioc_g_frequency = saa7134_g_frequency,
+ .vidioc_s_frequency = saa7134_s_frequency,
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+ .vidioc_g_register = vidioc_g_register,
+ .vidioc_s_register = vidioc_s_register,
+#endif
+ .vidioc_log_status = v4l2_ctrl_log_status,
+ .vidioc_subscribe_event = v4l2_ctrl_subscribe_event,
+ .vidioc_unsubscribe_event = v4l2_event_unsubscribe,
+};
+
+static const struct v4l2_file_operations radio_fops = {
+ .owner = THIS_MODULE,
+ .open = video_open,
+ .read = radio_read,
+ .release = video_release,
+ .unlocked_ioctl = video_ioctl2,
+ .poll = radio_poll,
+};
+
+static const struct v4l2_ioctl_ops radio_ioctl_ops = {
+ .vidioc_querycap = saa7134_querycap,
+ .vidioc_g_tuner = radio_g_tuner,
+ .vidioc_s_tuner = radio_s_tuner,
+ .vidioc_g_frequency = saa7134_g_frequency,
+ .vidioc_s_frequency = saa7134_s_frequency,
+ .vidioc_subscribe_event = v4l2_ctrl_subscribe_event,
+ .vidioc_unsubscribe_event = v4l2_event_unsubscribe,
+};
+
+/* ----------------------------------------------------------- */
+/* exported stuff */
+
+struct video_device saa7134_video_template = {
+ .name = "saa7134-video",
+ .fops = &video_fops,
+ .ioctl_ops = &video_ioctl_ops,
+ .tvnorms = SAA7134_NORMS,
+};
+
+struct video_device saa7134_radio_template = {
+ .name = "saa7134-radio",
+ .fops = &radio_fops,
+ .ioctl_ops = &radio_ioctl_ops,
+};
+
+static const struct v4l2_ctrl_ops saa7134_ctrl_ops = {
+ .s_ctrl = saa7134_s_ctrl,
+};
+
+static const struct v4l2_ctrl_config saa7134_ctrl_invert = {
+ .ops = &saa7134_ctrl_ops,
+ .id = V4L2_CID_PRIVATE_INVERT,
+ .name = "Invert",
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .min = 0,
+ .max = 1,
+ .step = 1,
+};
+
+static const struct v4l2_ctrl_config saa7134_ctrl_y_odd = {
+ .ops = &saa7134_ctrl_ops,
+ .id = V4L2_CID_PRIVATE_Y_ODD,
+ .name = "Y Offset Odd Field",
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .min = 0,
+ .max = 128,
+ .step = 1,
+};
+
+static const struct v4l2_ctrl_config saa7134_ctrl_y_even = {
+ .ops = &saa7134_ctrl_ops,
+ .id = V4L2_CID_PRIVATE_Y_EVEN,
+ .name = "Y Offset Even Field",
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .min = 0,
+ .max = 128,
+ .step = 1,
+};
+
+static const struct v4l2_ctrl_config saa7134_ctrl_automute = {
+ .ops = &saa7134_ctrl_ops,
+ .id = V4L2_CID_PRIVATE_AUTOMUTE,
+ .name = "Automute",
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .min = 0,
+ .max = 1,
+ .step = 1,
+ .def = 1,
+};
+
+int saa7134_video_init1(struct saa7134_dev *dev)
+{
+ struct v4l2_ctrl_handler *hdl = &dev->ctrl_handler;
+ struct vb2_queue *q;
+ int ret;
+
+ /* sanitycheck insmod options */
+ if (gbuffers < 2 || gbuffers > VIDEO_MAX_FRAME)
+ gbuffers = 2;
+ if (gbufsize > gbufsize_max)
+ gbufsize = gbufsize_max;
+ gbufsize = (gbufsize + PAGE_SIZE - 1) & PAGE_MASK;
+
+ v4l2_ctrl_handler_init(hdl, 11);
+ v4l2_ctrl_new_std(hdl, &saa7134_ctrl_ops,
+ V4L2_CID_BRIGHTNESS, 0, 255, 1, 128);
+ v4l2_ctrl_new_std(hdl, &saa7134_ctrl_ops,
+ V4L2_CID_CONTRAST, 0, 127, 1, 68);
+ v4l2_ctrl_new_std(hdl, &saa7134_ctrl_ops,
+ V4L2_CID_SATURATION, 0, 127, 1, 64);
+ v4l2_ctrl_new_std(hdl, &saa7134_ctrl_ops,
+ V4L2_CID_HUE, -128, 127, 1, 0);
+ v4l2_ctrl_new_std(hdl, &saa7134_ctrl_ops,
+ V4L2_CID_HFLIP, 0, 1, 1, 0);
+ v4l2_ctrl_new_std(hdl, &saa7134_ctrl_ops,
+ V4L2_CID_AUDIO_MUTE, 0, 1, 1, 0);
+ v4l2_ctrl_new_std(hdl, &saa7134_ctrl_ops,
+ V4L2_CID_AUDIO_VOLUME, -15, 15, 1, 0);
+ v4l2_ctrl_new_custom(hdl, &saa7134_ctrl_invert, NULL);
+ v4l2_ctrl_new_custom(hdl, &saa7134_ctrl_y_odd, NULL);
+ v4l2_ctrl_new_custom(hdl, &saa7134_ctrl_y_even, NULL);
+ v4l2_ctrl_new_custom(hdl, &saa7134_ctrl_automute, NULL);
+ if (hdl->error)
+ return hdl->error;
+ if (card_has_radio(dev)) {
+ hdl = &dev->radio_ctrl_handler;
+ v4l2_ctrl_handler_init(hdl, 2);
+ v4l2_ctrl_add_handler(hdl, &dev->ctrl_handler,
+ v4l2_ctrl_radio_filter, false);
+ if (hdl->error)
+ return hdl->error;
+ }
+ dev->ctl_mute = 1;
+
+ if (dev->tda9887_conf && saa7134_ctrl_automute.def)
+ dev->tda9887_conf |= TDA9887_AUTOMUTE;
+ dev->automute = 0;
+
+ INIT_LIST_HEAD(&dev->video_q.queue);
+ timer_setup(&dev->video_q.timeout, saa7134_buffer_timeout, 0);
+ dev->video_q.dev = dev;
+ dev->fmt = format_by_fourcc(V4L2_PIX_FMT_BGR24);
+ dev->width = 720;
+ dev->height = 576;
+ dev->field = V4L2_FIELD_INTERLACED;
+
+ if (saa7134_boards[dev->board].video_out)
+ saa7134_videoport_init(dev);
+
+ q = &dev->video_vbq;
+ q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ /*
+ * Do not add VB2_USERPTR unless explicitly requested: the saa7134 DMA
+ * engine cannot handle transfers that do not start at the beginning
+ * of a page. A user-provided pointer can start anywhere in a page, so
+ * USERPTR support is a no-go unless the application knows about these
+ * limitations and has special support for this.
+ */
+ q->io_modes = VB2_MMAP | VB2_DMABUF | VB2_READ;
+ if (saa7134_userptr)
+ q->io_modes |= VB2_USERPTR;
+ q->drv_priv = &dev->video_q;
+ q->ops = &vb2_qops;
+ q->gfp_flags = GFP_DMA32;
+ q->mem_ops = &vb2_dma_sg_memops;
+ q->buf_struct_size = sizeof(struct saa7134_buf);
+ q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
+ q->lock = &dev->lock;
+ q->dev = &dev->pci->dev;
+ ret = vb2_queue_init(q);
+ if (ret)
+ return ret;
+ saa7134_pgtable_alloc(dev->pci, &dev->video_q.pt);
+
+ q = &dev->vbi_vbq;
+ q->type = V4L2_BUF_TYPE_VBI_CAPTURE;
+ /* Don't add VB2_USERPTR, see comment above */
+ q->io_modes = VB2_MMAP | VB2_READ;
+ if (saa7134_userptr)
+ q->io_modes |= VB2_USERPTR;
+ q->drv_priv = &dev->vbi_q;
+ q->ops = &saa7134_vbi_qops;
+ q->gfp_flags = GFP_DMA32;
+ q->mem_ops = &vb2_dma_sg_memops;
+ q->buf_struct_size = sizeof(struct saa7134_buf);
+ q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
+ q->lock = &dev->lock;
+ q->dev = &dev->pci->dev;
+ ret = vb2_queue_init(q);
+ if (ret)
+ return ret;
+ saa7134_pgtable_alloc(dev->pci, &dev->vbi_q.pt);
+
+ return 0;
+}
+
+void saa7134_video_fini(struct saa7134_dev *dev)
+{
+ del_timer_sync(&dev->video_q.timeout);
+ /* free stuff */
+ saa7134_pgtable_free(dev->pci, &dev->video_q.pt);
+ saa7134_pgtable_free(dev->pci, &dev->vbi_q.pt);
+ v4l2_ctrl_handler_free(&dev->ctrl_handler);
+ if (card_has_radio(dev))
+ v4l2_ctrl_handler_free(&dev->radio_ctrl_handler);
+}
+
+int saa7134_videoport_init(struct saa7134_dev *dev)
+{
+ /* enable video output */
+ int vo = saa7134_boards[dev->board].video_out;
+ int video_reg;
+ unsigned int vid_port_opts = saa7134_boards[dev->board].vid_port_opts;
+
+ /* Configure videoport */
+ saa_writeb(SAA7134_VIDEO_PORT_CTRL0, video_out[vo][0]);
+ video_reg = video_out[vo][1];
+ if (vid_port_opts & SET_T_CODE_POLARITY_NON_INVERTED)
+ video_reg &= ~VP_T_CODE_P_INVERTED;
+ saa_writeb(SAA7134_VIDEO_PORT_CTRL1, video_reg);
+ saa_writeb(SAA7134_VIDEO_PORT_CTRL2, video_out[vo][2]);
+ saa_writeb(SAA7134_VIDEO_PORT_CTRL4, video_out[vo][4]);
+ video_reg = video_out[vo][5];
+ if (vid_port_opts & SET_CLOCK_NOT_DELAYED)
+ video_reg &= ~VP_CLK_CTRL2_DELAYED;
+ if (vid_port_opts & SET_CLOCK_INVERTED)
+ video_reg |= VP_CLK_CTRL1_INVERTED;
+ saa_writeb(SAA7134_VIDEO_PORT_CTRL5, video_reg);
+ video_reg = video_out[vo][6];
+ if (vid_port_opts & SET_VSYNC_OFF) {
+ video_reg &= ~VP_VS_TYPE_MASK;
+ video_reg |= VP_VS_TYPE_OFF;
+ }
+ saa_writeb(SAA7134_VIDEO_PORT_CTRL6, video_reg);
+ saa_writeb(SAA7134_VIDEO_PORT_CTRL7, video_out[vo][7]);
+ saa_writeb(SAA7134_VIDEO_PORT_CTRL8, video_out[vo][8]);
+
+ /* Start videoport */
+ saa_writeb(SAA7134_VIDEO_PORT_CTRL3, video_out[vo][3]);
+
+ return 0;
+}
+
+int saa7134_video_init2(struct saa7134_dev *dev)
+{
+ /* init video hw */
+ set_tvnorm(dev,&tvnorms[0]);
+ video_mux(dev,0);
+ v4l2_ctrl_handler_setup(&dev->ctrl_handler);
+ saa7134_tvaudio_setmute(dev);
+ saa7134_tvaudio_setvolume(dev,dev->ctl_volume);
+ return 0;
+}
+
+void saa7134_irq_video_signalchange(struct saa7134_dev *dev)
+{
+ static const char *st[] = {
+ "(no signal)", "NTSC", "PAL", "SECAM" };
+ u32 st1,st2;
+
+ st1 = saa_readb(SAA7134_STATUS_VIDEO1);
+ st2 = saa_readb(SAA7134_STATUS_VIDEO2);
+ video_dbg("DCSDT: pll: %s, sync: %s, norm: %s\n",
+ (st1 & 0x40) ? "not locked" : "locked",
+ (st2 & 0x40) ? "no" : "yes",
+ st[st1 & 0x03]);
+ dev->nosignal = (st1 & 0x40) || (st2 & 0x40) || !(st2 & 0x1);
+
+ if (dev->nosignal) {
+ /* no video signal -> mute audio */
+ if (dev->ctl_automute)
+ dev->automute = 1;
+ saa7134_tvaudio_setmute(dev);
+ } else {
+ /* wake up tvaudio audio carrier scan thread */
+ saa7134_tvaudio_do_scan(dev);
+ }
+
+ if ((st2 & 0x80) && !noninterlaced && !dev->nosignal)
+ saa_clearb(SAA7134_SYNC_CTRL, 0x20);
+ else
+ saa_setb(SAA7134_SYNC_CTRL, 0x20);
+
+ if (dev->mops && dev->mops->signal_change)
+ dev->mops->signal_change(dev);
+}
+
+
+void saa7134_irq_video_done(struct saa7134_dev *dev, unsigned long status)
+{
+ enum v4l2_field field;
+
+ spin_lock(&dev->slock);
+ if (dev->video_q.curr) {
+ field = dev->field;
+ if (V4L2_FIELD_HAS_BOTH(field)) {
+ /* make sure we have seen both fields */
+ if ((status & 0x10) == 0x00) {
+ dev->video_q.curr->top_seen = 1;
+ goto done;
+ }
+ if (!dev->video_q.curr->top_seen)
+ goto done;
+ } else if (field == V4L2_FIELD_TOP) {
+ if ((status & 0x10) != 0x10)
+ goto done;
+ } else if (field == V4L2_FIELD_BOTTOM) {
+ if ((status & 0x10) != 0x00)
+ goto done;
+ }
+ saa7134_buffer_finish(dev, &dev->video_q, VB2_BUF_STATE_DONE);
+ }
+ saa7134_buffer_next(dev, &dev->video_q);
+
+ done:
+ spin_unlock(&dev->slock);
+}
diff --git a/drivers/media/pci/saa7134/saa7134.h b/drivers/media/pci/saa7134/saa7134.h
new file mode 100644
index 0000000000..9f27e3775c
--- /dev/null
+++ b/drivers/media/pci/saa7134/saa7134.h
@@ -0,0 +1,907 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ *
+ * v4l2 device driver for philips saa7134 based TV cards
+ *
+ * (c) 2001,02 Gerd Knorr <kraxel@bytesex.org>
+ */
+
+#define SAA7134_VERSION "0, 2, 17"
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/pci.h>
+#include <linux/i2c.h>
+#include <linux/videodev2.h>
+#include <linux/kdev_t.h>
+#include <linux/input.h>
+#include <linux/notifier.h>
+#include <linux/delay.h>
+#include <linux/mutex.h>
+#include <linux/pm_qos.h>
+
+#include <asm/io.h>
+
+#include <media/v4l2-common.h>
+#include <media/v4l2-ioctl.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-fh.h>
+#include <media/v4l2-ctrls.h>
+#include <media/tuner.h>
+#include <media/rc-core.h>
+#include <media/i2c/ir-kbd-i2c.h>
+#include <media/videobuf2-dma-sg.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#if IS_ENABLED(CONFIG_VIDEO_SAA7134_DVB)
+#include <media/videobuf2-dvb.h>
+#endif
+#include "tda8290.h"
+
+#define UNSET (-1U)
+
+/* ----------------------------------------------------------- */
+/* enums */
+
+enum saa7134_tvaudio_mode {
+ TVAUDIO_FM_MONO = 1,
+ TVAUDIO_FM_BG_STEREO = 2,
+ TVAUDIO_FM_SAT_STEREO = 3,
+ TVAUDIO_FM_K_STEREO = 4,
+ TVAUDIO_NICAM_AM = 5,
+ TVAUDIO_NICAM_FM = 6,
+};
+
+enum saa7134_audio_in {
+ TV = 1,
+ LINE1 = 2,
+ LINE2 = 3,
+ LINE2_LEFT,
+};
+
+enum saa7134_video_out {
+ CCIR656 = 1,
+};
+
+/* ----------------------------------------------------------- */
+/* static data */
+
+struct saa7134_tvnorm {
+ char *name;
+ v4l2_std_id id;
+
+ /* video decoder */
+ unsigned int sync_control;
+ unsigned int luma_control;
+ unsigned int chroma_ctrl1;
+ unsigned int chroma_gain;
+ unsigned int chroma_ctrl2;
+ unsigned int vgate_misc;
+
+ /* video scaler */
+ unsigned int h_start;
+ unsigned int h_stop;
+ unsigned int video_v_start;
+ unsigned int video_v_stop;
+ unsigned int vbi_v_start_0;
+ unsigned int vbi_v_stop_0;
+ unsigned int src_timing;
+ unsigned int vbi_v_start_1;
+};
+
+struct saa7134_tvaudio {
+ char *name;
+ v4l2_std_id std;
+ enum saa7134_tvaudio_mode mode;
+ int carr1;
+ int carr2;
+};
+
+struct saa7134_format {
+ unsigned int fourcc;
+ unsigned int depth;
+ unsigned int pm;
+ unsigned int vshift; /* vertical downsampling (for planar yuv) */
+ unsigned int hshift; /* horizontal downsampling (for planar yuv) */
+ unsigned int bswap:1;
+ unsigned int wswap:1;
+ unsigned int yuv:1;
+ unsigned int planar:1;
+ unsigned int uvswap:1;
+};
+
+struct saa7134_card_ir {
+ struct rc_dev *dev;
+
+ char phys[32];
+
+ u32 polling;
+ u32 last_gpio;
+ u32 mask_keycode, mask_keydown, mask_keyup;
+
+ bool running;
+
+ struct timer_list timer;
+
+ /* IR core raw decoding */
+ u32 raw_decode;
+};
+
+/* ----------------------------------------------------------- */
+/* card configuration */
+
+#define SAA7134_BOARD_NOAUTO UNSET
+#define SAA7134_BOARD_UNKNOWN 0
+#define SAA7134_BOARD_PROTEUS_PRO 1
+#define SAA7134_BOARD_FLYVIDEO3000 2
+#define SAA7134_BOARD_FLYVIDEO2000 3
+#define SAA7134_BOARD_EMPRESS 4
+#define SAA7134_BOARD_MONSTERTV 5
+#define SAA7134_BOARD_MD9717 6
+#define SAA7134_BOARD_TVSTATION_RDS 7
+#define SAA7134_BOARD_CINERGY400 8
+#define SAA7134_BOARD_MD5044 9
+#define SAA7134_BOARD_KWORLD 10
+#define SAA7134_BOARD_CINERGY600 11
+#define SAA7134_BOARD_MD7134 12
+#define SAA7134_BOARD_TYPHOON_90031 13
+#define SAA7134_BOARD_ELSA 14
+#define SAA7134_BOARD_ELSA_500TV 15
+#define SAA7134_BOARD_ASUSTeK_TVFM7134 16
+#define SAA7134_BOARD_VA1000POWER 17
+#define SAA7134_BOARD_BMK_MPEX_NOTUNER 18
+#define SAA7134_BOARD_VIDEOMATE_TV 19
+#define SAA7134_BOARD_CRONOS_PLUS 20
+#define SAA7134_BOARD_10MOONSTVMASTER 21
+#define SAA7134_BOARD_MD2819 22
+#define SAA7134_BOARD_BMK_MPEX_TUNER 23
+#define SAA7134_BOARD_TVSTATION_DVR 24
+#define SAA7134_BOARD_ASUSTEK_TVFM7133 25
+#define SAA7134_BOARD_PINNACLE_PCTV_STEREO 26
+#define SAA7134_BOARD_MANLI_MTV002 27
+#define SAA7134_BOARD_MANLI_MTV001 28
+#define SAA7134_BOARD_TG3000TV 29
+#define SAA7134_BOARD_ECS_TVP3XP 30
+#define SAA7134_BOARD_ECS_TVP3XP_4CB5 31
+#define SAA7134_BOARD_AVACSSMARTTV 32
+#define SAA7134_BOARD_AVERMEDIA_DVD_EZMAKER 33
+#define SAA7134_BOARD_NOVAC_PRIMETV7133 34
+#define SAA7134_BOARD_AVERMEDIA_STUDIO_305 35
+#define SAA7134_BOARD_UPMOST_PURPLE_TV 36
+#define SAA7134_BOARD_ITEMS_MTV005 37
+#define SAA7134_BOARD_CINERGY200 38
+#define SAA7134_BOARD_FLYTVPLATINUM_MINI 39
+#define SAA7134_BOARD_VIDEOMATE_TV_PVR 40
+#define SAA7134_BOARD_VIDEOMATE_TV_GOLD_PLUS 41
+#define SAA7134_BOARD_SABRENT_SBTTVFM 42
+#define SAA7134_BOARD_ZOLID_XPERT_TV7134 43
+#define SAA7134_BOARD_EMPIRE_PCI_TV_RADIO_LE 44
+#define SAA7134_BOARD_AVERMEDIA_STUDIO_307 45
+#define SAA7134_BOARD_AVERMEDIA_CARDBUS 46
+#define SAA7134_BOARD_CINERGY400_CARDBUS 47
+#define SAA7134_BOARD_CINERGY600_MK3 48
+#define SAA7134_BOARD_VIDEOMATE_GOLD_PLUS 49
+#define SAA7134_BOARD_PINNACLE_300I_DVBT_PAL 50
+#define SAA7134_BOARD_PROVIDEO_PV952 51
+#define SAA7134_BOARD_AVERMEDIA_305 52
+#define SAA7134_BOARD_ASUSTeK_TVFM7135 53
+#define SAA7134_BOARD_FLYTVPLATINUM_FM 54
+#define SAA7134_BOARD_FLYDVBTDUO 55
+#define SAA7134_BOARD_AVERMEDIA_307 56
+#define SAA7134_BOARD_AVERMEDIA_GO_007_FM 57
+#define SAA7134_BOARD_ADS_INSTANT_TV 58
+#define SAA7134_BOARD_KWORLD_VSTREAM_XPERT 59
+#define SAA7134_BOARD_FLYDVBT_DUO_CARDBUS 60
+#define SAA7134_BOARD_PHILIPS_TOUGH 61
+#define SAA7134_BOARD_VIDEOMATE_TV_GOLD_PLUSII 62
+#define SAA7134_BOARD_KWORLD_XPERT 63
+#define SAA7134_BOARD_FLYTV_DIGIMATRIX 64
+#define SAA7134_BOARD_KWORLD_TERMINATOR 65
+#define SAA7134_BOARD_YUAN_TUN900 66
+#define SAA7134_BOARD_BEHOLD_409FM 67
+#define SAA7134_BOARD_GOTVIEW_7135 68
+#define SAA7134_BOARD_PHILIPS_EUROPA 69
+#define SAA7134_BOARD_VIDEOMATE_DVBT_300 70
+#define SAA7134_BOARD_VIDEOMATE_DVBT_200 71
+#define SAA7134_BOARD_RTD_VFG7350 72
+#define SAA7134_BOARD_RTD_VFG7330 73
+#define SAA7134_BOARD_FLYTVPLATINUM_MINI2 74
+#define SAA7134_BOARD_AVERMEDIA_AVERTVHD_A180 75
+#define SAA7134_BOARD_MONSTERTV_MOBILE 76
+#define SAA7134_BOARD_PINNACLE_PCTV_110i 77
+#define SAA7134_BOARD_ASUSTeK_P7131_DUAL 78
+#define SAA7134_BOARD_SEDNA_PC_TV_CARDBUS 79
+#define SAA7134_BOARD_ASUSTEK_DIGIMATRIX_TV 80
+#define SAA7134_BOARD_PHILIPS_TIGER 81
+#define SAA7134_BOARD_MSI_TVATANYWHERE_PLUS 82
+#define SAA7134_BOARD_CINERGY250PCI 83
+#define SAA7134_BOARD_FLYDVB_TRIO 84
+#define SAA7134_BOARD_AVERMEDIA_777 85
+#define SAA7134_BOARD_FLYDVBT_LR301 86
+#define SAA7134_BOARD_ADS_DUO_CARDBUS_PTV331 87
+#define SAA7134_BOARD_TEVION_DVBT_220RF 88
+#define SAA7134_BOARD_ELSA_700TV 89
+#define SAA7134_BOARD_KWORLD_ATSC110 90
+#define SAA7134_BOARD_AVERMEDIA_A169_B 91
+#define SAA7134_BOARD_AVERMEDIA_A169_B1 92
+#define SAA7134_BOARD_MD7134_BRIDGE_2 93
+#define SAA7134_BOARD_FLYDVBT_HYBRID_CARDBUS 94
+#define SAA7134_BOARD_FLYVIDEO3000_NTSC 95
+#define SAA7134_BOARD_MEDION_MD8800_QUADRO 96
+#define SAA7134_BOARD_FLYDVBS_LR300 97
+#define SAA7134_BOARD_PROTEUS_2309 98
+#define SAA7134_BOARD_AVERMEDIA_A16AR 99
+#define SAA7134_BOARD_ASUS_EUROPA2_HYBRID 100
+#define SAA7134_BOARD_PINNACLE_PCTV_310i 101
+#define SAA7134_BOARD_AVERMEDIA_STUDIO_507 102
+#define SAA7134_BOARD_VIDEOMATE_DVBT_200A 103
+#define SAA7134_BOARD_HAUPPAUGE_HVR1110 104
+#define SAA7134_BOARD_CINERGY_HT_PCMCIA 105
+#define SAA7134_BOARD_ENCORE_ENLTV 106
+#define SAA7134_BOARD_ENCORE_ENLTV_FM 107
+#define SAA7134_BOARD_CINERGY_HT_PCI 108
+#define SAA7134_BOARD_PHILIPS_TIGER_S 109
+#define SAA7134_BOARD_AVERMEDIA_M102 110
+#define SAA7134_BOARD_ASUS_P7131_4871 111
+#define SAA7134_BOARD_ASUSTeK_P7131_HYBRID_LNA 112
+#define SAA7134_BOARD_ECS_TVP3XP_4CB6 113
+#define SAA7134_BOARD_KWORLD_DVBT_210 114
+#define SAA7134_BOARD_SABRENT_TV_PCB05 115
+#define SAA7134_BOARD_10MOONSTVMASTER3 116
+#define SAA7134_BOARD_AVERMEDIA_SUPER_007 117
+#define SAA7134_BOARD_BEHOLD_401 118
+#define SAA7134_BOARD_BEHOLD_403 119
+#define SAA7134_BOARD_BEHOLD_403FM 120
+#define SAA7134_BOARD_BEHOLD_405 121
+#define SAA7134_BOARD_BEHOLD_405FM 122
+#define SAA7134_BOARD_BEHOLD_407 123
+#define SAA7134_BOARD_BEHOLD_407FM 124
+#define SAA7134_BOARD_BEHOLD_409 125
+#define SAA7134_BOARD_BEHOLD_505FM 126
+#define SAA7134_BOARD_BEHOLD_507_9FM 127
+#define SAA7134_BOARD_BEHOLD_COLUMBUS_TVFM 128
+#define SAA7134_BOARD_BEHOLD_607FM_MK3 129
+#define SAA7134_BOARD_BEHOLD_M6 130
+#define SAA7134_BOARD_TWINHAN_DTV_DVB_3056 131
+#define SAA7134_BOARD_GENIUS_TVGO_A11MCE 132
+#define SAA7134_BOARD_PHILIPS_SNAKE 133
+#define SAA7134_BOARD_CREATIX_CTX953 134
+#define SAA7134_BOARD_MSI_TVANYWHERE_AD11 135
+#define SAA7134_BOARD_AVERMEDIA_CARDBUS_506 136
+#define SAA7134_BOARD_AVERMEDIA_A16D 137
+#define SAA7134_BOARD_AVERMEDIA_M115 138
+#define SAA7134_BOARD_VIDEOMATE_T750 139
+#define SAA7134_BOARD_AVERMEDIA_A700_PRO 140
+#define SAA7134_BOARD_AVERMEDIA_A700_HYBRID 141
+#define SAA7134_BOARD_BEHOLD_H6 142
+#define SAA7134_BOARD_BEHOLD_M63 143
+#define SAA7134_BOARD_BEHOLD_M6_EXTRA 144
+#define SAA7134_BOARD_AVERMEDIA_M103 145
+#define SAA7134_BOARD_ASUSTeK_P7131_ANALOG 146
+#define SAA7134_BOARD_ASUSTeK_TIGER_3IN1 147
+#define SAA7134_BOARD_ENCORE_ENLTV_FM53 148
+#define SAA7134_BOARD_AVERMEDIA_M135A 149
+#define SAA7134_BOARD_REAL_ANGEL_220 150
+#define SAA7134_BOARD_ADS_INSTANT_HDTV_PCI 151
+#define SAA7134_BOARD_ASUSTeK_TIGER 152
+#define SAA7134_BOARD_KWORLD_PLUS_TV_ANALOG 153
+#define SAA7134_BOARD_AVERMEDIA_GO_007_FM_PLUS 154
+#define SAA7134_BOARD_HAUPPAUGE_HVR1150 155
+#define SAA7134_BOARD_HAUPPAUGE_HVR1120 156
+#define SAA7134_BOARD_AVERMEDIA_STUDIO_507UA 157
+#define SAA7134_BOARD_AVERMEDIA_CARDBUS_501 158
+#define SAA7134_BOARD_BEHOLD_505RDS_MK5 159
+#define SAA7134_BOARD_BEHOLD_507RDS_MK3 160
+#define SAA7134_BOARD_BEHOLD_507RDS_MK5 161
+#define SAA7134_BOARD_BEHOLD_607FM_MK5 162
+#define SAA7134_BOARD_BEHOLD_609FM_MK3 163
+#define SAA7134_BOARD_BEHOLD_609FM_MK5 164
+#define SAA7134_BOARD_BEHOLD_607RDS_MK3 165
+#define SAA7134_BOARD_BEHOLD_607RDS_MK5 166
+#define SAA7134_BOARD_BEHOLD_609RDS_MK3 167
+#define SAA7134_BOARD_BEHOLD_609RDS_MK5 168
+#define SAA7134_BOARD_VIDEOMATE_S350 169
+#define SAA7134_BOARD_AVERMEDIA_STUDIO_505 170
+#define SAA7134_BOARD_BEHOLD_X7 171
+#define SAA7134_BOARD_ROVERMEDIA_LINK_PRO_FM 172
+#define SAA7134_BOARD_ZOLID_HYBRID_PCI 173
+#define SAA7134_BOARD_ASUS_EUROPA_HYBRID 174
+#define SAA7134_BOARD_LEADTEK_WINFAST_DTV1000S 175
+#define SAA7134_BOARD_BEHOLD_505RDS_MK3 176
+#define SAA7134_BOARD_HAWELL_HW_404M7 177
+#define SAA7134_BOARD_BEHOLD_H7 178
+#define SAA7134_BOARD_BEHOLD_A7 179
+#define SAA7134_BOARD_AVERMEDIA_M733A 180
+#define SAA7134_BOARD_TECHNOTREND_BUDGET_T3000 181
+#define SAA7134_BOARD_KWORLD_PCI_SBTVD_FULLSEG 182
+#define SAA7134_BOARD_VIDEOMATE_M1F 183
+#define SAA7134_BOARD_ENCORE_ENLTV_FM3 184
+#define SAA7134_BOARD_MAGICPRO_PROHDTV_PRO2 185
+#define SAA7134_BOARD_BEHOLD_501 186
+#define SAA7134_BOARD_BEHOLD_503FM 187
+#define SAA7134_BOARD_SENSORAY811_911 188
+#define SAA7134_BOARD_KWORLD_PC150U 189
+#define SAA7134_BOARD_ASUSTeK_PS3_100 190
+#define SAA7134_BOARD_HAWELL_HW_9004V1 191
+#define SAA7134_BOARD_AVERMEDIA_A706 192
+#define SAA7134_BOARD_WIS_VOYAGER 193
+#define SAA7134_BOARD_AVERMEDIA_505 194
+#define SAA7134_BOARD_LEADTEK_WINFAST_TV2100_FM 195
+#define SAA7134_BOARD_SNAZIO_TVPVR_PRO 196
+#define SAA7134_BOARD_LEADTEK_WINFAST_HDTV200_H 197
+
+#define SAA7134_MAXBOARDS 32
+#define SAA7134_INPUT_MAX 8
+
+/* ----------------------------------------------------------- */
+/* Since we support 2 remote types, lets tell them apart */
+
+#define SAA7134_REMOTE_GPIO 1
+#define SAA7134_REMOTE_I2C 2
+
+/* ----------------------------------------------------------- */
+/* Video Output Port Register Initialization Options */
+
+#define SET_T_CODE_POLARITY_NON_INVERTED (1 << 0)
+#define SET_CLOCK_NOT_DELAYED (1 << 1)
+#define SET_CLOCK_INVERTED (1 << 2)
+#define SET_VSYNC_OFF (1 << 3)
+
+enum saa7134_input_types {
+ SAA7134_NO_INPUT = 0,
+ SAA7134_INPUT_MUTE,
+ SAA7134_INPUT_RADIO,
+ SAA7134_INPUT_TV,
+ SAA7134_INPUT_TV_MONO,
+ SAA7134_INPUT_COMPOSITE,
+ SAA7134_INPUT_COMPOSITE0,
+ SAA7134_INPUT_COMPOSITE1,
+ SAA7134_INPUT_COMPOSITE2,
+ SAA7134_INPUT_COMPOSITE3,
+ SAA7134_INPUT_COMPOSITE4,
+ SAA7134_INPUT_SVIDEO,
+ SAA7134_INPUT_SVIDEO0,
+ SAA7134_INPUT_SVIDEO1,
+ SAA7134_INPUT_COMPOSITE_OVER_SVIDEO,
+};
+
+struct saa7134_input {
+ enum saa7134_input_types type;
+ unsigned int vmux;
+ enum saa7134_audio_in amux;
+ unsigned int gpio;
+};
+
+enum saa7134_mpeg_type {
+ SAA7134_MPEG_UNUSED,
+ SAA7134_MPEG_EMPRESS,
+ SAA7134_MPEG_DVB,
+ SAA7134_MPEG_GO7007,
+};
+
+enum saa7134_mpeg_ts_type {
+ SAA7134_MPEG_TS_PARALLEL = 0,
+ SAA7134_MPEG_TS_SERIAL,
+};
+
+struct saa7134_board {
+ char *name;
+ unsigned int audio_clock;
+
+ /* input switching */
+ unsigned int gpiomask;
+ struct saa7134_input inputs[SAA7134_INPUT_MAX];
+ struct saa7134_input radio;
+ struct saa7134_input mute;
+
+ /* i2c chip info */
+ unsigned int tuner_type;
+ unsigned int radio_type;
+ unsigned char tuner_addr;
+ unsigned char radio_addr;
+ unsigned char empress_addr;
+ unsigned char rds_addr;
+
+ unsigned int tda9887_conf;
+ struct tda829x_config tda829x_conf;
+
+ /* peripheral I/O */
+ enum saa7134_video_out video_out;
+ enum saa7134_mpeg_type mpeg;
+ enum saa7134_mpeg_ts_type ts_type;
+ unsigned int vid_port_opts;
+ unsigned int ts_force_val:1;
+};
+
+#define card_has_radio(dev) (SAA7134_NO_INPUT != saa7134_boards[dev->board].radio.type)
+#define card_is_empress(dev) (SAA7134_MPEG_EMPRESS == saa7134_boards[dev->board].mpeg)
+#define card_is_dvb(dev) (SAA7134_MPEG_DVB == saa7134_boards[dev->board].mpeg)
+#define card_is_go7007(dev) (SAA7134_MPEG_GO7007 == saa7134_boards[dev->board].mpeg)
+#define card_has_mpeg(dev) (SAA7134_MPEG_UNUSED != saa7134_boards[dev->board].mpeg)
+#define card(dev) (saa7134_boards[dev->board])
+#define card_in(dev,n) (saa7134_boards[dev->board].inputs[n])
+
+#define V4L2_CID_PRIVATE_INVERT (V4L2_CID_USER_SAA7134_BASE + 0)
+#define V4L2_CID_PRIVATE_Y_ODD (V4L2_CID_USER_SAA7134_BASE + 1)
+#define V4L2_CID_PRIVATE_Y_EVEN (V4L2_CID_USER_SAA7134_BASE + 2)
+#define V4L2_CID_PRIVATE_AUTOMUTE (V4L2_CID_USER_SAA7134_BASE + 3)
+
+/* ----------------------------------------------------------- */
+/* device / file handle status */
+
+#define RESOURCE_VIDEO 2
+#define RESOURCE_VBI 4
+#define RESOURCE_EMPRESS 8
+
+#define INTERLACE_AUTO 0
+#define INTERLACE_ON 1
+#define INTERLACE_OFF 2
+
+#define BUFFER_TIMEOUT msecs_to_jiffies(500) /* 0.5 seconds */
+#define TS_BUFFER_TIMEOUT msecs_to_jiffies(1000) /* 1 second */
+
+struct saa7134_dev;
+struct saa7134_dma;
+
+/* saa7134 page table */
+struct saa7134_pgtable {
+ unsigned int size;
+ __le32 *cpu;
+ dma_addr_t dma;
+};
+
+/* tvaudio thread status */
+struct saa7134_thread {
+ struct task_struct *thread;
+ unsigned int scan1;
+ unsigned int scan2;
+ unsigned int mode;
+ unsigned int stopped;
+};
+
+/* buffer for one video/vbi/ts frame */
+struct saa7134_buf {
+ /* common v4l buffer stuff -- must be first */
+ struct vb2_v4l2_buffer vb2;
+
+ /* saa7134 specific */
+ unsigned int top_seen;
+ int (*activate)(struct saa7134_dev *dev,
+ struct saa7134_buf *buf,
+ struct saa7134_buf *next);
+
+ struct list_head entry;
+};
+
+struct saa7134_dmaqueue {
+ struct saa7134_dev *dev;
+ struct saa7134_buf *curr;
+ struct list_head queue;
+ struct timer_list timeout;
+ unsigned int need_two;
+ unsigned int seq_nr;
+ struct saa7134_pgtable pt;
+};
+
+/* dmasound dsp status */
+struct saa7134_dmasound {
+ struct mutex lock;
+ int minor_mixer;
+ int minor_dsp;
+ unsigned int users_dsp;
+
+ /* mixer */
+ enum saa7134_audio_in input;
+ unsigned int count;
+ unsigned int line1;
+ unsigned int line2;
+
+ /* dsp */
+ unsigned int afmt;
+ unsigned int rate;
+ unsigned int channels;
+ unsigned int recording_on;
+ unsigned int dma_running;
+ unsigned int blocks;
+ unsigned int blksize;
+ unsigned int bufsize;
+ struct saa7134_pgtable pt;
+ void *vaddr;
+ struct scatterlist *sglist;
+ int sglen;
+ unsigned long nr_pages;
+ unsigned int dma_blk;
+ unsigned int read_offset;
+ unsigned int read_count;
+ void * priv_data;
+ struct snd_pcm_substream *substream;
+};
+
+/* ts/mpeg status */
+struct saa7134_ts {
+ /* TS capture */
+ int nr_packets;
+ int nr_bufs;
+};
+
+/* ts/mpeg ops */
+struct saa7134_mpeg_ops {
+ enum saa7134_mpeg_type type;
+ struct list_head next;
+ int (*init)(struct saa7134_dev *dev);
+ int (*fini)(struct saa7134_dev *dev);
+ void (*signal_change)(struct saa7134_dev *dev);
+ void (*irq_ts_done)(struct saa7134_dev *dev,
+ unsigned long status);
+};
+
+enum saa7134_pads {
+ SAA7134_PAD_IF_INPUT,
+ SAA7134_PAD_VID_OUT,
+ SAA7134_NUM_PADS
+};
+
+/* global device status */
+struct saa7134_dev {
+ struct list_head devlist;
+ struct mutex lock;
+ spinlock_t slock;
+ struct v4l2_device v4l2_dev;
+ /* workstruct for loading modules */
+ struct work_struct request_module_wk;
+
+ /* insmod option/autodetected */
+ int autodetected;
+
+ /* various device info */
+ unsigned int resources;
+ struct video_device *video_dev;
+ struct video_device *radio_dev;
+ struct video_device *vbi_dev;
+ struct saa7134_dmasound dmasound;
+
+ /* infrared remote */
+ int has_remote;
+ struct saa7134_card_ir *remote;
+
+ /* pci i/o */
+ char name[32];
+ int nr;
+ struct pci_dev *pci;
+ unsigned char pci_rev,pci_lat;
+ __u32 __iomem *lmmio;
+ __u8 __iomem *bmmio;
+
+ /* config info */
+ unsigned int board;
+ unsigned int tuner_type;
+ unsigned int radio_type;
+ unsigned char tuner_addr;
+ unsigned char radio_addr;
+
+ unsigned int tda9887_conf;
+ unsigned int gpio_value;
+
+ /* i2c i/o */
+ struct i2c_adapter i2c_adap;
+ struct i2c_client i2c_client;
+ unsigned char eedata[256];
+ int has_rds;
+
+ /* video+ts+vbi capture */
+ struct saa7134_dmaqueue video_q;
+ struct vb2_queue video_vbq;
+ struct saa7134_dmaqueue vbi_q;
+ struct vb2_queue vbi_vbq;
+ enum v4l2_field field;
+ struct saa7134_format *fmt;
+ unsigned int width, height;
+ unsigned int vbi_hlen, vbi_vlen;
+ struct pm_qos_request qos_request;
+
+ /* SAA7134_MPEG_* */
+ struct saa7134_ts ts;
+ struct saa7134_dmaqueue ts_q;
+ enum v4l2_field ts_field;
+ int ts_started;
+ struct saa7134_mpeg_ops *mops;
+
+ /* SAA7134_MPEG_EMPRESS only */
+ struct video_device *empress_dev;
+ struct v4l2_subdev *empress_sd;
+ struct vb2_queue empress_vbq;
+ struct work_struct empress_workqueue;
+ int empress_started;
+ struct v4l2_ctrl_handler empress_ctrl_handler;
+
+ /* various v4l controls */
+ struct saa7134_tvnorm *tvnorm; /* video */
+ struct saa7134_tvaudio *tvaudio;
+ struct v4l2_ctrl_handler ctrl_handler;
+ unsigned int ctl_input;
+ int ctl_bright;
+ int ctl_contrast;
+ int ctl_hue;
+ int ctl_saturation;
+ int ctl_mute; /* audio */
+ int ctl_volume;
+ int ctl_invert; /* private */
+ int ctl_mirror;
+ int ctl_y_odd;
+ int ctl_y_even;
+ int ctl_automute;
+
+ /* crop */
+ struct v4l2_rect crop_bounds;
+ struct v4l2_rect crop_defrect;
+ struct v4l2_rect crop_current;
+
+ /* other global state info */
+ unsigned int automute;
+ struct saa7134_thread thread;
+ struct saa7134_input *input;
+ struct saa7134_input *hw_input;
+ unsigned int hw_mute;
+ int last_carrier;
+ int nosignal;
+ unsigned int insuspend;
+ struct v4l2_ctrl_handler radio_ctrl_handler;
+
+ /* I2C keyboard data */
+ struct IR_i2c_init_data init_data;
+
+#ifdef CONFIG_MEDIA_CONTROLLER
+ struct media_device *media_dev;
+
+ struct media_entity input_ent[SAA7134_INPUT_MAX + 1];
+ struct media_pad input_pad[SAA7134_INPUT_MAX + 1];
+
+ struct media_entity demod;
+ struct media_pad demod_pad[SAA7134_NUM_PADS];
+
+ struct media_pad video_pad, vbi_pad;
+ struct media_entity *decoder;
+#endif
+
+#if IS_ENABLED(CONFIG_VIDEO_SAA7134_DVB)
+ /* SAA7134_MPEG_DVB only */
+ struct vb2_dvb_frontends frontends;
+ int (*original_demod_sleep)(struct dvb_frontend *fe);
+ int (*original_set_voltage)(struct dvb_frontend *fe,
+ enum fe_sec_voltage voltage);
+ int (*original_set_high_voltage)(struct dvb_frontend *fe, long arg);
+#endif
+ void (*gate_ctrl)(struct saa7134_dev *dev, int open);
+};
+
+/* ----------------------------------------------------------- */
+
+#define saa_readl(reg) readl(dev->lmmio + (reg))
+#define saa_writel(reg,value) writel((value), dev->lmmio + (reg));
+#define saa_andorl(reg,mask,value) \
+ writel((readl(dev->lmmio+(reg)) & ~(mask)) |\
+ ((value) & (mask)), dev->lmmio+(reg))
+#define saa_setl(reg,bit) saa_andorl((reg),(bit),(bit))
+#define saa_clearl(reg,bit) saa_andorl((reg),(bit),0)
+
+#define saa_readb(reg) readb(dev->bmmio + (reg))
+#define saa_writeb(reg,value) writeb((value), dev->bmmio + (reg));
+#define saa_andorb(reg,mask,value) \
+ writeb((readb(dev->bmmio+(reg)) & ~(mask)) |\
+ ((value) & (mask)), dev->bmmio+(reg))
+#define saa_setb(reg,bit) saa_andorb((reg),(bit),(bit))
+#define saa_clearb(reg,bit) saa_andorb((reg),(bit),0)
+
+#define saa_wait(us) { udelay(us); }
+
+#define SAA7134_NORMS (\
+ V4L2_STD_PAL | V4L2_STD_PAL_N | \
+ V4L2_STD_PAL_Nc | V4L2_STD_SECAM | \
+ V4L2_STD_NTSC | V4L2_STD_PAL_M | \
+ V4L2_STD_PAL_60)
+
+#define GRP_EMPRESS (1)
+#define saa_call_all(dev, o, f, args...) do { \
+ if (dev->gate_ctrl) \
+ dev->gate_ctrl(dev, 1); \
+ v4l2_device_call_all(&(dev)->v4l2_dev, 0, o, f , ##args); \
+ if (dev->gate_ctrl) \
+ dev->gate_ctrl(dev, 0); \
+} while (0)
+
+#define saa_call_empress(dev, o, f, args...) ({ \
+ long _rc; \
+ if (dev->gate_ctrl) \
+ dev->gate_ctrl(dev, 1); \
+ _rc = v4l2_device_call_until_err(&(dev)->v4l2_dev, \
+ GRP_EMPRESS, o, f , ##args); \
+ if (dev->gate_ctrl) \
+ dev->gate_ctrl(dev, 0); \
+ _rc; \
+})
+
+static inline bool is_empress(struct file *file)
+{
+ struct video_device *vdev = video_devdata(file);
+ struct saa7134_dev *dev = video_get_drvdata(vdev);
+
+ return vdev->queue == &dev->empress_vbq;
+}
+
+/* ----------------------------------------------------------- */
+/* saa7134-core.c */
+
+extern struct list_head saa7134_devlist;
+extern struct mutex saa7134_devlist_lock;
+extern bool saa7134_userptr;
+
+void saa7134_track_gpio(struct saa7134_dev *dev, const char *msg);
+void saa7134_set_gpio(struct saa7134_dev *dev, int bit_no, int value);
+
+#define SAA7134_PGTABLE_SIZE 4096
+
+int saa7134_pgtable_alloc(struct pci_dev *pci, struct saa7134_pgtable *pt);
+int saa7134_pgtable_build(struct pci_dev *pci, struct saa7134_pgtable *pt,
+ struct scatterlist *list, unsigned int length,
+ unsigned int startpage);
+void saa7134_pgtable_free(struct pci_dev *pci, struct saa7134_pgtable *pt);
+
+int saa7134_buffer_count(unsigned int size, unsigned int count);
+int saa7134_buffer_startpage(struct saa7134_buf *buf);
+unsigned long saa7134_buffer_base(struct saa7134_buf *buf);
+
+int saa7134_buffer_queue(struct saa7134_dev *dev, struct saa7134_dmaqueue *q,
+ struct saa7134_buf *buf);
+void saa7134_buffer_finish(struct saa7134_dev *dev, struct saa7134_dmaqueue *q,
+ unsigned int state);
+void saa7134_buffer_next(struct saa7134_dev *dev, struct saa7134_dmaqueue *q);
+void saa7134_buffer_timeout(struct timer_list *t);
+void saa7134_stop_streaming(struct saa7134_dev *dev, struct saa7134_dmaqueue *q);
+
+int saa7134_set_dmabits(struct saa7134_dev *dev);
+
+extern int (*saa7134_dmasound_init)(struct saa7134_dev *dev);
+extern int (*saa7134_dmasound_exit)(struct saa7134_dev *dev);
+
+
+/* ----------------------------------------------------------- */
+/* saa7134-cards.c */
+
+extern struct saa7134_board saa7134_boards[];
+extern const char * const saa7134_input_name[];
+extern const unsigned int saa7134_bcount;
+extern struct pci_device_id saa7134_pci_tbl[];
+
+extern int saa7134_board_init1(struct saa7134_dev *dev);
+extern int saa7134_board_init2(struct saa7134_dev *dev);
+int saa7134_tuner_callback(void *priv, int component, int command, int arg);
+
+
+/* ----------------------------------------------------------- */
+/* saa7134-i2c.c */
+
+int saa7134_i2c_register(struct saa7134_dev *dev);
+int saa7134_i2c_unregister(struct saa7134_dev *dev);
+
+
+/* ----------------------------------------------------------- */
+/* saa7134-video.c */
+
+extern unsigned int video_debug;
+extern struct video_device saa7134_video_template;
+extern struct video_device saa7134_radio_template;
+
+void saa7134_vb2_buffer_queue(struct vb2_buffer *vb);
+int saa7134_vb2_start_streaming(struct vb2_queue *vq, unsigned int count);
+void saa7134_vb2_stop_streaming(struct vb2_queue *vq);
+
+int saa7134_s_std(struct file *file, void *priv, v4l2_std_id id);
+int saa7134_g_std(struct file *file, void *priv, v4l2_std_id *id);
+int saa7134_querystd(struct file *file, void *priv, v4l2_std_id *std);
+int saa7134_enum_input(struct file *file, void *priv, struct v4l2_input *i);
+int saa7134_g_input(struct file *file, void *priv, unsigned int *i);
+int saa7134_s_input(struct file *file, void *priv, unsigned int i);
+int saa7134_querycap(struct file *file, void *priv,
+ struct v4l2_capability *cap);
+int saa7134_g_tuner(struct file *file, void *priv,
+ struct v4l2_tuner *t);
+int saa7134_s_tuner(struct file *file, void *priv,
+ const struct v4l2_tuner *t);
+int saa7134_g_frequency(struct file *file, void *priv,
+ struct v4l2_frequency *f);
+int saa7134_s_frequency(struct file *file, void *priv,
+ const struct v4l2_frequency *f);
+
+int saa7134_videoport_init(struct saa7134_dev *dev);
+void saa7134_set_tvnorm_hw(struct saa7134_dev *dev);
+
+int saa7134_video_init1(struct saa7134_dev *dev);
+int saa7134_video_init2(struct saa7134_dev *dev);
+void saa7134_irq_video_signalchange(struct saa7134_dev *dev);
+void saa7134_irq_video_done(struct saa7134_dev *dev, unsigned long status);
+void saa7134_video_fini(struct saa7134_dev *dev);
+
+
+/* ----------------------------------------------------------- */
+/* saa7134-ts.c */
+
+#define TS_PACKET_SIZE 188 /* TS packets 188 bytes */
+
+int saa7134_ts_buffer_init(struct vb2_buffer *vb2);
+int saa7134_ts_buffer_prepare(struct vb2_buffer *vb2);
+int saa7134_ts_queue_setup(struct vb2_queue *q,
+ unsigned int *nbuffers, unsigned int *nplanes,
+ unsigned int sizes[], struct device *alloc_devs[]);
+int saa7134_ts_start_streaming(struct vb2_queue *vq, unsigned int count);
+void saa7134_ts_stop_streaming(struct vb2_queue *vq);
+
+extern struct vb2_ops saa7134_ts_qops;
+
+int saa7134_ts_init1(struct saa7134_dev *dev);
+int saa7134_ts_fini(struct saa7134_dev *dev);
+void saa7134_irq_ts_done(struct saa7134_dev *dev, unsigned long status);
+
+int saa7134_ts_register(struct saa7134_mpeg_ops *ops);
+void saa7134_ts_unregister(struct saa7134_mpeg_ops *ops);
+
+int saa7134_ts_init_hw(struct saa7134_dev *dev);
+
+int saa7134_ts_start(struct saa7134_dev *dev);
+int saa7134_ts_stop(struct saa7134_dev *dev);
+
+/* ----------------------------------------------------------- */
+/* saa7134-vbi.c */
+
+extern const struct vb2_ops saa7134_vbi_qops;
+
+int saa7134_vbi_init1(struct saa7134_dev *dev);
+int saa7134_vbi_fini(struct saa7134_dev *dev);
+void saa7134_irq_vbi_done(struct saa7134_dev *dev, unsigned long status);
+
+
+/* ----------------------------------------------------------- */
+/* saa7134-tvaudio.c */
+
+int saa7134_tvaudio_rx2mode(u32 rx);
+
+void saa7134_tvaudio_setmute(struct saa7134_dev *dev);
+void saa7134_tvaudio_setinput(struct saa7134_dev *dev,
+ struct saa7134_input *in);
+void saa7134_tvaudio_setvolume(struct saa7134_dev *dev, int level);
+int saa7134_tvaudio_getstereo(struct saa7134_dev *dev);
+
+void saa7134_tvaudio_init(struct saa7134_dev *dev);
+int saa7134_tvaudio_init2(struct saa7134_dev *dev);
+int saa7134_tvaudio_fini(struct saa7134_dev *dev);
+int saa7134_tvaudio_do_scan(struct saa7134_dev *dev);
+int saa7134_tvaudio_close(struct saa7134_dev *dev);
+
+int saa_dsp_writel(struct saa7134_dev *dev, int reg, u32 value);
+
+void saa7134_enable_i2s(struct saa7134_dev *dev);
+
+/* ----------------------------------------------------------- */
+/* saa7134-oss.c */
+
+int saa7134_oss_init1(struct saa7134_dev *dev);
+int saa7134_oss_fini(struct saa7134_dev *dev);
+void saa7134_irq_oss_done(struct saa7134_dev *dev, unsigned long status);
+
+/* ----------------------------------------------------------- */
+/* saa7134-input.c */
+
+#if defined(CONFIG_VIDEO_SAA7134_RC)
+int saa7134_input_init1(struct saa7134_dev *dev);
+void saa7134_input_fini(struct saa7134_dev *dev);
+void saa7134_input_irq(struct saa7134_dev *dev);
+void saa7134_probe_i2c_ir(struct saa7134_dev *dev);
+int saa7134_ir_open(struct rc_dev *dev);
+void saa7134_ir_close(struct rc_dev *dev);
+#else
+#define saa7134_input_init1(dev) ((void)0)
+#define saa7134_input_fini(dev) ((void)0)
+#define saa7134_input_irq(dev) ((void)0)
+#define saa7134_probe_i2c_ir(dev) ((void)0)
+#define saa7134_ir_open(dev) ((void)0)
+#define saa7134_ir_close(dev) ((void)0)
+#endif