add idl4k kernel firmware version 1.13.0.105

This commit is contained in:
Jaroslav Kysela
2015-03-26 17:22:37 +01:00
parent 5194d2792e
commit e9070cdc77
31064 changed files with 12769984 additions and 0 deletions

View File

@@ -0,0 +1,22 @@
config DVB_BT8XX
tristate "BT8xx based PCI cards"
depends on DVB_CORE && PCI && I2C && VIDEO_BT848
select DVB_MT352 if !DVB_FE_CUSTOMISE
select DVB_SP887X if !DVB_FE_CUSTOMISE
select DVB_NXT6000 if !DVB_FE_CUSTOMISE
select DVB_CX24110 if !DVB_FE_CUSTOMISE
select DVB_OR51211 if !DVB_FE_CUSTOMISE
select DVB_LGDT330X if !DVB_FE_CUSTOMISE
select DVB_ZL10353 if !DVB_FE_CUSTOMISE
select MEDIA_TUNER_SIMPLE if !MEDIA_TUNER_CUSTOMISE
help
Support for PCI cards based on the Bt8xx PCI bridge. Examples are
the Nebula cards, the Pinnacle PCTV cards, the Twinhan DST cards,
the pcHDTV HD2000 cards, the DViCO FusionHDTV Lite cards, and
some AVerMedia cards.
Since these cards have no MPEG decoder onboard, they transmit
only compressed MPEG data over the PCI 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.

View File

@@ -0,0 +1,6 @@
obj-$(CONFIG_DVB_BT8XX) += bt878.o dvb-bt8xx.o dst.o dst_ca.o
EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core
EXTRA_CFLAGS += -Idrivers/media/dvb/frontends
EXTRA_CFLAGS += -Idrivers/media/video/bt8xx
EXTRA_CFLAGS += -Idrivers/media/common/tuners

View File

@@ -0,0 +1,622 @@
/*
* bt878.c: part of the driver for the Pinnacle PCTV Sat DVB PCI card
*
* Copyright (C) 2002 Peter Hettkamp <peter.hettkamp@htp-tel.de>
*
* large parts based on the bttv driver
* Copyright (C) 1996,97,98 Ralph Metzler (rjkm@metzlerbros.de)
* & Marcus Metzler (mocm@metzlerbros.de)
* (c) 1999,2000 Gerd Knorr <kraxel@goldbach.in-berlin.de>
*
* 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; either version 2
* of the License, or (at your option) any later version.
*
* 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
* Or, point your browser to http://www.gnu.org/copyleft/gpl.html
*
*/
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/pci.h>
#include <asm/io.h>
#include <linux/ioport.h>
#include <asm/pgtable.h>
#include <asm/page.h>
#include <linux/types.h>
#include <linux/interrupt.h>
#include <linux/kmod.h>
#include <linux/vmalloc.h>
#include <linux/init.h>
#include "dmxdev.h"
#include "dvbdev.h"
#include "bt878.h"
#include "dst_priv.h"
/**************************************/
/* Miscellaneous utility definitions */
/**************************************/
static unsigned int bt878_verbose = 1;
static unsigned int bt878_debug;
module_param_named(verbose, bt878_verbose, int, 0444);
MODULE_PARM_DESC(verbose,
"verbose startup messages, default is 1 (yes)");
module_param_named(debug, bt878_debug, int, 0644);
MODULE_PARM_DESC(debug, "Turn on/off debugging, default is 0 (off).");
int bt878_num;
struct bt878 bt878[BT878_MAX];
EXPORT_SYMBOL(bt878_num);
EXPORT_SYMBOL(bt878);
#define btwrite(dat,adr) bmtwrite((dat), (bt->bt878_mem+(adr)))
#define btread(adr) bmtread(bt->bt878_mem+(adr))
#define btand(dat,adr) btwrite((dat) & btread(adr), adr)
#define btor(dat,adr) btwrite((dat) | btread(adr), adr)
#define btaor(dat,mask,adr) btwrite((dat) | ((mask) & btread(adr)), adr)
#if defined(dprintk)
#undef dprintk
#endif
#define dprintk(fmt, arg...) \
do { \
if (bt878_debug) \
printk(KERN_DEBUG fmt, ##arg); \
} while (0)
static void bt878_mem_free(struct bt878 *bt)
{
if (bt->buf_cpu) {
pci_free_consistent(bt->dev, bt->buf_size, bt->buf_cpu,
bt->buf_dma);
bt->buf_cpu = NULL;
}
if (bt->risc_cpu) {
pci_free_consistent(bt->dev, bt->risc_size, bt->risc_cpu,
bt->risc_dma);
bt->risc_cpu = NULL;
}
}
static int bt878_mem_alloc(struct bt878 *bt)
{
if (!bt->buf_cpu) {
bt->buf_size = 128 * 1024;
bt->buf_cpu =
pci_alloc_consistent(bt->dev, bt->buf_size,
&bt->buf_dma);
if (!bt->buf_cpu)
return -ENOMEM;
memset(bt->buf_cpu, 0, bt->buf_size);
}
if (!bt->risc_cpu) {
bt->risc_size = PAGE_SIZE;
bt->risc_cpu =
pci_alloc_consistent(bt->dev, bt->risc_size,
&bt->risc_dma);
if (!bt->risc_cpu) {
bt878_mem_free(bt);
return -ENOMEM;
}
memset(bt->risc_cpu, 0, bt->risc_size);
}
return 0;
}
/* RISC instructions */
#define RISC_WRITE (0x01 << 28)
#define RISC_JUMP (0x07 << 28)
#define RISC_SYNC (0x08 << 28)
/* RISC bits */
#define RISC_WR_SOL (1 << 27)
#define RISC_WR_EOL (1 << 26)
#define RISC_IRQ (1 << 24)
#define RISC_STATUS(status) ((((~status) & 0x0F) << 20) | ((status & 0x0F) << 16))
#define RISC_SYNC_RESYNC (1 << 15)
#define RISC_SYNC_FM1 0x06
#define RISC_SYNC_VRO 0x0C
#define RISC_FLUSH() bt->risc_pos = 0
#define RISC_INSTR(instr) bt->risc_cpu[bt->risc_pos++] = cpu_to_le32(instr)
static int bt878_make_risc(struct bt878 *bt)
{
bt->block_bytes = bt->buf_size >> 4;
bt->block_count = 1 << 4;
bt->line_bytes = bt->block_bytes;
bt->line_count = bt->block_count;
while (bt->line_bytes > 4095) {
bt->line_bytes >>= 1;
bt->line_count <<= 1;
}
if (bt->line_count > 255) {
printk(KERN_ERR "bt878: buffer size error!\n");
return -EINVAL;
}
return 0;
}
static void bt878_risc_program(struct bt878 *bt, u32 op_sync_orin)
{
u32 buf_pos = 0;
u32 line;
RISC_FLUSH();
RISC_INSTR(RISC_SYNC | RISC_SYNC_FM1 | op_sync_orin);
RISC_INSTR(0);
dprintk("bt878: risc len lines %u, bytes per line %u\n",
bt->line_count, bt->line_bytes);
for (line = 0; line < bt->line_count; line++) {
// At the beginning of every block we issue an IRQ with previous (finished) block number set
if (!(buf_pos % bt->block_bytes))
RISC_INSTR(RISC_WRITE | RISC_WR_SOL | RISC_WR_EOL |
RISC_IRQ |
RISC_STATUS(((buf_pos /
bt->block_bytes) +
(bt->block_count -
1)) %
bt->block_count) | bt->
line_bytes);
else
RISC_INSTR(RISC_WRITE | RISC_WR_SOL | RISC_WR_EOL |
bt->line_bytes);
RISC_INSTR(bt->buf_dma + buf_pos);
buf_pos += bt->line_bytes;
}
RISC_INSTR(RISC_SYNC | op_sync_orin | RISC_SYNC_VRO);
RISC_INSTR(0);
RISC_INSTR(RISC_JUMP);
RISC_INSTR(bt->risc_dma);
btwrite((bt->line_count << 16) | bt->line_bytes, BT878_APACK_LEN);
}
/*****************************/
/* Start/Stop grabbing funcs */
/*****************************/
void bt878_start(struct bt878 *bt, u32 controlreg, u32 op_sync_orin,
u32 irq_err_ignore)
{
u32 int_mask;
dprintk("bt878 debug: bt878_start (ctl=%8.8x)\n", controlreg);
/* complete the writing of the risc dma program now we have
* the card specifics
*/
bt878_risc_program(bt, op_sync_orin);
controlreg &= ~0x1f;
controlreg |= 0x1b;
btwrite(bt->risc_dma, BT878_ARISC_START);
/* original int mask had :
* 6 2 8 4 0
* 1111 1111 1000 0000 0000
* SCERR|OCERR|PABORT|RIPERR|FDSR|FTRGT|FBUS|RISCI
* Hacked for DST to:
* SCERR | OCERR | FDSR | FTRGT | FBUS | RISCI
*/
int_mask = BT878_ASCERR | BT878_AOCERR | BT878_APABORT |
BT878_ARIPERR | BT878_APPERR | BT878_AFDSR | BT878_AFTRGT |
BT878_AFBUS | BT878_ARISCI;
/* ignore pesky bits */
int_mask &= ~irq_err_ignore;
btwrite(int_mask, BT878_AINT_MASK);
btwrite(controlreg, BT878_AGPIO_DMA_CTL);
}
void bt878_stop(struct bt878 *bt)
{
u32 stat;
int i = 0;
dprintk("bt878 debug: bt878_stop\n");
btwrite(0, BT878_AINT_MASK);
btand(~0x13, BT878_AGPIO_DMA_CTL);
do {
stat = btread(BT878_AINT_STAT);
if (!(stat & BT878_ARISC_EN))
break;
i++;
} while (i < 500);
dprintk("bt878(%d) debug: bt878_stop, i=%d, stat=0x%8.8x\n",
bt->nr, i, stat);
}
EXPORT_SYMBOL(bt878_start);
EXPORT_SYMBOL(bt878_stop);
/*****************************/
/* Interrupt service routine */
/*****************************/
static irqreturn_t bt878_irq(int irq, void *dev_id)
{
u32 stat, astat, mask;
int count;
struct bt878 *bt;
bt = (struct bt878 *) dev_id;
count = 0;
while (1) {
stat = btread(BT878_AINT_STAT);
mask = btread(BT878_AINT_MASK);
if (!(astat = (stat & mask)))
return IRQ_NONE; /* this interrupt is not for me */
/* dprintk("bt878(%d) debug: irq count %d, stat 0x%8.8x, mask 0x%8.8x\n",bt->nr,count,stat,mask); */
btwrite(astat, BT878_AINT_STAT); /* try to clear interrupt condition */
if (astat & (BT878_ASCERR | BT878_AOCERR)) {
if (bt878_verbose) {
printk(KERN_INFO
"bt878(%d): irq%s%s risc_pc=%08x\n",
bt->nr,
(astat & BT878_ASCERR) ? " SCERR" :
"",
(astat & BT878_AOCERR) ? " OCERR" :
"", btread(BT878_ARISC_PC));
}
}
if (astat & (BT878_APABORT | BT878_ARIPERR | BT878_APPERR)) {
if (bt878_verbose) {
printk(KERN_INFO
"bt878(%d): irq%s%s%s risc_pc=%08x\n",
bt->nr,
(astat & BT878_APABORT) ? " PABORT" :
"",
(astat & BT878_ARIPERR) ? " RIPERR" :
"",
(astat & BT878_APPERR) ? " PPERR" :
"", btread(BT878_ARISC_PC));
}
}
if (astat & (BT878_AFDSR | BT878_AFTRGT | BT878_AFBUS)) {
if (bt878_verbose) {
printk(KERN_INFO
"bt878(%d): irq%s%s%s risc_pc=%08x\n",
bt->nr,
(astat & BT878_AFDSR) ? " FDSR" : "",
(astat & BT878_AFTRGT) ? " FTRGT" :
"",
(astat & BT878_AFBUS) ? " FBUS" : "",
btread(BT878_ARISC_PC));
}
}
if (astat & BT878_ARISCI) {
bt->finished_block = (stat & BT878_ARISCS) >> 28;
tasklet_schedule(&bt->tasklet);
break;
}
count++;
if (count > 20) {
btwrite(0, BT878_AINT_MASK);
printk(KERN_ERR
"bt878(%d): IRQ lockup, cleared int mask\n",
bt->nr);
break;
}
}
return IRQ_HANDLED;
}
int
bt878_device_control(struct bt878 *bt, unsigned int cmd, union dst_gpio_packet *mp)
{
int retval;
retval = 0;
if (mutex_lock_interruptible(&bt->gpio_lock))
return -ERESTARTSYS;
/* special gpio signal */
switch (cmd) {
case DST_IG_ENABLE:
// dprintk("dvb_bt8xx: dst enable mask 0x%02x enb 0x%02x \n", mp->dstg.enb.mask, mp->dstg.enb.enable);
retval = bttv_gpio_enable(bt->bttv_nr,
mp->enb.mask,
mp->enb.enable);
break;
case DST_IG_WRITE:
// dprintk("dvb_bt8xx: dst write gpio mask 0x%02x out 0x%02x\n", mp->dstg.outp.mask, mp->dstg.outp.highvals);
retval = bttv_write_gpio(bt->bttv_nr,
mp->outp.mask,
mp->outp.highvals);
break;
case DST_IG_READ:
/* read */
retval = bttv_read_gpio(bt->bttv_nr, &mp->rd.value);
// dprintk("dvb_bt8xx: dst read gpio 0x%02x\n", (unsigned)mp->dstg.rd.value);
break;
case DST_IG_TS:
/* Set packet size */
bt->TS_Size = mp->psize;
break;
default:
retval = -EINVAL;
break;
}
mutex_unlock(&bt->gpio_lock);
return retval;
}
EXPORT_SYMBOL(bt878_device_control);
#define BROOKTREE_878_DEVICE(vend, dev, name) \
{ \
.vendor = PCI_VENDOR_ID_BROOKTREE, \
.device = PCI_DEVICE_ID_BROOKTREE_878, \
.subvendor = (vend), .subdevice = (dev), \
.driver_data = (unsigned long) name \
}
static struct pci_device_id bt878_pci_tbl[] __devinitdata = {
BROOKTREE_878_DEVICE(0x0071, 0x0101, "Nebula Electronics DigiTV"),
BROOKTREE_878_DEVICE(0x1461, 0x0761, "AverMedia AverTV DVB-T 761"),
BROOKTREE_878_DEVICE(0x11bd, 0x001c, "Pinnacle PCTV Sat"),
BROOKTREE_878_DEVICE(0x11bd, 0x0026, "Pinnacle PCTV SAT CI"),
BROOKTREE_878_DEVICE(0x1822, 0x0001, "Twinhan VisionPlus DVB"),
BROOKTREE_878_DEVICE(0x270f, 0xfc00,
"ChainTech digitop DST-1000 DVB-S"),
BROOKTREE_878_DEVICE(0x1461, 0x0771, "AVermedia AverTV DVB-T 771"),
BROOKTREE_878_DEVICE(0x18ac, 0xdb10, "DViCO FusionHDTV DVB-T Lite"),
BROOKTREE_878_DEVICE(0x18ac, 0xdb11, "Ultraview DVB-T Lite"),
BROOKTREE_878_DEVICE(0x18ac, 0xd500, "DViCO FusionHDTV 5 Lite"),
BROOKTREE_878_DEVICE(0x7063, 0x2000, "pcHDTV HD-2000 TV"),
BROOKTREE_878_DEVICE(0x1822, 0x0026, "DNTV Live! Mini"),
{ }
};
MODULE_DEVICE_TABLE(pci, bt878_pci_tbl);
static const char * __devinit card_name(const struct pci_device_id *id)
{
return id->driver_data ? (const char *)id->driver_data : "Unknown";
}
/***********************/
/* PCI device handling */
/***********************/
static int __devinit bt878_probe(struct pci_dev *dev,
const struct pci_device_id *pci_id)
{
int result = 0;
unsigned char lat;
struct bt878 *bt;
#if defined(__powerpc__)
unsigned int cmd;
#endif
unsigned int cardid;
printk(KERN_INFO "bt878: Bt878 AUDIO function found (%d).\n",
bt878_num);
if (bt878_num >= BT878_MAX) {
printk(KERN_ERR "bt878: Too many devices inserted\n");
result = -ENOMEM;
goto fail0;
}
if (pci_enable_device(dev))
return -EIO;
cardid = dev->subsystem_device << 16;
cardid |= dev->subsystem_vendor;
printk(KERN_INFO "%s: card id=[0x%x],[ %s ] has DVB functions.\n",
__func__, cardid, card_name(pci_id));
bt = &bt878[bt878_num];
bt->dev = dev;
bt->nr = bt878_num;
bt->shutdown = 0;
bt->id = dev->device;
bt->irq = dev->irq;
bt->bt878_adr = pci_resource_start(dev, 0);
if (!request_mem_region(pci_resource_start(dev, 0),
pci_resource_len(dev, 0), "bt878")) {
result = -EBUSY;
goto fail0;
}
pci_read_config_byte(dev, PCI_CLASS_REVISION, &bt->revision);
pci_read_config_byte(dev, PCI_LATENCY_TIMER, &lat);
printk(KERN_INFO "bt878(%d): Bt%x (rev %d) at %02x:%02x.%x, ",
bt878_num, bt->id, bt->revision, dev->bus->number,
PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn));
printk("irq: %d, latency: %d, memory: 0x%lx\n",
bt->irq, lat, bt->bt878_adr);
#if defined(__powerpc__)
/* on OpenFirmware machines (PowerMac at least), PCI memory cycle */
/* response on cards with no firmware is not enabled by OF */
pci_read_config_dword(dev, PCI_COMMAND, &cmd);
cmd = (cmd | PCI_COMMAND_MEMORY);
pci_write_config_dword(dev, PCI_COMMAND, cmd);
#endif
#ifdef __sparc__
bt->bt878_mem = (unsigned char *) bt->bt878_adr;
#else
bt->bt878_mem = ioremap(bt->bt878_adr, 0x1000);
#endif
/* clear interrupt mask */
btwrite(0, BT848_INT_MASK);
result = request_irq(bt->irq, bt878_irq,
IRQF_SHARED | IRQF_DISABLED, "bt878",
(void *) bt);
if (result == -EINVAL) {
printk(KERN_ERR "bt878(%d): Bad irq number or handler\n",
bt878_num);
goto fail1;
}
if (result == -EBUSY) {
printk(KERN_ERR
"bt878(%d): IRQ %d busy, change your PnP config in BIOS\n",
bt878_num, bt->irq);
goto fail1;
}
if (result < 0)
goto fail1;
pci_set_master(dev);
pci_set_drvdata(dev, bt);
if ((result = bt878_mem_alloc(bt))) {
printk(KERN_ERR "bt878: failed to allocate memory!\n");
goto fail2;
}
bt878_make_risc(bt);
btwrite(0, BT878_AINT_MASK);
bt878_num++;
return 0;
fail2:
free_irq(bt->irq, bt);
fail1:
release_mem_region(pci_resource_start(bt->dev, 0),
pci_resource_len(bt->dev, 0));
fail0:
pci_disable_device(dev);
return result;
}
static void __devexit bt878_remove(struct pci_dev *pci_dev)
{
u8 command;
struct bt878 *bt = pci_get_drvdata(pci_dev);
if (bt878_verbose)
printk(KERN_INFO "bt878(%d): unloading\n", bt->nr);
/* turn off all capturing, DMA and IRQs */
btand(~0x13, BT878_AGPIO_DMA_CTL);
/* first disable interrupts before unmapping the memory! */
btwrite(0, BT878_AINT_MASK);
btwrite(~0U, BT878_AINT_STAT);
/* disable PCI bus-mastering */
pci_read_config_byte(bt->dev, PCI_COMMAND, &command);
/* Should this be &=~ ?? */
command &= ~PCI_COMMAND_MASTER;
pci_write_config_byte(bt->dev, PCI_COMMAND, command);
free_irq(bt->irq, bt);
printk(KERN_DEBUG "bt878_mem: 0x%p.\n", bt->bt878_mem);
if (bt->bt878_mem)
iounmap(bt->bt878_mem);
release_mem_region(pci_resource_start(bt->dev, 0),
pci_resource_len(bt->dev, 0));
/* wake up any waiting processes
because shutdown flag is set, no new processes (in this queue)
are expected
*/
bt->shutdown = 1;
bt878_mem_free(bt);
pci_set_drvdata(pci_dev, NULL);
pci_disable_device(pci_dev);
return;
}
static struct pci_driver bt878_pci_driver = {
.name = "bt878",
.id_table = bt878_pci_tbl,
.probe = bt878_probe,
.remove = __devexit_p(bt878_remove),
};
static int bt878_pci_driver_registered;
/*******************************/
/* Module management functions */
/*******************************/
static int bt878_init_module(void)
{
bt878_num = 0;
bt878_pci_driver_registered = 0;
printk(KERN_INFO "bt878: AUDIO driver version %d.%d.%d loaded\n",
(BT878_VERSION_CODE >> 16) & 0xff,
(BT878_VERSION_CODE >> 8) & 0xff,
BT878_VERSION_CODE & 0xff);
/*
bt878_check_chipset();
*/
/* later we register inside of bt878_find_audio_dma()
* because we may want to ignore certain cards */
bt878_pci_driver_registered = 1;
return pci_register_driver(&bt878_pci_driver);
}
static void bt878_cleanup_module(void)
{
if (bt878_pci_driver_registered) {
bt878_pci_driver_registered = 0;
pci_unregister_driver(&bt878_pci_driver);
}
return;
}
module_init(bt878_init_module);
module_exit(bt878_cleanup_module);
//MODULE_AUTHOR("XXX");
MODULE_LICENSE("GPL");
/*
* Local variables:
* c-basic-offset: 8
* End:
*/

View File

@@ -0,0 +1,159 @@
/*
bt878.h - Bt878 audio module (register offsets)
Copyright (C) 2002 Peter Hettkamp <peter.hettkamp@htp-tel.de>
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; either version 2 of the License, or
(at your option) any later version.
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.
*/
#ifndef _BT878_H_
#define _BT878_H_
#include <linux/interrupt.h>
#include <linux/pci.h>
#include <linux/sched.h>
#include <linux/spinlock.h>
#include <linux/mutex.h>
#include "bt848.h"
#include "bttv.h"
#define BT878_VERSION_CODE 0x000000
#define BT878_AINT_STAT 0x100
#define BT878_ARISCS (0xf<<28)
#define BT878_ARISC_EN (1<<27)
#define BT878_ASCERR (1<<19)
#define BT878_AOCERR (1<<18)
#define BT878_APABORT (1<<17)
#define BT878_ARIPERR (1<<16)
#define BT878_APPERR (1<<15)
#define BT878_AFDSR (1<<14)
#define BT878_AFTRGT (1<<13)
#define BT878_AFBUS (1<<12)
#define BT878_ARISCI (1<<11)
#define BT878_AOFLOW (1<<3)
#define BT878_AINT_MASK 0x104
#define BT878_AGPIO_DMA_CTL 0x10c
#define BT878_A_GAIN (0xf<<28)
#define BT878_A_G2X (1<<27)
#define BT878_A_PWRDN (1<<26)
#define BT878_A_SEL (3<<24)
#define BT878_DA_SCE (1<<23)
#define BT878_DA_LRI (1<<22)
#define BT878_DA_MLB (1<<21)
#define BT878_DA_LRD (0x1f<<16)
#define BT878_DA_DPM (1<<15)
#define BT878_DA_SBR (1<<14)
#define BT878_DA_ES2 (1<<13)
#define BT878_DA_LMT (1<<12)
#define BT878_DA_SDR (0xf<<8)
#define BT878_DA_IOM (3<<6)
#define BT878_DA_APP (1<<5)
#define BT878_ACAP_EN (1<<4)
#define BT878_PKTP (3<<2)
#define BT878_RISC_EN (1<<1)
#define BT878_FIFO_EN 1
#define BT878_APACK_LEN 0x110
#define BT878_AFP_LEN (0xff<<16)
#define BT878_ALP_LEN 0xfff
#define BT878_ARISC_START 0x114
#define BT878_ARISC_PC 0x120
/* BT878 FUNCTION 0 REGISTERS */
#define BT878_GPIO_DMA_CTL 0x10c
/* Interrupt register */
#define BT878_INT_STAT 0x100
#define BT878_INT_MASK 0x104
#define BT878_I2CRACK (1<<25)
#define BT878_I2CDONE (1<<8)
#define BT878_MAX 4
#define BT878_RISC_SYNC_MASK (1 << 15)
#define BTTV_BOARD_UNKNOWN 0x00
#define BTTV_BOARD_PINNACLESAT 0x5e
#define BTTV_BOARD_NEBULA_DIGITV 0x68
#define BTTV_BOARD_PC_HDTV 0x70
#define BTTV_BOARD_TWINHAN_DST 0x71
#define BTTV_BOARD_AVDVBT_771 0x7b
#define BTTV_BOARD_AVDVBT_761 0x7c
#define BTTV_BOARD_DVICO_DVBT_LITE 0x80
#define BTTV_BOARD_DVICO_FUSIONHDTV_5_LITE 0x87
extern int bt878_num;
struct bt878 {
struct mutex gpio_lock;
unsigned int nr;
unsigned int bttv_nr;
struct i2c_adapter *adapter;
struct pci_dev *dev;
unsigned int id;
unsigned int TS_Size;
unsigned char revision;
unsigned int irq;
unsigned long bt878_adr;
volatile void __iomem *bt878_mem; /* function 1 */
volatile u32 finished_block;
volatile u32 last_block;
u32 block_count;
u32 block_bytes;
u32 line_bytes;
u32 line_count;
u32 buf_size;
u8 *buf_cpu;
dma_addr_t buf_dma;
u32 risc_size;
__le32 *risc_cpu;
dma_addr_t risc_dma;
u32 risc_pos;
struct tasklet_struct tasklet;
int shutdown;
};
extern struct bt878 bt878[BT878_MAX];
void bt878_start(struct bt878 *bt, u32 controlreg, u32 op_sync_orin,
u32 irq_err_ignore);
void bt878_stop(struct bt878 *bt);
#if defined(__powerpc__) /* big-endian */
static inline void io_st_le32(volatile unsigned __iomem *addr, unsigned val)
{
st_le32(addr, val);
eieio();
}
#define bmtwrite(dat,adr) io_st_le32((adr),(dat))
#define bmtread(adr) ld_le32((adr))
#else
#define bmtwrite(dat,adr) writel((dat), (adr))
#define bmtread(adr) readl(adr)
#endif
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,724 @@
/*
CA-driver for TwinHan DST Frontend/Card
Copyright (C) 2004, 2005 Manu Abraham (manu@kromtek.com)
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; either version 2 of the License, or
(at your option) any later version.
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/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/smp_lock.h>
#include <linux/string.h>
#include <linux/dvb/ca.h>
#include "dvbdev.h"
#include "dvb_frontend.h"
#include "dst_ca.h"
#include "dst_common.h"
#define DST_CA_ERROR 0
#define DST_CA_NOTICE 1
#define DST_CA_INFO 2
#define DST_CA_DEBUG 3
#define dprintk(x, y, z, format, arg...) do { \
if (z) { \
if ((x > DST_CA_ERROR) && (x > y)) \
printk(KERN_ERR "%s: " format "\n", __func__ , ##arg); \
else if ((x > DST_CA_NOTICE) && (x > y)) \
printk(KERN_NOTICE "%s: " format "\n", __func__ , ##arg); \
else if ((x > DST_CA_INFO) && (x > y)) \
printk(KERN_INFO "%s: " format "\n", __func__ , ##arg); \
else if ((x > DST_CA_DEBUG) && (x > y)) \
printk(KERN_DEBUG "%s: " format "\n", __func__ , ##arg); \
} else { \
if (x > y) \
printk(format, ## arg); \
} \
} while(0)
static unsigned int verbose = 5;
module_param(verbose, int, 0644);
MODULE_PARM_DESC(verbose, "verbose startup messages, default is 1 (yes)");
/* Need some more work */
static int ca_set_slot_descr(void)
{
/* We could make this more graceful ? */
return -EOPNOTSUPP;
}
/* Need some more work */
static int ca_set_pid(void)
{
/* We could make this more graceful ? */
return -EOPNOTSUPP;
}
static void put_command_and_length(u8 *data, int command, int length)
{
data[0] = (command >> 16) & 0xff;
data[1] = (command >> 8) & 0xff;
data[2] = command & 0xff;
data[3] = length;
}
static void put_checksum(u8 *check_string, int length)
{
dprintk(verbose, DST_CA_DEBUG, 1, " Computing string checksum.");
dprintk(verbose, DST_CA_DEBUG, 1, " -> string length : 0x%02x", length);
check_string[length] = dst_check_sum (check_string, length);
dprintk(verbose, DST_CA_DEBUG, 1, " -> checksum : 0x%02x", check_string[length]);
}
static int dst_ci_command(struct dst_state* state, u8 * data, u8 *ca_string, u8 len, int read)
{
u8 reply;
mutex_lock(&state->dst_mutex);
dst_comm_init(state);
msleep(65);
if (write_dst(state, data, len)) {
dprintk(verbose, DST_CA_INFO, 1, " Write not successful, trying to recover");
dst_error_recovery(state);
goto error;
}
if ((dst_pio_disable(state)) < 0) {
dprintk(verbose, DST_CA_ERROR, 1, " DST PIO disable failed.");
goto error;
}
if (read_dst(state, &reply, GET_ACK) < 0) {
dprintk(verbose, DST_CA_INFO, 1, " Read not successful, trying to recover");
dst_error_recovery(state);
goto error;
}
if (read) {
if (! dst_wait_dst_ready(state, LONG_DELAY)) {
dprintk(verbose, DST_CA_NOTICE, 1, " 8820 not ready");
goto error;
}
if (read_dst(state, ca_string, 128) < 0) { /* Try to make this dynamic */
dprintk(verbose, DST_CA_INFO, 1, " Read not successful, trying to recover");
dst_error_recovery(state);
goto error;
}
}
mutex_unlock(&state->dst_mutex);
return 0;
error:
mutex_unlock(&state->dst_mutex);
return -EIO;
}
static int dst_put_ci(struct dst_state *state, u8 *data, int len, u8 *ca_string, int read)
{
u8 dst_ca_comm_err = 0;
while (dst_ca_comm_err < RETRIES) {
dprintk(verbose, DST_CA_NOTICE, 1, " Put Command");
if (dst_ci_command(state, data, ca_string, len, read)) { // If error
dst_error_recovery(state);
dst_ca_comm_err++; // work required here.
} else {
break;
}
}
if(dst_ca_comm_err == RETRIES)
return -1;
return 0;
}
static int ca_get_app_info(struct dst_state *state)
{
int length, str_length;
static u8 command[8] = {0x07, 0x40, 0x01, 0x00, 0x01, 0x00, 0x00, 0xff};
put_checksum(&command[0], command[0]);
if ((dst_put_ci(state, command, sizeof(command), state->messages, GET_REPLY)) < 0) {
dprintk(verbose, DST_CA_ERROR, 1, " -->dst_put_ci FAILED !");
return -1;
}
dprintk(verbose, DST_CA_INFO, 1, " -->dst_put_ci SUCCESS !");
dprintk(verbose, DST_CA_INFO, 1, " ================================ CI Module Application Info ======================================");
dprintk(verbose, DST_CA_INFO, 1, " Application Type=[%d], Application Vendor=[%d], Vendor Code=[%d]\n%s: Application info=[%s]",
state->messages[7], (state->messages[8] << 8) | state->messages[9],
(state->messages[10] << 8) | state->messages[11], __func__, (char *)(&state->messages[12]));
dprintk(verbose, DST_CA_INFO, 1, " ==================================================================================================");
// Transform dst message to correct application_info message
length = state->messages[5];
str_length = length - 6;
if (str_length < 0) {
str_length = 0;
dprintk(verbose, DST_CA_ERROR, 1, "Invalid string length returned in ca_get_app_info(). Recovering.");
}
// First, the command and length fields
put_command_and_length(&state->messages[0], CA_APP_INFO, length);
// Copy application_type, application_manufacturer and manufacturer_code
memcpy(&state->messages[4], &state->messages[7], 5);
// Set string length and copy string
state->messages[9] = str_length;
memcpy(&state->messages[10], &state->messages[12], str_length);
return 0;
}
static int ca_get_ca_info(struct dst_state *state)
{
int srcPtr, dstPtr, i, num_ids;
static u8 slot_command[8] = {0x07, 0x40, 0x00, 0x00, 0x02, 0x00, 0x00, 0xff};
const int in_system_id_pos = 8, out_system_id_pos = 4, in_num_ids_pos = 7;
put_checksum(&slot_command[0], slot_command[0]);
if ((dst_put_ci(state, slot_command, sizeof (slot_command), state->messages, GET_REPLY)) < 0) {
dprintk(verbose, DST_CA_ERROR, 1, " -->dst_put_ci FAILED !");
return -1;
}
dprintk(verbose, DST_CA_INFO, 1, " -->dst_put_ci SUCCESS !");
// Print raw data
dprintk(verbose, DST_CA_INFO, 0, " DST data = [");
for (i = 0; i < state->messages[0] + 1; i++) {
dprintk(verbose, DST_CA_INFO, 0, " 0x%02x", state->messages[i]);
}
dprintk(verbose, DST_CA_INFO, 0, "]\n");
// Set the command and length of the output
num_ids = state->messages[in_num_ids_pos];
if (num_ids >= 100) {
num_ids = 100;
dprintk(verbose, DST_CA_ERROR, 1, "Invalid number of ids (>100). Recovering.");
}
put_command_and_length(&state->messages[0], CA_INFO, num_ids * 2);
dprintk(verbose, DST_CA_INFO, 0, " CA_INFO = [");
srcPtr = in_system_id_pos;
dstPtr = out_system_id_pos;
for(i = 0; i < num_ids; i++) {
dprintk(verbose, DST_CA_INFO, 0, " 0x%02x%02x", state->messages[srcPtr + 0], state->messages[srcPtr + 1]);
// Append to output
state->messages[dstPtr + 0] = state->messages[srcPtr + 0];
state->messages[dstPtr + 1] = state->messages[srcPtr + 1];
srcPtr += 2;
dstPtr += 2;
}
dprintk(verbose, DST_CA_INFO, 0, "]\n");
return 0;
}
static int ca_get_slot_caps(struct dst_state *state, struct ca_caps *p_ca_caps, void __user *arg)
{
int i;
u8 slot_cap[256];
static u8 slot_command[8] = {0x07, 0x40, 0x02, 0x00, 0x02, 0x00, 0x00, 0xff};
put_checksum(&slot_command[0], slot_command[0]);
if ((dst_put_ci(state, slot_command, sizeof (slot_command), slot_cap, GET_REPLY)) < 0) {
dprintk(verbose, DST_CA_ERROR, 1, " -->dst_put_ci FAILED !");
return -1;
}
dprintk(verbose, DST_CA_NOTICE, 1, " -->dst_put_ci SUCCESS !");
/* Will implement the rest soon */
dprintk(verbose, DST_CA_INFO, 1, " Slot cap = [%d]", slot_cap[7]);
dprintk(verbose, DST_CA_INFO, 0, "===================================\n");
for (i = 0; i < slot_cap[0] + 1; i++)
dprintk(verbose, DST_CA_INFO, 0, " %d", slot_cap[i]);
dprintk(verbose, DST_CA_INFO, 0, "\n");
p_ca_caps->slot_num = 1;
p_ca_caps->slot_type = 1;
p_ca_caps->descr_num = slot_cap[7];
p_ca_caps->descr_type = 1;
if (copy_to_user(arg, p_ca_caps, sizeof (struct ca_caps)))
return -EFAULT;
return 0;
}
/* Need some more work */
static int ca_get_slot_descr(struct dst_state *state, struct ca_msg *p_ca_message, void __user *arg)
{
return -EOPNOTSUPP;
}
static int ca_get_slot_info(struct dst_state *state, struct ca_slot_info *p_ca_slot_info, void __user *arg)
{
int i;
static u8 slot_command[8] = {0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff};
u8 *slot_info = state->messages;
put_checksum(&slot_command[0], 7);
if ((dst_put_ci(state, slot_command, sizeof (slot_command), slot_info, GET_REPLY)) < 0) {
dprintk(verbose, DST_CA_ERROR, 1, " -->dst_put_ci FAILED !");
return -1;
}
dprintk(verbose, DST_CA_INFO, 1, " -->dst_put_ci SUCCESS !");
/* Will implement the rest soon */
dprintk(verbose, DST_CA_INFO, 1, " Slot info = [%d]", slot_info[3]);
dprintk(verbose, DST_CA_INFO, 0, "===================================\n");
for (i = 0; i < 8; i++)
dprintk(verbose, DST_CA_INFO, 0, " %d", slot_info[i]);
dprintk(verbose, DST_CA_INFO, 0, "\n");
if (slot_info[4] & 0x80) {
p_ca_slot_info->flags = CA_CI_MODULE_PRESENT;
p_ca_slot_info->num = 1;
p_ca_slot_info->type = CA_CI;
} else if (slot_info[4] & 0x40) {
p_ca_slot_info->flags = CA_CI_MODULE_READY;
p_ca_slot_info->num = 1;
p_ca_slot_info->type = CA_CI;
} else
p_ca_slot_info->flags = 0;
if (copy_to_user(arg, p_ca_slot_info, sizeof (struct ca_slot_info)))
return -EFAULT;
return 0;
}
static int ca_get_message(struct dst_state *state, struct ca_msg *p_ca_message, void __user *arg)
{
u8 i = 0;
u32 command = 0;
if (copy_from_user(p_ca_message, arg, sizeof (struct ca_msg)))
return -EFAULT;
if (p_ca_message->msg) {
dprintk(verbose, DST_CA_NOTICE, 1, " Message = [%02x %02x %02x]", p_ca_message->msg[0], p_ca_message->msg[1], p_ca_message->msg[2]);
for (i = 0; i < 3; i++) {
command = command | p_ca_message->msg[i];
if (i < 2)
command = command << 8;
}
dprintk(verbose, DST_CA_NOTICE, 1, " Command=[0x%x]", command);
switch (command) {
case CA_APP_INFO:
memcpy(p_ca_message->msg, state->messages, 128);
if (copy_to_user(arg, p_ca_message, sizeof (struct ca_msg)) )
return -EFAULT;
break;
case CA_INFO:
memcpy(p_ca_message->msg, state->messages, 128);
if (copy_to_user(arg, p_ca_message, sizeof (struct ca_msg)) )
return -EFAULT;
break;
}
}
return 0;
}
static int handle_dst_tag(struct dst_state *state, struct ca_msg *p_ca_message, struct ca_msg *hw_buffer, u32 length)
{
if (state->dst_hw_cap & DST_TYPE_HAS_SESSION) {
hw_buffer->msg[2] = p_ca_message->msg[1]; /* MSB */
hw_buffer->msg[3] = p_ca_message->msg[2]; /* LSB */
} else {
if (length > 247) {
dprintk(verbose, DST_CA_ERROR, 1, " Message too long ! *** Bailing Out *** !");
return -1;
}
hw_buffer->msg[0] = (length & 0xff) + 7;
hw_buffer->msg[1] = 0x40;
hw_buffer->msg[2] = 0x03;
hw_buffer->msg[3] = 0x00;
hw_buffer->msg[4] = 0x03;
hw_buffer->msg[5] = length & 0xff;
hw_buffer->msg[6] = 0x00;
/*
* Need to compute length for EN50221 section 8.3.2, for the time being
* assuming 8.3.2 is not applicable
*/
memcpy(&hw_buffer->msg[7], &p_ca_message->msg[4], length);
}
return 0;
}
static int write_to_8820(struct dst_state *state, struct ca_msg *hw_buffer, u8 length, u8 reply)
{
if ((dst_put_ci(state, hw_buffer->msg, length, hw_buffer->msg, reply)) < 0) {
dprintk(verbose, DST_CA_ERROR, 1, " DST-CI Command failed.");
dprintk(verbose, DST_CA_NOTICE, 1, " Resetting DST.");
rdc_reset_state(state);
return -1;
}
dprintk(verbose, DST_CA_NOTICE, 1, " DST-CI Command success.");
return 0;
}
static u32 asn_1_decode(u8 *asn_1_array)
{
u8 length_field = 0, word_count = 0, count = 0;
u32 length = 0;
length_field = asn_1_array[0];
dprintk(verbose, DST_CA_DEBUG, 1, " Length field=[%02x]", length_field);
if (length_field < 0x80) {
length = length_field & 0x7f;
dprintk(verbose, DST_CA_DEBUG, 1, " Length=[%02x]\n", length);
} else {
word_count = length_field & 0x7f;
for (count = 0; count < word_count; count++) {
length = length << 8;
length += asn_1_array[count + 1];
dprintk(verbose, DST_CA_DEBUG, 1, " Length=[%04x]", length);
}
}
return length;
}
static int debug_string(u8 *msg, u32 length, u32 offset)
{
u32 i;
dprintk(verbose, DST_CA_DEBUG, 0, " String=[ ");
for (i = offset; i < length; i++)
dprintk(verbose, DST_CA_DEBUG, 0, "%02x ", msg[i]);
dprintk(verbose, DST_CA_DEBUG, 0, "]\n");
return 0;
}
static int ca_set_pmt(struct dst_state *state, struct ca_msg *p_ca_message, struct ca_msg *hw_buffer, u8 reply, u8 query)
{
u32 length = 0;
u8 tag_length = 8;
length = asn_1_decode(&p_ca_message->msg[3]);
dprintk(verbose, DST_CA_DEBUG, 1, " CA Message length=[%d]", length);
debug_string(&p_ca_message->msg[4], length, 0); /* length is excluding tag & length */
memset(hw_buffer->msg, '\0', length);
handle_dst_tag(state, p_ca_message, hw_buffer, length);
put_checksum(hw_buffer->msg, hw_buffer->msg[0]);
debug_string(hw_buffer->msg, (length + tag_length), 0); /* tags too */
write_to_8820(state, hw_buffer, (length + tag_length), reply);
return 0;
}
/* Board supports CA PMT reply ? */
static int dst_check_ca_pmt(struct dst_state *state, struct ca_msg *p_ca_message, struct ca_msg *hw_buffer)
{
int ca_pmt_reply_test = 0;
/* Do test board */
/* Not there yet but soon */
/* CA PMT Reply capable */
if (ca_pmt_reply_test) {
if ((ca_set_pmt(state, p_ca_message, hw_buffer, 1, GET_REPLY)) < 0) {
dprintk(verbose, DST_CA_ERROR, 1, " ca_set_pmt.. failed !");
return -1;
}
/* Process CA PMT Reply */
/* will implement soon */
dprintk(verbose, DST_CA_ERROR, 1, " Not there yet");
}
/* CA PMT Reply not capable */
if (!ca_pmt_reply_test) {
if ((ca_set_pmt(state, p_ca_message, hw_buffer, 0, NO_REPLY)) < 0) {
dprintk(verbose, DST_CA_ERROR, 1, " ca_set_pmt.. failed !");
return -1;
}
dprintk(verbose, DST_CA_NOTICE, 1, " ca_set_pmt.. success !");
/* put a dummy message */
}
return 0;
}
static int ca_send_message(struct dst_state *state, struct ca_msg *p_ca_message, void __user *arg)
{
int i = 0;
unsigned int ca_message_header_len;
u32 command = 0;
struct ca_msg *hw_buffer;
int result = 0;
if ((hw_buffer = kmalloc(sizeof (struct ca_msg), GFP_KERNEL)) == NULL) {
dprintk(verbose, DST_CA_ERROR, 1, " Memory allocation failure");
return -ENOMEM;
}
dprintk(verbose, DST_CA_DEBUG, 1, " ");
if (copy_from_user(p_ca_message, arg, sizeof (struct ca_msg))) {
result = -EFAULT;
goto free_mem_and_exit;
}
if (p_ca_message->msg) {
ca_message_header_len = p_ca_message->length; /* Restore it back when you are done */
/* EN50221 tag */
command = 0;
for (i = 0; i < 3; i++) {
command = command | p_ca_message->msg[i];
if (i < 2)
command = command << 8;
}
dprintk(verbose, DST_CA_DEBUG, 1, " Command=[0x%x]\n", command);
switch (command) {
case CA_PMT:
dprintk(verbose, DST_CA_DEBUG, 1, "Command = SEND_CA_PMT");
if ((ca_set_pmt(state, p_ca_message, hw_buffer, 0, 0)) < 0) { // code simplification started
dprintk(verbose, DST_CA_ERROR, 1, " -->CA_PMT Failed !");
result = -1;
goto free_mem_and_exit;
}
dprintk(verbose, DST_CA_INFO, 1, " -->CA_PMT Success !");
break;
case CA_PMT_REPLY:
dprintk(verbose, DST_CA_INFO, 1, "Command = CA_PMT_REPLY");
/* Have to handle the 2 basic types of cards here */
if ((dst_check_ca_pmt(state, p_ca_message, hw_buffer)) < 0) {
dprintk(verbose, DST_CA_ERROR, 1, " -->CA_PMT_REPLY Failed !");
result = -1;
goto free_mem_and_exit;
}
dprintk(verbose, DST_CA_INFO, 1, " -->CA_PMT_REPLY Success !");
break;
case CA_APP_INFO_ENQUIRY: // only for debugging
dprintk(verbose, DST_CA_INFO, 1, " Getting Cam Application information");
if ((ca_get_app_info(state)) < 0) {
dprintk(verbose, DST_CA_ERROR, 1, " -->CA_APP_INFO_ENQUIRY Failed !");
result = -1;
goto free_mem_and_exit;
}
dprintk(verbose, DST_CA_INFO, 1, " -->CA_APP_INFO_ENQUIRY Success !");
break;
case CA_INFO_ENQUIRY:
dprintk(verbose, DST_CA_INFO, 1, " Getting CA Information");
if ((ca_get_ca_info(state)) < 0) {
dprintk(verbose, DST_CA_ERROR, 1, " -->CA_INFO_ENQUIRY Failed !");
result = -1;
goto free_mem_and_exit;
}
dprintk(verbose, DST_CA_INFO, 1, " -->CA_INFO_ENQUIRY Success !");
break;
}
}
free_mem_and_exit:
kfree (hw_buffer);
return result;
}
static long dst_ca_ioctl(struct file *file, unsigned int cmd, unsigned long ioctl_arg)
{
struct dvb_device *dvbdev;
struct dst_state *state;
struct ca_slot_info *p_ca_slot_info;
struct ca_caps *p_ca_caps;
struct ca_msg *p_ca_message;
void __user *arg = (void __user *)ioctl_arg;
int result = 0;
lock_kernel();
dvbdev = (struct dvb_device *)file->private_data;
state = (struct dst_state *)dvbdev->priv;
p_ca_message = kmalloc(sizeof (struct ca_msg), GFP_KERNEL);
p_ca_slot_info = kmalloc(sizeof (struct ca_slot_info), GFP_KERNEL);
p_ca_caps = kmalloc(sizeof (struct ca_caps), GFP_KERNEL);
if (!p_ca_message || !p_ca_slot_info || !p_ca_caps) {
dprintk(verbose, DST_CA_ERROR, 1, " Memory allocation failure");
result = -ENOMEM;
goto free_mem_and_exit;
}
/* We have now only the standard ioctl's, the driver is upposed to handle internals. */
switch (cmd) {
case CA_SEND_MSG:
dprintk(verbose, DST_CA_INFO, 1, " Sending message");
if ((ca_send_message(state, p_ca_message, arg)) < 0) {
dprintk(verbose, DST_CA_ERROR, 1, " -->CA_SEND_MSG Failed !");
result = -1;
goto free_mem_and_exit;
}
break;
case CA_GET_MSG:
dprintk(verbose, DST_CA_INFO, 1, " Getting message");
if ((ca_get_message(state, p_ca_message, arg)) < 0) {
dprintk(verbose, DST_CA_ERROR, 1, " -->CA_GET_MSG Failed !");
result = -1;
goto free_mem_and_exit;
}
dprintk(verbose, DST_CA_INFO, 1, " -->CA_GET_MSG Success !");
break;
case CA_RESET:
dprintk(verbose, DST_CA_ERROR, 1, " Resetting DST");
dst_error_bailout(state);
msleep(4000);
break;
case CA_GET_SLOT_INFO:
dprintk(verbose, DST_CA_INFO, 1, " Getting Slot info");
if ((ca_get_slot_info(state, p_ca_slot_info, arg)) < 0) {
dprintk(verbose, DST_CA_ERROR, 1, " -->CA_GET_SLOT_INFO Failed !");
result = -1;
goto free_mem_and_exit;
}
dprintk(verbose, DST_CA_INFO, 1, " -->CA_GET_SLOT_INFO Success !");
break;
case CA_GET_CAP:
dprintk(verbose, DST_CA_INFO, 1, " Getting Slot capabilities");
if ((ca_get_slot_caps(state, p_ca_caps, arg)) < 0) {
dprintk(verbose, DST_CA_ERROR, 1, " -->CA_GET_CAP Failed !");
result = -1;
goto free_mem_and_exit;
}
dprintk(verbose, DST_CA_INFO, 1, " -->CA_GET_CAP Success !");
break;
case CA_GET_DESCR_INFO:
dprintk(verbose, DST_CA_INFO, 1, " Getting descrambler description");
if ((ca_get_slot_descr(state, p_ca_message, arg)) < 0) {
dprintk(verbose, DST_CA_ERROR, 1, " -->CA_GET_DESCR_INFO Failed !");
result = -1;
goto free_mem_and_exit;
}
dprintk(verbose, DST_CA_INFO, 1, " -->CA_GET_DESCR_INFO Success !");
break;
case CA_SET_DESCR:
dprintk(verbose, DST_CA_INFO, 1, " Setting descrambler");
if ((ca_set_slot_descr()) < 0) {
dprintk(verbose, DST_CA_ERROR, 1, " -->CA_SET_DESCR Failed !");
result = -1;
goto free_mem_and_exit;
}
dprintk(verbose, DST_CA_INFO, 1, " -->CA_SET_DESCR Success !");
break;
case CA_SET_PID:
dprintk(verbose, DST_CA_INFO, 1, " Setting PID");
if ((ca_set_pid()) < 0) {
dprintk(verbose, DST_CA_ERROR, 1, " -->CA_SET_PID Failed !");
result = -1;
goto free_mem_and_exit;
}
dprintk(verbose, DST_CA_INFO, 1, " -->CA_SET_PID Success !");
default:
result = -EOPNOTSUPP;
};
free_mem_and_exit:
kfree (p_ca_message);
kfree (p_ca_slot_info);
kfree (p_ca_caps);
unlock_kernel();
return result;
}
static int dst_ca_open(struct inode *inode, struct file *file)
{
dprintk(verbose, DST_CA_DEBUG, 1, " Device opened [%p] ", file);
try_module_get(THIS_MODULE);
return 0;
}
static int dst_ca_release(struct inode *inode, struct file *file)
{
dprintk(verbose, DST_CA_DEBUG, 1, " Device closed.");
module_put(THIS_MODULE);
return 0;
}
static ssize_t dst_ca_read(struct file *file, char __user *buffer, size_t length, loff_t *offset)
{
ssize_t bytes_read = 0;
dprintk(verbose, DST_CA_DEBUG, 1, " Device read.");
return bytes_read;
}
static ssize_t dst_ca_write(struct file *file, const char __user *buffer, size_t length, loff_t *offset)
{
dprintk(verbose, DST_CA_DEBUG, 1, " Device write.");
return 0;
}
static const struct file_operations dst_ca_fops = {
.owner = THIS_MODULE,
.unlocked_ioctl = dst_ca_ioctl,
.open = dst_ca_open,
.release = dst_ca_release,
.read = dst_ca_read,
.write = dst_ca_write
};
static struct dvb_device dvbdev_ca = {
.priv = NULL,
.users = 1,
.readers = 1,
.writers = 1,
.fops = &dst_ca_fops
};
struct dvb_device *dst_ca_attach(struct dst_state *dst, struct dvb_adapter *dvb_adapter)
{
struct dvb_device *dvbdev;
dprintk(verbose, DST_CA_ERROR, 1, "registering DST-CA device");
if (dvb_register_device(dvb_adapter, &dvbdev, &dvbdev_ca, dst, DVB_DEVICE_CA) == 0) {
dst->dst_ca = dvbdev;
return dst->dst_ca;
}
return NULL;
}
EXPORT_SYMBOL(dst_ca_attach);
MODULE_DESCRIPTION("DST DVB-S/T/C Combo CA driver");
MODULE_AUTHOR("Manu Abraham");
MODULE_LICENSE("GPL");

