Commit 2b7f4a04 authored by Michael Hunold's avatar Michael Hunold Committed by Linus Torvalds

[PATCH] DVB: Update DVB budget drivers

 - [DVB] budget-av: patch by Kenneth Aafløy to add support for Typhoon
   DVB-S budget card
 - [DVB] budget.c: support for Fujitsu-Siemens Activy Card
 - [DVB] budget-ci: add preliminary CI support
parent 2343a8c0
...@@ -39,6 +39,7 @@ struct budget_av { ...@@ -39,6 +39,7 @@ struct budget_av {
struct budget budget; struct budget budget;
struct video_device vd; struct video_device vd;
int cur_input; int cur_input;
int has_saa7113;
}; };
/**************************************************************************** /****************************************************************************
...@@ -149,6 +150,9 @@ static int saa7113_setinput (struct budget_av *budget_av, int input) ...@@ -149,6 +150,9 @@ static int saa7113_setinput (struct budget_av *budget_av, int input)
{ {
struct budget *budget = &budget_av->budget; struct budget *budget = &budget_av->budget;
if ( 1 != budget_av->has_saa7113 )
return -ENODEV;
if (input == 1) { if (input == 1) {
i2c_writereg(budget->i2c_bus, 0x4a, 0x02, 0xc7); i2c_writereg(budget->i2c_bus, 0x4a, 0x02, 0xc7);
i2c_writereg(budget->i2c_bus, 0x4a, 0x09, 0x80); i2c_writereg(budget->i2c_bus, 0x4a, 0x09, 0x80);
...@@ -170,11 +174,13 @@ static int budget_av_detach (struct saa7146_dev *dev) ...@@ -170,11 +174,13 @@ static int budget_av_detach (struct saa7146_dev *dev)
DEB_EE(("dev: %p\n",dev)); DEB_EE(("dev: %p\n",dev));
if ( 1 == budget_av->has_saa7113 ) {
saa7146_setgpio(dev, 0, SAA7146_GPIO_OUTLO); saa7146_setgpio(dev, 0, SAA7146_GPIO_OUTLO);
dvb_delay(200); dvb_delay(200);
saa7146_unregister_device (&budget_av->vd, dev); saa7146_unregister_device (&budget_av->vd, dev);
}
err = ttpci_budget_deinit (&budget_av->budget); err = ttpci_budget_deinit (&budget_av->budget);
...@@ -221,11 +227,8 @@ static int budget_av_attach (struct saa7146_dev* dev, ...@@ -221,11 +227,8 @@ static int budget_av_attach (struct saa7146_dev* dev,
saa7146_setgpio(dev, 0, SAA7146_GPIO_OUTHI); saa7146_setgpio(dev, 0, SAA7146_GPIO_OUTHI);
dvb_delay(500); dvb_delay(500);
if ((err = saa7113_init (budget_av))) { if ( 0 == saa7113_init(budget_av) ) {
/* fixme: proper cleanup here */ budget_av->has_saa7113 = 1;
ERR(("cannot init saa7113.\n"));
return err;
}
if ( 0 != saa7146_vv_init(dev,&vv_data)) { if ( 0 != saa7146_vv_init(dev,&vv_data)) {
/* fixme: proper cleanup here */ /* fixme: proper cleanup here */
...@@ -246,14 +249,12 @@ static int budget_av_attach (struct saa7146_dev* dev, ...@@ -246,14 +249,12 @@ static int budget_av_attach (struct saa7146_dev* dev,
SAA7146_HPS_SYNC_PORT_A); SAA7146_HPS_SYNC_PORT_A);
saa7113_setinput (budget_av, 0); saa7113_setinput (budget_av, 0);
} else {
budget_av->has_saa7113 = 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); saa7146_setgpio(dev, 0, SAA7146_GPIO_OUTLO);
set_current_state(TASK_INTERRUPTIBLE); }
schedule_timeout (20);
*/
/* fixme: find some sane values here... */ /* fixme: find some sane values here... */
saa7146_write(dev, PCI_BT_V1, 0x1c00101f); saa7146_write(dev, PCI_BT_V1, 0x1c00101f);
...@@ -333,13 +334,13 @@ static int av_ioctl(struct saa7146_fh *fh, unsigned int cmd, void *arg) ...@@ -333,13 +334,13 @@ static int av_ioctl(struct saa7146_fh *fh, unsigned int cmd, void *arg)
static struct saa7146_standard standard[] = { static struct saa7146_standard standard[] = {
{ {
.name = "PAL", .id = V4L2_STD_PAL, .name = "PAL", .id = V4L2_STD_PAL,
.v_offset = 0x17, .v_field = 288, .v_calc = 576, .v_offset = 0x17, .v_field = 288,
.h_offset = 0x14, .h_pixels = 680, .h_calc = 680+1, .h_offset = 0x14, .h_pixels = 680,
.v_max_out = 576, .h_max_out = 768, .v_max_out = 576, .h_max_out = 768
}, { }, {
.name = "NTSC", .id = V4L2_STD_NTSC, .name = "NTSC", .id = V4L2_STD_NTSC,
.v_offset = 0x16, .v_field = 240, .v_calc = 480, .v_offset = 0x16, .v_field = 240,
.h_offset = 0x06, .h_pixels = 708, .h_calc = 708+1, .h_offset = 0x06, .h_pixels = 708,
.v_max_out = 480, .h_max_out = 640, .v_max_out = 480, .h_max_out = 640,
} }
}; };
......
...@@ -6,6 +6,8 @@ ...@@ -6,6 +6,8 @@
* msp430 IR support contributed by Jack Thomasson <jkt@Helius.COM> * msp430 IR support contributed by Jack Thomasson <jkt@Helius.COM>
* partially based on the Siemens DVB driver by Ralph+Marcus Metzler * partially based on the Siemens DVB driver by Ralph+Marcus Metzler
* *
* CI interface support (c) 2004 Andrew de Quincey <adq_dvb@lidskialf.net>
*
* This program is free software; you can redistribute it and/or * This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License * modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2 * as published by the Free Software Foundation; either version 2
...@@ -34,37 +36,103 @@ ...@@ -34,37 +36,103 @@
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/interrupt.h> #include <linux/interrupt.h>
#include <linux/input.h> #include <linux/input.h>
#include <linux/spinlock.h>
#include "dvb_functions.h"
#include "dvb_ca_en50221.h"
#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0))
#include "input_fake.h"
#endif
#define DEBIADDR_IR 0x1234
#define DEBIADDR_CICONTROL 0x0000
#define DEBIADDR_CIVERSION 0x4000
#define DEBIADDR_IO 0x1000
#define DEBIADDR_ATTR 0x3000
#define CICONTROL_RESET 0x01
#define CICONTROL_ENABLETS 0x02
#define CICONTROL_CAMDETECT 0x08
#define DEBICICTL 0x00420000
#define DEBICICAM 0x02420000
#define SLOTSTATUS_NONE 1
#define SLOTSTATUS_PRESENT 2
#define SLOTSTATUS_RESET 4
#define SLOTSTATUS_READY 8
#define SLOTSTATUS_OCCUPIED (SLOTSTATUS_PRESENT|SLOTSTATUS_RESET|SLOTSTATUS_READY)
struct budget_ci { struct budget_ci {
struct budget budget; struct budget budget;
struct input_dev input_dev; struct input_dev input_dev;
struct tasklet_struct msp430_irq_tasklet; struct tasklet_struct msp430_irq_tasklet;
struct tasklet_struct ciintf_irq_tasklet;
spinlock_t debilock;
int slot_status;
struct dvb_ca_en50221 ca;
char ir_dev_name[50];
}; };
static u32 budget_debiread4 (struct saa7146_dev *saa, u32 config, int addr, int count) static u32 budget_debiread (struct budget_ci* budget_ci, u32 config, int addr, int count)
{ {
struct saa7146_dev *saa = budget_ci->budget.dev;
u32 result = 0; u32 result = 0;
if (count > 4 || count <= 0) if (count > 4 || count <= 0)
return 0; return 0;
if (saa7146_wait_for_debi_done(saa) < 0) spin_lock(&budget_ci->debilock);
if (saa7146_wait_for_debi_done(saa) < 0) {
spin_unlock(&budget_ci->debilock);
return 0; return 0;
}
saa7146_write (saa, DEBI_COMMAND, saa7146_write (saa, DEBI_COMMAND,
(count << 17) | 0x10000 | (addr & 0xffff)); (count << 17) | 0x10000 | (addr & 0xffff));
saa7146_write(saa, DEBI_CONFIG, config); saa7146_write(saa, DEBI_CONFIG, config);
saa7146_write(saa, DEBI_PAGE, 0);
saa7146_write(saa, MC2, (2 << 16) | 2); saa7146_write(saa, MC2, (2 << 16) | 2);
saa7146_wait_for_debi_done(saa); saa7146_wait_for_debi_done(saa);
result = saa7146_read(saa, DEBI_AD); result = saa7146_read(saa, 0x88);
result &= (0xffffffffUL >> ((4 - count) * 8)); result &= (0xffffffffUL >> ((4 - count) * 8));
spin_unlock(&budget_ci->debilock);
return result; return result;
} }
static u8 budget_debiwrite (struct budget_ci* budget_ci, u32 config, int addr, int count, u32 value)
{
struct saa7146_dev *saa = budget_ci->budget.dev;
if (count > 4 || count <= 0)
return 0;
spin_lock(&budget_ci->debilock);
if (saa7146_wait_for_debi_done(saa) < 0) {
spin_unlock(&budget_ci->debilock);
return 0;
}
saa7146_write (saa, DEBI_COMMAND,
(count << 17) | 0x00000 | (addr & 0xffff));
saa7146_write(saa, DEBI_CONFIG, config);
saa7146_write(saa, DEBI_PAGE, 0);
saa7146_write(saa, DEBI_AD, value);
saa7146_write(saa, MC2, (2 << 16) | 2);
saa7146_wait_for_debi_done(saa);
spin_unlock(&budget_ci->debilock);
return 0;
}
/* from reading the following remotes: /* from reading the following remotes:
Zenith Universal 7 / TV Mode 807 / VCR Mode 837 Zenith Universal 7 / TV Mode 807 / VCR Mode 837
Hauppauge (from NOVA-CI-s box product) Hauppauge (from NOVA-CI-s box product)
...@@ -140,9 +208,8 @@ static void msp430_ir_debounce (unsigned long data) ...@@ -140,9 +208,8 @@ static void msp430_ir_debounce (unsigned long data)
static void msp430_ir_interrupt (unsigned long data) static void msp430_ir_interrupt (unsigned long data)
{ {
struct budget_ci *budget_ci = (struct budget_ci*) 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; struct input_dev *dev = &budget_ci->input_dev;
unsigned int code = budget_debiread4(saa, DEBINOSWAP, 0x1234, 2) >> 8; unsigned int code = budget_debiread(budget_ci, DEBINOSWAP, DEBIADDR_IR, 2) >> 8;
if (code & 0x40) { if (code & 0x40) {
code &= 0x3f; code &= 0x3f;
...@@ -182,7 +249,8 @@ static int msp430_ir_init (struct budget_ci *budget_ci) ...@@ -182,7 +249,8 @@ static int msp430_ir_init (struct budget_ci *budget_ci)
memset(&budget_ci->input_dev, 0, sizeof(struct input_dev)); memset(&budget_ci->input_dev, 0, sizeof(struct input_dev));
budget_ci->input_dev.name = saa->name; sprintf (budget_ci->ir_dev_name, "Budget-CI dvb ir receiver %s", saa->name);
budget_ci->input_dev.name = budget_ci->ir_dev_name;
set_bit(EV_KEY, budget_ci->input_dev.evbit); set_bit(EV_KEY, budget_ci->input_dev.evbit);
...@@ -209,7 +277,6 @@ static void msp430_ir_deinit (struct budget_ci *budget_ci) ...@@ -209,7 +277,6 @@ static void msp430_ir_deinit (struct budget_ci *budget_ci)
saa7146_write(saa, IER, saa7146_read(saa, IER) & ~MASK_06); saa7146_write(saa, IER, saa7146_read(saa, IER) & ~MASK_06);
saa7146_setgpio(saa, 3, SAA7146_GPIO_INPUT); saa7146_setgpio(saa, 3, SAA7146_GPIO_INPUT);
saa7146_setgpio(saa, 2, SAA7146_GPIO_INPUT);
if (del_timer(&dev->timer)) if (del_timer(&dev->timer))
input_event(dev, EV_KEY, key_map[dev->repeat_key], !!0); input_event(dev, EV_KEY, key_map[dev->repeat_key], !!0);
...@@ -217,6 +284,209 @@ static void msp430_ir_deinit (struct budget_ci *budget_ci) ...@@ -217,6 +284,209 @@ static void msp430_ir_deinit (struct budget_ci *budget_ci)
input_unregister_device(dev); input_unregister_device(dev);
} }
static int ciintf_read_attribute_mem(struct dvb_ca_en50221* ca, int slot, int address) {
struct budget_ci* budget_ci = (struct budget_ci*) ca->data;
if (slot != 0) return -EINVAL;
return budget_debiread(budget_ci, DEBICICAM, DEBIADDR_ATTR | (address & 0xfff), 1);
}
static int ciintf_write_attribute_mem(struct dvb_ca_en50221* ca, int slot, int address, u8 value) {
struct budget_ci* budget_ci = (struct budget_ci*) ca->data;
if (slot != 0) return -EINVAL;
return budget_debiwrite(budget_ci, DEBICICAM, DEBIADDR_ATTR | (address & 0xfff), 1, value);
}
static int ciintf_read_cam_control(struct dvb_ca_en50221* ca, int slot, u8 address) {
struct budget_ci* budget_ci = (struct budget_ci*) ca->data;
if (slot != 0) return -EINVAL;
return budget_debiread(budget_ci, DEBICICAM, DEBIADDR_IO | (address & 3), 1);
}
static int ciintf_write_cam_control(struct dvb_ca_en50221* ca, int slot, u8 address, u8 value) {
struct budget_ci* budget_ci = (struct budget_ci*) ca->data;
if (slot != 0) return -EINVAL;
return budget_debiwrite(budget_ci, DEBICICAM, DEBIADDR_IO | (address & 3), 1, value);
}
static int ciintf_slot_reset(struct dvb_ca_en50221* ca, int slot) {
struct budget_ci* budget_ci = (struct budget_ci*) ca->data;
struct saa7146_dev *saa = budget_ci->budget.dev;
if (slot != 0) return -EINVAL;
// trigger on RISING edge during reset so we know when READY is re-asserted
saa7146_setgpio(saa, 0, SAA7146_GPIO_IRQHI);
budget_ci->slot_status = SLOTSTATUS_RESET;
budget_debiwrite(budget_ci, DEBICICTL, DEBIADDR_CICONTROL, 1, 0);
dvb_delay(1);
budget_debiwrite(budget_ci, DEBICICTL, DEBIADDR_CICONTROL, 1, CICONTROL_RESET);
saa7146_setgpio(saa, 1, SAA7146_GPIO_OUTHI);
ttpci_budget_set_video_port(saa, BUDGET_VIDEO_PORTB);
return 0;
}
static int ciintf_slot_shutdown(struct dvb_ca_en50221* ca, int slot) {
struct budget_ci* budget_ci = (struct budget_ci*) ca->data;
struct saa7146_dev *saa = budget_ci->budget.dev;
if (slot != 0) return -EINVAL;
saa7146_setgpio(saa, 1, SAA7146_GPIO_OUTHI);
ttpci_budget_set_video_port(saa, BUDGET_VIDEO_PORTB);
return 0;
}
static int ciintf_slot_ts_enable(struct dvb_ca_en50221* ca, int slot) {
struct budget_ci* budget_ci = (struct budget_ci*) ca->data;
struct saa7146_dev *saa = budget_ci->budget.dev;
int tmp;
if (slot != 0) return -EINVAL;
saa7146_setgpio(saa, 1, SAA7146_GPIO_OUTLO);
tmp = budget_debiread(budget_ci, DEBICICTL, DEBIADDR_CICONTROL, 1);
budget_debiwrite(budget_ci, DEBICICTL, DEBIADDR_CICONTROL, 1, tmp | CICONTROL_ENABLETS);
ttpci_budget_set_video_port(saa, BUDGET_VIDEO_PORTA);
return 0;
}
static void ciintf_interrupt (unsigned long data)
{
struct budget_ci *budget_ci = (struct budget_ci*) data;
struct saa7146_dev *saa = budget_ci->budget.dev;
unsigned int flags;
// ensure we don't get spurious IRQs during initialisation
if (!budget_ci->budget.ci_present) return;
flags = budget_debiread(budget_ci, DEBICICTL, DEBIADDR_CICONTROL, 1);
// always set the GPIO mode back to "normal", in case the card is
// yanked at an inopportune moment
saa7146_setgpio(saa, 0, SAA7146_GPIO_IRQLO);
if (flags & CICONTROL_CAMDETECT) {
if (budget_ci->slot_status & SLOTSTATUS_NONE) {
// CAM insertion IRQ
budget_ci->slot_status = SLOTSTATUS_PRESENT;
dvb_ca_en50221_camchange_irq(&budget_ci->ca, 0, DVB_CA_EN50221_CAMCHANGE_INSERTED);
} else if (budget_ci->slot_status & SLOTSTATUS_RESET) {
// CAM ready (reset completed)
budget_ci->slot_status = SLOTSTATUS_READY;
dvb_ca_en50221_camready_irq(&budget_ci->ca, 0);
} else if (budget_ci->slot_status & SLOTSTATUS_READY) {
// FR/DA IRQ
dvb_ca_en50221_frda_irq(&budget_ci->ca, 0);
}
} else {
if (budget_ci->slot_status & SLOTSTATUS_OCCUPIED) {
budget_ci->slot_status = SLOTSTATUS_NONE;
dvb_ca_en50221_camchange_irq(&budget_ci->ca, 0, DVB_CA_EN50221_CAMCHANGE_REMOVED);
}
}
}
static int ciintf_init(struct budget_ci* budget_ci)
{
struct saa7146_dev *saa = budget_ci->budget.dev;
int flags;
int result;
memset(&budget_ci->ca, 0, sizeof(struct dvb_ca_en50221));
// enable DEBI pins
saa7146_write(saa, MC1, saa7146_read(saa, MC1) | (0x800 << 16) | 0x800);
// test if it is there
if ((budget_debiread(budget_ci, DEBICICTL, DEBIADDR_CIVERSION, 1) & 0xa0) != 0xa0) {
result = -ENODEV;
goto error;
}
// determine whether a CAM is present or not
flags = budget_debiread(budget_ci, DEBICICTL, DEBIADDR_CICONTROL, 1);
budget_ci->slot_status = SLOTSTATUS_NONE;
if (flags & CICONTROL_CAMDETECT) budget_ci->slot_status = SLOTSTATUS_PRESENT;
// register CI interface
budget_ci->ca.read_attribute_mem = ciintf_read_attribute_mem;
budget_ci->ca.write_attribute_mem = ciintf_write_attribute_mem;
budget_ci->ca.read_cam_control = ciintf_read_cam_control;
budget_ci->ca.write_cam_control = ciintf_write_cam_control;
budget_ci->ca.slot_reset = ciintf_slot_reset;
budget_ci->ca.slot_shutdown = ciintf_slot_shutdown;
budget_ci->ca.slot_ts_enable = ciintf_slot_ts_enable;
budget_ci->ca.data = budget_ci;
if ((result = dvb_ca_en50221_init(budget_ci->budget.dvb_adapter,
&budget_ci->ca,
DVB_CA_EN50221_FLAG_IRQ_CAMCHANGE |
DVB_CA_EN50221_FLAG_IRQ_FR |
DVB_CA_EN50221_FLAG_IRQ_DA,
1)) != 0) {
printk("budget_ci: CI interface detected, but initialisation failed.\n");
goto error;
}
// Setup CI slot IRQ
tasklet_init (&budget_ci->ciintf_irq_tasklet, ciintf_interrupt, (unsigned long) budget_ci);
saa7146_setgpio(saa, 0, SAA7146_GPIO_IRQLO);
saa7146_write(saa, IER, saa7146_read(saa, IER) | MASK_03);
budget_debiwrite(budget_ci, DEBICICTL, DEBIADDR_CICONTROL, 1, CICONTROL_RESET);
// success!
printk("budget_ci: CI interface initialised\n");
budget_ci->budget.ci_present = 1;
// forge a fake CI IRQ so the CAM state is setup correctly
flags = DVB_CA_EN50221_CAMCHANGE_REMOVED;
if (budget_ci->slot_status != SLOTSTATUS_NONE) flags = DVB_CA_EN50221_CAMCHANGE_INSERTED;
dvb_ca_en50221_camchange_irq(&budget_ci->ca, 0, flags);
return 0;
error:
saa7146_write(saa, MC1, saa7146_read(saa, MC1) | (0x800 << 16));
return result;
}
static void ciintf_deinit(struct budget_ci* budget_ci)
{
struct saa7146_dev *saa = budget_ci->budget.dev;
// disable CI interrupts
saa7146_write(saa, IER, saa7146_read(saa, IER) & ~MASK_03);
saa7146_setgpio(saa, 0, SAA7146_GPIO_INPUT);
tasklet_kill(&budget_ci->ciintf_irq_tasklet);
budget_debiwrite(budget_ci, DEBICICTL, DEBIADDR_CICONTROL, 1, 0);
dvb_delay(1);
budget_debiwrite(budget_ci, DEBICICTL, DEBIADDR_CICONTROL, 1, CICONTROL_RESET);
// disable TS data stream to CI interface
saa7146_setgpio(saa, 1, SAA7146_GPIO_INPUT);
// release the CA device
dvb_ca_en50221_release(&budget_ci->ca);
// disable DEBI pins
saa7146_write(saa, MC1, saa7146_read(saa, MC1) | (0x800 << 16));
}
static void budget_ci_irq (struct saa7146_dev *dev, u32 *isr) static void budget_ci_irq (struct saa7146_dev *dev, u32 *isr)
{ {
...@@ -229,6 +499,9 @@ static void budget_ci_irq (struct saa7146_dev *dev, u32 *isr) ...@@ -229,6 +499,9 @@ static void budget_ci_irq (struct saa7146_dev *dev, u32 *isr)
if (*isr & MASK_10) if (*isr & MASK_10)
ttpci_budget_irq10_handler (dev, isr); ttpci_budget_irq10_handler (dev, isr);
if ((*isr & MASK_03) && (budget_ci->budget.ci_present))
tasklet_schedule (&budget_ci->ciintf_irq_tasklet);
} }
...@@ -244,6 +517,9 @@ static int budget_ci_attach (struct saa7146_dev* dev, ...@@ -244,6 +517,9 @@ static int budget_ci_attach (struct saa7146_dev* dev,
DEB_EE(("budget_ci: %p\n", budget_ci)); DEB_EE(("budget_ci: %p\n", budget_ci));
spin_lock_init(&budget_ci->debilock);
budget_ci->budget.ci_present = 0;
if ((err = ttpci_budget_init (&budget_ci->budget, dev, info))) { if ((err = ttpci_budget_init (&budget_ci->budget, dev, info))) {
kfree (budget_ci); kfree (budget_ci);
return err; return err;
...@@ -256,6 +532,9 @@ static int budget_ci_attach (struct saa7146_dev* dev, ...@@ -256,6 +532,9 @@ static int budget_ci_attach (struct saa7146_dev* dev,
msp430_ir_init (budget_ci); msp430_ir_init (budget_ci);
// UNCOMMENT TO TEST CI INTERFACE
// ciintf_init(budget_ci);
return 0; return 0;
} }
...@@ -264,14 +543,20 @@ static int budget_ci_attach (struct saa7146_dev* dev, ...@@ -264,14 +543,20 @@ static int budget_ci_attach (struct saa7146_dev* dev,
static int budget_ci_detach (struct saa7146_dev* dev) static int budget_ci_detach (struct saa7146_dev* dev)
{ {
struct budget_ci *budget_ci = (struct budget_ci*) dev->ext_priv; struct budget_ci *budget_ci = (struct budget_ci*) dev->ext_priv;
struct saa7146_dev *saa = budget_ci->budget.dev;
int err; int err;
if (budget_ci->budget.ci_present) ciintf_deinit(budget_ci);
err = ttpci_budget_deinit (&budget_ci->budget); err = ttpci_budget_deinit (&budget_ci->budget);
tasklet_kill (&budget_ci->msp430_irq_tasklet); tasklet_kill (&budget_ci->msp430_irq_tasklet);
msp430_ir_deinit (budget_ci); msp430_ir_deinit (budget_ci);
// disable frontend and CI interface
saa7146_setgpio(saa, 2, SAA7146_GPIO_INPUT);
kfree (budget_ci); kfree (budget_ci);
return err; return err;
...@@ -304,7 +589,7 @@ static struct saa7146_extension budget_extension = { ...@@ -304,7 +589,7 @@ static struct saa7146_extension budget_extension = {
.attach = budget_ci_attach, .attach = budget_ci_attach,
.detach = budget_ci_detach, .detach = budget_ci_detach,
.irq_mask = MASK_06 | MASK_10, .irq_mask = MASK_03 | MASK_06 | MASK_10,
.irq_func = budget_ci_irq, .irq_func = budget_ci_irq,
}; };
...@@ -325,7 +610,7 @@ module_init(budget_ci_init); ...@@ -325,7 +610,7 @@ module_init(budget_ci_init);
module_exit(budget_ci_exit); module_exit(budget_ci_exit);
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
MODULE_AUTHOR("Michael Hunold, Jack Thomasson, others"); MODULE_AUTHOR("Michael Hunold, Jack Thomasson, Andrew de Quincey, others");
MODULE_DESCRIPTION("driver for the SAA7146 based so-called " MODULE_DESCRIPTION("driver for the SAA7146 based so-called "
"budget PCI DVB cards w/ CI-module produced by " "budget PCI DVB cards w/ CI-module produced by "
"Siemens, Technotrend, Hauppauge"); "Siemens, Technotrend, Hauppauge");
......
/*
* budget-core.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
*
* 26feb2004 Support for FS Activy Card (Grundig tuner) by
* Michael Dreher <michael@5dot1.de>,
* Oliver Endriss <o.endriss@gmx.de>,
* Andreas 'randy' Weinberger
*
* 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 "budget.h"
#include "ttpci-eeprom.h" #include "ttpci-eeprom.h"
...@@ -38,10 +74,33 @@ static int start_ts_capture (struct budget *budget) ...@@ -38,10 +74,33 @@ static int start_ts_capture (struct budget *budget)
budget->tsf=0xff; budget->tsf=0xff;
budget->ttbp=0; budget->ttbp=0;
/*
* Signal path on the Activy:
*
* tuner -> SAA7146 port A -> SAA7146 BRS -> SAA7146 DMA3 -> memory
*
* Since the tuner feeds 204 bytes packets into the SAA7146,
* DMA3 is configured to strip the trailing 16 FEC bytes:
* Pitch: 188, NumBytes3: 188, NumLines3: 1024
*/
if (budget->card->type == BUDGET_FS_ACTIVY) {
saa7146_write(dev, DD1_INIT, 0x04000000);
saa7146_write(dev, MC2, (MASK_09 | MASK_25));
saa7146_write(dev, BRS_CTRL, 0x00000000);
} else {
if (budget->video_port == BUDGET_VIDEO_PORTA) {
saa7146_write(dev, DD1_INIT, 0x06000200);
saa7146_write(dev, MC2, (MASK_09 | MASK_25 | MASK_10 | MASK_26));
saa7146_write(dev, BRS_CTRL, 0x00000000);
} else {
saa7146_write(dev, DD1_INIT, 0x02000600); saa7146_write(dev, DD1_INIT, 0x02000600);
saa7146_write(dev, MC2, (MASK_09 | MASK_25 | MASK_10 | MASK_26)); saa7146_write(dev, MC2, (MASK_09 | MASK_25 | MASK_10 | MASK_26));
saa7146_write(dev, BRS_CTRL, 0x60000000); saa7146_write(dev, BRS_CTRL, 0x60000000);
}
}
saa7146_write(dev, MC2, (MASK_08 | MASK_24)); saa7146_write(dev, MC2, (MASK_08 | MASK_24));
mdelay(10); mdelay(10);
...@@ -49,9 +108,15 @@ static int start_ts_capture (struct budget *budget) ...@@ -49,9 +108,15 @@ static int start_ts_capture (struct budget *budget)
saa7146_write(dev, BASE_EVEN3, 0); saa7146_write(dev, BASE_EVEN3, 0);
saa7146_write(dev, PROT_ADDR3, TS_WIDTH*TS_HEIGHT); saa7146_write(dev, PROT_ADDR3, TS_WIDTH*TS_HEIGHT);
saa7146_write(dev, BASE_PAGE3, budget->pt.dma |ME1|0x90); saa7146_write(dev, BASE_PAGE3, budget->pt.dma |ME1|0x90);
saa7146_write(dev, PITCH3, TS_WIDTH);
if (budget->card->type == BUDGET_FS_ACTIVY) {
saa7146_write(dev, PITCH3, TS_WIDTH/2);
saa7146_write(dev, NUM_LINE_BYTE3, ((TS_HEIGHT*2)<<16)|(TS_WIDTH/2));
} else {
saa7146_write(dev, PITCH3, TS_WIDTH);
saa7146_write(dev, NUM_LINE_BYTE3, (TS_HEIGHT<<16)|TS_WIDTH); saa7146_write(dev, NUM_LINE_BYTE3, (TS_HEIGHT<<16)|TS_WIDTH);
}
saa7146_write(dev, MC2, (MASK_04 | MASK_20)); saa7146_write(dev, MC2, (MASK_04 | MASK_20));
saa7146_write(dev, MC1, (MASK_04 | MASK_20)); // DMA3 on saa7146_write(dev, MC1, (MASK_04 | MASK_20)); // DMA3 on
...@@ -99,23 +164,31 @@ static int budget_start_feed(struct dvb_demux_feed *feed) ...@@ -99,23 +164,31 @@ static int budget_start_feed(struct dvb_demux_feed *feed)
{ {
struct dvb_demux *demux = feed->demux; struct dvb_demux *demux = feed->demux;
struct budget *budget = (struct budget*) demux->priv; struct budget *budget = (struct budget*) demux->priv;
int status;
DEB_EE(("budget: %p\n",budget)); DEB_EE(("budget: %p\n",budget));
if (!demux->dmx.frontend) if (!demux->dmx.frontend)
return -EINVAL; return -EINVAL;
return start_ts_capture (budget); spin_lock(&budget->feedlock);
status = start_ts_capture (budget);
spin_unlock(&budget->feedlock);
return status;
} }
static int budget_stop_feed(struct dvb_demux_feed *feed) static int budget_stop_feed(struct dvb_demux_feed *feed)
{ {
struct dvb_demux *demux = feed->demux; struct dvb_demux *demux = feed->demux;
struct budget *budget = (struct budget *) demux->priv; struct budget *budget = (struct budget *) demux->priv;
int status;
DEB_EE(("budget: %p\n",budget)); DEB_EE(("budget: %p\n",budget));
return stop_ts_capture (budget); spin_lock(&budget->feedlock);
status = stop_ts_capture (budget);
spin_unlock(&budget->feedlock);
return status;
} }
...@@ -208,18 +281,27 @@ int ttpci_budget_init (struct budget *budget, ...@@ -208,18 +281,27 @@ int ttpci_budget_init (struct budget *budget,
budget->card = bi; budget->card = bi;
budget->dev = (struct saa7146_dev *) dev; budget->dev = (struct saa7146_dev *) dev;
dvb_register_adapter(&budget->dvb_adapter, budget->card->name); dvb_register_adapter(&budget->dvb_adapter, budget->card->name, THIS_MODULE);
/* set dd1 stream a & b */ /* set dd1 stream a & b */
saa7146_write(dev, DD1_STREAM_B, 0x00000000); saa7146_write(dev, DD1_STREAM_B, 0x00000000);
saa7146_write(dev, MC2, (MASK_09 | MASK_25));
saa7146_write(dev, MC2, (MASK_10 | MASK_26));
saa7146_write(dev, DD1_INIT, 0x02000000); saa7146_write(dev, DD1_INIT, 0x02000000);
saa7146_write(dev, MC2, (MASK_09 | MASK_25 | MASK_10 | MASK_26)); saa7146_write(dev, MC2, (MASK_09 | MASK_25 | MASK_10 | MASK_26));
if (bi->type != BUDGET_FS_ACTIVY)
budget->video_port = BUDGET_VIDEO_PORTB;
else
budget->video_port = BUDGET_VIDEO_PORTA;
spin_lock_init(&budget->feedlock);
/* the Siemens DVB needs this if you want to have the i2c chips /* the Siemens DVB needs this if you want to have the i2c chips
get recognized before the main driver is loaded */ get recognized before the main driver is loaded */
saa7146_write(dev, GPIO_CTRL, 0x500000); if (bi->type != BUDGET_FS_ACTIVY)
saa7146_write(dev, GPIO_CTRL, 0x500000); /* GPIO 3 = 1 */
saa7146_i2c_adapter_prepare(dev, NULL, SAA7146_I2C_BUS_BIT_RATE_120); saa7146_i2c_adapter_prepare(dev, NULL, 0, SAA7146_I2C_BUS_BIT_RATE_120);
budget->i2c_bus = dvb_register_i2c_bus (master_xfer, dev, budget->i2c_bus = dvb_register_i2c_bus (master_xfer, dev,
budget->dvb_adapter, 0); budget->dvb_adapter, 0);
...@@ -242,7 +324,11 @@ int ttpci_budget_init (struct budget *budget, ...@@ -242,7 +324,11 @@ int ttpci_budget_init (struct budget *budget,
tasklet_init (&budget->vpe_tasklet, vpeirq, (unsigned long) budget); tasklet_init (&budget->vpe_tasklet, vpeirq, (unsigned long) budget);
saa7146_setgpio(dev, 2, SAA7146_GPIO_OUTHI); /* frontend power on */ /* frontend power on */
if (bi->type == BUDGET_FS_ACTIVY)
saa7146_setgpio(dev, 1, SAA7146_GPIO_OUTHI);
else
saa7146_setgpio(dev, 2, SAA7146_GPIO_OUTHI);
if (budget_register(budget) == 0) { if (budget_register(budget) == 0) {
return 0; return 0;
...@@ -292,10 +378,28 @@ void ttpci_budget_irq10_handler (struct saa7146_dev* dev, u32 *isr) ...@@ -292,10 +378,28 @@ void ttpci_budget_irq10_handler (struct saa7146_dev* dev, u32 *isr)
tasklet_schedule (&budget->vpe_tasklet); tasklet_schedule (&budget->vpe_tasklet);
} }
void ttpci_budget_set_video_port(struct saa7146_dev* dev, int video_port)
{
struct budget *budget = (struct budget*)dev->ext_priv;
spin_lock(&budget->feedlock);
budget->video_port = video_port;
if (budget->feeding) {
int oldfeeding = budget->feeding;
budget->feeding = 1;
stop_ts_capture(budget);
start_ts_capture(budget);
budget->feeding = oldfeeding;
}
spin_unlock(&budget->feedlock);
}
EXPORT_SYMBOL_GPL(ttpci_budget_init); EXPORT_SYMBOL_GPL(ttpci_budget_init);
EXPORT_SYMBOL_GPL(ttpci_budget_deinit); EXPORT_SYMBOL_GPL(ttpci_budget_deinit);
EXPORT_SYMBOL_GPL(ttpci_budget_irq10_handler); EXPORT_SYMBOL_GPL(ttpci_budget_irq10_handler);
EXPORT_SYMBOL_GPL(ttpci_budget_set_video_port);
EXPORT_SYMBOL_GPL(budget_debug); EXPORT_SYMBOL_GPL(budget_debug);
MODULE_PARM(budget_debug,"i"); MODULE_PARM(budget_debug,"i");
......
...@@ -8,6 +8,11 @@ ...@@ -8,6 +8,11 @@
* Copyright (C) 1999-2002 Ralph Metzler * Copyright (C) 1999-2002 Ralph Metzler
* & Marcus Metzler for convergence integrated media GmbH * & Marcus Metzler for convergence integrated media GmbH
* *
* 26feb2004 Support for FS Activy Card (Grundig tuner) by
* Michael Dreher <michael@5dot1.de>,
* Oliver Endriss <o.endriss@gmx.de> and
* Andreas 'randy' Weinberger
*
* This program is free software; you can redistribute it and/or * This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License * modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2 * as published by the Free Software Foundation; either version 2
...@@ -142,6 +147,49 @@ int budget_diseqc_ioctl (struct dvb_frontend *fe, unsigned int cmd, void *arg) ...@@ -142,6 +147,49 @@ int budget_diseqc_ioctl (struct dvb_frontend *fe, unsigned int cmd, void *arg)
} }
/*
* Routines for the Fujitsu Siemens Activy budget card
* 22 kHz tone and DiSEqC are handled by the frontend.
* Voltage must be set here.
*/
static int SetVoltage_Activy (struct budget *budget, fe_sec_voltage_t voltage)
{
struct saa7146_dev *dev=budget->dev;
DEB_EE(("budget: %p\n",budget));
switch (voltage) {
case SEC_VOLTAGE_13:
saa7146_setgpio(dev, 2, SAA7146_GPIO_OUTLO);
break;
case SEC_VOLTAGE_18:
saa7146_setgpio(dev, 2, SAA7146_GPIO_OUTHI);
break;
default:
return -EINVAL;
}
return 0;
}
static int budget_ioctl_activy (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_VOLTAGE:
return SetVoltage_Activy (budget, (fe_sec_voltage_t) arg);
default:
return -EOPNOTSUPP;
}
return 0;
}
static int budget_attach (struct saa7146_dev* dev, struct saa7146_pci_extension_data *info) static int budget_attach (struct saa7146_dev* dev, struct saa7146_pci_extension_data *info)
{ {
struct budget *budget = NULL; struct budget *budget = NULL;
...@@ -160,6 +208,10 @@ static int budget_attach (struct saa7146_dev* dev, struct saa7146_pci_extension_ ...@@ -160,6 +208,10 @@ static int budget_attach (struct saa7146_dev* dev, struct saa7146_pci_extension_
return err; return err;
} }
if (budget->card->type == BUDGET_FS_ACTIVY)
dvb_add_frontend_ioctls (budget->dvb_adapter,
budget_ioctl_activy, NULL, budget);
else
dvb_add_frontend_ioctls (budget->dvb_adapter, dvb_add_frontend_ioctls (budget->dvb_adapter,
budget_diseqc_ioctl, NULL, budget); budget_diseqc_ioctl, NULL, budget);
...@@ -174,6 +226,10 @@ static int budget_detach (struct saa7146_dev* dev) ...@@ -174,6 +226,10 @@ static int budget_detach (struct saa7146_dev* dev)
struct budget *budget = (struct budget*) dev->ext_priv; struct budget *budget = (struct budget*) dev->ext_priv;
int err; int err;
if (budget->card->type == BUDGET_FS_ACTIVY)
dvb_remove_frontend_ioctls (budget->dvb_adapter,
budget_ioctl_activy, NULL);
else
dvb_remove_frontend_ioctls (budget->dvb_adapter, dvb_remove_frontend_ioctls (budget->dvb_adapter,
budget_diseqc_ioctl, NULL); budget_diseqc_ioctl, NULL);
...@@ -193,6 +249,7 @@ MAKE_BUDGET_INFO(ttbs, "TT-Budget/WinTV-NOVA-S PCI", BUDGET_TT); ...@@ -193,6 +249,7 @@ 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(ttbc, "TT-Budget/WinTV-NOVA-C PCI", BUDGET_TT);
MAKE_BUDGET_INFO(ttbt, "TT-Budget/WinTV-NOVA-T 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); MAKE_BUDGET_INFO(satel, "SATELCO Multimedia PCI", BUDGET_TT_HW_DISEQC);
MAKE_BUDGET_INFO(fsacs, "Fujitsu Siemens Activy Budget-S PCI", BUDGET_FS_ACTIVY);
/* Uncomment for Budget Patch */ /* Uncomment for Budget Patch */
/*MAKE_BUDGET_INFO(fs_1_3,"Siemens/Technotrend/Hauppauge PCI rev1.3+Budget_Patch", BUDGET_PATCH);*/ /*MAKE_BUDGET_INFO(fs_1_3,"Siemens/Technotrend/Hauppauge PCI rev1.3+Budget_Patch", BUDGET_PATCH);*/
...@@ -203,6 +260,7 @@ static struct pci_device_id pci_tbl[] = { ...@@ -203,6 +260,7 @@ static struct pci_device_id pci_tbl[] = {
MAKE_EXTENSION_PCI(ttbc, 0x13c2, 0x1004), MAKE_EXTENSION_PCI(ttbc, 0x13c2, 0x1004),
MAKE_EXTENSION_PCI(ttbt, 0x13c2, 0x1005), MAKE_EXTENSION_PCI(ttbt, 0x13c2, 0x1005),
MAKE_EXTENSION_PCI(satel, 0x13c2, 0x1013), MAKE_EXTENSION_PCI(satel, 0x13c2, 0x1013),
MAKE_EXTENSION_PCI(fsacs, 0x1131, 0x4f61),
{ {
.vendor = 0, .vendor = 0,
} }
......
...@@ -46,10 +46,15 @@ struct budget { ...@@ -46,10 +46,15 @@ struct budget {
int fe_synced; int fe_synced;
struct semaphore pid_mutex; struct semaphore pid_mutex;
int ci_present;
int video_port;
u8 tsf; u8 tsf;
u32 ttbp; u32 ttbp;
int feeding; int feeding;
spinlock_t feedlock;
struct dvb_adapter *dvb_adapter; struct dvb_adapter *dvb_adapter;
void *priv; void *priv;
}; };
...@@ -73,13 +78,17 @@ static struct saa7146_pci_extension_data x_var = { \ ...@@ -73,13 +78,17 @@ static struct saa7146_pci_extension_data x_var = { \
#define BUDGET_TT_HW_DISEQC 1 #define BUDGET_TT_HW_DISEQC 1
#define BUDGET_KNC1 2 #define BUDGET_KNC1 2
#define BUDGET_PATCH 3 #define BUDGET_PATCH 3
#define BUDGET_FS_ACTIVY 4
#define BUDGET_VIDEO_PORTA 0
#define BUDGET_VIDEO_PORTB 1
extern int ttpci_budget_init (struct budget *budget, extern int ttpci_budget_init (struct budget *budget,
struct saa7146_dev* dev, struct saa7146_dev* dev,
struct saa7146_pci_extension_data *info); struct saa7146_pci_extension_data *info);
extern int ttpci_budget_deinit (struct budget *budget); extern int ttpci_budget_deinit (struct budget *budget);
extern void ttpci_budget_irq10_handler (struct saa7146_dev* dev, u32 *isr); extern void ttpci_budget_irq10_handler (struct saa7146_dev* dev, u32 *isr);
extern void ttpci_budget_set_video_port(struct saa7146_dev* dev, int video_port);
#endif #endif
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment