aboutsummaryrefslogtreecommitdiff
path: root/drivers/media/usb/tm6000
diff options
context:
space:
mode:
authorMauro Carvalho Chehab <mchehab@redhat.com>2012-08-14 00:13:22 -0300
committerMauro Carvalho Chehab <mchehab@redhat.com>2012-08-15 16:25:07 -0300
commit0c0d06cac63ee327ceaab4b5ffe2206574ab86bd (patch)
treee759f0dc3185d97f2a0c6b5cd5e32ea6faa74d40 /drivers/media/usb/tm6000
parent84cfe9e79bd5ac11c963f4841158454fefa872f6 (diff)
[media] rename most media/video usb drivers to media/usb
Rename all USB drivers with their own directory under drivers/media/video into drivers/media/usb and update the building system. Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
Diffstat (limited to 'drivers/media/usb/tm6000')
-rw-r--r--drivers/media/usb/tm6000/Kconfig33
-rw-r--r--drivers/media/usb/tm6000/Makefile15
-rw-r--r--drivers/media/usb/tm6000/tm6000-alsa.c528
-rw-r--r--drivers/media/usb/tm6000/tm6000-cards.c1413
-rw-r--r--drivers/media/usb/tm6000/tm6000-core.c935
-rw-r--r--drivers/media/usb/tm6000/tm6000-dvb.c467
-rw-r--r--drivers/media/usb/tm6000/tm6000-i2c.c334
-rw-r--r--drivers/media/usb/tm6000/tm6000-input.c498
-rw-r--r--drivers/media/usb/tm6000/tm6000-regs.h600
-rw-r--r--drivers/media/usb/tm6000/tm6000-stds.c638
-rw-r--r--drivers/media/usb/tm6000/tm6000-usb-isoc.h50
-rw-r--r--drivers/media/usb/tm6000/tm6000-video.c1852
-rw-r--r--drivers/media/usb/tm6000/tm6000.h399
13 files changed, 7762 insertions, 0 deletions
diff --git a/drivers/media/usb/tm6000/Kconfig b/drivers/media/usb/tm6000/Kconfig
new file mode 100644
index 00000000000..a43b77abd93
--- /dev/null
+++ b/drivers/media/usb/tm6000/Kconfig
@@ -0,0 +1,33 @@
+config VIDEO_TM6000
+ tristate "TV Master TM5600/6000/6010 driver"
+ depends on VIDEO_DEV && I2C && INPUT && RC_CORE && USB
+ select VIDEO_TUNER
+ select MEDIA_TUNER_XC2028
+ select MEDIA_TUNER_XC5000
+ select VIDEOBUF_VMALLOC
+ help
+ Support for TM5600/TM6000/TM6010 USB Device
+
+ Since these cards have no MPEG decoder onboard, they transmit
+ only compressed MPEG data over the usb bus, so you need
+ an external software decoder to watch TV on your computer.
+
+ Say Y if you own such a device and want to use it.
+
+config VIDEO_TM6000_ALSA
+ tristate "TV Master TM5600/6000/6010 audio support"
+ depends on VIDEO_TM6000 && SND
+ select SND_PCM
+ ---help---
+ This is a video4linux driver for direct (DMA) audio for
+ TM5600/TM6000/TM6010 USB Devices.
+
+ To compile this driver as a module, choose M here: the
+ module will be called tm6000-alsa.
+
+config VIDEO_TM6000_DVB
+ tristate "DVB Support for tm6000 based TV cards"
+ depends on VIDEO_TM6000 && DVB_CORE && USB
+ select DVB_ZL10353
+ ---help---
+ This adds support for DVB cards based on the tm5600/tm6000 chip.
diff --git a/drivers/media/usb/tm6000/Makefile b/drivers/media/usb/tm6000/Makefile
new file mode 100644
index 00000000000..1feb8c9c816
--- /dev/null
+++ b/drivers/media/usb/tm6000/Makefile
@@ -0,0 +1,15 @@
+tm6000-y := tm6000-cards.o \
+ tm6000-core.o \
+ tm6000-i2c.o \
+ tm6000-video.o \
+ tm6000-stds.o \
+ tm6000-input.o
+
+obj-$(CONFIG_VIDEO_TM6000) += tm6000.o
+obj-$(CONFIG_VIDEO_TM6000_ALSA) += tm6000-alsa.o
+obj-$(CONFIG_VIDEO_TM6000_DVB) += tm6000-dvb.o
+
+ccflags-y := -Idrivers/media/video
+ccflags-y += -Idrivers/media/tuners
+ccflags-y += -Idrivers/media/dvb-core
+ccflags-y += -Idrivers/media/dvb-frontends
diff --git a/drivers/media/usb/tm6000/tm6000-alsa.c b/drivers/media/usb/tm6000/tm6000-alsa.c
new file mode 100644
index 00000000000..bd07ec70795
--- /dev/null
+++ b/drivers/media/usb/tm6000/tm6000-alsa.c
@@ -0,0 +1,528 @@
+/*
+ *
+ * Support for audio capture for tm5600/6000/6010
+ * (c) 2007-2008 Mauro Carvalho Chehab <mchehab@redhat.com>
+ *
+ * Based on cx88-alsa.c
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/device.h>
+#include <linux/interrupt.h>
+#include <linux/usb.h>
+#include <linux/slab.h>
+#include <linux/vmalloc.h>
+
+#include <linux/delay.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/control.h>
+#include <sound/initval.h>
+
+
+#include "tm6000.h"
+#include "tm6000-regs.h"
+
+#undef dprintk
+
+#define dprintk(level, fmt, arg...) do { \
+ if (debug >= level) \
+ printk(KERN_INFO "%s/1: " fmt, chip->core->name , ## arg); \
+ } while (0)
+
+/****************************************************************************
+ Module global static vars
+ ****************************************************************************/
+
+static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-MAX */
+
+static bool enable[SNDRV_CARDS] = {1, [1 ... (SNDRV_CARDS - 1)] = 1};
+
+module_param_array(enable, bool, NULL, 0444);
+MODULE_PARM_DESC(enable, "Enable tm6000x soundcard. default enabled.");
+
+module_param_array(index, int, NULL, 0444);
+MODULE_PARM_DESC(index, "Index value for tm6000x capture interface(s).");
+
+
+/****************************************************************************
+ Module macros
+ ****************************************************************************/
+
+MODULE_DESCRIPTION("ALSA driver module for tm5600/tm6000/tm6010 based TV cards");
+MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>");
+MODULE_LICENSE("GPL");
+MODULE_SUPPORTED_DEVICE("{{Trident,tm5600},"
+ "{{Trident,tm6000},"
+ "{{Trident,tm6010}");
+static unsigned int debug;
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "enable debug messages");
+
+/****************************************************************************
+ Module specific funtions
+ ****************************************************************************/
+
+/*
+ * BOARD Specific: Sets audio DMA
+ */
+
+static int _tm6000_start_audio_dma(struct snd_tm6000_card *chip)
+{
+ struct tm6000_core *core = chip->core;
+
+ dprintk(1, "Starting audio DMA\n");
+
+ /* Enables audio */
+ tm6000_set_reg_mask(core, TM6010_REQ07_RCC_ACTIVE_IF, 0x40, 0x40);
+
+ tm6000_set_audio_bitrate(core, 48000);
+
+ return 0;
+}
+
+/*
+ * BOARD Specific: Resets audio DMA
+ */
+static int _tm6000_stop_audio_dma(struct snd_tm6000_card *chip)
+{
+ struct tm6000_core *core = chip->core;
+
+ dprintk(1, "Stopping audio DMA\n");
+
+ /* Disables audio */
+ tm6000_set_reg_mask(core, TM6010_REQ07_RCC_ACTIVE_IF, 0x00, 0x40);
+
+ return 0;
+}
+
+static void dsp_buffer_free(struct snd_pcm_substream *substream)
+{
+ struct snd_tm6000_card *chip = snd_pcm_substream_chip(substream);
+
+ dprintk(2, "Freeing buffer\n");
+
+ vfree(substream->runtime->dma_area);
+ substream->runtime->dma_area = NULL;
+ substream->runtime->dma_bytes = 0;
+}
+
+static int dsp_buffer_alloc(struct snd_pcm_substream *substream, int size)
+{
+ struct snd_tm6000_card *chip = snd_pcm_substream_chip(substream);
+
+ dprintk(2, "Allocating buffer\n");
+
+ if (substream->runtime->dma_area) {
+ if (substream->runtime->dma_bytes > size)
+ return 0;
+
+ dsp_buffer_free(substream);
+ }
+
+ substream->runtime->dma_area = vmalloc(size);
+ if (!substream->runtime->dma_area)
+ return -ENOMEM;
+
+ substream->runtime->dma_bytes = size;
+
+ return 0;
+}
+
+
+/****************************************************************************
+ ALSA PCM Interface
+ ****************************************************************************/
+
+/*
+ * Digital hardware definition
+ */
+#define DEFAULT_FIFO_SIZE 4096
+
+static struct snd_pcm_hardware snd_tm6000_digital_hw = {
+ .info = SNDRV_PCM_INFO_BATCH |
+ SNDRV_PCM_INFO_MMAP |
+ SNDRV_PCM_INFO_INTERLEAVED |
+ SNDRV_PCM_INFO_BLOCK_TRANSFER |
+ SNDRV_PCM_INFO_MMAP_VALID,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,
+
+ .rates = SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_KNOT,
+ .rate_min = 48000,
+ .rate_max = 48000,
+ .channels_min = 2,
+ .channels_max = 2,
+ .period_bytes_min = 64,
+ .period_bytes_max = 12544,
+ .periods_min = 2,
+ .periods_max = 98,
+ .buffer_bytes_max = 62720 * 8,
+};
+
+/*
+ * audio pcm capture open callback
+ */
+static int snd_tm6000_pcm_open(struct snd_pcm_substream *substream)
+{
+ struct snd_tm6000_card *chip = snd_pcm_substream_chip(substream);
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ int err;
+
+ err = snd_pcm_hw_constraint_pow2(runtime, 0,
+ SNDRV_PCM_HW_PARAM_PERIODS);
+ if (err < 0)
+ goto _error;
+
+ chip->substream = substream;
+
+ runtime->hw = snd_tm6000_digital_hw;
+ snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS);
+
+ return 0;
+_error:
+ dprintk(1, "Error opening PCM!\n");
+ return err;
+}
+
+/*
+ * audio close callback
+ */
+static int snd_tm6000_close(struct snd_pcm_substream *substream)
+{
+ struct snd_tm6000_card *chip = snd_pcm_substream_chip(substream);
+ struct tm6000_core *core = chip->core;
+
+ if (atomic_read(&core->stream_started) > 0) {
+ atomic_set(&core->stream_started, 0);
+ schedule_work(&core->wq_trigger);
+ }
+
+ return 0;
+}
+
+static int tm6000_fillbuf(struct tm6000_core *core, char *buf, int size)
+{
+ struct snd_tm6000_card *chip = core->adev;
+ struct snd_pcm_substream *substream = chip->substream;
+ struct snd_pcm_runtime *runtime;
+ int period_elapsed = 0;
+ unsigned int stride, buf_pos;
+ int length;
+
+ if (atomic_read(&core->stream_started) == 0)
+ return 0;
+
+ if (!size || !substream) {
+ dprintk(1, "substream was NULL\n");
+ return -EINVAL;
+ }
+
+ runtime = substream->runtime;
+ if (!runtime || !runtime->dma_area) {
+ dprintk(1, "runtime was NULL\n");
+ return -EINVAL;
+ }
+
+ buf_pos = chip->buf_pos;
+ stride = runtime->frame_bits >> 3;
+
+ if (stride == 0) {
+ dprintk(1, "stride is zero\n");
+ return -EINVAL;
+ }
+
+ length = size / stride;
+ if (length == 0) {
+ dprintk(1, "%s: length was zero\n", __func__);
+ return -EINVAL;
+ }
+
+ dprintk(1, "Copying %d bytes at %p[%d] - buf size=%d x %d\n", size,
+ runtime->dma_area, buf_pos,
+ (unsigned int)runtime->buffer_size, stride);
+
+ if (buf_pos + length >= runtime->buffer_size) {
+ unsigned int cnt = runtime->buffer_size - buf_pos;
+ memcpy(runtime->dma_area + buf_pos * stride, buf, cnt * stride);
+ memcpy(runtime->dma_area, buf + cnt * stride,
+ length * stride - cnt * stride);
+ } else
+ memcpy(runtime->dma_area + buf_pos * stride, buf,
+ length * stride);
+
+ snd_pcm_stream_lock(substream);
+
+ chip->buf_pos += length;
+ if (chip->buf_pos >= runtime->buffer_size)
+ chip->buf_pos -= runtime->buffer_size;
+
+ chip->period_pos += length;
+ if (chip->period_pos >= runtime->period_size) {
+ chip->period_pos -= runtime->period_size;
+ period_elapsed = 1;
+ }
+
+ snd_pcm_stream_unlock(substream);
+
+ if (period_elapsed)
+ snd_pcm_period_elapsed(substream);
+
+ return 0;
+}
+
+/*
+ * hw_params callback
+ */
+static int snd_tm6000_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *hw_params)
+{
+ int size, rc;
+
+ size = params_period_bytes(hw_params) * params_periods(hw_params);
+
+ rc = dsp_buffer_alloc(substream, size);
+ if (rc < 0)
+ return rc;
+
+ return 0;
+}
+
+/*
+ * hw free callback
+ */
+static int snd_tm6000_hw_free(struct snd_pcm_substream *substream)
+{
+ struct snd_tm6000_card *chip = snd_pcm_substream_chip(substream);
+ struct tm6000_core *core = chip->core;
+
+ if (atomic_read(&core->stream_started) > 0) {
+ atomic_set(&core->stream_started, 0);
+ schedule_work(&core->wq_trigger);
+ }
+
+ dsp_buffer_free(substream);
+ return 0;
+}
+
+/*
+ * prepare callback
+ */
+static int snd_tm6000_prepare(struct snd_pcm_substream *substream)
+{
+ struct snd_tm6000_card *chip = snd_pcm_substream_chip(substream);
+
+ chip->buf_pos = 0;
+ chip->period_pos = 0;
+
+ return 0;
+}
+
+
+/*
+ * trigger callback
+ */
+static void audio_trigger(struct work_struct *work)
+{
+ struct tm6000_core *core = container_of(work, struct tm6000_core,
+ wq_trigger);
+ struct snd_tm6000_card *chip = core->adev;
+
+ if (atomic_read(&core->stream_started)) {
+ dprintk(1, "starting capture");
+ _tm6000_start_audio_dma(chip);
+ } else {
+ dprintk(1, "stopping capture");
+ _tm6000_stop_audio_dma(chip);
+ }
+}
+
+static int snd_tm6000_card_trigger(struct snd_pcm_substream *substream, int cmd)
+{
+ struct snd_tm6000_card *chip = snd_pcm_substream_chip(substream);
+ struct tm6000_core *core = chip->core;
+ int err = 0;
+
+ switch (cmd) {
+ case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: /* fall through */
+ case SNDRV_PCM_TRIGGER_RESUME: /* fall through */
+ case SNDRV_PCM_TRIGGER_START:
+ atomic_set(&core->stream_started, 1);
+ break;
+ case SNDRV_PCM_TRIGGER_PAUSE_PUSH: /* fall through */
+ case SNDRV_PCM_TRIGGER_SUSPEND: /* fall through */
+ case SNDRV_PCM_TRIGGER_STOP:
+ atomic_set(&core->stream_started, 0);
+ break;
+ default:
+ err = -EINVAL;
+ break;
+ }
+ schedule_work(&core->wq_trigger);
+
+ return err;
+}
+/*
+ * pointer callback
+ */
+static snd_pcm_uframes_t snd_tm6000_pointer(struct snd_pcm_substream *substream)
+{
+ struct snd_tm6000_card *chip = snd_pcm_substream_chip(substream);
+
+ return chip->buf_pos;
+}
+
+static struct page *snd_pcm_get_vmalloc_page(struct snd_pcm_substream *subs,
+ unsigned long offset)
+{
+ void *pageptr = subs->runtime->dma_area + offset;
+
+ return vmalloc_to_page(pageptr);
+}
+
+/*
+ * operators
+ */
+static struct snd_pcm_ops snd_tm6000_pcm_ops = {
+ .open = snd_tm6000_pcm_open,
+ .close = snd_tm6000_close,
+ .ioctl = snd_pcm_lib_ioctl,
+ .hw_params = snd_tm6000_hw_params,
+ .hw_free = snd_tm6000_hw_free,
+ .prepare = snd_tm6000_prepare,
+ .trigger = snd_tm6000_card_trigger,
+ .pointer = snd_tm6000_pointer,
+ .page = snd_pcm_get_vmalloc_page,
+};
+
+/*
+ * create a PCM device
+ */
+
+/* FIXME: Control interface - How to control volume/mute? */
+
+/****************************************************************************
+ Basic Flow for Sound Devices
+ ****************************************************************************/
+
+/*
+ * Alsa Constructor - Component probe
+ */
+static int tm6000_audio_init(struct tm6000_core *dev)
+{
+ struct snd_card *card;
+ struct snd_tm6000_card *chip;
+ int rc;
+ static int devnr;
+ char component[14];
+ struct snd_pcm *pcm;
+
+ if (!dev)
+ return 0;
+
+ if (devnr >= SNDRV_CARDS)
+ return -ENODEV;
+
+ if (!enable[devnr])
+ return -ENOENT;
+
+ rc = snd_card_create(index[devnr], "tm6000", THIS_MODULE, 0, &card);
+ if (rc < 0) {
+ snd_printk(KERN_ERR "cannot create card instance %d\n", devnr);
+ return rc;
+ }
+ strcpy(card->driver, "tm6000-alsa");
+ strcpy(card->shortname, "TM5600/60x0");
+ sprintf(card->longname, "TM5600/60x0 Audio at bus %d device %d",
+ dev->udev->bus->busnum, dev->udev->devnum);
+
+ sprintf(component, "USB%04x:%04x",
+ le16_to_cpu(dev->udev->descriptor.idVendor),
+ le16_to_cpu(dev->udev->descriptor.idProduct));
+ snd_component_add(card, component);
+ snd_card_set_dev(card, &dev->udev->dev);
+
+ chip = kzalloc(sizeof(struct snd_tm6000_card), GFP_KERNEL);
+ if (!chip) {
+ rc = -ENOMEM;
+ goto error;
+ }
+
+ chip->core = dev;
+ chip->card = card;
+ dev->adev = chip;
+ spin_lock_init(&chip->reg_lock);
+
+ rc = snd_pcm_new(card, "TM6000 Audio", 0, 0, 1, &pcm);
+ if (rc < 0)
+ goto error_chip;
+
+ pcm->info_flags = 0;
+ pcm->private_data = chip;
+ strcpy(pcm->name, "Trident TM5600/60x0");
+
+ snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_tm6000_pcm_ops);
+
+ INIT_WORK(&dev->wq_trigger, audio_trigger);
+ rc = snd_card_register(card);
+ if (rc < 0)
+ goto error_chip;
+
+ dprintk(1, "Registered audio driver for %s\n", card->longname);
+
+ return 0;
+
+error_chip:
+ kfree(chip);
+ dev->adev = NULL;
+error:
+ snd_card_free(card);
+ return rc;
+}
+
+static int tm6000_audio_fini(struct tm6000_core *dev)
+{
+ struct snd_tm6000_card *chip = dev->adev;
+
+ if (!dev)
+ return 0;
+
+ if (!chip)
+ return 0;
+
+ if (!chip->card)
+ return 0;
+
+ snd_card_free(chip->card);
+ chip->card = NULL;
+ kfree(chip);
+ dev->adev = NULL;
+
+ return 0;
+}
+
+static struct tm6000_ops audio_ops = {
+ .type = TM6000_AUDIO,
+ .name = "TM6000 Audio Extension",
+ .init = tm6000_audio_init,
+ .fini = tm6000_audio_fini,
+ .fillbuf = tm6000_fillbuf,
+};
+
+static int __init tm6000_alsa_register(void)
+{
+ return tm6000_register_extension(&audio_ops);
+}
+
+static void __exit tm6000_alsa_unregister(void)
+{
+ tm6000_unregister_extension(&audio_ops);
+}
+
+module_init(tm6000_alsa_register);
+module_exit(tm6000_alsa_unregister);
diff --git a/drivers/media/usb/tm6000/tm6000-cards.c b/drivers/media/usb/tm6000/tm6000-cards.c
new file mode 100644
index 00000000000..034659b1317
--- /dev/null
+++ b/drivers/media/usb/tm6000/tm6000-cards.c
@@ -0,0 +1,1413 @@
+/*
+ * tm6000-cards.c - driver for TM5600/TM6000/TM6010 USB video capture devices
+ *
+ * Copyright (C) 2006-2007 Mauro Carvalho Chehab <mchehab@infradead.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation version 2
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/delay.h>
+#include <linux/i2c.h>
+#include <linux/usb.h>
+#include <linux/slab.h>
+#include <media/v4l2-common.h>
+#include <media/tuner.h>
+#include <media/tvaudio.h>
+#include <media/i2c-addr.h>
+#include <media/rc-map.h>
+
+#include "tm6000.h"
+#include "tm6000-regs.h"
+#include "tuner-xc2028.h"
+#include "xc5000.h"
+
+#define TM6000_BOARD_UNKNOWN 0
+#define TM5600_BOARD_GENERIC 1
+#define TM6000_BOARD_GENERIC 2
+#define TM6010_BOARD_GENERIC 3
+#define TM5600_BOARD_10MOONS_UT821 4
+#define TM5600_BOARD_10MOONS_UT330 5
+#define TM6000_BOARD_ADSTECH_DUAL_TV 6
+#define TM6000_BOARD_FREECOM_AND_SIMILAR 7
+#define TM6000_BOARD_ADSTECH_MINI_DUAL_TV 8
+#define TM6010_BOARD_HAUPPAUGE_900H 9
+#define TM6010_BOARD_BEHOLD_WANDER 10
+#define TM6010_BOARD_BEHOLD_VOYAGER 11
+#define TM6010_BOARD_TERRATEC_CINERGY_HYBRID_XE 12
+#define TM6010_BOARD_TWINHAN_TU501 13
+#define TM6010_BOARD_BEHOLD_WANDER_LITE 14
+#define TM6010_BOARD_BEHOLD_VOYAGER_LITE 15
+#define TM5600_BOARD_TERRATEC_GRABSTER 16
+
+#define is_generic(model) ((model == TM6000_BOARD_UNKNOWN) || \
+ (model == TM5600_BOARD_GENERIC) || \
+ (model == TM6000_BOARD_GENERIC) || \
+ (model == TM6010_BOARD_GENERIC))
+
+#define TM6000_MAXBOARDS 16
+static unsigned int card[] = {[0 ... (TM6000_MAXBOARDS - 1)] = UNSET };
+
+module_param_array(card, int, NULL, 0444);
+
+static unsigned long tm6000_devused;
+
+
+struct tm6000_board {
+ char *name;
+ char eename[16]; /* EEPROM name */
+ unsigned eename_size; /* size of EEPROM name */
+ unsigned eename_pos; /* Position where it appears at ROM */
+
+ struct tm6000_capabilities caps;
+
+ enum tm6000_devtype type; /* variant of the chipset */
+ int tuner_type; /* type of the tuner */
+ int tuner_addr; /* tuner address */
+ int demod_addr; /* demodulator address */
+
+ struct tm6000_gpio gpio;
+
+ struct tm6000_input vinput[3];
+ struct tm6000_input rinput;
+
+ char *ir_codes;
+};
+
+static struct tm6000_board tm6000_boards[] = {
+ [TM6000_BOARD_UNKNOWN] = {
+ .name = "Unknown tm6000 video grabber",
+ .caps = {
+ .has_tuner = 1,
+ .has_eeprom = 1,
+ },
+ .gpio = {
+ .tuner_reset = TM6000_GPIO_1,
+ },
+ .vinput = { {
+ .type = TM6000_INPUT_TV,
+ .vmux = TM6000_VMUX_VIDEO_B,
+ .amux = TM6000_AMUX_ADC1,
+ }, {
+ .type = TM6000_INPUT_COMPOSITE1,
+ .vmux = TM6000_VMUX_VIDEO_A,
+ .amux = TM6000_AMUX_ADC2,
+ }, {
+ .type = TM6000_INPUT_SVIDEO,
+ .vmux = TM6000_VMUX_VIDEO_AB,
+ .amux = TM6000_AMUX_ADC2,
+ },
+ },
+ },
+ [TM5600_BOARD_GENERIC] = {
+ .name = "Generic tm5600 board",
+ .type = TM5600,
+ .tuner_type = TUNER_XC2028,
+ .tuner_addr = 0xc2 >> 1,
+ .caps = {
+ .has_tuner = 1,
+ .has_eeprom = 1,
+ },
+ .gpio = {
+ .tuner_reset = TM6000_GPIO_1,
+ },
+ .vinput = { {
+ .type = TM6000_INPUT_TV,
+ .vmux = TM6000_VMUX_VIDEO_B,
+ .amux = TM6000_AMUX_ADC1,
+ }, {
+ .type = TM6000_INPUT_COMPOSITE1,
+ .vmux = TM6000_VMUX_VIDEO_A,
+ .amux = TM6000_AMUX_ADC2,
+ }, {
+ .type = TM6000_INPUT_SVIDEO,
+ .vmux = TM6000_VMUX_VIDEO_AB,
+ .amux = TM6000_AMUX_ADC2,
+ },
+ },
+ },
+ [TM6000_BOARD_GENERIC] = {
+ .name = "Generic tm6000 board",
+ .tuner_type = TUNER_XC2028,
+ .tuner_addr = 0xc2 >> 1,
+ .caps = {
+ .has_tuner = 1,
+ .has_eeprom = 1,
+ },
+ .gpio = {
+ .tuner_reset = TM6000_GPIO_1,
+ },
+ .vinput = { {
+ .type = TM6000_INPUT_TV,
+ .vmux = TM6000_VMUX_VIDEO_B,
+ .amux = TM6000_AMUX_ADC1,
+ }, {
+ .type = TM6000_INPUT_COMPOSITE1,
+ .vmux = TM6000_VMUX_VIDEO_A,
+ .amux = TM6000_AMUX_ADC2,
+ }, {
+ .type = TM6000_INPUT_SVIDEO,
+ .vmux = TM6000_VMUX_VIDEO_AB,
+ .amux = TM6000_AMUX_ADC2,
+ },
+ },
+ },
+ [TM6010_BOARD_GENERIC] = {
+ .name = "Generic tm6010 board",
+ .type = TM6010,
+ .tuner_type = TUNER_XC2028,
+ .tuner_addr = 0xc2 >> 1,
+ .demod_addr = 0x1e >> 1,
+ .caps = {
+ .has_tuner = 1,
+ .has_dvb = 1,
+ .has_zl10353 = 1,
+ .has_eeprom = 1,
+ .has_remote = 1,
+ },
+ .gpio = {
+ .tuner_reset = TM6010_GPIO_2,
+ .tuner_on = TM6010_GPIO_3,
+ .demod_reset = TM6010_GPIO_1,
+ .demod_on = TM6010_GPIO_4,
+ .power_led = TM6010_GPIO_7,
+ .dvb_led = TM6010_GPIO_5,
+ .ir = TM6010_GPIO_0,
+ },
+ .vinput = { {
+ .type = TM6000_INPUT_TV,
+ .vmux = TM6000_VMUX_VIDEO_B,
+ .amux = TM6000_AMUX_SIF1,
+ }, {
+ .type = TM6000_INPUT_COMPOSITE1,
+ .vmux = TM6000_VMUX_VIDEO_A,
+ .amux = TM6000_AMUX_ADC2,
+ }, {
+ .type = TM6000_INPUT_SVIDEO,
+ .vmux = TM6000_VMUX_VIDEO_AB,
+ .amux = TM6000_AMUX_ADC2,
+ },
+ },
+ },
+ [TM5600_BOARD_10MOONS_UT821] = {
+ .name = "10Moons UT 821",
+ .tuner_type = TUNER_XC2028,
+ .eename = { '1', '0', 'M', 'O', 'O', 'N', 'S', '5', '6', '0', '0', 0xff, 0x45, 0x5b},
+ .eename_size = 14,
+ .eename_pos = 0x14,
+ .type = TM5600,
+ .tuner_addr = 0xc2 >> 1,
+ .caps = {
+ .has_tuner = 1,
+ .has_eeprom = 1,
+ },
+ .gpio = {
+ .tuner_reset = TM6000_GPIO_1,
+ },
+ .vinput = { {
+ .type = TM6000_INPUT_TV,
+ .vmux = TM6000_VMUX_VIDEO_B,
+ .amux = TM6000_AMUX_ADC1,
+ }, {
+ .type = TM6000_INPUT_COMPOSITE1,
+ .vmux = TM6000_VMUX_VIDEO_A,
+ .amux = TM6000_AMUX_ADC2,
+ }, {
+ .type = TM6000_INPUT_SVIDEO,
+ .vmux = TM6000_VMUX_VIDEO_AB,
+ .amux = TM6000_AMUX_ADC2,
+ },
+ },
+ },
+ [TM5600_BOARD_10MOONS_UT330] = {
+ .name = "10Moons UT 330",
+ .tuner_type = TUNER_PHILIPS_FQ1216AME_MK4,
+ .tuner_addr = 0xc8 >> 1,
+ .caps = {
+ .has_tuner = 1,
+ .has_dvb = 0,
+ .has_zl10353 = 0,
+ .has_eeprom = 1,
+ },
+ .vinput = { {
+ .type = TM6000_INPUT_TV,
+ .vmux = TM6000_VMUX_VIDEO_B,
+ .amux = TM6000_AMUX_ADC1,
+ }, {
+ .type = TM6000_INPUT_COMPOSITE1,
+ .vmux = TM6000_VMUX_VIDEO_A,
+ .amux = TM6000_AMUX_ADC2,
+ }, {
+ .type = TM6000_INPUT_SVIDEO,
+ .vmux = TM6000_VMUX_VIDEO_AB,
+ .amux = TM6000_AMUX_ADC2,
+ },
+ },
+ },
+ [TM6000_BOARD_ADSTECH_DUAL_TV] = {
+ .name = "ADSTECH Dual TV USB",
+ .tuner_type = TUNER_XC2028,
+ .tuner_addr = 0xc8 >> 1,
+ .caps = {
+ .has_tuner = 1,
+ .has_tda9874 = 1,
+ .has_dvb = 1,
+ .has_zl10353 = 1,
+ .has_eeprom = 1,
+ },
+ .vinput = { {
+ .type = TM6000_INPUT_TV,
+ .vmux = TM6000_VMUX_VIDEO_B,
+ .amux = TM6000_AMUX_ADC1,
+ }, {
+ .type = TM6000_INPUT_COMPOSITE1,
+ .vmux = TM6000_VMUX_VIDEO_A,
+ .amux = TM6000_AMUX_ADC2,
+ }, {
+ .type = TM6000_INPUT_SVIDEO,
+ .vmux = TM6000_VMUX_VIDEO_AB,
+ .amux = TM6000_AMUX_ADC2,
+ },
+ },
+ },
+ [TM6000_BOARD_FREECOM_AND_SIMILAR] = {
+ .name = "Freecom Hybrid Stick / Moka DVB-T Receiver Dual",
+ .tuner_type = TUNER_XC2028, /* has a XC3028 */
+ .tuner_addr = 0xc2 >> 1,
+ .demod_addr = 0x1e >> 1,
+ .caps = {
+ .has_tuner = 1,
+ .has_dvb = 1,
+ .has_zl10353 = 1,
+ .has_eeprom = 0,
+ .has_remote = 1,
+ },
+ .gpio = {
+ .tuner_reset = TM6000_GPIO_4,
+ },
+ .vinput = { {
+ .type = TM6000_INPUT_TV,
+ .vmux = TM6000_VMUX_VIDEO_B,
+ .amux = TM6000_AMUX_ADC1,
+ }, {
+ .type = TM6000_INPUT_COMPOSITE1,
+ .vmux = TM6000_VMUX_VIDEO_A,
+ .amux = TM6000_AMUX_ADC2,
+ }, {
+ .type = TM6000_INPUT_SVIDEO,
+ .vmux = TM6000_VMUX_VIDEO_AB,
+ .amux = TM6000_AMUX_ADC2,
+ },
+ },
+ },
+ [TM6000_BOARD_ADSTECH_MINI_DUAL_TV] = {
+ .name = "ADSTECH Mini Dual TV USB",
+ .tuner_type = TUNER_XC2028, /* has a XC3028 */
+ .tuner_addr = 0xc8 >> 1,
+ .demod_addr = 0x1e >> 1,
+ .caps = {
+ .has_tuner = 1,
+ .has_dvb = 1,
+ .has_zl10353 = 1,
+ .has_eeprom = 0,
+ },
+ .gpio = {
+ .tuner_reset = TM6000_GPIO_4,
+ },
+ .vinput = { {
+ .type = TM6000_INPUT_TV,
+ .vmux = TM6000_VMUX_VIDEO_B,
+ .amux = TM6000_AMUX_ADC1,
+ }, {
+ .type = TM6000_INPUT_COMPOSITE1,
+ .vmux = TM6000_VMUX_VIDEO_A,
+ .amux = TM6000_AMUX_ADC2,
+ }, {
+ .type = TM6000_INPUT_SVIDEO,
+ .vmux = TM6000_VMUX_VIDEO_AB,
+ .amux = TM6000_AMUX_ADC2,
+ },
+ },
+ },
+ [TM6010_BOARD_HAUPPAUGE_900H] = {
+ .name = "Hauppauge WinTV HVR-900H / WinTV USB2-Stick",
+ .eename = { 'H', 0, 'V', 0, 'R', 0, '9', 0, '0', 0, '0', 0, 'H', 0 },
+ .eename_size = 14,
+ .eename_pos = 0x42,
+ .tuner_type = TUNER_XC2028, /* has a XC3028 */
+ .tuner_addr = 0xc2 >> 1,
+ .demod_addr = 0x1e >> 1,
+ .type = TM6010,
+ .ir_codes = RC_MAP_HAUPPAUGE,
+ .caps = {
+ .has_tuner = 1,
+ .has_dvb = 1,
+ .has_zl10353 = 1,
+ .has_eeprom = 1,
+ .has_remote = 1,
+ },
+ .gpio = {
+ .tuner_reset = TM6010_GPIO_2,
+ .tuner_on = TM6010_GPIO_3,
+ .demod_reset = TM6010_GPIO_1,
+ .demod_on = TM6010_GPIO_4,
+ .power_led = TM6010_GPIO_7,
+ .dvb_led = TM6010_GPIO_5,
+ .ir = TM6010_GPIO_0,
+ },
+ .vinput = { {
+ .type = TM6000_INPUT_TV,
+ .vmux = TM6000_VMUX_VIDEO_B,
+ .amux = TM6000_AMUX_SIF1,
+ }, {
+ .type = TM6000_INPUT_COMPOSITE1,
+ .vmux = TM6000_VMUX_VIDEO_A,
+ .amux = TM6000_AMUX_ADC2,
+ }, {
+ .type = TM6000_INPUT_SVIDEO,
+ .vmux = TM6000_VMUX_VIDEO_AB,
+ .amux = TM6000_AMUX_ADC2,
+ },
+ },
+ },
+ [TM6010_BOARD_BEHOLD_WANDER] = {
+ .name = "Beholder Wander DVB-T/TV/FM USB2.0",
+ .tuner_type = TUNER_XC5000,
+ .tuner_addr = 0xc2 >> 1,
+ .demod_addr = 0x1e >> 1,
+ .type = TM6010,
+ .caps = {
+ .has_tuner = 1,
+ .has_dvb = 1,
+ .has_zl10353 = 1,
+ .has_eeprom = 1,
+ .has_remote = 1,
+ .has_radio = 1,
+ },
+ .gpio = {
+ .tuner_reset = TM6010_GPIO_0,
+ .demod_reset = TM6010_GPIO_1,
+ .power_led = TM6010_GPIO_6,
+ },
+ .vinput = { {
+ .type = TM6000_INPUT_TV,
+ .vmux = TM6000_VMUX_VIDEO_B,
+ .amux = TM6000_AMUX_SIF1,
+ }, {
+ .type = TM6000_INPUT_COMPOSITE1,
+ .vmux = TM6000_VMUX_VIDEO_A,
+ .amux = TM6000_AMUX_ADC2,
+ }, {
+ .type = TM6000_INPUT_SVIDEO,
+ .vmux = TM6000_VMUX_VIDEO_AB,
+ .amux = TM6000_AMUX_ADC2,
+ },
+ },
+ .rinput = {
+ .type = TM6000_INPUT_RADIO,
+ .amux = TM6000_AMUX_ADC1,
+ },
+ },
+ [TM6010_BOARD_BEHOLD_VOYAGER] = {
+ .name = "Beholder Voyager TV/FM USB2.0",
+ .tuner_type = TUNER_XC5000,
+ .tuner_addr = 0xc2 >> 1,
+ .type = TM6010,
+ .caps = {
+ .has_tuner = 1,
+ .has_dvb = 0,
+ .has_zl10353 = 0,
+ .has_eeprom = 1,
+ .has_remote = 1,
+ .has_radio = 1,
+ },
+ .gpio = {
+ .tuner_reset = TM6010_GPIO_0,
+ .power_led = TM6010_GPIO_6,
+ },
+ .vinput = { {
+ .type = TM6000_INPUT_TV,
+ .vmux = TM6000_VMUX_VIDEO_B,
+ .amux = TM6000_AMUX_SIF1,
+ }, {
+ .type = TM6000_INPUT_COMPOSITE1,
+ .vmux = TM6000_VMUX_VIDEO_A,
+ .amux = TM6000_AMUX_ADC2,
+ }, {
+ .type = TM6000_INPUT_SVIDEO,
+ .vmux = TM6000_VMUX_VIDEO_AB,
+ .amux = TM6000_AMUX_ADC2,
+ },
+ },
+ .rinput = {
+ .type = TM6000_INPUT_RADIO,
+ .amux = TM6000_AMUX_ADC1,
+ },
+ },
+ [TM6010_BOARD_TERRATEC_CINERGY_HYBRID_XE] = {
+ .name = "Terratec Cinergy Hybrid XE / Cinergy Hybrid-Stick",
+ .tuner_type = TUNER_XC2028, /* has a XC3028 */
+ .tuner_addr = 0xc2 >> 1,
+ .demod_addr = 0x1e >> 1,
+ .type = TM6010,
+ .caps = {
+ .has_tuner = 1,
+ .has_dvb = 1,
+ .has_zl10353 = 1,
+ .has_eeprom = 1,
+ .has_remote = 1,
+ .has_radio = 1,
+ },
+ .gpio = {
+ .tuner_reset = TM6010_GPIO_2,
+ .tuner_on = TM6010_GPIO_3,
+ .demod_reset = TM6010_GPIO_1,
+ .demod_on = TM6010_GPIO_4,
+ .power_led = TM6010_GPIO_7,
+ .dvb_led = TM6010_GPIO_5,
+ .ir = TM6010_GPIO_0,
+ },
+ .ir_codes = RC_MAP_NEC_TERRATEC_CINERGY_XS,
+ .vinput = { {
+ .type = TM6000_INPUT_TV,
+ .vmux = TM6000_VMUX_VIDEO_B,
+ .amux = TM6000_AMUX_SIF1,
+ }, {
+ .type = TM6000_INPUT_COMPOSITE1,
+ .vmux = TM6000_VMUX_VIDEO_A,
+ .amux = TM6000_AMUX_ADC2,
+ }, {
+ .type = TM6000_INPUT_SVI