View File

@@ -0,0 +1,58 @@
/*
CA-driver for TwinHan DST Frontend/Card
Copyright (C) 2004, 2005 Manu Abraham (manu@kromtek.com)
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; either version 2 of the License, or
(at your option) any later version.
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.
*/
#ifndef _DST_CA_H_
#define _DST_CA_H_
#define RETRIES 5
#define CA_APP_INFO_ENQUIRY 0x9f8020
#define CA_APP_INFO 0x9f8021
#define CA_ENTER_MENU 0x9f8022
#define CA_INFO_ENQUIRY 0x9f8030
#define CA_INFO 0x9f8031
#define CA_PMT 0x9f8032
#define CA_PMT_REPLY 0x9f8033
#define CA_CLOSE_MMI 0x9f8800
#define CA_DISPLAY_CONTROL 0x9f8801
#define CA_DISPLAY_REPLY 0x9f8802
#define CA_TEXT_LAST 0x9f8803
#define CA_TEXT_MORE 0x9f8804
#define CA_KEYPAD_CONTROL 0x9f8805
#define CA_KEYPRESS 0x9f8806
#define CA_ENQUIRY 0x9f8807
#define CA_ANSWER 0x9f8808
#define CA_MENU_LAST 0x9f8809
#define CA_MENU_MORE 0x9f880a
#define CA_MENU_ANSWER 0x9f880b
#define CA_LIST_LAST 0x9f880c
#define CA_LIST_MORE 0x9f880d
struct dst_ca_private {
struct dst_state *dst;
struct dvb_device *dvbdev;
};
#endif

