diff options
Diffstat (limited to 'linux/drivers/media/dvb/ttpci')
-rw-r--r-- | linux/drivers/media/dvb/ttpci/Kconfig | 68 | ||||
-rw-r--r-- | linux/drivers/media/dvb/ttpci/Makefile | 13 | ||||
-rw-r--r-- | linux/drivers/media/dvb/ttpci/budget-av.c | 395 | ||||
-rw-r--r-- | linux/drivers/media/dvb/ttpci/budget-ci.c | 434 | ||||
-rw-r--r-- | linux/drivers/media/dvb/ttpci/budget-core.c | 339 | ||||
-rw-r--r-- | linux/drivers/media/dvb/ttpci/budget-patch.c | 335 | ||||
-rw-r--r-- | linux/drivers/media/dvb/ttpci/budget.c | 267 | ||||
-rw-r--r-- | linux/drivers/media/dvb/ttpci/budget.h | 86 |
8 files changed, 1935 insertions, 2 deletions
diff --git a/linux/drivers/media/dvb/ttpci/Kconfig b/linux/drivers/media/dvb/ttpci/Kconfig index 8396852b0..64a4f9788 100644 --- a/linux/drivers/media/dvb/ttpci/Kconfig +++ b/linux/drivers/media/dvb/ttpci/Kconfig @@ -22,3 +22,71 @@ config DVB_AV7110_OSD its menus, so say Y if you want to use this software. All other people say N. + +config DVB_BUDGET + tristate "Budget cards" + depends on DVB_CORE + help + Support for simple SAA7146 based DVB cards + (so called Budget- or Nova-PCI cards) without onboard + MPEG2 decoder. + + Say Y if you own such a card and want to use it. + + This driver is available as a module called + dvb-ttpci-budget.o ( = code which can be inserted in + and removed from the running kernel whenever you want). + If you want to compile it as a module, say M + here and read <file:Documentation/modules.txt>. + +config DVB_BUDGET_CI + tristate "Budget cards with onboard CI connector" + depends on VIDEO_DEV && DVB_CORE && DVB_BUDGET + help + Support for simple SAA7146 based DVB cards + (so called Budget- or Nova-PCI cards) without onboard + MPEG2 decoder, but with onboard Common Interface connector. + + Say Y if you own such a card and want to use it. + + This driver is available as a module called + dvb-ttpci-budget-av.o ( = code which can be inserted in + and removed from the running kernel whenever you want). + If you want to compile it as a module, say M + here and read <file:Documentation/modules.txt>. + +config DVB_BUDGET_AV + tristate "Budget cards with analog video inputs" + depends on VIDEO_DEV && DVB_CORE && DVB_BUDGET + help + Support for simple SAA7146 based DVB cards + (so called Budget- or Nova-PCI cards) without onboard + MPEG2 decoder, but with one or more analog video inputs. + + Say Y if you own such a card and want to use it. + + This driver is available as a module called + dvb-ttpci-budget-av.o ( = code which can be inserted in + and removed from the running kernel whenever you want). + here and read <file:Documentation/modules.txt>. + +config DVB_BUDGET_PATCH + tristate "AV7110 cards with Budget Patch" + depends on DVB_CORE && DVB_BUDGET + help + Support for Budget Patch (full TS) modification on + SAA7146+AV7110 based cards (DVB-S cards). This + driver doesn't use onboard MPEG2 decoder. The + card is driven in Budget-only mode. Card is + required to have loaded firmware to tune properly. + Firmware can be loaded by insertion and removal of + standard AV7110 driver prior to loading this + driver. + + Say Y if you own such a card and want to use it. + + This driver is available as a module called + dvb-ttpci-budget-patch.o ( = code which can be inserted in + and removed from the running kernel whenever you want). + If you want to compile it as a module, say M + here and read <file:Documentation/modules.txt>. diff --git a/linux/drivers/media/dvb/ttpci/Makefile b/linux/drivers/media/dvb/ttpci/Makefile index 5a9fd0c0c..c1e1f7b4c 100644 --- a/linux/drivers/media/dvb/ttpci/Makefile +++ b/linux/drivers/media/dvb/ttpci/Makefile @@ -1,9 +1,18 @@ # -# Makefile for the kernel AV7110 DVB device driver +# Makefile for the kernel SAA7146 FULL TS DVB device driver +# and the AV7110 DVB device driver # +dvb-ttpci-budget-objs := budget.o +dvb-ttpci-budget-av-objs := budget-av.o +dvb-ttpci-budget-ci-objs := budget-ci.o +dvb-ttpci-budget-patch-objs := budget-patch.o dvb-ttpci-objs := av7110.o av7110_ipack.o av7110_ir.o +obj-$(CONFIG_DVB_BUDGET) += budget-core.o dvb-ttpci-budget.o +obj-$(CONFIG_DVB_BUDGET_CI) += budget-core.o dvb-ttpci-budget-ci.o +obj-$(CONFIG_DVB_BUDGET_AV) += budget-core.o dvb-ttpci-budget-av.o +obj-$(CONFIG_DVB_BUDGET_PATCH) += budget-core.o dvb-ttpci-budget-patch.o obj-$(CONFIG_DVB_AV7110) += dvb-ttpci.o -EXTRA_CFLAGS = -Idrivers/media/dvb/dvb-core/ -I$(src)/../../common/ -I$(src)/../../common/saa7146 +EXTRA_CFLAGS = -Idrivers/media/dvb/dvb-core/ diff --git a/linux/drivers/media/dvb/ttpci/budget-av.c b/linux/drivers/media/dvb/ttpci/budget-av.c new file mode 100644 index 000000000..66173a760 --- /dev/null +++ b/linux/drivers/media/dvb/ttpci/budget-av.c @@ -0,0 +1,395 @@ +/* + * budget-av.c: driver for the SAA7146 based Budget DVB cards + * with analog video in + * + * Compiled from various sources by Michael Hunold <michael@mihu.de> + * + * Copyright (C) 2002 Ralph Metzler <rjkm@metzlerbros.de> + * + * Copyright (C) 1999-2002 Ralph Metzler + * & Marcus Metzler for convergence integrated media GmbH + * + * 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 + * + * + * the project's page is at http://www.linuxtv.org/dvb/ + */ + +#include "budget.h" +#include "saa7146_vv.h" + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,51) + #define KBUILD_MODNAME budget_av +#endif + + +struct budget_av { + struct budget budget; + struct video_device vd; + int cur_input; +}; + +/**************************************************************************** + * INITIALIZATION + ****************************************************************************/ + +static inline +void ddelay(int i) +{ + current->state=TASK_INTERRUPTIBLE; + schedule_timeout((HZ*i)/100); +} + + +static +u8 i2c_readreg (struct dvb_i2c_bus *i2c, u8 id, u8 reg) +{ + u8 mm1[] = {0x00}; + u8 mm2[] = {0x00}; + struct i2c_msg msgs[2]; + + msgs[0].flags = 0; + msgs[1].flags = I2C_M_RD; + msgs[0].addr = msgs[1].addr=id/2; + mm1[0] = reg; + msgs[0].len = 1; msgs[1].len = 1; + msgs[0].buf = mm1; msgs[1].buf = mm2; + + i2c->xfer(i2c, msgs, 2); + + return mm2[0]; +} + + +static +int i2c_writereg (struct dvb_i2c_bus *i2c, u8 id, u8 reg, u8 val) +{ + u8 msg[2]={ reg, val }; + struct i2c_msg msgs; + + msgs.flags=0; + msgs.addr=id/2; + msgs.len=2; + msgs.buf=msg; + return i2c->xfer (i2c, &msgs, 1); +} + + +static const +u8 saa7113_tab[] = { + 0x01, 0x08, + 0x02, 0xc0, + 0x03, 0x33, + 0x04, 0x00, + 0x05, 0x00, + 0x06, 0xeb, + 0x07, 0xe0, + 0x08, 0x28, + 0x09, 0x00, + 0x0a, 0x80, + 0x0b, 0x47, + 0x0c, 0x40, + 0x0d, 0x00, + 0x0e, 0x01, + 0x0f, 0x44, + + 0x10, 0x08, + 0x11, 0x0c, + 0x12, 0x7b, + 0x13, 0x00, + 0x15, 0x00, 0x16, 0x00, 0x17, 0x00, + + 0x57, 0xff, + 0x40, 0x82, 0x58, 0x00, 0x59, 0x54, 0x5a, 0x07, + 0x5b, 0x83, 0x5e, 0x00, + 0xff +}; + + +static +int saa7113_init (struct budget_av *budget_av) +{ + struct budget *budget = &budget_av->budget; + const u8 *data = saa7113_tab; + + if (i2c_writereg (budget->i2c_bus, 0x4a, 0x01, 0x08) != 1) { + DEB_D(("saa7113: not found on KNC card\n")); + return -ENODEV; + } + + INFO(("saa7113: detected and initializing\n")); + + while (*data != 0xff) { + i2c_writereg(budget->i2c_bus, 0x4a, *data, *(data+1)); + data += 2; + } + + DEB_D(("saa7113: status=%02x\n", + i2c_readreg(budget->i2c_bus, 0x4a, 0x1f))); + + return 0; +} + + +static +int saa7113_setinput (struct budget_av *budget_av, int input) +{ + struct budget *budget = &budget_av->budget; + + if (input == 1) { + i2c_writereg(budget->i2c_bus, 0x4a, 0x02, 0xc7); + i2c_writereg(budget->i2c_bus, 0x4a, 0x09, 0x80); + } else if (input == 0) { + i2c_writereg(budget->i2c_bus, 0x4a, 0x02, 0xc0); + i2c_writereg(budget->i2c_bus, 0x4a, 0x09, 0x00); + } else + return -EINVAL; + + budget_av->cur_input = input; + return 0; +} + + +static +int budget_av_detach (struct saa7146_dev *dev) +{ + struct budget_av *budget_av = (struct budget_av*) dev->ext_priv; + int err; + + DEB_EE(("dev: %p\n",dev)); + + saa7146_setgpio(dev, 0, SAA7146_GPIO_OUTLO); + + ddelay(20); + + saa7146_unregister_device (&budget_av->vd, dev); + + err = ttpci_budget_deinit (&budget_av->budget); + + kfree (budget_av); + + return err; +} + + +static +int budget_av_attach (struct saa7146_dev* dev, + struct saa7146_pci_extension_data *info) +{ + struct budget_av *budget_av; + struct budget_info *bi = info->ext_priv; + int err; + + DEB_EE(("dev: %p\n",dev)); + + if (bi->type != BUDGET_KNC1) { + return -ENODEV; + } + + if (!(budget_av = kmalloc(sizeof(struct budget_av), GFP_KERNEL))) + return -ENOMEM; + + memset(budget_av, 0, sizeof(struct budget_av)); + + if ((err = ttpci_budget_init(&budget_av->budget, dev, info))) { + kfree(budget_av); + return err; + } + + dev->ext_priv = budget_av; + + /* knc1 initialization */ + saa7146_write(dev, DD1_STREAM_B, 0x04000000); + saa7146_write(dev, DD1_INIT, 0x07000600); + saa7146_write(dev, MC2, MASK_09 | MASK_25 | MASK_10 | MASK_26); + + //test_knc_ci(av7110); + + saa7146_setgpio(dev, 0, SAA7146_GPIO_OUTHI); + ddelay(50); + + if ((err = saa7113_init (budget_av))) { + budget_av_detach(dev); + return err; + } + + saa7146_vv_init(dev); + if ((err = saa7146_register_device(&budget_av->vd, dev, "knc1", + VFL_TYPE_GRABBER))) + { + ERR(("cannot register capture v4l2 device.\n")); + budget_av_detach(dev); + return err; + } + + /* beware: this modifies dev->vv ... */ + saa7146_set_hps_source_and_sync(dev, SAA7146_HPS_SOURCE_PORT_A, + SAA7146_HPS_SYNC_PORT_A); + + saa7113_setinput (budget_av, 0); + + /* what is this? since we don't support open()/close() + notifications, we simply put this into the release handler... */ +// saa7146_setgpio(dev, 0, SAA7146_GPIO_OUTLO); + ddelay(20); + + /* fixme: find some sane values here... */ + saa7146_write(dev, PCI_BT_V1, 0x1c00101f); + + return 0; +} + + + +#define KNC1_INPUTS 2 +static struct v4l2_input knc1_inputs[KNC1_INPUTS] = { + { 0, "Composite", V4L2_INPUT_TYPE_TUNER, 1, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0 }, + { 1, "S-Video", V4L2_INPUT_TYPE_CAMERA, 2, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0 }, +}; + + +static +struct saa7146_extension_ioctls ioctls[] = { + { VIDIOC_ENUMINPUT, SAA7146_EXCLUSIVE }, + { VIDIOC_G_INPUT, SAA7146_EXCLUSIVE }, + { VIDIOC_S_INPUT, SAA7146_EXCLUSIVE }, + { 0, 0 } +}; + + +static +int av_ioctl(struct saa7146_dev *dev, unsigned int cmd, void *arg) +{ + struct budget_av *budget_av = (struct budget_av*) dev->ext_priv; +/* + struct saa7146_vv *vv = dev->vv_data; +*/ + switch(cmd) { + case VIDIOC_ENUMINPUT: + { + struct v4l2_input *i = arg; + + DEB_EE(("VIDIOC_ENUMINPUT %d.\n",i->index)); + if( i->index < 0 || i->index >= KNC1_INPUTS) { + return -EINVAL; + } + memcpy(i, &knc1_inputs[i->index], sizeof(struct v4l2_input)); + return 0; + } + case VIDIOC_G_INPUT: + { + int *input = (int *)arg; + + *input = budget_av->cur_input; + + DEB_EE(("VIDIOC_G_INPUT %d.\n",*input)); + return 0; + } + case VIDIOC_S_INPUT: + { + int input = *(int *)arg; + DEB_EE(("VIDIOC_S_INPUT %d.\n", input)); + return saa7113_setinput (budget_av, input); + } + default: +/* + DEB2(printk("does not handle this ioctl.\n")); +*/ + return -ENOIOCTLCMD; + } + return 0; +} + +static +struct saa7146_standard standard[] = { + { "PAL", V4L2_STD_PAL, SAA7146_PAL_VALUES }, + { "NTSC", V4L2_STD_NTSC, SAA7146_NTSC_VALUES }, +}; + + +static +struct saa7146_ext_vv vv_data = { + .inputs = 2, + .capabilities = 0, // perhaps later: V4L2_CAP_VBI_CAPTURE, but that need tweaking with the saa7113 + .flags = 0, + .stds = &standard[0], + .num_stds = sizeof(standard)/sizeof(struct saa7146_standard), + .ioctls = &ioctls[0], + .ioctl = av_ioctl, +}; + + + +static struct saa7146_extension budget_extension; + + +MAKE_BUDGET_INFO(knc1, "KNC1 DVB-S", BUDGET_KNC1); + +static +struct pci_device_id pci_tbl [] = { + MAKE_EXTENSION_PCI(knc1, 0x1131, 0x4f56), + { + .vendor = 0, + } +}; + + + +static +struct saa7146_extension budget_extension = { + .name = "budget dvb /w video in\0", + .pci_tbl = pci_tbl, + + .module = THIS_MODULE, + .attach = budget_av_attach, + .detach = budget_av_detach, + + .ext_vv_data = &vv_data, + + .irq_mask = MASK_10, + .irq_func = ttpci_budget_irq10_handler, +}; + + +static +int __init budget_av_init(void) +{ + DEB_EE((".\n")); + + if (saa7146_register_extension(&budget_extension)) + return -ENODEV; + + return 0; +} + + +static +void __exit budget_av_exit(void) +{ + DEB_EE((".\n")); + saa7146_unregister_extension(&budget_extension); +} + +module_init(budget_av_init); +module_exit(budget_av_exit); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Ralph Metzler, Marcus Metzler, Michael Hunold, others"); +MODULE_DESCRIPTION("driver for the SAA7146 based so-called " + "budget PCI DVB w/ analog input (e.g. the KNC cards)"); + diff --git a/linux/drivers/media/dvb/ttpci/budget-ci.c b/linux/drivers/media/dvb/ttpci/budget-ci.c new file mode 100644 index 000000000..a4f5bad49 --- /dev/null +++ b/linux/drivers/media/dvb/ttpci/budget-ci.c @@ -0,0 +1,434 @@ +/* + * budget-ci.c: driver for the SAA7146 based Budget DVB cards + * + * Compiled from various sources by Michael Hunold <michael@mihu.de> + * + * msp430 IR support contributed by Jack Thomasson <jkt@Helius.COM> + * partially based on the Siemens DVB driver by Ralph+Marcus Metzler + * + * 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 + * + * + * the project's page is at http://www.linuxtv.org/dvb/ + */ + +#include "budget.h" +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,51) + #define KBUILD_MODNAME budget +#endif + + +#include <linux/module.h> +#include <linux/errno.h> +#include <linux/slab.h> +#include <linux/interrupt.h> +#include <linux/input.h> + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)) +#include "input_fake.h" +#endif + + + +struct budget_ci { + struct budget budget; + struct input_dev input_dev; + struct tasklet_struct msp430_irq_tasklet; +}; + + + +#ifndef BORROWED_FROM_AV7110_H_BUT_REALLY_BELONGS_IN_SAA7146_DEFS_H + +#define DEBINOSWAP 0x000e0000 +#define GPIO_IRQHI 0x10 +#define GPIO_INPUT 0x00 + +void gpio_set(struct saa7146_dev* saa, u8 pin, u8 data) +{ + u32 value = 0; + + /* sanity check */ + if(pin > 3) + return; + + /* read old register contents */ + value = saa7146_read(saa, GPIO_CTRL ); + + value &= ~(0xff << (8*pin)); + value |= (data << (8*pin)); + + saa7146_write(saa, GPIO_CTRL, value); +} + + + +static +int wait_for_debi_done(struct saa7146_dev *saa) +{ + int start = jiffies; + + /* wait for registers to be programmed */ + while (1) { + if (saa7146_read(saa, MC2) & 2) + break; + if (jiffies - start > HZ / 20) { + printk ("DVB (%s): timed out while waiting" + " for registers getting programmed\n", + __FUNCTION__); + return -ETIMEDOUT; + } + } + + /* wait for transfer to complete */ + start = jiffies; + while (1) { + if (!(saa7146_read(saa, PSR) & SPCI_DEBI_S)) + break; + saa7146_read(saa, MC2); + if (jiffies - start > HZ / 4) { + printk ("DVB (%s): timed out while waiting" + " for transfer completion\n", + __FUNCTION__); + return -ETIMEDOUT; + } + } + + return 0; +} + + +static +u32 debiread (struct saa7146_dev *saa, u32 config, int addr, int count) +{ + u32 result = 0; + + if (count > 4 || count <= 0) + return 0; + + if (wait_for_debi_done(saa) < 0) + return 0; + + saa7146_write (saa, DEBI_COMMAND, + (count << 17) | 0x10000 | (addr & 0xffff)); + + saa7146_write(saa, DEBI_CONFIG, config); + saa7146_write(saa, MC2, (2 << 16) | 2); + + wait_for_debi_done(saa); + + result = saa7146_read(saa, DEBI_AD); + result &= (0xffffffffUL >> ((4 - count) * 8)); + + return result; +} + + + +/* DEBI during interrupt */ +static inline +u32 irdebi(struct saa7146_dev *saa, u32 config, int addr, u32 val, int count) +{ + u32 res; + res = debiread(saa, config, addr, count); + return res; +} +#endif + + + + +/* from reading the following remotes: + Zenith Universal 7 / TV Mode 807 / VCR Mode 837 + Hauppauge (from NOVA-CI-s box product) + i've taken a "middle of the road" approach and note the differences +*/ +static + u16 key_map[64] = { + /* 0x0X */ + KEY_0, KEY_1, KEY_2, KEY_3, KEY_4, KEY_5, KEY_6, KEY_7, KEY_8, + KEY_9, + KEY_ENTER, + 0, + KEY_POWER, /* RADIO on Hauppauge */ + KEY_MUTE, + 0, + KEY_A, /* TV on Hauppauge */ + /* 0x1X */ + KEY_VOLUMEUP, KEY_VOLUMEDOWN, + 0, 0, + KEY_B, + 0, 0, 0, 0, 0, 0, 0, + KEY_UP, KEY_DOWN, + KEY_OPTION, /* RESERVED on Hauppauge */ + 0, + /* 0x2X */ + KEY_CHANNELUP, KEY_CHANNELDOWN, + KEY_PREVIOUS, /* Prev. Ch on Zenith, SOURCE on Hauppauge */ + 0, 0, 0, + KEY_CYCLEWINDOWS, /* MINIMIZE on Hauppauge */ + 0, + KEY_ENTER, /* VCR mode on Zenith */ + KEY_PAUSE, + 0, + KEY_RIGHT, KEY_LEFT, + 0, + KEY_MENU, /* FULL SCREEN on Hauppauge */ + 0, + /* 0x3X */ + 0, + KEY_PREVIOUS, /* VCR mode on Zenith */ + KEY_REWIND, + 0, + KEY_FASTFORWARD, + KEY_PLAY, KEY_STOP, + KEY_RECORD, + KEY_TUNER, /* TV/VCR on Zenith */ + 0, + KEY_C, + 0, + KEY_EXIT, + 0, + KEY_TUNER, /* VCR mode on Zenith */ + 0, +}; + + +static +void msp430_ir_debounce (unsigned long data) +{ + struct input_dev *dev = (struct input_dev *) data; + + if (dev->rep[0] == 0 || dev->rep[0] == ~0) { + input_event(dev, EV_KEY, key_map[dev->repeat_key], !!0); + return; + } + + dev->rep[0] = 0; + dev->timer.expires = jiffies + HZ * 350 / 1000; + add_timer(&dev->timer); + input_event(dev, EV_KEY, key_map[dev->repeat_key], 2); /* REPEAT */ +} + + + +static +void msp430_ir_interrupt (unsigned long data) +{ + struct budget_ci *budget_ci = (struct budget_ci*) data; + struct saa7146_dev *saa = budget_ci->budget.dev; + struct input_dev *dev = &budget_ci->input_dev; + unsigned int code = irdebi(saa, DEBINOSWAP, 0x1234, 0, 2) >> 8; + + if (code & 0x40) { + code &= 0x3f; + + if (timer_pending(&dev->timer)) { + if (code == dev->repeat_key) { + ++dev->rep[0]; + return; + } + del_timer(&dev->timer); + input_event(dev, EV_KEY, key_map[dev->repeat_key], !!0); + } + + if (!key_map[code]) { + printk ("DVB (%s): no key for %02x!\n", + __FUNCTION__, code); + return; + } + + /* initialize debounce and repeat */ + dev->repeat_key = code; + /* Zenith remote _always_ sends 2 sequences */ + dev->rep[0] = ~0; + /* 350 milliseconds */ + dev->timer.expires = jiffies + HZ * 350 / 1000; + /* MAKE */ + input_event(dev, EV_KEY, key_map[code], !0); + add_timer(&dev->timer); + } +} + + +static +int msp430_ir_init (struct budget_ci *budget_ci) +{ + struct saa7146_dev *saa = budget_ci->budget.dev; + int i; + + memset(&budget_ci->input_dev, 0, sizeof(struct input_dev)); + + budget_ci->input_dev.name = saa->name; + + set_bit(EV_KEY, budget_ci->input_dev.evbit); + + for (i=0; i<sizeof(key_map)/sizeof(*key_map); i++) + if (key_map[i]) + set_bit(key_map[i], budget_ci->input_dev.keybit); + + input_register_device(&budget_ci->input_dev); + + budget_ci->input_dev.timer.function = msp430_ir_debounce; + + saa7146_write(saa, IER, saa7146_read(saa, IER) | MASK_06); + + gpio_set(saa, 3, GPIO_IRQHI); + + return 0; +} + + +static +void msp430_ir_deinit (struct budget_ci *budget_ci) +{ + struct saa7146_dev *saa = budget_ci->budget.dev; + struct input_dev *dev = &budget_ci->input_dev; + + saa7146_write(saa, IER, saa7146_read(saa, IER) & ~MASK_06); + gpio_set(saa, 3, GPIO_INPUT); + gpio_set(saa, 2, GPIO_INPUT); + + if (del_timer(&dev->timer)) + input_event(dev, EV_KEY, key_map[dev->repeat_key], !!0); + + input_unregister_device(dev); +} + + +static +void budget_ci_irq (struct saa7146_dev *dev, u32 *isr) +{ + struct budget_ci *budget_ci = (struct budget_ci*) dev->ext_priv; + + DEB_EE(("dev: %p, budget_ci: %p\n", dev, budget_ci)); + + if (*isr & MASK_06) + tasklet_schedule (&budget_ci->msp430_irq_tasklet); + + if (*isr & MASK_10) + ttpci_budget_irq10_handler (dev, isr); +} + + + +static +int budget_ci_attach (struct saa7146_dev* dev, + struct saa7146_pci_extension_data *info) +{ + struct budget_ci *budget_ci; + int err; + + if (!(budget_ci = kmalloc (sizeof(struct budget_ci), GFP_KERNEL))) + return -ENOMEM; + + DEB_EE(("budget_ci: %p\n", budget_ci)); + + if ((err = ttpci_budget_init (&budget_ci->budget, dev, info))) { + kfree (budget_ci); + return err; + } + + dev->ext_priv = budget_ci; + + tasklet_init (&budget_ci->msp430_irq_tasklet, msp430_ir_interrupt, + (unsigned long) budget_ci); + + msp430_ir_init (budget_ci); + + return 0; +} + + + +static +int budget_ci_detach (struct saa7146_dev* dev) +{ + struct budget_ci *budget_ci = (struct budget_ci*) dev->ext_priv; + int err; + + err = ttpci_budget_deinit (&budget_ci->budget); + + tasklet_kill (&budget_ci->msp430_irq_tasklet); + + msp430_ir_deinit (budget_ci); + + kfree (budget_ci); + + return err; +} + + + +static struct saa7146_extension budget_extension; + +MAKE_BUDGET_INFO(ttbci, "TT-Budget/WinTV-NOVA-CI PCI", BUDGET_TT_HW_DISEQC); + +static +struct pci_device_id pci_tbl[] = { + MAKE_EXTENSION_PCI(ttbci, 0x13c2, 0x100c), + MAKE_EXTENSION_PCI(ttbci, 0x13c2, 0x100f), + { + .vendor = 0, + } +}; + + + +static +struct saa7146_extension budget_extension = { + .name = "budget_ci dvb\0", + .flags = 0, + .ext_vv_data = NULL, + + .module = THIS_MODULE, + .pci_tbl = &pci_tbl[0], + .attach = budget_ci_attach, + .detach = budget_ci_detach, + + .irq_mask = MASK_06 | MASK_10, + .irq_func = budget_ci_irq, +}; + + +static +int __init budget_ci_init(void) +{ + if (saa7146_register_extension(&budget_extension)) + return -ENODEV; + + return 0; +} + + +static +void __exit budget_ci_exit(void) +{ + DEB_EE((".\n")); + saa7146_unregister_extension(&budget_extension); +} + +module_init(budget_ci_init); +module_exit(budget_ci_exit); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Michael Hunold, Jack Thomasson, others"); +MODULE_DESCRIPTION("driver for the SAA7146 based so-called " + "budget PCI DVB cards w/ CI-module produced by " + "Siemens, Technotrend, Hauppauge"); + diff --git a/linux/drivers/media/dvb/ttpci/budget-core.c b/linux/drivers/media/dvb/ttpci/budget-core.c new file mode 100644 index 000000000..71cbcfffd --- /dev/null +++ b/linux/drivers/media/dvb/ttpci/budget-core.c @@ -0,0 +1,339 @@ +#include "budget.h" +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,51) + #define KBUILD_MODNAME budget +#endif + +int budget_debug = 0; + +/**************************************************************************** + * General helper functions + ****************************************************************************/ + +static inline void ddelay(int i) +{ + current->state=TASK_INTERRUPTIBLE; + schedule_timeout((HZ*i)/100); +} + +/**************************************************************************** + * TT budget / WinTV Nova + ****************************************************************************/ + +static +int stop_ts_capture(struct budget *budget) +{ + DEB_EE(("budget: %p\n",budget)); + + if (--budget->feeding) + return budget->feeding; + + saa7146_write(budget->dev, MC1, MASK_20); // DMA3 off + IER_DISABLE(budget->dev, MASK_10); + return 0; +} + + +static +int start_ts_capture (struct budget *budget) +{ + struct saa7146_dev *dev=budget->dev; + + DEB_EE(("budget: %p\n",budget)); + + if (budget->feeding) + return ++budget->feeding; + + saa7146_write(dev, MC1, MASK_20); // DMA3 off + + memset(budget->grabbing, 0x00, TS_HEIGHT*TS_WIDTH); + + saa7146_write(dev, PCI_BT_V1, 0x001c0000 | + (saa7146_read(dev, PCI_BT_V1) & ~0x001f0000)); + + budget->tsf=0xff; + budget->ttbp=0; + saa7146_write(dev, DD1_INIT, 0x02000600); + saa7146_write(dev, MC2, (MASK_09 | MASK_25 | MASK_10 | MASK_26)); + + saa7146_write(dev, BRS_CTRL, 0x60000000); + saa7146_write(dev, MC2, (MASK_08 | MASK_24)); + mdelay(10); + + saa7146_write(dev, BASE_ODD3, 0); + saa7146_write(dev, BASE_EVEN3, TS_WIDTH*TS_HEIGHT/2); + saa7146_write(dev, PROT_ADDR3, TS_WIDTH*TS_HEIGHT); + saa7146_write(dev, BASE_PAGE3, budget->pt.dma |ME1|0x90); + saa7146_write(dev, PITCH3, TS_WIDTH); + + saa7146_write(dev, NUM_LINE_BYTE3, ((TS_HEIGHT/2)<<16)|TS_WIDTH); + saa7146_write(dev, MC2, (MASK_04 | MASK_20)); + saa7146_write(dev, MC1, (MASK_04 | MASK_20)); // DMA3 on + + IER_ENABLE(budget->dev, MASK_10); // VPE + + return ++budget->feeding; +} + + +static +void vpeirq (unsigned long data) +{ + struct budget *budget = (struct budget*) data; + u8 *mem = (u8 *)(budget->grabbing); + u32 olddma = budget->ttbp; + u32 newdma = saa7146_read(budget->dev, PCI_VDP3); + + /* nearest lower position divisible by 188 */ + newdma -= newdma % 188; + + if (newdma >= TS_BUFLEN) + return; + + budget->ttbp = newdma; + + if(budget->feeding == 0 || newdma == olddma) + return; + + if (newdma > olddma) { /* no wraparound, dump olddma..newdma */ + if(mem[olddma] == 0x47) + dvb_dmx_swfilter_packets(&budget->demux, + mem+olddma, (newdma-olddma) / 188); + } else { /* wraparound, dump olddma..buflen and 0..newdma */ + if(mem[olddma] == 0x47) + dvb_dmx_swfilter_packets(&budget->demux, + mem+olddma, (TS_BUFLEN-olddma) / 188); + if(mem[0] == 0x47) + dvb_dmx_swfilter_packets(&budget->demux, + mem, newdma / 188); + } +} + + +/**************************************************************************** + * DVB API SECTION + ****************************************************************************/ + +static +int budget_start_feed(struct dvb_demux_feed *feed) +{ + struct dvb_demux *demux = feed->demux; + struct budget *budget = (struct budget*) demux->priv; + + DEB_EE(("budget: %p\n",budget)); + + if (!demux->dmx.frontend) + return -EINVAL; + + return start_ts_capture (budget); +} + +static +int budget_stop_feed(struct dvb_demux_feed *feed) +{ + struct dvb_demux *demux = feed->demux; + struct budget *budget = (struct budget *) demux->priv; + + DEB_EE(("budget: %p\n",budget)); + + return stop_ts_capture (budget); +} + + +static +int budget_register(struct budget *budget) +{ + int ret; + dmx_frontend_t *dvbfront=&budget->hw_frontend; + struct dvb_demux *dvbdemux=&budget->demux; + + DEB_EE(("budget: %p\n",budget)); + + memcpy(budget->demux_id, "demux0_0", 9); + budget->demux_id[5] = budget->dvb_adapter->num + '0'; + dvbdemux->priv = (void *) budget; + + dvbdemux->filternum = 256; + dvbdemux->feednum = 256; + dvbdemux->start_feed = budget_start_feed; + dvbdemux->stop_feed = budget_stop_feed; + dvbdemux->write_to_decoder = NULL; + + dvbdemux->dmx.vendor = "CIM"; + dvbdemux->dmx.model = "sw"; + dvbdemux->dmx.id = budget->demux_id; + dvbdemux->dmx.capabilities = (DMX_TS_FILTERING | DMX_SECTION_FILTERING | + DMX_MEMORY_BASED_FILTERING); + + dvb_dmx_init(&budget->demux); + + dvbfront->id = "hw_frontend"; + dvbfront->vendor = "VLSI"; + dvbfront->model = "DVB Frontend"; + dvbfront->source = DMX_FRONTEND_0; + + budget->dmxdev.filternum = 256; + budget->dmxdev.demux = &dvbdemux->dmx; + budget->dmxdev.capabilities = 0; + + dvb_dmxdev_init(&budget->dmxdev, budget->dvb_adapter); + + ret=dvbdemux->dmx.add_frontend (&dvbdemux->dmx, + &budget->hw_frontend); + if (ret < 0) + return ret; + + budget->mem_frontend.id = "mem_frontend"; + budget->mem_frontend.vendor = "memory"; + budget->mem_frontend.model = "sw"; + budget->mem_frontend.source = DMX_MEMORY_FE; + ret=dvbdemux->dmx.add_frontend (&dvbdemux->dmx, + &budget->mem_frontend); + if (ret<0) + return ret; + + ret=dvbdemux->dmx.connect_frontend (&dvbdemux->dmx, + &budget->hw_frontend); + if (ret < 0) + return ret; + + budget->dvb_net.card_num = budget->dvb_adapter->num; + dvb_net_init(budget->dvb_adapter, &budget->dvb_net, &dvbdemux->dmx); + + return 0; +} + + +static +void budget_unregister(struct budget *budget) +{ + struct dvb_demux *dvbdemux=&budget->demux; + + DEB_EE(("budget: %p\n",budget)); + + dvb_net_release(&budget->dvb_net); + + dvbdemux->dmx.close(&dvbdemux->dmx); + dvbdemux->dmx.remove_frontend(&dvbdemux->dmx, &budget->hw_frontend); + dvbdemux->dmx.remove_frontend(&dvbdemux->dmx, &budget->mem_frontend); + + dvb_dmxdev_release(&budget->dmxdev); + dvb_dmx_release(&budget->demux); +} + + +static +int master_xfer (struct dvb_i2c_bus *i2c, const struct i2c_msg msgs[], int num) +{ + struct saa7146_dev *dev = i2c->data; + return saa7146_i2c_transfer(dev, msgs, num, 6); +} + + +int ttpci_budget_init (struct budget *budget, + struct saa7146_dev* dev, + struct saa7146_pci_extension_data *info) +{ + int length = TS_WIDTH*TS_HEIGHT; + int ret = 0; + struct budget_info *bi = info->ext_priv; + + memset(budget, 0, sizeof(struct budget)); + + DEB_EE(("dev: %p, budget: %p\n", dev, budget)); + + budget->card = bi; + budget->dev = (struct saa7146_dev *) dev; + + dvb_register_adapter(&budget->dvb_adapter, budget->card->name); + + /* set dd1 stream a & b */ + saa7146_write(dev, DD1_STREAM_B, 0x00000000); + saa7146_write(dev, DD1_INIT, 0x02000000); + saa7146_write(dev, MC2, (MASK_09 | MASK_25 | MASK_10 | MASK_26)); + + /* the Siemens DVB needs this if you want to have the i2c chips + get recognized before the main driver is loaded */ + saa7146_write(dev, GPIO_CTRL, 0x500000); + + saa7146_i2c_adapter_prepare(dev, NULL, SAA7146_I2C_BUS_BIT_RATE_3200); + + budget->i2c_bus = dvb_register_i2c_bus (master_xfer, dev, + budget->dvb_adapter, 0); + + if (!budget->i2c_bus) { + dvb_unregister_adapter (budget->dvb_adapter); + return -ENOMEM; + } + + if( NULL == (budget->grabbing = saa7146_vmalloc_build_pgtable(dev->pci,length,&budget->pt))) { + ret = -ENOMEM; + goto err; + } + + saa7146_write(dev, PCI_BT_V1, 0x001c0000); + /* upload all */ + saa7146_write(dev, GPIO_CTRL, 0x000000); + + tasklet_init (&budget->vpe_tasklet, vpeirq, (unsigned long) budget); + + saa7146_setgpio(dev, 2, SAA7146_GPIO_OUTHI); /* frontend power on */ + + if (budget_register(budget) == 0) + return 0; + +err: + if (budget->grabbing) + vfree(budget->grabbing); + + dvb_unregister_i2c_bus (master_xfer,budget->i2c_bus->adapter, + budget->i2c_bus->id); + + dvb_unregister_adapter (budget->dvb_adapter); + + return ret; +} + + +int ttpci_budget_deinit (struct budget *budget) +{ + struct saa7146_dev *dev = budget->dev; + + DEB_EE(("budget: %p\n", budget)); + + budget_unregister (budget); + + dvb_unregister_i2c_bus (master_xfer, budget->i2c_bus->adapter, + budget->i2c_bus->id); + + dvb_unregister_adapter (budget->dvb_adapter); + + tasklet_kill (&budget->vpe_tasklet); + + saa7146_pgtable_free (dev->pci, &budget->pt); + + vfree (budget->grabbing); + kfree (budget); + + return 0; +} + +void ttpci_budget_irq10_handler (struct saa7146_dev* dev, u32 *isr) +{ + struct budget *budget = (struct budget*)dev->ext_priv; + + DEB_EE(("dev: %p, budget: %p\n",dev,budget)); + + if (*isr & MASK_10) + tasklet_schedule (&budget->vpe_tasklet); +} + + +EXPORT_SYMBOL_GPL(ttpci_budget_init); +EXPORT_SYMBOL_GPL(ttpci_budget_deinit); +EXPORT_SYMBOL_GPL(ttpci_budget_irq10_handler); +EXPORT_SYMBOL_GPL(budget_debug); + +MODULE_PARM(budget_debug,"i"); +MODULE_LICENSE("GPL"); + + diff --git a/linux/drivers/media/dvb/ttpci/budget-patch.c b/linux/drivers/media/dvb/ttpci/budget-patch.c new file mode 100644 index 000000000..7e1cb6d73 --- /dev/null +++ b/linux/drivers/media/dvb/ttpci/budget-patch.c @@ -0,0 +1,335 @@ +/* + * budget-patch.c: driver for Budget Patch, + * hardware modification of DVB-S cards enabling full TS + * + * Written by Emard <emard@softhome.net> + * + * Original idea by Roberto Deza <rdeza@unav.es> + * + * Special thanks to Holger Waechtler, Michael Hunold, Marian Durkovic + * and Metzlerbros + * + * 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 + * + * + * the project's page is at http://www.linuxtv.org/dvb/ + */ + +#include "budget.h" +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,51) + #define KBUILD_MODNAME budget_patch +#endif + +#define budget_patch budget + +static struct saa7146_extension budget_extension; + +MAKE_BUDGET_INFO(fs_1_3,"Siemens/Technotrend/Hauppauge PCI rev1.3+Budget_Patch", BUDGET_PATCH); + +static +struct pci_device_id pci_tbl[] = { + MAKE_EXTENSION_PCI(fs_1_3,0x13c2, 0x0000), + { + .vendor = 0, + } +}; + + +#define COMMAND (DPRAM_BASE + 0x0FC) +#define DPRAM_BASE 0x4000 +#define DEBINOSWAP 0x000e0000 + + +typedef enum { + AudioDAC, + CabADAC, + ON22K, + OFF22K, + MainSwitch, + ADSwitch, + SendDiSEqC, + SetRegister +} AUDCOM; + + +typedef enum { + COMTYPE_NOCOM, + COMTYPE_PIDFILTER, + COMTYPE_MPEGDECODER, + COMTYPE_OSD, + COMTYPE_BMP, + COMTYPE_ENCODER, + COMTYPE_AUDIODAC, + COMTYPE_REQUEST, + COMTYPE_SYSTEM, + COMTYPE_REC_PLAY, + COMTYPE_COMMON_IF, + COMTYPE_PID_FILTER, + COMTYPE_PES, + COMTYPE_TS, + COMTYPE_VIDEO, + COMTYPE_AUDIO, + COMTYPE_CI_LL, +} COMTYPE; + + +static +int wdebi(struct budget_patch *budget, u32 config, int addr, u32 val, int count) +{ + struct saa7146_dev *dev=budget->dev; + + DEB_EE(("budget: %p\n", budget)); + + if (count <= 0 || count > 4) + return -1; + + saa7146_write(dev, DEBI_CONFIG, config); + + saa7146_write(dev, DEBI_AD, val ); + saa7146_write(dev, DEBI_COMMAND, (count << 17) | (addr & 0xffff)); + saa7146_write(dev, MC2, (2 << 16) | 2); + mdelay(5); + + return 0; +} + + +static +int SOutCommand(struct budget_patch *budget, u16* buf, int length) +{ + int i; + + DEB_EE(("budget: %p\n", budget)); + + for (i = 2; i < length; i++) + wdebi(budget, DEBINOSWAP, COMMAND + 2*i, (u32) buf[i], 2); + + if (length) + wdebi(budget, DEBINOSWAP, COMMAND + 2, (u32) buf[1], 2); + else + wdebi(budget, DEBINOSWAP, COMMAND + 2, 0, 2); + + wdebi(budget, DEBINOSWAP, COMMAND, (u32) buf[0], 2); + return 0; +} + + +static +void av7110_set22k(struct budget_patch *budget, int state) +{ + u16 buf[2] = {( COMTYPE_AUDIODAC << 8) | (state ? ON22K : OFF22K), 0}; + + DEB_EE(("budget: %p\n", budget)); + SOutCommand(budget, buf, 2); +} + + +static int +av7110_send_diseqc_msg(struct budget_patch *budget, int len, u8 *msg, int burst) +{ + int i; + u16 buf[18] = { ((COMTYPE_AUDIODAC << 8) | SendDiSEqC), + 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; + + DEB_EE(("budget: %p\n", budget)); + + if (len>10) + len=10; + + buf[1] = len+2; + buf[2] = len; + + if (burst != -1) + buf[3]=burst ? 0x01 : 0x00; + else + buf[3]=0xffff; + + for (i=0; i<len; i++) + buf[i+4]=msg[i]; + + SOutCommand(budget, buf, 18); + return 0; +} + + +int budget_patch_diseqc_ioctl (struct dvb_frontend *fe, unsigned int cmd, void *arg) +{ + struct budget_patch *budget = fe->before_after_data; + + DEB_EE(("budget: %p\n", budget)); + + switch (cmd) { + case FE_SET_TONE: + switch ((fe_sec_tone_mode_t) arg) { + case SEC_TONE_ON: + av7110_set22k (budget, 1); + break; + case SEC_TONE_OFF: + av7110_set22k (budget, 0); + break; + default: + return -EINVAL; + } + break; + + case FE_DISEQC_SEND_MASTER_CMD: + { + struct dvb_diseqc_master_cmd *cmd = arg; + + av7110_send_diseqc_msg (budget, cmd->msg_len, cmd->msg, 0); + break; + } + + case FE_DISEQC_SEND_BURST: + av7110_send_diseqc_msg (budget, 0, NULL, (int) arg); + break; + + default: + return -EOPNOTSUPP; + } + + return 0; +} + + +static +int budget_patch_attach (struct saa7146_dev* dev, struct saa7146_pci_extension_data *info) +{ + struct budget_patch *budget; + int err; + int cnt; + + if (!(budget = kmalloc (sizeof(struct budget_patch), GFP_KERNEL))) + return -ENOMEM; + + DEB_EE(("budget: %p\n",budget)); + + if ((err = ttpci_budget_init (budget, dev, info))) { + kfree (budget); + return err; + } + +/* +** This code will setup the SAA7146_RPS1 to generate a square +** wave on GPIO3, changing when a field (TS_HEIGHT/2 "lines" of +** TS_WIDTH packets) has been acquired on SAA7146_D1B video port; +** then, this GPIO3 output which is connected to the D1B_VSYNC +** input, will trigger the acquisition of the alternate field +** and so on. +** Currently, the TT_budget / WinTV_Nova cards have two ICs +** (74HCT4040, LVC74) for the generation of this VSYNC signal, +** which seems that can be done perfectly without this :-)). +*/ + cnt = 0; // Setup RPS1 "program" (p35) + // Wait reset Source Line Counter Threshold (p36) + dev->rps1[cnt++]=cpu_to_le32(CMD_PAUSE | RPS_INV | EVT_HS); + // Wait Source Line Counter Threshold (p36) + dev->rps1[cnt++]=cpu_to_le32(CMD_PAUSE | EVT_HS); + // Set GPIO3=1 (p42) + dev->rps1[cnt++]=cpu_to_le32(CMD_WR_REG_MASK | (GPIO_CTRL>>2)); + dev->rps1[cnt++]=cpu_to_le32(GPIO3_MSK); + dev->rps1[cnt++]=cpu_to_le32(SAA7146_GPIO_OUTHI<<24); + // Wait reset Source Line Counter Threshold (p36) + dev->rps1[cnt++]=cpu_to_le32(CMD_PAUSE | RPS_INV | EVT_HS); + // Wait Source Line Counter Threshold + dev->rps1[cnt++]=cpu_to_le32(CMD_PAUSE | EVT_HS); + // Set GPIO3=0 (p42) + dev->rps1[cnt++]=cpu_to_le32(CMD_WR_REG_MASK | (GPIO_CTRL>>2)); + dev->rps1[cnt++]=cpu_to_le32(GPIO3_MSK); + dev->rps1[cnt++]=cpu_to_le32(SAA7146_GPIO_OUTLO<<24); + // Jump to begin of RPS program (p37) + dev->rps1[cnt++]=cpu_to_le32(CMD_JUMP); + dev->rps1[cnt++]=cpu_to_le32(virt_to_bus(&dev->rps1[0])); + + // Fix VSYNC level + saa7146_setgpio(dev, 3, SAA7146_GPIO_OUTLO); + // Set RPS1 Address register to point to RPS code (r108 p42) + saa7146_write(dev, RPS_ADDR1, virt_to_bus(&dev->rps1[0])); + // Set Source Line Counter Threshold, using BRS (rCC p43) + saa7146_write(dev, RPS_THRESH1, ((TS_HEIGHT/2) | MASK_12)); + // Enable RPS1 (rFC p33) + saa7146_write(dev, MC1, (MASK_13 | MASK_29)); + + dvb_add_frontend_ioctls (budget->dvb_adapter, + budget_patch_diseqc_ioctl, NULL, budget); + + dev->ext_priv = budget; + + return 0; +} + + +static +int budget_patch_detach (struct saa7146_dev* dev) +{ + struct budget_patch *budget = (struct budget_patch*) dev->ext_priv; + int err; + + dvb_remove_frontend_ioctls (budget->dvb_adapter, + budget_patch_diseqc_ioctl, NULL); + + err = ttpci_budget_deinit (budget); + + kfree (budget); + + return err; +} + + +static +int __init budget_patch_init(void) +{ + if (saa7146_register_extension(&budget_extension)) + return -ENODEV; + + return 0; +} + + +static +void __exit budget_patch_exit(void) +{ + DEB_EE((".\n")); + saa7146_unregister_extension(&budget_extension); +} + + +static +struct saa7146_extension budget_extension = { + .name = "budget_patch dvb\0", + .flags = 0, + .ext_vv_data = NULL, + + .module = THIS_MODULE, + .pci_tbl = pci_tbl, + .attach = budget_patch_attach, + .detach = budget_patch_detach, + + .irq_mask = MASK_10, + .irq_func = ttpci_budget_irq10_handler, +}; + + +module_init(budget_patch_init); +module_exit(budget_patch_exit); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Emard, Roberto Deza, Holger Waechtler, Michael Hunold, others"); +MODULE_DESCRIPTION("Driver for full TS modified DVB-S SAA7146+AV7110 " + "based so-called Budget Patch cards"); + diff --git a/linux/drivers/media/dvb/ttpci/budget.c b/linux/drivers/media/dvb/ttpci/budget.c new file mode 100644 index 000000000..545101f44 --- /dev/null +++ b/linux/drivers/media/dvb/ttpci/budget.c @@ -0,0 +1,267 @@ +/* + * budget.c: driver for the SAA7146 based Budget DVB cards + * + * Compiled from various sources by Michael Hunold <michael@mihu.de> + * + * Copyright (C) 2002 Ralph Metzler <rjkm@metzlerbros.de> + * + * Copyright (C) 1999-2002 Ralph Metzler + * & Marcus Metzler for convergence integrated media GmbH + * + * 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 + * + * + * the project's page is at http://www.linuxtv.org/dvb/ + */ + +#include "budget.h" +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,51) + #define KBUILD_MODNAME budget +#endif + + + +static inline void ddelay(int i) +{ + current->state=TASK_INTERRUPTIBLE; + schedule_timeout((HZ*i)/100); +} + + +static +void Set22K (struct budget *budget, int state) +{ + struct saa7146_dev *dev=budget->dev; + DEB_EE(("budget: %p\n",budget)); + saa7146_setgpio(dev, 3, (state ? SAA7146_GPIO_OUTHI : SAA7146_GPIO_OUTLO)); +} + + +/* Diseqc functions only for TT Budget card */ +/* taken from the Skyvision DVB driver by + Ralph Metzler <rjkm@metzlerbros.de> */ + +static +void DiseqcSendBit (struct budget *budget, int data) +{ + struct saa7146_dev *dev=budget->dev; + DEB_EE(("budget: %p\n",budget)); + + saa7146_setgpio(dev, 3, SAA7146_GPIO_OUTHI); + udelay(data ? 500 : 1000); + saa7146_setgpio(dev, 3, SAA7146_GPIO_OUTLO); + udelay(data ? 1000 : 500); +} + + +static +void DiseqcSendByte (struct budget *budget, int data) +{ + int i, par=1, d; + + DEB_EE(("budget: %p\n",budget)); + + for (i=7; i>=0; i--) { + d = (data>>i)&1; + par ^= d; + DiseqcSendBit(budget, d); + } + + DiseqcSendBit(budget, par); +} + + +static +int SendDiSEqCMsg (struct budget *budget, int len, u8 *msg, int burst) +{ + struct saa7146_dev *dev=budget->dev; + int i; + + DEB_EE(("budget: %p\n",budget)); + + saa7146_setgpio(dev, 3, SAA7146_GPIO_OUTLO); + mdelay(16); + + for (i=0; i<len; i++) + DiseqcSendByte(budget, msg[i]); + + mdelay(16); + + if (burst!=-1) { + if (burst) + DiseqcSendByte(budget, 0xff); + else { + saa7146_setgpio(dev, 3, SAA7146_GPIO_OUTHI); + udelay(12500); + saa7146_setgpio(dev, 3, SAA7146_GPIO_OUTLO); + } + ddelay(2); + } + + return 0; +} + + +int budget_diseqc_ioctl (struct dvb_frontend *fe, unsigned int cmd, void *arg) +{ + struct budget *budget = fe->before_after_data; + + DEB_EE(("budget: %p\n",budget)); + + switch (cmd) { + case FE_SET_TONE: + switch ((fe_sec_tone_mode_t) arg) { + case SEC_TONE_ON: + Set22K (budget, 1); + break; + case SEC_TONE_OFF: + Set22K (budget, 0); + break; + default: + return -EINVAL; + }; + break; + + case FE_DISEQC_SEND_MASTER_CMD: + { + struct dvb_diseqc_master_cmd *cmd = arg; + + SendDiSEqCMsg (budget, cmd->msg_len, cmd->msg, 0); + break; + } + + case FE_DISEQC_SEND_BURST: + SendDiSEqCMsg (budget, 0, NULL, (int) arg); + break; + + default: + return -EOPNOTSUPP; + }; + + return 0; +} + + +static +int budget_attach (struct saa7146_dev* dev, struct saa7146_pci_extension_data *info) +{ + struct budget *budget; + int err; + + if (!(budget = kmalloc (sizeof(struct budget), GFP_KERNEL))) + return -ENOMEM; + + DEB_EE(("budget: %p\n",budget)); + + if ((err = ttpci_budget_init (budget, dev, info))) { + kfree (budget); + return err; + } + + dvb_add_frontend_ioctls (budget->dvb_adapter, + budget_diseqc_ioctl, NULL, budget); + + dev->ext_priv = budget; + + return 0; +} + + +static +int budget_detach (struct saa7146_dev* dev) +{ + struct budget *budget = (struct budget*) dev->ext_priv; + int err; + + dvb_remove_frontend_ioctls (budget->dvb_adapter, + budget_diseqc_ioctl, NULL); + + err = ttpci_budget_deinit (budget); + + kfree (budget); + + return err; +} + + + +static struct saa7146_extension budget_extension; + +MAKE_BUDGET_INFO(ttbs, "TT-Budget/WinTV-NOVA-S PCI", BUDGET_TT); +MAKE_BUDGET_INFO(ttbc, "TT-Budget/WinTV-NOVA-C PCI", BUDGET_TT); +MAKE_BUDGET_INFO(ttbt, "TT-Budget/WinTV-NOVA-T PCI", BUDGET_TT); +MAKE_BUDGET_INFO(satel, "SATELCO Multimedia PCI", BUDGET_TT_HW_DISEQC); +/* Uncomment for Budget Patch */ +/*MAKE_BUDGET_INFO(fs_1_3,"Siemens/Technotrend/Hauppauge PCI rev1.3+Budget_Patch", BUDGET_PATCH);*/ + +static +struct pci_device_id pci_tbl[] = { + /* Uncomment for Budget Patch */ + /*MAKE_EXTENSION_PCI(fs_1_3,0x13c2, 0x0000),*/ + MAKE_EXTENSION_PCI(ttbs, 0x13c2, 0x1003), + MAKE_EXTENSION_PCI(ttbc, 0x13c2, 0x1004), + MAKE_EXTENSION_PCI(ttbt, 0x13c2, 0x1005), + MAKE_EXTENSION_PCI(satel, 0x13c2, 0x1013), + { + .vendor = 0, + } +}; + + + +static +struct saa7146_extension budget_extension = { + .name = "budget dvb\0", + .flags = 0, + .ext_vv_data = NULL, + + .module = THIS_MODULE, + .pci_tbl = pci_tbl, + .attach = budget_attach, + .detach = budget_detach, + + .irq_mask = MASK_10, + .irq_func = ttpci_budget_irq10_handler, +}; + + +static +int __init budget_init(void) +{ + if (saa7146_register_extension(&budget_extension)) + return -ENODEV; + + return 0; +} + + +static +void __exit budget_exit(void) +{ + DEB_EE((".\n")); + saa7146_unregister_extension(&budget_extension); +} + +module_init(budget_init); +module_exit(budget_exit); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Ralph Metzler, Marcus Metzler, Michael Hunold, others"); +MODULE_DESCRIPTION("driver for the SAA7146 based so-called " + "budget PCI DVB cards by Siemens, Technotrend, Hauppauge"); + diff --git a/linux/drivers/media/dvb/ttpci/budget.h b/linux/drivers/media/dvb/ttpci/budget.h new file mode 100644 index 000000000..09dbb2735 --- /dev/null +++ b/linux/drivers/media/dvb/ttpci/budget.h @@ -0,0 +1,86 @@ +#ifndef __BUDGET_DVB__ +#define __BUDGET_DVB__ + +#include "dvb_i2c.h" +#include "dvb_frontend.h" +#include "dvbdev.h" +#include "demux.h" +#include "dvb_demux.h" +#include "dmxdev.h" +#include "dvb_filter.h" +#include "dvb_net.h" +#include "saa7146.h" + + +extern int budget_debug; + +struct budget_info { + char *name; + int type; +}; + +/* place to store all the necessary device information */ +struct budget { + + /* devices */ + struct dvb_device dvb_dev; + dvb_net_t dvb_net; + + struct saa7146_dev *dev; + + struct dvb_i2c_bus *i2c_bus; + struct budget_info *card; + + unsigned char *grabbing; + struct saa7146_pgtable pt; + + struct tasklet_struct fidb_tasklet; + struct tasklet_struct vpe_tasklet; + + dmxdev_t dmxdev; + struct dvb_demux demux; + char demux_id[16]; + + dmx_frontend_t hw_frontend; + dmx_frontend_t mem_frontend; + + int fe_synced; + struct semaphore pid_mutex; + + u8 tsf; + u32 ttbp; + int feeding; + + struct dvb_adapter *dvb_adapter; + void *priv; +}; + + + +#define MAKE_BUDGET_INFO(x_var,x_name,x_type) \ +static struct budget_info x_var ## _info = { \ + .name=x_name, \ + .type=x_type }; \ +static struct saa7146_pci_extension_data x_var = { \ + .ext_priv = &x_var ## _info, \ + .ext = &budget_extension }; + +#define TS_WIDTH (4*188) +#define TS_HEIGHT (1024/4) +#define TS_BUFLEN (TS_WIDTH*TS_HEIGHT) +#define TS_MAX_PACKETS (TS_BUFLEN/TS_SIZE) + +#define BUDGET_TT 0 +#define BUDGET_TT_HW_DISEQC 1 +#define BUDGET_KNC1 2 +#define BUDGET_PATCH 3 + + +extern int ttpci_budget_init (struct budget *budget, + struct saa7146_dev* dev, + struct saa7146_pci_extension_data *info); +extern int ttpci_budget_deinit (struct budget *budget); +extern void ttpci_budget_irq10_handler (struct saa7146_dev* dev, u32 *isr); + +#endif + |