diff options
author | Holger Waechtler <devnull@localhost> | 2002-10-24 11:36:18 +0000 |
---|---|---|
committer | Holger Waechtler <devnull@localhost> | 2002-10-24 11:36:18 +0000 |
commit | 326bbd0529e5a070b90f21f5fb5364a6ee7fe0fe (patch) | |
tree | 785fd92ae7fdfee311e3a6e31a9ba3640459a2dd /linux | |
parent | 414d11591555c94ae972697c1fba5753110a9d68 (diff) | |
download | mediapointer-dvb-s2-326bbd0529e5a070b90f21f5fb5364a6ee7fe0fe.tar.gz mediapointer-dvb-s2-326bbd0529e5a070b90f21f5fb5364a6ee7fe0fe.tar.bz2 |
Alps TDLB7 DVB-T driver by Juergen Peitz <peitz@snafu.de>
Diffstat (limited to 'linux')
-rw-r--r-- | linux/drivers/media/dvb/frontends/Config.in | 1 | ||||
-rw-r--r-- | linux/drivers/media/dvb/frontends/Makefile | 1 | ||||
-rw-r--r-- | linux/drivers/media/dvb/frontends/README.alps_tdlb7 | 10 | ||||
-rw-r--r-- | linux/drivers/media/dvb/frontends/alps_tdlb7.c | 437 |
4 files changed, 449 insertions, 0 deletions
diff --git a/linux/drivers/media/dvb/frontends/Config.in b/linux/drivers/media/dvb/frontends/Config.in index d44894a0b..e397173b4 100644 --- a/linux/drivers/media/dvb/frontends/Config.in +++ b/linux/drivers/media/dvb/frontends/Config.in @@ -3,6 +3,7 @@ comment 'Supported Frontend Modules' dep_tristate ' Alps BSRU6 (QPSK)' CONFIG_DVB_ALPS_BSRU6 $CONFIG_DVB_CORE dep_tristate ' Alps BSRV2 (QPSK)' CONFIG_DVB_ALPS_BSRV2 $CONFIG_DVB_CORE +dep_tristate ' Alps TDLB7 (OFDM)' CONFIG_DVB_ALPS_TDLB7 $CONFIG_DVB_CORE dep_tristate ' Alps TDMB7 (OFDM)' CONFIG_DVB_ALPS_TDMB7 $CONFIG_DVB_CORE dep_tristate ' Grundig 29504-491 (QPSK)' CONFIG_DVB_GRUNDIG_29504_491 $CONFIG_DVB_CORE dep_tristate ' Grundig 29504-401 (OFDM)' CONFIG_DVB_GRUNDIG_29504_401 $CONFIG_DVB_CORE diff --git a/linux/drivers/media/dvb/frontends/Makefile b/linux/drivers/media/dvb/frontends/Makefile index 5fd14508f..c693af892 100644 --- a/linux/drivers/media/dvb/frontends/Makefile +++ b/linux/drivers/media/dvb/frontends/Makefile @@ -6,6 +6,7 @@ EXTRA_CFLAGS = -Idrivers/media/dvb/dvb-core/ obj-$(CONFIG_DVB_ALPS_BSRU6) += alps_bsru6.o obj-$(CONFIG_DVB_ALPS_BSRV2) += alps_bsrv2.o +obj-$(CONFIG_DVB_ALPS_TDLB7) += alps_tdlb7.o obj-$(CONFIG_DVB_ALPS_TDMB7) += alps_tdmb7.o obj-$(CONFIG_DVB_GRUNDIG_29504_491) += grundig_29504-491.o obj-$(CONFIG_DVB_GRUNDIG_29504_401) += grundig_29504-401.o diff --git a/linux/drivers/media/dvb/frontends/README.alps_tdlb7 b/linux/drivers/media/dvb/frontends/README.alps_tdlb7 new file mode 100644 index 000000000..6d42294b5 --- /dev/null +++ b/linux/drivers/media/dvb/frontends/README.alps_tdlb7 @@ -0,0 +1,10 @@ +This tuner module needs the file "Sc_main.mc" from the windows driver. +It should be copied to "/usr/lib/DVB/driver/frontends". Or give the +module parameter: mcfile="/PATH/FILENAME". The microcode from this file has +to be loaded only once after a power on. Because this takes some +time, you can pass the module parameter: loadcode=0 if you only want to +reload the dvb driver. +This driver is working fine on my computer, but I am not a real expert for +linux modules. So I hope somebody else, who knows more about linux programming +and dvb frontends, will do some work an this driver. +If you have questions, mail to peitz@snafu.de diff --git a/linux/drivers/media/dvb/frontends/alps_tdlb7.c b/linux/drivers/media/dvb/frontends/alps_tdlb7.c new file mode 100644 index 000000000..82e6e442a --- /dev/null +++ b/linux/drivers/media/dvb/frontends/alps_tdlb7.c @@ -0,0 +1,437 @@ +/* + Driver for Alps TDLB7 Frontend + + Copyright (C) 1999 Juergen Peitz <peitz@snafu.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. + +*/ + + +/* + + Wrote this code mainly to get my own card running. It's working for me, but I + hope somebody who knows more about linux programming and the DVB driver can + improve it. + + Reused a lot from the existing driver and tuner code. + Thanks to everybody who worked on it! + + This driver needs a copy of the microcode file 'Sc_main.mc' from the Haupauge + windows driver in the 'usr/lib/DVB/driver/frontends' directory. + You can also pass the complete file name with the module parameter 'mcfile'. + + The code only needs to be loaded once after a power on. Because loading the + microcode to the card takes some time, you can use the 'loadcode=0' module + parameter, if you only want to reload the dvb driver. + + Juergen Peitz + +*/ + + + +#define __KERNEL_SYSCALLS__ +#include <linux/module.h> +#include <linux/init.h> +#include <linux/vmalloc.h> +#include <linux/fs.h> +#include <linux/unistd.h> + +#include "compat.h" +#include "dvb_frontend.h" + +static int debug = 0; + +static int loadcode = 1; + +static char * mcfile = "/usr/lib/DVB/driver/frontends/Sc_main.mc"; + +#define dprintk if (debug) printk + +/* microcode size for sp8870 */ +#define SP8870_CODE_SIZE 16384 + +/* starting point for microcode in file 'Sc_main.mc' */ +#define SP8870_CODE_OFFSET 0x0A + + +static int errno; + +static +struct dvb_frontend_info tdlb7_info = { + name: "Alps TDLB7", + type: FE_OFDM, + frequency_min: 470000000, + frequency_max: 860000000, + frequency_stepsize: 166666, +#if 0 + frequency_tolerance: ???, + symbol_rate_min: ???, + symbol_rate_max: ???, + symbol_rate_tolerance: ???, + notifier_delay: 0, +#endif + caps: FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 | + FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO | + FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 +}; + + +static +int sp8870_writereg (struct dvb_i2c_bus *i2c, u16 reg, u16 data) +{ + u8 buf [] = { reg >> 8, reg & 0xff, data >> 8, data & 0xff }; + struct i2c_msg msg = { addr: 0x71, flags: 0, buf: buf, len: 4 }; + int err; + + if ((err = i2c->xfer (i2c, &msg, 1)) != 1) { + dprintk ("%s: writereg error (err == %i, reg == 0x%02x, data == 0x%02x)\n", __FUNCTION__, err, reg, data); + return -EREMOTEIO; + } + + return 0; +} + + +static +u16 sp8870_readreg (struct dvb_i2c_bus *i2c, u16 reg) +{ + int ret; + u8 b0 [] = { reg >> 8 , reg & 0xff }; + u8 b1 [] = { 0, 0 }; + struct i2c_msg msg [] = { { addr: 0x71, flags: 0, buf: b0, len: 2 }, + { addr: 0x71, flags: I2C_M_RD, buf: b1, len: 2 } }; + + ret = i2c->xfer (i2c, msg, 2); + + if (ret != 2) + dprintk("%s: readreg error (ret == %i)\n", __FUNCTION__, ret); + + return (b1[0] << 8 | b1[1]); +} + + +static +int sp5659_write (struct dvb_i2c_bus *i2c, u8 data [4]) +{ + int ret; + struct i2c_msg msg = { addr: 0x60, flags: 0, buf: data, len: 4 }; + + ret = i2c->xfer (i2c, &msg, 1); + + if (ret != 1) + printk("%s: i/o error (ret == %i)\n", __FUNCTION__, ret); + + return (ret != 1) ? -1 : 0; +} + + +static +int sp5659_set_tv_freq (struct dvb_i2c_bus *i2c, u32 freq, u8 pwr) +{ + u32 div = (freq + 36200000) / 166666; + u8 buf [4] = { (div >> 8) & 0x7f, div & 0xff, 0x85, (pwr << 5) | 0x30 }; + + return sp5659_write (i2c, buf); +} + + +static +int sp8870_read_code(const char *fn, char **fp) +{ + int fd; + loff_t l; + char *dp; + + fd = open(fn, 0, 0); + if (fd == -1) { + printk(KERN_INFO "%s: Unable to load '%s'.\n", __FUNCTION__, fn); + return -1; + } + l = lseek(fd, 0L, 2); + if (l <= 0 || l < SP8870_CODE_OFFSET+SP8870_CODE_SIZE) { + printk(KERN_INFO "%s: code file too small '%s'\n", __FUNCTION__, fn); + sys_close(fd); + return -1; + } + lseek(fd, SP8870_CODE_OFFSET, 0); + *fp= dp = vmalloc(SP8870_CODE_SIZE); + if (dp == NULL) { + printk(KERN_INFO "%s: Out of memory loading '%s'.\n", __FUNCTION__, fn); + sys_close(fd); + return -1; + } + if (read(fd, dp, SP8870_CODE_SIZE) != SP8870_CODE_SIZE) { + printk(KERN_INFO "%s: Failed to read '%s'.\n",__FUNCTION__, fn); + vfree(dp); + sys_close(fd); + return -1; + } + sys_close(fd); + *fp = dp; + return 0; +} + + +static +int sp8870_load_code(struct dvb_i2c_bus *i2c) +{ + /* this takes a long time. is there a way to do it faster? */ + char *lcode; + struct i2c_msg msg; + unsigned char buf[255]; + int err; + int p=0; + int c; + mm_segment_t fs = get_fs(); + + sp8870_writereg(i2c,0x8F08,0x1FFF); + sp8870_writereg(i2c,0x8F0A,0x0000); + + set_fs(get_ds()); + if (sp8870_read_code(mcfile,(char**) &lcode)<0) return -1; + set_fs(fs); + while (p<SP8870_CODE_SIZE){ + c = (p<=SP8870_CODE_SIZE-252) ? 252 : SP8870_CODE_SIZE-p; + buf[0]=0xCF; + buf[1]=0x0A; + memcpy(&buf[2],lcode+p,c); + c+=2; + msg.addr=0x71; + msg.flags=0; + msg.buf=buf; + msg.len=c; + if ((err = i2c->xfer (i2c, &msg, 1)) != 1) { + dprintk ("%s: i2c error (err == %i)\n", __FUNCTION__, err); + vfree(lcode); + return -EREMOTEIO; + } + + p+=252; + } + vfree(lcode); + return 0; +}; + + +static +int sp8870_init (struct dvb_i2c_bus *i2c) +{ + + dprintk ("%s\n", __FUNCTION__); + + sp8870_readreg(i2c,0x200); + sp8870_readreg(i2c,0x200); + sp8870_readreg(i2c,0x0F00); /* system controller stop */ + sp8870_readreg(i2c,0x0301); /* ???????? */ + sp8870_readreg(i2c,0x0309); /* integer carrier offset */ + sp8870_readreg(i2c,0x030A); /* fractional carrier offset */ + sp8870_readreg(i2c,0x0311); /* filter for 8 Mhz channel */ + sp8870_readreg(i2c,0x0319); /* sample rate correction bit [23..17] */ + sp8870_readreg(i2c,0x031A); /* sample rate correction bit [16..0] */ + sp8870_readreg(i2c,0x0338); /* ???????? */ + sp8870_readreg(i2c,0x0F00); + sp8870_readreg(i2c,0x0200); + + if (loadcode) { + dprintk("%s: loading mcfile '%s' !\n", __FUNCTION__, mcfile); + if (sp8870_load_code(i2c)==0) + dprintk("%s: microcode loaded!\n", __FUNCTION__); + }else{ + dprintk("%s: without loading mcfile!\n", __FUNCTION__); + } + + return 0; +} + + +static +int sp8870_reset (struct dvb_i2c_bus *i2c) +{ + dprintk("%s\n", __FUNCTION__); + sp8870_writereg(i2c,0x0F00,0x0000); /* system controller stop */ + sp8870_writereg(i2c,0x0301,0x0003); /* ???????? */ + sp8870_writereg(i2c,0x0309,0x0400); /* integer carrier offset */ + sp8870_writereg(i2c,0x030A,0x0000); /* fractional carrier offset */ + sp8870_writereg(i2c,0x0311,0x0000); /* filter for 8 Mhz channel */ + sp8870_writereg(i2c,0x0319,0x000A); /* sample rate correction bit [23..17] */ + sp8870_writereg(i2c,0x031A,0x0AAB); /* sample rate correction bit [16..0] */ + sp8870_writereg(i2c,0x0338,0x0000); /* ???????? */ + sp8870_writereg(i2c,0x0201,0x0000); /* interrupts for change of lock or tuner adjustment disabled */ + sp8870_writereg(i2c,0x0F00,0x0001); /* system controller start */ + + return 0; +} + +static +int tdlb7_ioctl (struct dvb_frontend *fe, unsigned int cmd, void *arg) +{ + struct dvb_i2c_bus *i2c = fe->i2c; + + switch (cmd) { + case FE_GET_INFO: + memcpy (arg, &tdlb7_info, sizeof(struct dvb_frontend_info)); + break; + + case FE_READ_STATUS: + { + fe_status_t *status = arg; + int sync = sp8870_readreg (i2c, 0x0200); + + *status=0; + + if (sync&0x04) // FIXME: find criteria for having signal + *status |= FE_HAS_SIGNAL; + + if (sync&0x04) // FIXME: find criteria + *status |= FE_HAS_CARRIER; + + if (sync&0x04) // FIXME + *status |= FE_HAS_VITERBI; + + if (sync&0x08) // FIXME + *status |= FE_HAS_SYNC; + + if (sync&0x04) + *status |= FE_HAS_LOCK; + break; + + } + + case FE_READ_BER: + { + u32 *ber=(u32 *) arg; + *ber=sp8870_readreg(i2c,0x0C07); // bit error rate before Viterbi + break; + + } + + case FE_READ_SIGNAL_STRENGTH: // not supported by hardware? + { + s32 *signal=(s32 *) arg; + *signal=0; + break; + } + + case FE_READ_SNR: // not supported by hardware? + { + s32 *snr=(s32 *) arg; + *snr=0; + break; + } + + case FE_READ_UNCORRECTED_BLOCKS: // not supported by hardware? + { + u32 *ublocks=(u32 *) arg; + *ublocks=0; + break; + } + + case FE_SET_FRONTEND: + { + struct dvb_frontend_parameters *p = arg; + sp5659_set_tv_freq (i2c, p->frequency, 0); + // all other parameters are set by the on card + // system controller. Don't know how to pass + // distinct values to the card. + break; + } + + case FE_GET_FRONTEND: // how to do this? + { + break; + } + + case FE_SLEEP: // is this supported by hardware? + return -EOPNOTSUPP; + + case FE_INIT: + return sp8870_init (i2c); + + case FE_RESET: + return sp8870_reset (i2c); + + default: + return -EOPNOTSUPP; + }; + + return 0; +} + + +static +int tdlb7_attach (struct dvb_i2c_bus *i2c) +{ + + struct i2c_msg msg = { addr: 0x71, flags: 0, buf: NULL, len: 0 }; + + dprintk ("%s\n", __FUNCTION__); + + if (i2c->xfer (i2c, &msg, 1) != 1) + return -ENODEV; + + dvb_register_frontend (tdlb7_ioctl, i2c, NULL, &tdlb7_info); + + return 0; +} + + +static +void tdlb7_detach (struct dvb_i2c_bus *i2c) +{ + dprintk ("%s\n", __FUNCTION__); + + dvb_unregister_frontend (tdlb7_ioctl, i2c); +} + + +static +int __init init_tdlb7 (void) +{ + dprintk ("%s\n", __FUNCTION__); + + return dvb_register_i2c_device (THIS_MODULE, tdlb7_attach, tdlb7_detach); +} + + +static +void __exit exit_tdlb7 (void) +{ + dprintk ("%s\n", __FUNCTION__); + + dvb_unregister_i2c_device (tdlb7_attach); +} + + +module_init(init_tdlb7); +module_exit(exit_tdlb7); + + +MODULE_PARM(debug,"i"); +MODULE_PARM_DESC(debug, "enable verbose debug messages"); + +MODULE_PARM(loadcode,"i"); +MODULE_PARM_DESC(loadcode, "load tuner microcode"); + +MODULE_PARM(mcfile,"s"); +MODULE_PARM_DESC(mcfile, "where to find the microcode file"); + +MODULE_DESCRIPTION("TDLB7 DVB-T Frontend"); +MODULE_AUTHOR("Juergen Peitz"); +MODULE_LICENSE("GPL"); + + |