View File

@@ -0,0 +1,182 @@
/*
Frontend-driver for TwinHan DST Frontend
Copyright (C) 2003 Jamie Honan
Copyright (C) 2004, 2005 Manu Abraham (manu@kromtek.com)
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; either version 2 of the License, or
(at your option) any later version.
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.
*/
#ifndef DST_COMMON_H
#define DST_COMMON_H
#include <linux/dvb/frontend.h>
#include <linux/device.h>
#include <linux/mutex.h>
#include "bt878.h"
#include "dst_ca.h"
#define NO_DELAY 0
#define LONG_DELAY 1
#define DEVICE_INIT 2
#define DELAY 1
#define DST_TYPE_IS_SAT 0
#define DST_TYPE_IS_TERR 1
#define DST_TYPE_IS_CABLE 2
#define DST_TYPE_IS_ATSC 3
#define DST_TYPE_HAS_TS188 1
#define DST_TYPE_HAS_TS204 2
#define DST_TYPE_HAS_SYMDIV 4
#define DST_TYPE_HAS_FW_1 8
#define DST_TYPE_HAS_FW_2 16
#define DST_TYPE_HAS_FW_3 32
#define DST_TYPE_HAS_FW_BUILD 64
#define DST_TYPE_HAS_OBS_REGS 128
#define DST_TYPE_HAS_INC_COUNT 256
#define DST_TYPE_HAS_MULTI_FE 512
#define DST_TYPE_HAS_NEWTUNE_2 1024
#define DST_TYPE_HAS_DBOARD 2048
#define DST_TYPE_HAS_VLF 4096
/* Card capability list */
#define DST_TYPE_HAS_MAC 1
#define DST_TYPE_HAS_DISEQC3 2
#define DST_TYPE_HAS_DISEQC4 4
#define DST_TYPE_HAS_DISEQC5 8
#define DST_TYPE_HAS_MOTO 16
#define DST_TYPE_HAS_CA 32
#define DST_TYPE_HAS_ANALOG 64 /* Analog inputs */
#define DST_TYPE_HAS_SESSION 128
#define TUNER_TYPE_MULTI 1
#define TUNER_TYPE_UNKNOWN 2
/* DVB-S */
#define TUNER_TYPE_L64724 4
#define TUNER_TYPE_STV0299 8
#define TUNER_TYPE_MB86A15 16
/* DVB-T */
#define TUNER_TYPE_TDA10046 32
/* ATSC */
#define TUNER_TYPE_NXT200x 64
#define RDC_8820_PIO_0_DISABLE 0
#define RDC_8820_PIO_0_ENABLE 1
#define RDC_8820_INT 2
#define RDC_8820_RESET 4
/* DST Communication */
#define GET_REPLY 1
#define NO_REPLY 0
#define GET_ACK 1
#define FIXED_COMM 8
#define ACK 0xff
struct dst_state {
struct i2c_adapter* i2c;
struct bt878* bt;
/* configuration settings */
const struct dst_config* config;
struct dvb_frontend frontend;
/* private ASIC data */
u8 tx_tuna[10];
u8 rx_tuna[10];
u8 rxbuffer[10];
u8 diseq_flags;
u8 dst_type;
u32 type_flags;
u32 frequency; /* intermediate frequency in kHz for QPSK */
fe_spectral_inversion_t inversion;
u32 symbol_rate; /* symbol rate in Symbols per second */
fe_code_rate_t fec;
fe_sec_voltage_t voltage;
fe_sec_tone_mode_t tone;
u32 decode_freq;
u8 decode_lock;
u16 decode_strength;
u16 decode_snr;
unsigned long cur_jiff;
u8 k22;
fe_bandwidth_t bandwidth;
u32 dst_hw_cap;
u8 dst_fw_version;
fe_sec_mini_cmd_t minicmd;
fe_modulation_t modulation;
u8 messages[256];
u8 mac_address[8];
u8 fw_version[8];
u8 card_info[8];
u8 vendor[8];
u8 board_info[8];
u32 tuner_type;
char *tuner_name;
struct mutex dst_mutex;
u8 fw_name[8];
struct dvb_device *dst_ca;
};
struct tuner_types {
u32 tuner_type;
char *tuner_name;
char *board_name;
char *fw_name;
};
struct dst_types {
char *device_id;
int offset;
u8 dst_type;
u32 type_flags;
u32 dst_feature;
u32 tuner_type;
};
struct dst_config
{
/* the ASIC i2c address */
u8 demod_address;
};
int rdc_reset_state(struct dst_state *state);
int dst_wait_dst_ready(struct dst_state *state, u8 delay_mode);
int dst_pio_disable(struct dst_state *state);
int dst_error_recovery(struct dst_state* state);
int dst_error_bailout(struct dst_state *state);
int dst_comm_init(struct dst_state* state);
int write_dst(struct dst_state *state, u8 * data, u8 len);
int read_dst(struct dst_state *state, u8 * ret, u8 len);
u8 dst_check_sum(u8 * buf, u32 len);
struct dst_state* dst_attach(struct dst_state* state, struct dvb_adapter *dvb_adapter);
struct dvb_device *dst_ca_attach(struct dst_state *state, struct dvb_adapter *dvb_adapter);
#endif // DST_COMMON_H

View File

@@ -0,0 +1,35 @@
/*
* dst-bt878.h: part of the DST driver for the TwinHan DST Frontend
*
* Copyright (C) 2003 Jamie Honan
*/
struct dst_gpio_enable {
u32 mask;
u32 enable;
};
struct dst_gpio_output {
u32 mask;
u32 highvals;
};
struct dst_gpio_read {
unsigned long value;
};
union dst_gpio_packet {
struct dst_gpio_enable enb;
struct dst_gpio_output outp;
struct dst_gpio_read rd;
int psize;
};
#define DST_IG_ENABLE 0
#define DST_IG_WRITE 1
#define DST_IG_READ 2
#define DST_IG_TS 3
struct bt878;
int bt878_device_control(struct bt878 *bt, unsigned int cmd, union dst_gpio_packet *mp);

View File

@@ -0,0 +1,970 @@
/*
* Bt8xx based DVB adapter driver
*
* Copyright (C) 2002,2003 Florian Schirmer <jolt@tuxbox.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; either version 2 of the License, or
* (at your option) any later version.
*
* 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/bitops.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/device.h>
#include <linux/delay.h>
#include <linux/slab.h>
#include <linux/i2c.h>
#include "dmxdev.h"
#include "dvbdev.h"
#include "dvb_demux.h"
#include "dvb_frontend.h"
#include "dvb-bt8xx.h"
#include "bt878.h"
static int debug;
module_param(debug, int, 0644);
MODULE_PARM_DESC(debug, "Turn on/off debugging (default:off).");
DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
#define dprintk( args... ) \
do { \
if (debug) printk(KERN_DEBUG args); \
} while (0)
#define IF_FREQUENCYx6 217 /* 6 * 36.16666666667MHz */
static void dvb_bt8xx_task(unsigned long data)
{
struct dvb_bt8xx_card *card = (struct dvb_bt8xx_card *)data;
//printk("%d ", card->bt->finished_block);
while (card->bt->last_block != card->bt->finished_block) {
(card->bt->TS_Size ? dvb_dmx_swfilter_204 : dvb_dmx_swfilter)
(&card->demux,
&card->bt->buf_cpu[card->bt->last_block *
card->bt->block_bytes],
card->bt->block_bytes);
card->bt->last_block = (card->bt->last_block + 1) %
card->bt->block_count;
}
}
static int dvb_bt8xx_start_feed(struct dvb_demux_feed *dvbdmxfeed)
{
struct dvb_demux*dvbdmx = dvbdmxfeed->demux;
struct dvb_bt8xx_card *card = dvbdmx->priv;
int rc;
dprintk("dvb_bt8xx: start_feed\n");
if (!dvbdmx->dmx.frontend)
return -EINVAL;
mutex_lock(&card->lock);
card->nfeeds++;
rc = card->nfeeds;
if (card->nfeeds == 1)
bt878_start(card->bt, card->gpio_mode,
card->op_sync_orin, card->irq_err_ignore);
mutex_unlock(&card->lock);
return rc;
}
static int dvb_bt8xx_stop_feed(struct dvb_demux_feed *dvbdmxfeed)
{
struct dvb_demux *dvbdmx = dvbdmxfeed->demux;
struct dvb_bt8xx_card *card = dvbdmx->priv;
dprintk("dvb_bt8xx: stop_feed\n");
if (!dvbdmx->dmx.frontend)
return -EINVAL;
mutex_lock(&card->lock);
card->nfeeds--;
if (card->nfeeds == 0)
bt878_stop(card->bt);
mutex_unlock(&card->lock);
return 0;
}
static int is_pci_slot_eq(struct pci_dev* adev, struct pci_dev* bdev)
{
if ((adev->subsystem_vendor == bdev->subsystem_vendor) &&
(adev->subsystem_device == bdev->subsystem_device) &&
(adev->bus->number == bdev->bus->number) &&
(PCI_SLOT(adev->devfn) == PCI_SLOT(bdev->devfn)))
return 1;
return 0;
}
static struct bt878 __devinit *dvb_bt8xx_878_match(unsigned int bttv_nr, struct pci_dev* bttv_pci_dev)
{
unsigned int card_nr;
/* Hmm, n squared. Hope n is small */
for (card_nr = 0; card_nr < bt878_num; card_nr++)
if (is_pci_slot_eq(bt878[card_nr].dev, bttv_pci_dev))
return &bt878[card_nr];
return NULL;
}
static int thomson_dtt7579_demod_init(struct dvb_frontend* fe)
{
static u8 mt352_clock_config [] = { 0x89, 0x38, 0x38 };
static u8 mt352_reset [] = { 0x50, 0x80 };
static u8 mt352_adc_ctl_1_cfg [] = { 0x8E, 0x40 };
static u8 mt352_agc_cfg [] = { 0x67, 0x28, 0x20 };
static u8 mt352_gpp_ctl_cfg [] = { 0x8C, 0x33 };
static u8 mt352_capt_range_cfg[] = { 0x75, 0x32 };
mt352_write(fe, mt352_clock_config, sizeof(mt352_clock_config));
udelay(2000);
mt352_write(fe, mt352_reset, sizeof(mt352_reset));
mt352_write(fe, mt352_adc_ctl_1_cfg, sizeof(mt352_adc_ctl_1_cfg));
mt352_write(fe, mt352_agc_cfg, sizeof(mt352_agc_cfg));
mt352_write(fe, mt352_gpp_ctl_cfg, sizeof(mt352_gpp_ctl_cfg));
mt352_write(fe, mt352_capt_range_cfg, sizeof(mt352_capt_range_cfg));
return 0;
}
static int thomson_dtt7579_tuner_calc_regs(struct dvb_frontend* fe, struct dvb_frontend_parameters* params, u8* pllbuf, int buf_len)
{
u32 div;
unsigned char bs = 0;
unsigned char cp = 0;
if (buf_len < 5)
return -EINVAL;
div = (((params->frequency + 83333) * 3) / 500000) + IF_FREQUENCYx6;
if (params->frequency < 542000000)
cp = 0xb4;
else if (params->frequency < 771000000)
cp = 0xbc;
else
cp = 0xf4;
if (params->frequency == 0)
bs = 0x03;
else if (params->frequency < 443250000)
bs = 0x02;
else
bs = 0x08;
pllbuf[0] = 0x60;
pllbuf[1] = div >> 8;
pllbuf[2] = div & 0xff;
pllbuf[3] = cp;
pllbuf[4] = bs;
return 5;
}
static struct mt352_config thomson_dtt7579_config = {
.demod_address = 0x0f,
.demod_init = thomson_dtt7579_demod_init,
};
static struct zl10353_config thomson_dtt7579_zl10353_config = {
.demod_address = 0x0f,
};
static int cx24108_tuner_set_params(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
{
u32 freq = params->frequency;
int i, a, n, pump;
u32 band, pll;
u32 osci[]={950000,1019000,1075000,1178000,1296000,1432000,
1576000,1718000,1856000,2036000,2150000};
u32 bandsel[]={0,0x00020000,0x00040000,0x00100800,0x00101000,
0x00102000,0x00104000,0x00108000,0x00110000,
0x00120000,0x00140000};
#define XTAL 1011100 /* Hz, really 1.0111 MHz and a /10 prescaler */
printk("cx24108 debug: entering SetTunerFreq, freq=%d\n",freq);
/* This is really the bit driving the tuner chip cx24108 */
if (freq<950000)
freq = 950000; /* kHz */
else if (freq>2150000)
freq = 2150000; /* satellite IF is 950..2150MHz */
/* decide which VCO to use for the input frequency */
for(i = 1; (i < ARRAY_SIZE(osci)) && (osci[i] < freq); i++);
printk("cx24108 debug: select vco #%d (f=%d)\n",i,freq);
band=bandsel[i];
/* the gain values must be set by SetSymbolrate */
/* compute the pll divider needed, from Conexant data sheet,
resolved for (n*32+a), remember f(vco) is f(receive) *2 or *4,
depending on the divider bit. It is set to /4 on the 2 lowest
bands */
n=((i<=2?2:1)*freq*10L)/(XTAL/100);
a=n%32; n/=32; if(a==0) n--;
pump=(freq<(osci[i-1]+osci[i])/2);
pll=0xf8000000|
((pump?1:2)<<(14+11))|
((n&0x1ff)<<(5+11))|
((a&0x1f)<<11);
/* everything is shifted left 11 bits to left-align the bits in the
32bit word. Output to the tuner goes MSB-aligned, after all */
printk("cx24108 debug: pump=%d, n=%d, a=%d\n",pump,n,a);
cx24110_pll_write(fe,band);
/* set vga and vca to their widest-band settings, as a precaution.
SetSymbolrate might not be called to set this up */
cx24110_pll_write(fe,0x500c0000);
cx24110_pll_write(fe,0x83f1f800);
cx24110_pll_write(fe,pll);
//writereg(client,0x56,0x7f);
return 0;
}
static int pinnsat_tuner_init(struct dvb_frontend* fe)
{
struct dvb_bt8xx_card *card = fe->dvb->priv;
bttv_gpio_enable(card->bttv_nr, 1, 1); /* output */
bttv_write_gpio(card->bttv_nr, 1, 1); /* relay on */
return 0;
}
static int pinnsat_tuner_sleep(struct dvb_frontend* fe)
{
struct dvb_bt8xx_card *card = fe->dvb->priv;
bttv_write_gpio(card->bttv_nr, 1, 0); /* relay off */
return 0;
}
static struct cx24110_config pctvsat_config = {
.demod_address = 0x55,
};
static int microtune_mt7202dtf_tuner_set_params(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
{
struct dvb_bt8xx_card *card = (struct dvb_bt8xx_card *) fe->dvb->priv;
u8 cfg, cpump, band_select;
u8 data[4];
u32 div;
struct i2c_msg msg = { .addr = 0x60, .flags = 0, .buf = data, .len = sizeof(data) };
div = (36000000 + params->frequency + 83333) / 166666;
cfg = 0x88;
if (params->frequency < 175000000)
cpump = 2;
else if (params->frequency < 390000000)
cpump = 1;
else if (params->frequency < 470000000)
cpump = 2;
else if (params->frequency < 750000000)
cpump = 2;
else
cpump = 3;
if (params->frequency < 175000000)
band_select = 0x0e;
else if (params->frequency < 470000000)
band_select = 0x05;
else
band_select = 0x03;
data[0] = (div >> 8) & 0x7f;
data[1] = div & 0xff;
data[2] = ((div >> 10) & 0x60) | cfg;
data[3] = (cpump << 6) | band_select;
if (fe->ops.i2c_gate_ctrl)
fe->ops.i2c_gate_ctrl(fe, 1);
i2c_transfer(card->i2c_adapter, &msg, 1);
return (div * 166666 - 36000000);
}
static int microtune_mt7202dtf_request_firmware(struct dvb_frontend* fe, const struct firmware **fw, char* name)
{
struct dvb_bt8xx_card* bt = (struct dvb_bt8xx_card*) fe->dvb->priv;
return request_firmware(fw, name, &bt->bt->dev->dev);
}
static struct sp887x_config microtune_mt7202dtf_config = {
.demod_address = 0x70,
.request_firmware = microtune_mt7202dtf_request_firmware,
};
static int advbt771_samsung_tdtc9251dh0_demod_init(struct dvb_frontend* fe)
{
static u8 mt352_clock_config [] = { 0x89, 0x38, 0x2d };
static u8 mt352_reset [] = { 0x50, 0x80 };
static u8 mt352_adc_ctl_1_cfg [] = { 0x8E, 0x40 };
static u8 mt352_agc_cfg [] = { 0x67, 0x10, 0x23, 0x00, 0xFF, 0xFF,
0x00, 0xFF, 0x00, 0x40, 0x40 };
static u8 mt352_av771_extra[] = { 0xB5, 0x7A };
static u8 mt352_capt_range_cfg[] = { 0x75, 0x32 };
mt352_write(fe, mt352_clock_config, sizeof(mt352_clock_config));
udelay(2000);
mt352_write(fe, mt352_reset, sizeof(mt352_reset));
mt352_write(fe, mt352_adc_ctl_1_cfg, sizeof(mt352_adc_ctl_1_cfg));
mt352_write(fe, mt352_agc_cfg,sizeof(mt352_agc_cfg));
udelay(2000);
mt352_write(fe, mt352_av771_extra,sizeof(mt352_av771_extra));
mt352_write(fe, mt352_capt_range_cfg, sizeof(mt352_capt_range_cfg));
return 0;
}
static int advbt771_samsung_tdtc9251dh0_tuner_calc_regs(struct dvb_frontend* fe, struct dvb_frontend_parameters* params, u8* pllbuf, int buf_len)
{
u32 div;
unsigned char bs = 0;
unsigned char cp = 0;
if (buf_len < 5) return -EINVAL;
div = (((params->frequency + 83333) * 3) / 500000) + IF_FREQUENCYx6;
if (params->frequency < 150000000)
cp = 0xB4;
else if (params->frequency < 173000000)
cp = 0xBC;
else if (params->frequency < 250000000)
cp = 0xB4;
else if (params->frequency < 400000000)
cp = 0xBC;
else if (params->frequency < 420000000)
cp = 0xF4;
else if (params->frequency < 470000000)
cp = 0xFC;
else if (params->frequency < 600000000)
cp = 0xBC;
else if (params->frequency < 730000000)
cp = 0xF4;
else
cp = 0xFC;
if (params->frequency < 150000000)
bs = 0x01;
else if (params->frequency < 173000000)
bs = 0x01;
else if (params->frequency < 250000000)
bs = 0x02;
else if (params->frequency < 400000000)
bs = 0x02;
else if (params->frequency < 420000000)
bs = 0x02;
else if (params->frequency < 470000000)
bs = 0x02;
else if (params->frequency < 600000000)
bs = 0x08;
else if (params->frequency < 730000000)
bs = 0x08;
else
bs = 0x08;
pllbuf[0] = 0x61;
pllbuf[1] = div >> 8;
pllbuf[2] = div & 0xff;
pllbuf[3] = cp;
pllbuf[4] = bs;
return 5;
}
static struct mt352_config advbt771_samsung_tdtc9251dh0_config = {
.demod_address = 0x0f,
.demod_init = advbt771_samsung_tdtc9251dh0_demod_init,
};
static struct dst_config dst_config = {
.demod_address = 0x55,
};
static int or51211_request_firmware(struct dvb_frontend* fe, const struct firmware **fw, char* name)
{
struct dvb_bt8xx_card* bt = (struct dvb_bt8xx_card*) fe->dvb->priv;
return request_firmware(fw, name, &bt->bt->dev->dev);
}
static void or51211_setmode(struct dvb_frontend * fe, int mode)
{
struct dvb_bt8xx_card *bt = fe->dvb->priv;
bttv_write_gpio(bt->bttv_nr, 0x0002, mode); /* Reset */
msleep(20);
}
static void or51211_reset(struct dvb_frontend * fe)
{
struct dvb_bt8xx_card *bt = fe->dvb->priv;
/* RESET DEVICE
* reset is controled by GPIO-0
* when set to 0 causes reset and when to 1 for normal op
* must remain reset for 128 clock cycles on a 50Mhz clock
* also PRM1 PRM2 & PRM4 are controled by GPIO-1,GPIO-2 & GPIO-4
* We assume that the reset has be held low long enough or we
* have been reset by a power on. When the driver is unloaded
* reset set to 0 so if reloaded we have been reset.
*/
/* reset & PRM1,2&4 are outputs */
int ret = bttv_gpio_enable(bt->bttv_nr, 0x001F, 0x001F);
if (ret != 0)
printk(KERN_WARNING "or51211: Init Error - Can't Reset DVR (%i)\n", ret);
bttv_write_gpio(bt->bttv_nr, 0x001F, 0x0000); /* Reset */
msleep(20);
/* Now set for normal operation */
bttv_write_gpio(bt->bttv_nr, 0x0001F, 0x0001);
/* wait for operation to begin */
msleep(500);
}
static void or51211_sleep(struct dvb_frontend * fe)
{
struct dvb_bt8xx_card *bt = fe->dvb->priv;
bttv_write_gpio(bt->bttv_nr, 0x0001, 0x0000);
}
static struct or51211_config or51211_config = {
.demod_address = 0x15,
.request_firmware = or51211_request_firmware,
.setmode = or51211_setmode,
.reset = or51211_reset,
.sleep = or51211_sleep,
};
static int vp3021_alps_tded4_tuner_set_params(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
{
struct dvb_bt8xx_card *card = (struct dvb_bt8xx_card *) fe->dvb->priv;
u8 buf[4];
u32 div;
struct i2c_msg msg = { .addr = 0x60, .flags = 0, .buf = buf, .len = sizeof(buf) };
div = (params->frequency + 36166667) / 166667;
buf[0] = (div >> 8) & 0x7F;
buf[1] = div & 0xFF;
buf[2] = 0x85;
if ((params->frequency >= 47000000) && (params->frequency < 153000000))
buf[3] = 0x01;
else if ((params->frequency >= 153000000) && (params->frequency < 430000000))
buf[3] = 0x02;
else if ((params->frequency >= 430000000) && (params->frequency < 824000000))
buf[3] = 0x0C;
else if ((params->frequency >= 824000000) && (params->frequency < 863000000))
buf[3] = 0x8C;
else
return -EINVAL;
if (fe->ops.i2c_gate_ctrl)
fe->ops.i2c_gate_ctrl(fe, 1);
i2c_transfer(card->i2c_adapter, &msg, 1);
return 0;
}
static struct nxt6000_config vp3021_alps_tded4_config = {
.demod_address = 0x0a,
.clock_inversion = 1,
};
static int digitv_alps_tded4_demod_init(struct dvb_frontend* fe)
{
static u8 mt352_clock_config [] = { 0x89, 0x38, 0x2d };
static u8 mt352_reset [] = { 0x50, 0x80 };
static u8 mt352_adc_ctl_1_cfg [] = { 0x8E, 0x40 };
static u8 mt352_agc_cfg [] = { 0x67, 0x20, 0xa0 };
static u8 mt352_capt_range_cfg[] = { 0x75, 0x32 };
mt352_write(fe, mt352_clock_config, sizeof(mt352_clock_config));
udelay(2000);
mt352_write(fe, mt352_reset, sizeof(mt352_reset));
mt352_write(fe, mt352_adc_ctl_1_cfg, sizeof(mt352_adc_ctl_1_cfg));
mt352_write(fe, mt352_agc_cfg,sizeof(mt352_agc_cfg));
mt352_write(fe, mt352_capt_range_cfg, sizeof(mt352_capt_range_cfg));
return 0;
}
static int digitv_alps_tded4_tuner_calc_regs(struct dvb_frontend* fe, struct dvb_frontend_parameters* params, u8* pllbuf, int buf_len)
{
u32 div;
struct dvb_ofdm_parameters *op = &params->u.ofdm;
if (buf_len < 5)
return -EINVAL;
div = (((params->frequency + 83333) * 3) / 500000) + IF_FREQUENCYx6;
pllbuf[0] = 0x61;
pllbuf[1] = (div >> 8) & 0x7F;
pllbuf[2] = div & 0xFF;
pllbuf[3] = 0x85;
dprintk("frequency %u, div %u\n", params->frequency, div);
if (params->frequency < 470000000)
pllbuf[4] = 0x02;
else if (params->frequency > 823000000)
pllbuf[4] = 0x88;
else
pllbuf[4] = 0x08;
if (op->bandwidth == 8)
pllbuf[4] |= 0x04;
return 5;
}
static void digitv_alps_tded4_reset(struct dvb_bt8xx_card *bt)
{
/*
* Reset the frontend, must be called before trying
* to initialise the MT352 or mt352_attach
* will fail. Same goes for the nxt6000 frontend.
*
*/
int ret = bttv_gpio_enable(bt->bttv_nr, 0x08, 0x08);
if (ret != 0)
printk(KERN_WARNING "digitv_alps_tded4: Init Error - Can't Reset DVR (%i)\n", ret);
/* Pulse the reset line */
bttv_write_gpio(bt->bttv_nr, 0x08, 0x08); /* High */
bttv_write_gpio(bt->bttv_nr, 0x08, 0x00); /* Low */
msleep(100);
bttv_write_gpio(bt->bttv_nr, 0x08, 0x08); /* High */
}
static struct mt352_config digitv_alps_tded4_config = {
.demod_address = 0x0a,
.demod_init = digitv_alps_tded4_demod_init,
};
static struct lgdt330x_config tdvs_tua6034_config = {
.demod_address = 0x0e,
.demod_chip = LGDT3303,
.serial_mpeg = 0x40, /* TPSERIAL for 3303 in TOP_CONTROL */
};
static void lgdt330x_reset(struct dvb_bt8xx_card *bt)
{
/* Set pin 27 of the lgdt3303 chip high to reset the frontend */
/* Pulse the reset line */
bttv_write_gpio(bt->bttv_nr, 0x00e00007, 0x00000001); /* High */
bttv_write_gpio(bt->bttv_nr, 0x00e00007, 0x00000000); /* Low */
msleep(100);
bttv_write_gpio(bt->bttv_nr, 0x00e00007, 0x00000001); /* High */
msleep(100);
}
static void frontend_init(struct dvb_bt8xx_card *card, u32 type)
{
struct dst_state* state = NULL;
switch(type) {
case BTTV_BOARD_DVICO_DVBT_LITE:
card->fe = dvb_attach(mt352_attach, &thomson_dtt7579_config, card->i2c_adapter);
if (card->fe == NULL)
card->fe = dvb_attach(zl10353_attach, &thomson_dtt7579_zl10353_config,
card->i2c_adapter);
if (card->fe != NULL) {
card->fe->ops.tuner_ops.calc_regs = thomson_dtt7579_tuner_calc_regs;
card->fe->ops.info.frequency_min = 174000000;
card->fe->ops.info.frequency_max = 862000000;
}
break;
case BTTV_BOARD_DVICO_FUSIONHDTV_5_LITE:
lgdt330x_reset(card);
card->fe = dvb_attach(lgdt330x_attach, &tdvs_tua6034_config, card->i2c_adapter);
if (card->fe != NULL) {
dvb_attach(simple_tuner_attach, card->fe,
card->i2c_adapter, 0x61,
TUNER_LG_TDVS_H06XF);
dprintk ("dvb_bt8xx: lgdt330x detected\n");
}
break;
case BTTV_BOARD_NEBULA_DIGITV:
/*
* It is possible to determine the correct frontend using the I2C bus (see the Nebula SDK);
* this would be a cleaner solution than trying each frontend in turn.
*/
/* Old Nebula (marked (c)2003 on high profile pci card) has nxt6000 demod */
digitv_alps_tded4_reset(card);
card->fe = dvb_attach(nxt6000_attach, &vp3021_alps_tded4_config, card->i2c_adapter);
if (card->fe != NULL) {
card->fe->ops.tuner_ops.set_params = vp3021_alps_tded4_tuner_set_params;
dprintk ("dvb_bt8xx: an nxt6000 was detected on your digitv card\n");
break;
}
/* New Nebula (marked (c)2005 on low profile pci card) has mt352 demod */
digitv_alps_tded4_reset(card);
card->fe = dvb_attach(mt352_attach, &digitv_alps_tded4_config, card->i2c_adapter);
if (card->fe != NULL) {
card->fe->ops.tuner_ops.calc_regs = digitv_alps_tded4_tuner_calc_regs;
dprintk ("dvb_bt8xx: an mt352 was detected on your digitv card\n");
}
break;
case BTTV_BOARD_AVDVBT_761:
card->fe = dvb_attach(sp887x_attach, &microtune_mt7202dtf_config, card->i2c_adapter);
if (card->fe) {
card->fe->ops.tuner_ops.set_params = microtune_mt7202dtf_tuner_set_params;
}
break;
case BTTV_BOARD_AVDVBT_771:
card->fe = dvb_attach(mt352_attach, &advbt771_samsung_tdtc9251dh0_config, card->i2c_adapter);
if (card->fe != NULL) {
card->fe->ops.tuner_ops.calc_regs = advbt771_samsung_tdtc9251dh0_tuner_calc_regs;
card->fe->ops.info.frequency_min = 174000000;
card->fe->ops.info.frequency_max = 862000000;
}
break;
case BTTV_BOARD_TWINHAN_DST:
/* DST is not a frontend driver !!! */
state = kmalloc(sizeof (struct dst_state), GFP_KERNEL);
if (!state) {
printk("dvb_bt8xx: No memory\n");
break;
}
/* Setup the Card */
state->config = &dst_config;
state->i2c = card->i2c_adapter;
state->bt = card->bt;
state->dst_ca = NULL;
/* DST is not a frontend, attaching the ASIC */
if (dvb_attach(dst_attach, state, &card->dvb_adapter) == NULL) {
printk("%s: Could not find a Twinhan DST.\n", __func__);
break;
}
/* Attach other DST peripherals if any */
/* Conditional Access device */
card->fe = &state->frontend;
if (state->dst_hw_cap & DST_TYPE_HAS_CA)
dvb_attach(dst_ca_attach, state, &card->dvb_adapter);
break;
case BTTV_BOARD_PINNACLESAT:
card->fe = dvb_attach(cx24110_attach, &pctvsat_config, card->i2c_adapter);
if (card->fe) {
card->fe->ops.tuner_ops.init = pinnsat_tuner_init;
card->fe->ops.tuner_ops.sleep = pinnsat_tuner_sleep;
card->fe->ops.tuner_ops.set_params = cx24108_tuner_set_params;
}
break;
case BTTV_BOARD_PC_HDTV:
card->fe = dvb_attach(or51211_attach, &or51211_config, card->i2c_adapter);
if (card->fe != NULL)
dvb_attach(simple_tuner_attach, card->fe,
card->i2c_adapter, 0x61,
TUNER_PHILIPS_FCV1236D);
break;
}
if (card->fe == NULL)
printk("dvb-bt8xx: A frontend driver was not found for device [%04x:%04x] subsystem [%04x:%04x]\n",
card->bt->dev->vendor,
card->bt->dev->device,
card->bt->dev->subsystem_vendor,
card->bt->dev->subsystem_device);
else
if (dvb_register_frontend(&card->dvb_adapter, card->fe)) {
printk("dvb-bt8xx: Frontend registration failed!\n");
dvb_frontend_detach(card->fe);
card->fe = NULL;
}
}
static int __devinit dvb_bt8xx_load_card(struct dvb_bt8xx_card *card, u32 type)
{
int result;
result = dvb_register_adapter(&card->dvb_adapter, card->card_name,
THIS_MODULE, &card->bt->dev->dev,
adapter_nr);
if (result < 0) {
printk("dvb_bt8xx: dvb_register_adapter failed (errno = %d)\n", result);
return result;
}
card->dvb_adapter.priv = card;
card->bt->adapter = card->i2c_adapter;
memset(&card->demux, 0, sizeof(struct dvb_demux));
card->demux.dmx.capabilities = DMX_TS_FILTERING | DMX_SECTION_FILTERING | DMX_MEMORY_BASED_FILTERING;
card->demux.priv = card;
card->demux.filternum = 256;
card->demux.feednum = 256;
card->demux.start_feed = dvb_bt8xx_start_feed;
card->demux.stop_feed = dvb_bt8xx_stop_feed;
card->demux.write_to_decoder = NULL;
if ((result = dvb_dmx_init(&card->demux)) < 0) {
printk("dvb_bt8xx: dvb_dmx_init failed (errno = %d)\n", result);
dvb_unregister_adapter(&card->dvb_adapter);
return result;
}
card->dmxdev.filternum = 256;
card->dmxdev.demux = &card->demux.dmx;
card->dmxdev.capabilities = 0;
if ((result = dvb_dmxdev_init(&card->dmxdev, &card->dvb_adapter)) < 0) {
printk("dvb_bt8xx: dvb_dmxdev_init failed (errno = %d)\n", result);
dvb_dmx_release(&card->demux);
dvb_unregister_adapter(&card->dvb_adapter);
return result;
}
card->fe_hw.source = DMX_FRONTEND_0;
if ((result = card->demux.dmx.add_frontend(&card->demux.dmx, &card->fe_hw)) < 0) {
printk("dvb_bt8xx: dvb_dmx_init failed (errno = %d)\n", result);
dvb_dmxdev_release(&card->dmxdev);
dvb_dmx_release(&card->demux);
dvb_unregister_adapter(&card->dvb_adapter);
return result;
}
card->fe_mem.source = DMX_MEMORY_FE;
if ((result = card->demux.dmx.add_frontend(&card->demux.dmx, &card->fe_mem)) < 0) {
printk("dvb_bt8xx: dvb_dmx_init failed (errno = %d)\n", result);
card->demux.dmx.remove_frontend(&card->demux.dmx, &card->fe_hw);
dvb_dmxdev_release(&card->dmxdev);
dvb_dmx_release(&card->demux);
dvb_unregister_adapter(&card->dvb_adapter);
return result;
}
if ((result = card->demux.dmx.connect_frontend(&card->demux.dmx, &card->fe_hw)) < 0) {
printk("dvb_bt8xx: dvb_dmx_init failed (errno = %d)\n", result);
card->demux.dmx.remove_frontend(&card->demux.dmx, &card->fe_mem);
card->demux.dmx.remove_frontend(&card->demux.dmx, &card->fe_hw);
dvb_dmxdev_release(&card->dmxdev);
dvb_dmx_release(&card->demux);
dvb_unregister_adapter(&card->dvb_adapter);
return result;
}
dvb_net_init(&card->dvb_adapter, &card->dvbnet, &card->demux.dmx);
tasklet_init(&card->bt->tasklet, dvb_bt8xx_task, (unsigned long) card);
frontend_init(card, type);
return 0;
}
static int __devinit dvb_bt8xx_probe(struct bttv_sub_device *sub)
{
struct dvb_bt8xx_card *card;
struct pci_dev* bttv_pci_dev;
int ret;
if (!(card = kzalloc(sizeof(struct dvb_bt8xx_card), GFP_KERNEL)))
return -ENOMEM;
mutex_init(&card->lock);
card->bttv_nr = sub->core->nr;
strlcpy(card->card_name, sub->core->v4l2_dev.name, sizeof(card->card_name));
card->i2c_adapter = &sub->core->i2c_adap;
switch(sub->core->type) {
case BTTV_BOARD_PINNACLESAT:
card->gpio_mode = 0x0400c060;
/* should be: BT878_A_GAIN=0,BT878_A_PWRDN,BT878_DA_DPM,BT878_DA_SBR,
BT878_DA_IOM=1,BT878_DA_APP to enable serial highspeed mode. */
card->op_sync_orin = BT878_RISC_SYNC_MASK;
card->irq_err_ignore = BT878_AFBUS | BT878_AFDSR;
break;
case BTTV_BOARD_DVICO_DVBT_LITE:
card->gpio_mode = 0x0400C060;
card->op_sync_orin = BT878_RISC_SYNC_MASK;
card->irq_err_ignore = BT878_AFBUS | BT878_AFDSR;
/* 26, 15, 14, 6, 5
* A_PWRDN DA_DPM DA_SBR DA_IOM_DA
* DA_APP(parallel) */
break;
case BTTV_BOARD_DVICO_FUSIONHDTV_5_LITE:
card->gpio_mode = 0x0400c060;
card->op_sync_orin = BT878_RISC_SYNC_MASK;
card->irq_err_ignore = BT878_AFBUS | BT878_AFDSR;
break;
case BTTV_BOARD_NEBULA_DIGITV:
case BTTV_BOARD_AVDVBT_761:
card->gpio_mode = (1 << 26) | (1 << 14) | (1 << 5);
card->op_sync_orin = BT878_RISC_SYNC_MASK;
card->irq_err_ignore = BT878_AFBUS | BT878_AFDSR;
/* A_PWRDN DA_SBR DA_APP (high speed serial) */
break;
case BTTV_BOARD_AVDVBT_771: //case 0x07711461:
card->gpio_mode = 0x0400402B;
card->op_sync_orin = BT878_RISC_SYNC_MASK;
card->irq_err_ignore = BT878_AFBUS | BT878_AFDSR;
/* A_PWRDN DA_SBR DA_APP[0] PKTP=10 RISC_ENABLE FIFO_ENABLE*/
break;
case BTTV_BOARD_TWINHAN_DST:
card->gpio_mode = 0x2204f2c;
card->op_sync_orin = BT878_RISC_SYNC_MASK;
card->irq_err_ignore = BT878_APABORT | BT878_ARIPERR |
BT878_APPERR | BT878_AFBUS;
/* 25,21,14,11,10,9,8,3,2 then
* 0x33 = 5,4,1,0
* A_SEL=SML, DA_MLB, DA_SBR,
* DA_SDR=f, fifo trigger = 32 DWORDS
* IOM = 0 == audio A/D
* DPM = 0 == digital audio mode
* == async data parallel port
* then 0x33 (13 is set by start_capture)
* DA_APP = async data parallel port,
* ACAP_EN = 1,
* RISC+FIFO ENABLE */
break;
case BTTV_BOARD_PC_HDTV:
card->gpio_mode = 0x0100EC7B;
card->op_sync_orin = BT878_RISC_SYNC_MASK;
card->irq_err_ignore = BT878_AFBUS | BT878_AFDSR;
break;
default:
printk(KERN_WARNING "dvb_bt8xx: Unknown bttv card type: %d.\n",
sub->core->type);
kfree(card);
return -ENODEV;
}
dprintk("dvb_bt8xx: identified card%d as %s\n", card->bttv_nr, card->card_name);
if (!(bttv_pci_dev = bttv_get_pcidev(card->bttv_nr))) {
printk("dvb_bt8xx: no pci device for card %d\n", card->bttv_nr);
kfree(card);
return -EFAULT;
}
if (!(card->bt = dvb_bt8xx_878_match(card->bttv_nr, bttv_pci_dev))) {
printk("dvb_bt8xx: unable to determine DMA core of card %d,\n",
card->bttv_nr);
printk("dvb_bt8xx: if you have the ALSA bt87x audio driver "
"installed, try removing it.\n");
kfree(card);
return -EFAULT;
}
mutex_init(&card->bt->gpio_lock);
card->bt->bttv_nr = sub->core->nr;
if ( (ret = dvb_bt8xx_load_card(card, sub->core->type)) ) {
kfree(card);
return ret;
}
dev_set_drvdata(&sub->dev, card);
return 0;
}
static void dvb_bt8xx_remove(struct bttv_sub_device *sub)
{
struct dvb_bt8xx_card *card = dev_get_drvdata(&sub->dev);
dprintk("dvb_bt8xx: unloading card%d\n", card->bttv_nr);
bt878_stop(card->bt);
tasklet_kill(&card->bt->tasklet);
dvb_net_release(&card->dvbnet);
card->demux.dmx.remove_frontend(&card->demux.dmx, &card->fe_mem);
card->demux.dmx.remove_frontend(&card->demux.dmx, &card->fe_hw);
dvb_dmxdev_release(&card->dmxdev);
dvb_dmx_release(&card->demux);
if (card->fe) {
dvb_unregister_frontend(card->fe);
dvb_frontend_detach(card->fe);
}
dvb_unregister_adapter(&card->dvb_adapter);
kfree(card);
}
static struct bttv_sub_driver driver = {
.drv = {
.name = "dvb-bt8xx",
},
.probe = dvb_bt8xx_probe,
.remove = dvb_bt8xx_remove,
/* FIXME:
* .shutdown = dvb_bt8xx_shutdown,
* .suspend = dvb_bt8xx_suspend,
* .resume = dvb_bt8xx_resume,
*/
};
static int __init dvb_bt8xx_init(void)
{
return bttv_sub_register(&driver, "dvb");
}
static void __exit dvb_bt8xx_exit(void)
{
bttv_sub_unregister(&driver);
}
module_init(dvb_bt8xx_init);
module_exit(dvb_bt8xx_exit);
MODULE_DESCRIPTION("Bt8xx based DVB adapter driver");
MODULE_AUTHOR("Florian Schirmer <jolt@tuxbox.org>");
MODULE_LICENSE("GPL");

View File

@@ -0,0 +1,63 @@
/*
* Bt8xx based DVB adapter driver
*
* Copyright (C) 2002,2003 Florian Schirmer <jolt@tuxbox.org>
* Copyright (C) 2002 Peter Hettkamp <peter.hettkamp@htp-tel.de>
* Copyright (C) 1999-2001 Ralph Metzler & Marcus Metzler for convergence integrated media GmbH
* Copyright (C) 1998,1999 Christian Theiss <mistert@rz.fh-augsburg.de>
*
* 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; either version 2 of the License, or
* (at your option) any later version.
*
* 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.
*
*/
#ifndef DVB_BT8XX_H
#define DVB_BT8XX_H
#include <linux/i2c.h>
#include <linux/mutex.h>
#include "dvbdev.h"
#include "dvb_net.h"
#include "bttv.h"
#include "mt352.h"
#include "sp887x.h"
#include "dst_common.h"
#include "nxt6000.h"
#include "cx24110.h"
#include "or51211.h"
#include "lgdt330x.h"
#include "zl10353.h"
#include "tuner-simple.h"
struct dvb_bt8xx_card {
struct mutex lock;
int nfeeds;
char card_name[32];
struct dvb_adapter dvb_adapter;
struct bt878 *bt;
unsigned int bttv_nr;
struct dvb_demux demux;
struct dmxdev dmxdev;
struct dmx_frontend fe_hw;
struct dmx_frontend fe_mem;
u32 gpio_mode;
u32 op_sync_orin;
u32 irq_err_ignore;
struct i2c_adapter *i2c_adapter;
struct dvb_net dvbnet;
struct dvb_frontend* fe;
};
#endif /* DVB_BT8XX_H */