summaryrefslogtreecommitdiff
path: root/drivers/media
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/media')
-rw-r--r--drivers/media/IR/Makefile2
-rw-r--r--drivers/media/IR/ir-functions.c2
-rw-r--r--drivers/media/IR/ir-keytable.c45
-rw-r--r--drivers/media/IR/ir-sysfs.c210
-rw-r--r--drivers/media/common/tuners/tuner-xc2028.c20
-rw-r--r--drivers/media/common/tuners/tuner-xc2028.h2
-rw-r--r--drivers/media/dvb/Kconfig4
-rw-r--r--drivers/media/dvb/Makefile14
-rw-r--r--drivers/media/dvb/bt8xx/bt878.c4
-rw-r--r--drivers/media/dvb/dm1105/dm1105.c4
-rw-r--r--drivers/media/dvb/dvb-core/dvb_net.c7
-rw-r--r--drivers/media/dvb/dvb-usb/cxusb.c3
-rw-r--r--drivers/media/dvb/dvb-usb/dw2102.c94
-rw-r--r--drivers/media/dvb/firewire/firedtv-1394.c19
-rw-r--r--drivers/media/dvb/firewire/firedtv-avc.c514
-rw-r--r--drivers/media/dvb/firewire/firedtv-dvb.c1
-rw-r--r--drivers/media/dvb/firewire/firedtv-fw.c41
-rw-r--r--drivers/media/dvb/firewire/firedtv.h6
-rw-r--r--drivers/media/dvb/frontends/Kconfig19
-rw-r--r--drivers/media/dvb/frontends/Makefile2
-rw-r--r--drivers/media/dvb/frontends/atbm8830.c16
-rw-r--r--drivers/media/dvb/frontends/dib8000.c2
-rw-r--r--drivers/media/dvb/frontends/dib8000.h2
-rw-r--r--drivers/media/dvb/frontends/lgdt3305.h6
-rw-r--r--drivers/media/dvb/frontends/mb86a16.c1878
-rw-r--r--drivers/media/dvb/frontends/mb86a16.h52
-rw-r--r--drivers/media/dvb/frontends/mb86a16_priv.h151
-rw-r--r--drivers/media/dvb/frontends/stv0900.h2
-rw-r--r--drivers/media/dvb/frontends/stv0900_core.c87
-rw-r--r--drivers/media/dvb/frontends/stv0900_priv.h11
-rw-r--r--drivers/media/dvb/frontends/stv0900_reg.h6
-rw-r--r--drivers/media/dvb/frontends/stv0900_sw.c44
-rw-r--r--drivers/media/dvb/frontends/tda10021.c4
-rw-r--r--drivers/media/dvb/frontends/tda665x.c257
-rw-r--r--drivers/media/dvb/frontends/tda665x.h52
-rw-r--r--drivers/media/dvb/mantis/Kconfig32
-rw-r--r--drivers/media/dvb/mantis/Makefile28
-rw-r--r--drivers/media/dvb/mantis/hopper_cards.c275
-rw-r--r--drivers/media/dvb/mantis/hopper_vp3028.c88
-rw-r--r--drivers/media/dvb/mantis/hopper_vp3028.h30
-rw-r--r--drivers/media/dvb/mantis/mantis_ca.c207
-rw-r--r--drivers/media/dvb/mantis/mantis_ca.h27
-rw-r--r--drivers/media/dvb/mantis/mantis_cards.c305
-rw-r--r--drivers/media/dvb/mantis/mantis_common.h179
-rw-r--r--drivers/media/dvb/mantis/mantis_core.c238
-rw-r--r--drivers/media/dvb/mantis/mantis_core.h57
-rw-r--r--drivers/media/dvb/mantis/mantis_dma.c256
-rw-r--r--drivers/media/dvb/mantis/mantis_dma.h30
-rw-r--r--drivers/media/dvb/mantis/mantis_dvb.c296
-rw-r--r--drivers/media/dvb/mantis/mantis_dvb.h35
-rw-r--r--drivers/media/dvb/mantis/mantis_evm.c117
-rw-r--r--drivers/media/dvb/mantis/mantis_hif.c240
-rw-r--r--drivers/media/dvb/mantis/mantis_hif.h29
-rw-r--r--drivers/media/dvb/mantis/mantis_i2c.c267
-rw-r--r--drivers/media/dvb/mantis/mantis_i2c.h30
-rw-r--r--drivers/media/dvb/mantis/mantis_input.c148
-rw-r--r--drivers/media/dvb/mantis/mantis_ioc.c130
-rw-r--r--drivers/media/dvb/mantis/mantis_ioc.h51
-rw-r--r--drivers/media/dvb/mantis/mantis_link.h83
-rw-r--r--drivers/media/dvb/mantis/mantis_pci.c177
-rw-r--r--drivers/media/dvb/mantis/mantis_pci.h27
-rw-r--r--drivers/media/dvb/mantis/mantis_pcmcia.c120
-rw-r--r--drivers/media/dvb/mantis/mantis_reg.h197
-rw-r--r--drivers/media/dvb/mantis/mantis_uart.c186
-rw-r--r--drivers/media/dvb/mantis/mantis_uart.h58
-rw-r--r--drivers/media/dvb/mantis/mantis_vp1033.c212
-rw-r--r--drivers/media/dvb/mantis/mantis_vp1033.h30
-rw-r--r--drivers/media/dvb/mantis/mantis_vp1034.c119
-rw-r--r--drivers/media/dvb/mantis/mantis_vp1034.h33
-rw-r--r--drivers/media/dvb/mantis/mantis_vp1041.c358
-rw-r--r--drivers/media/dvb/mantis/mantis_vp1041.h33
-rw-r--r--drivers/media/dvb/mantis/mantis_vp2033.c187
-rw-r--r--drivers/media/dvb/mantis/mantis_vp2033.h30
-rw-r--r--drivers/media/dvb/mantis/mantis_vp2040.c186
-rw-r--r--drivers/media/dvb/mantis/mantis_vp2040.h32
-rw-r--r--drivers/media/dvb/mantis/mantis_vp3028.c38
-rw-r--r--drivers/media/dvb/mantis/mantis_vp3028.h33
-rw-r--r--drivers/media/dvb/mantis/mantis_vp3030.c105
-rw-r--r--drivers/media/dvb/mantis/mantis_vp3030.h30
-rw-r--r--drivers/media/dvb/siano/sms-cards.c1
-rw-r--r--drivers/media/dvb/siano/smscoreapi.h77
-rw-r--r--drivers/media/dvb/siano/smsdvb.c318
-rw-r--r--drivers/media/dvb/ttpci/budget-ci.c2
-rw-r--r--drivers/media/video/bt8xx/bttv-input.c4
-rw-r--r--drivers/media/video/cx231xx/cx231xx-input.c2
-rw-r--r--drivers/media/video/cx23885/cx23885-dvb.c6
-rw-r--r--drivers/media/video/cx23885/cx23885-input.c2
-rw-r--r--drivers/media/video/cx88/cx88-input.c4
-rw-r--r--drivers/media/video/em28xx/em28xx-input.c83
-rw-r--r--drivers/media/video/gspca/gspca.c2
-rw-r--r--drivers/media/video/gspca/ov534.c2
-rw-r--r--drivers/media/video/gspca/sunplus.c1
-rw-r--r--drivers/media/video/ir-kbd-i2c.c4
-rw-r--r--drivers/media/video/saa7134/saa7134-input.c4
-rw-r--r--drivers/media/video/uvc/uvc_ctrl.c2
-rw-r--r--drivers/media/video/uvc/uvc_driver.c65
-rw-r--r--drivers/media/video/uvc/uvc_queue.c14
-rw-r--r--drivers/media/video/uvc/uvc_video.c55
-rw-r--r--drivers/media/video/uvc/uvcvideo.h9
99 files changed, 9172 insertions, 437 deletions
diff --git a/drivers/media/IR/Makefile b/drivers/media/IR/Makefile
index df5ddb4bbbf7..171890e7a41d 100644
--- a/drivers/media/IR/Makefile
+++ b/drivers/media/IR/Makefile
@@ -1,5 +1,5 @@
ir-common-objs := ir-functions.o ir-keymaps.o
-ir-core-objs := ir-keytable.o
+ir-core-objs := ir-keytable.o ir-sysfs.o
obj-$(CONFIG_IR_CORE) += ir-core.o
obj-$(CONFIG_VIDEO_IR) += ir-common.o
diff --git a/drivers/media/IR/ir-functions.c b/drivers/media/IR/ir-functions.c
index 776a136616d6..ab06919ad5fc 100644
--- a/drivers/media/IR/ir-functions.c
+++ b/drivers/media/IR/ir-functions.c
@@ -52,7 +52,7 @@ static void ir_input_key_event(struct input_dev *dev, struct ir_input_state *ir)
/* -------------------------------------------------------------------------- */
int ir_input_init(struct input_dev *dev, struct ir_input_state *ir,
- int ir_type)
+ const u64 ir_type)
{
ir->ir_type = ir_type;
diff --git a/drivers/media/IR/ir-keytable.c b/drivers/media/IR/ir-keytable.c
index bff7a5356037..c3e36b708bc7 100644
--- a/drivers/media/IR/ir-keytable.c
+++ b/drivers/media/IR/ir-keytable.c
@@ -65,7 +65,7 @@ exit:
* In order to reduce the quantity of table resizes, it has a minimum
* table size of IR_TAB_MIN_SIZE.
*/
-int ir_roundup_tablesize(int n_elems)
+static int ir_roundup_tablesize(int n_elems)
{
size_t size;
@@ -81,7 +81,6 @@ int ir_roundup_tablesize(int n_elems)
return n_elems;
}
-EXPORT_SYMBOL_GPL(ir_roundup_tablesize);
/**
* ir_copy_table() - copies a keytable, discarding the unused entries
@@ -89,9 +88,11 @@ EXPORT_SYMBOL_GPL(ir_roundup_tablesize);
* @origin: origin table
*
* Copies all entries where the keycode is not KEY_UNKNOWN/KEY_RESERVED
+ * Also copies table size and table protocol.
+ * NOTE: It shouldn't copy the lock field
*/
-int ir_copy_table(struct ir_scancode_table *destin,
+static int ir_copy_table(struct ir_scancode_table *destin,
const struct ir_scancode_table *origin)
{
int i, j = 0;
@@ -105,12 +106,12 @@ int ir_copy_table(struct ir_scancode_table *destin,
j++;
}
destin->size = j;
+ destin->ir_type = origin->ir_type;
IR_dprintk(1, "Copied %d scancodes to the new keycode table\n", destin->size);
return 0;
}
-EXPORT_SYMBOL_GPL(ir_copy_table);
/**
* ir_getkeycode() - get a keycode at the evdev scancode ->keycode table
@@ -399,12 +400,14 @@ EXPORT_SYMBOL_GPL(ir_g_keycode_from_table);
* @input_dev: the struct input_dev descriptor of the device
* @rc_tab: the struct ir_scancode_table table of scancode/keymap
*
- * This routine is used to initialize the input infrastructure to work with
- * an IR.
- * It should be called before registering the IR device.
+ * This routine is used to initialize the input infrastructure
+ * to work with an IR.
+ * It will register the input/evdev interface for the device and
+ * register the syfs code for IR class
*/
int ir_input_register(struct input_dev *input_dev,
- struct ir_scancode_table *rc_tab)
+ const struct ir_scancode_table *rc_tab,
+ const struct ir_dev_props *props)
{
struct ir_input_dev *ir_dev;
struct ir_scancode *keymap = rc_tab->scan;
@@ -417,7 +420,7 @@ int ir_input_register(struct input_dev *input_dev,
if (!ir_dev)
return -ENOMEM;
- spin_lock_init(&rc_tab->lock);
+ spin_lock_init(&ir_dev->rc_tab.lock);
ir_dev->rc_tab.size = ir_roundup_tablesize(rc_tab->size);
ir_dev->rc_tab.scan = kzalloc(ir_dev->rc_tab.size *
@@ -430,6 +433,7 @@ int ir_input_register(struct input_dev *input_dev,
ir_dev->rc_tab.size * sizeof(ir_dev->rc_tab.scan));
ir_copy_table(&ir_dev->rc_tab, rc_tab);
+ ir_dev->props = props;
/* set the bits for the keys */
IR_dprintk(1, "key map size: %d\n", rc_tab->size);
@@ -447,16 +451,31 @@ int ir_input_register(struct input_dev *input_dev,
input_set_drvdata(input_dev, ir_dev);
rc = input_register_device(input_dev);
+ if (rc < 0)
+ goto err;
+
+ rc = ir_register_class(input_dev);
if (rc < 0) {
- kfree(rc_tab->scan);
- kfree(ir_dev);
- input_set_drvdata(input_dev, NULL);
+ input_unregister_device(input_dev);
+ goto err;
}
+ return 0;
+
+err:
+ kfree(rc_tab->scan);
+ kfree(ir_dev);
+ input_set_drvdata(input_dev, NULL);
return rc;
}
EXPORT_SYMBOL_GPL(ir_input_register);
+/**
+ * ir_input_unregister() - unregisters IR and frees resources
+ * @input_dev: the struct input_dev descriptor of the device
+
+ * This routine is used to free memory and de-register interfaces.
+ */
void ir_input_unregister(struct input_dev *dev)
{
struct ir_input_dev *ir_dev = input_get_drvdata(dev);
@@ -472,6 +491,8 @@ void ir_input_unregister(struct input_dev *dev)
kfree(rc_tab->scan);
rc_tab->scan = NULL;
+ ir_unregister_class(dev);
+
kfree(ir_dev);
input_unregister_device(dev);
}
diff --git a/drivers/media/IR/ir-sysfs.c b/drivers/media/IR/ir-sysfs.c
new file mode 100644
index 000000000000..6ec7f89d5142
--- /dev/null
+++ b/drivers/media/IR/ir-sysfs.c
@@ -0,0 +1,210 @@
+/* ir-register.c - handle IR scancode->keycode tables
+ *
+ * Copyright (C) 2009 by Mauro Carvalho Chehab <mchehab@redhat.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation version 2 of the License.
+ *
+ * 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.
+ */
+
+#include <linux/input.h>
+#include <linux/device.h>
+#include <media/ir-core.h>
+
+#define IRRCV_NUM_DEVICES 256
+
+/* bit array to represent IR sysfs device number */
+static unsigned long ir_core_dev_number;
+
+/* class for /sys/class/irrcv */
+static struct class *ir_input_class;
+
+/**
+ * show_protocol() - shows the current IR protocol
+ * @d: the device descriptor
+ * @mattr: the device attribute struct (unused)
+ * @buf: a pointer to the output buffer
+ *
+ * This routine is a callback routine for input read the IR protocol type.
+ * it is trigged by reading /sys/class/irrcv/irrcv?/current_protocol.
+ * It returns the protocol name, as understood by the driver.
+ */
+static ssize_t show_protocol(struct device *d,
+ struct device_attribute *mattr, char *buf)
+{
+ char *s;
+ struct ir_input_dev *ir_dev = dev_get_drvdata(d);
+ u64 ir_type = ir_dev->rc_tab.ir_type;
+
+ IR_dprintk(1, "Current protocol is %lld\n", (long long)ir_type);
+
+ /* FIXME: doesn't support multiple protocols at the same time */
+ if (ir_type == IR_TYPE_UNKNOWN)
+ s = "Unknown";
+ else if (ir_type == IR_TYPE_RC5)
+ s = "RC-5";
+ else if (ir_type == IR_TYPE_PD)
+ s = "Pulse/distance";
+ else if (ir_type == IR_TYPE_NEC)
+ s = "NEC";
+ else
+ s = "Other";
+
+ return sprintf(buf, "%s\n", s);
+}
+
+/**
+ * store_protocol() - shows the current IR protocol
+ * @d: the device descriptor
+ * @mattr: the device attribute struct (unused)
+ * @buf: a pointer to the input buffer
+ * @len: length of the input buffer
+ *
+ * This routine is a callback routine for changing the IR protocol type.
+ * it is trigged by reading /sys/class/irrcv/irrcv?/current_protocol.
+ * It changes the IR the protocol name, if the IR type is recognized
+ * by the driver.
+ * If an unknown protocol name is used, returns -EINVAL.
+ */
+static ssize_t store_protocol(struct device *d,
+ struct device_attribute *mattr,
+ const char *data,
+ size_t len)
+{
+ struct ir_input_dev *ir_dev = dev_get_drvdata(d);
+ u64 ir_type = IR_TYPE_UNKNOWN;
+ int rc = -EINVAL;
+ unsigned long flags;
+ char *buf;
+
+ buf = strsep((char **) &data, "\n");
+
+ if (!strcasecmp(buf, "rc-5"))
+ ir_type = IR_TYPE_RC5;
+ else if (!strcasecmp(buf, "pd"))
+ ir_type = IR_TYPE_PD;
+ else if (!strcasecmp(buf, "nec"))
+ ir_type = IR_TYPE_NEC;
+
+ if (ir_type == IR_TYPE_UNKNOWN) {
+ IR_dprintk(1, "Error setting protocol to %lld\n",
+ (long long)ir_type);
+ return -EINVAL;
+ }
+
+ if (ir_dev->props && ir_dev->props->change_protocol)
+ rc = ir_dev->props->change_protocol(ir_dev->props->priv,
+ ir_type);
+
+ if (rc < 0) {
+ IR_dprintk(1, "Error setting protocol to %lld\n",
+ (long long)ir_type);
+ return -EINVAL;
+ }
+
+ spin_lock_irqsave(&ir_dev->rc_tab.lock, flags);
+ ir_dev->rc_tab.ir_type = ir_type;
+ spin_unlock_irqrestore(&ir_dev->rc_tab.lock, flags);
+
+ IR_dprintk(1, "Current protocol is %lld\n",
+ (long long)ir_type);
+
+ return len;
+}
+
+/*
+ * Static device attribute struct with the sysfs attributes for IR's
+ */
+static DEVICE_ATTR(current_protocol, S_IRUGO | S_IWUSR,
+ show_protocol, store_protocol);
+
+static struct attribute *ir_dev_attrs[] = {
+ &dev_attr_current_protocol.attr,
+};
+
+/**
+ * ir_register_class() - creates the sysfs for /sys/class/irrcv/irrcv?
+ * @input_dev: the struct input_dev descriptor of the device
+ *
+ * This routine is used to register the syfs code for IR class
+ */
+int ir_register_class(struct input_dev *input_dev)
+{
+ int rc;
+ struct kobject *kobj;
+
+ struct ir_input_dev *ir_dev = input_get_drvdata(input_dev);
+ int devno = find_first_zero_bit(&ir_core_dev_number,
+ IRRCV_NUM_DEVICES);
+
+ if (unlikely(devno < 0))
+ return devno;
+
+ ir_dev->attr.attrs = ir_dev_attrs;
+ ir_dev->class_dev = device_create(ir_input_class, NULL,
+ input_dev->dev.devt, ir_dev,
+ "irrcv%d", devno);
+ kobj = &ir_dev->class_dev->kobj;
+
+ printk(KERN_WARNING "Creating IR device %s\n", kobject_name(kobj));
+ rc = sysfs_create_group(kobj, &ir_dev->attr);
+ if (unlikely(rc < 0)) {
+ device_destroy(ir_input_class, input_dev->dev.devt);
+ return -ENOMEM;
+ }
+
+ ir_dev->devno = devno;
+ set_bit(devno, &ir_core_dev_number);
+
+ return 0;
+};
+
+/**
+ * ir_unregister_class() - removes the sysfs for sysfs for
+ * /sys/class/irrcv/irrcv?
+ * @input_dev: the struct input_dev descriptor of the device
+ *
+ * This routine is used to unregister the syfs code for IR class
+ */
+void ir_unregister_class(struct input_dev *input_dev)
+{
+ struct ir_input_dev *ir_dev = input_get_drvdata(input_dev);
+ struct kobject *kobj;
+
+ clear_bit(ir_dev->devno, &ir_core_dev_number);
+
+ kobj = &ir_dev->class_dev->kobj;
+
+ sysfs_remove_group(kobj, &ir_dev->attr);
+ device_destroy(ir_input_class, input_dev->dev.devt);
+
+ kfree(ir_dev->attr.name);
+}
+
+/*
+ * Init/exit code for the module. Basically, creates/removes /sys/class/irrcv
+ */
+
+static int __init ir_core_init(void)
+{
+ ir_input_class = class_create(THIS_MODULE, "irrcv");
+ if (IS_ERR(ir_input_class)) {
+ printk(KERN_ERR "ir_core: unable to register irrcv class\n");
+ return PTR_ERR(ir_input_class);
+ }
+
+ return 0;
+}
+
+static void __exit ir_core_exit(void)
+{
+ class_destroy(ir_input_class);
+}
+
+module_init(ir_core_init);
+module_exit(ir_core_exit);
diff --git a/drivers/media/common/tuners/tuner-xc2028.c b/drivers/media/common/tuners/tuner-xc2028.c
index f270e605da83..72baaf13207c 100644
--- a/drivers/media/common/tuners/tuner-xc2028.c
+++ b/drivers/media/common/tuners/tuner-xc2028.c
@@ -99,6 +99,7 @@ struct xc2028_data {
if (size != _rc) \
tuner_info("i2c output error: rc = %d (should be %d)\n",\
_rc, (int)size); \
+ msleep(priv->ctrl.msleep); \
_rc; \
})
@@ -118,6 +119,7 @@ struct xc2028_data {
if (isize != _rc) \
tuner_err("i2c input error: rc = %d (should be %d)\n", \
_rc, (int)isize); \
+ msleep(priv->ctrl.msleep); \
_rc; \
})
@@ -129,7 +131,7 @@ struct xc2028_data {
_val, sizeof(_val)))) { \
tuner_err("Error on line %d: %d\n", __LINE__, _rc); \
} else \
- msleep(10); \
+ msleep(priv->ctrl.msleep); \
_rc; \
})
@@ -808,10 +810,20 @@ check_device:
hwmodel, (version & 0xf000) >> 12, (version & 0xf00) >> 8,
(version & 0xf0) >> 4, version & 0xf);
+
+ if (priv->ctrl.read_not_reliable)
+ goto read_not_reliable;
+
/* Check firmware version against what we downloaded. */
if (priv->firm_version != ((version & 0xf0) << 4 | (version & 0x0f))) {
- tuner_err("Incorrect readback of firmware version.\n");
- goto fail;
+ if (!priv->ctrl.read_not_reliable) {
+ tuner_err("Incorrect readback of firmware version.\n");
+ goto fail;
+ } else {
+ tuner_err("Returned an incorrect version. However, "
+ "read is not reliable enough. Ignoring it.\n");
+ hwmodel = 3028;
+ }
}
/* Check that the tuner hardware model remains consistent over time. */
@@ -825,6 +837,7 @@ check_device:
goto fail;
}
+read_not_reliable:
memcpy(&priv->cur_fw, &new_fw, sizeof(priv->cur_fw));
/*
@@ -957,6 +970,7 @@ static int generic_set_freq(struct dvb_frontend *fe, u32 freq /* in HZ */,
The reset CLK is needed only with tm6000.
Driver should work fine even if this fails.
*/
+ msleep(priv->ctrl.msleep);
do_tuner_callback(fe, XC2028_RESET_CLK, 1);
msleep(10);
diff --git a/drivers/media/common/tuners/tuner-xc2028.h b/drivers/media/common/tuners/tuner-xc2028.h
index a90c35d50add..9778c96a5006 100644
--- a/drivers/media/common/tuners/tuner-xc2028.h
+++ b/drivers/media/common/tuners/tuner-xc2028.h
@@ -33,12 +33,14 @@ enum firmware_type {
struct xc2028_ctrl {
char *fname;
int max_len;
+ int msleep;
unsigned int scode_table;
unsigned int mts :1;
unsigned int input1:1;
unsigned int vhfbw7:1;
unsigned int uhfbw8:1;
unsigned int disable_power_mgmt:1;
+ unsigned int read_not_reliable:1;
unsigned int demod;
enum firmware_type type:2;
};
diff --git a/drivers/media/dvb/Kconfig b/drivers/media/dvb/Kconfig
index 35d0817126e9..cf8f65f309da 100644
--- a/drivers/media/dvb/Kconfig
+++ b/drivers/media/dvb/Kconfig
@@ -72,6 +72,10 @@ comment "Supported Earthsoft PT1 Adapters"
depends on DVB_CORE && PCI && I2C
source "drivers/media/dvb/pt1/Kconfig"
+comment "Supported Mantis Adapters"
+ depends on DVB_CORE && PCI && I2C
+ source "drivers/media/dvb/mantis/Kconfig"
+
comment "Supported DVB Frontends"
depends on DVB_CORE
source "drivers/media/dvb/frontends/Kconfig"
diff --git a/drivers/media/dvb/Makefile b/drivers/media/dvb/Makefile
index 16d262ddb45d..c12922c3659b 100644
--- a/drivers/media/dvb/Makefile
+++ b/drivers/media/dvb/Makefile
@@ -2,6 +2,18 @@
# Makefile for the kernel multimedia device drivers.
#
-obj-y := dvb-core/ frontends/ ttpci/ ttusb-dec/ ttusb-budget/ b2c2/ bt8xx/ dvb-usb/ pluto2/ siano/ dm1105/ pt1/
+obj-y := dvb-core/ \
+ frontends/ \
+ ttpci/ \
+ ttusb-dec/ \
+ ttusb-budget/ \
+ b2c2/ \
+ bt8xx/ \
+ dvb-usb/ \
+ pluto2/ \
+ siano/ \
+ dm1105/ \
+ pt1/ \
+ mantis/
obj-$(CONFIG_DVB_FIREDTV) += firewire/
diff --git a/drivers/media/dvb/bt8xx/bt878.c b/drivers/media/dvb/bt8xx/bt878.c
index a24c125331f0..2a0886ad787f 100644
--- a/drivers/media/dvb/bt8xx/bt878.c
+++ b/drivers/media/dvb/bt8xx/bt878.c
@@ -582,7 +582,7 @@ static int bt878_pci_driver_registered;
/* Module management functions */
/*******************************/
-static int bt878_init_module(void)
+static int __init bt878_init_module(void)
{
bt878_num = 0;
bt878_pci_driver_registered = 0;
@@ -600,7 +600,7 @@ static int bt878_init_module(void)
return pci_register_driver(&bt878_pci_driver);
}
-static void bt878_cleanup_module(void)
+static void __exit bt878_cleanup_module(void)
{
if (bt878_pci_driver_registered) {
bt878_pci_driver_registered = 0;
diff --git a/drivers/media/dvb/dm1105/dm1105.c b/drivers/media/dvb/dm1105/dm1105.c
index f0f483ac8b89..aadf803c261c 100644
--- a/drivers/media/dvb/dm1105/dm1105.c
+++ b/drivers/media/dvb/dm1105/dm1105.c
@@ -578,7 +578,7 @@ int __devinit dm1105_ir_init(struct dm1105dvb *dm1105)
{
struct input_dev *input_dev;
struct ir_scancode_table *ir_codes = &ir_codes_dm1105_nec_table;
- int ir_type = IR_TYPE_OTHER;
+ u64 ir_type = IR_TYPE_OTHER;
int err = -ENOMEM;
input_dev = input_allocate_device();
@@ -611,7 +611,7 @@ int __devinit dm1105_ir_init(struct dm1105dvb *dm1105)
INIT_WORK(&dm1105->ir.work, dm1105_emit_key);
- err = ir_input_register(input_dev, ir_codes);
+ err = ir_input_register(input_dev, ir_codes, NULL);
return err;
}
diff --git a/drivers/media/dvb/dvb-core/dvb_net.c b/drivers/media/dvb/dvb-core/dvb_net.c
index 8b8558fcb042..da6552d32cfe 100644
--- a/drivers/media/dvb/dvb-core/dvb_net.c
+++ b/drivers/media/dvb/dvb-core/dvb_net.c
@@ -949,11 +949,8 @@ static int dvb_net_filter_sec_set(struct net_device *dev,
(*secfilter)->filter_mask[10] = mac_mask[1];
(*secfilter)->filter_mask[11]=mac_mask[0];
- dprintk("%s: filter mac=%02x %02x %02x %02x %02x %02x\n",
- dev->name, mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
- dprintk("%s: filter mask=%02x %02x %02x %02x %02x %02x\n",
- dev->name, mac_mask[0], mac_mask[1], mac_mask[2],
- mac_mask[3], mac_mask[4], mac_mask[5]);
+ dprintk("%s: filter mac=%pM\n", dev->name, mac);
+ dprintk("%s: filter mask=%pM\n", dev->name, mac_mask);
return 0;
}
diff --git a/drivers/media/dvb/dvb-usb/cxusb.c b/drivers/media/dvb/dvb-usb/cxusb.c
index 05fb28e9c69e..a7b8405c291e 100644
--- a/drivers/media/dvb/dvb-usb/cxusb.c
+++ b/drivers/media/dvb/dvb-usb/cxusb.c
@@ -1184,6 +1184,9 @@ static struct atbm8830_config mygica_d689_atbm8830_cfg = {
.osc_clk_freq = 30400, /* in kHz */
.if_freq = 0, /* zero IF */
.zif_swap_iq = 1,
+ .agc_min = 0x2E,
+ .agc_max = 0x90,
+ .agc_hold_loop = 0,
};
static int cxusb_mygica_d689_frontend_attach(struct dvb_usb_adapter *adap)
diff --git a/drivers/media/dvb/dvb-usb/dw2102.c b/drivers/media/dvb/dvb-usb/dw2102.c
index 64132c0cf80d..83a35524a82a 100644
--- a/drivers/media/dvb/dvb-usb/dw2102.c
+++ b/drivers/media/dvb/dvb-usb/dw2102.c
@@ -1,6 +1,7 @@
/* DVB USB framework compliant Linux driver for the
* DVBWorld DVB-S 2101, 2102, DVB-S2 2104, DVB-C 3101,
-* TeVii S600, S630, S650 Cards
+* TeVii S600, S630, S650,
+* Prof 1100, 7500 Cards
* Copyright (C) 2008,2009 Igor M. Liplianin (liplianin@me.by)
*
* This program is free software; you can redistribute it and/or modify it
@@ -469,6 +470,7 @@ static int s6x0_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[],
int num)
{
struct dvb_usb_device *d = i2c_get_adapdata(adap);
+ struct usb_device *udev = d->udev;
int ret = 0;
int len, i, j;
@@ -488,8 +490,13 @@ static int s6x0_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[],
}
case (DW2102_VOLTAGE_CTRL): {
u8 obuf[2];
+
+ obuf[0] = 1;
+ obuf[1] = msg[j].buf[1];/* off-on */
+ ret = dw210x_op_rw(d->udev, 0x8a, 0, 0,
+ obuf, 2, DW210X_WRITE_MSG);
obuf[0] = 3;
- obuf[1] = msg[j].buf[0];
+ obuf[1] = msg[j].buf[0];/* 13v-18v */
ret = dw210x_op_rw(d->udev, 0x8a, 0, 0,
obuf, 2, DW210X_WRITE_MSG);
break;
@@ -527,6 +534,17 @@ static int s6x0_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[],
i += 16;
len -= 16;
} while (len > 0);
+ } else if ((udev->descriptor.idProduct == 0x7500)
+ && (j < (num - 1))) {
+ /* write register addr before read */
+ u8 obuf[msg[j].len + 2];
+ obuf[0] = msg[j + 1].len;
+ obuf[1] = (msg[j].addr << 1);
+ memcpy(obuf + 2, msg[j].buf, msg[j].len);
+ ret = dw210x_op_rw(d->udev, 0x92, 0, 0,
+ obuf, msg[j].len + 2,
+ DW210X_WRITE_MSG);
+ break;
} else {
/* write registers */
u8 obuf[msg[j].len + 2];
@@ -651,18 +669,25 @@ static int s6x0_read_mac_address(struct dvb_usb_device *d, u8 mac[6])
static int dw210x_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage)
{
- static u8 command_13v[1] = {0x00};
- static u8 command_18v[1] = {0x01};
- struct i2c_msg msg[] = {
- {.addr = DW2102_VOLTAGE_CTRL, .flags = 0,
- .buf = command_13v, .len = 1},
+ static u8 command_13v[] = {0x00, 0x01};
+ static u8 command_18v[] = {0x01, 0x01};
+ static u8 command_off[] = {0x00, 0x00};
+ struct i2c_msg msg = {
+ .addr = DW2102_VOLTAGE_CTRL,
+ .flags = 0,
+ .buf = command_off,
+ .len = 2,
};
struct dvb_usb_adapter *udev_adap =
(struct dvb_usb_adapter *)(fe->dvb->priv);
if (voltage == SEC_VOLTAGE_18)
- msg[0].buf = command_18v;
- i2c_transfer(&udev_adap->dev->i2c_adap, msg, 1);
+ msg.buf = command_18v;
+ else if (voltage == SEC_VOLTAGE_13)
+ msg.buf = command_13v;
+
+ i2c_transfer(&udev_adap->dev->i2c_adap, &msg, 1);
+
return 0;
}
@@ -735,6 +760,18 @@ static struct stv6110_config dw2104_stv6110_config = {
.clk_div = 1,
};
+static struct stv0900_config prof_7500_stv0900_config = {
+ .demod_address = 0x6a,
+ .demod_mode = 0,
+ .xtal = 27000000,
+ .clkmode = 3,/* 0-CLKI, 2-XTALI, else AUTO */
+ .diseqc_mode = 2,/* 2/3 PWM */
+ .tun1_maddress = 0,/* 0x60 */
+ .tun1_adc = 0,/* 2 Vpp */
+ .path1_mode = 3,
+ .tun1_type = 3,
+};
+
static int dw2104_frontend_attach(struct dvb_usb_adapter *d)
{
struct dvb_tuner_ops *tuner_ops = NULL;
@@ -882,6 +919,19 @@ static int s6x0_frontend_attach(struct dvb_usb_adapter *d)
return -EIO;
}
+static int prof_7500_frontend_attach(struct dvb_usb_adapter *d)
+{
+ d->fe = dvb_attach(stv0900_attach, &prof_7500_stv0900_config,
+ &d->dev->i2c_adap, 0);
+ if (d->fe == NULL)
+ return -EIO;
+ d->fe->ops.set_voltage = dw210x_set_voltage;
+
+ info("Attached STV0900+STB6100A!\n");
+
+ return 0;
+}
+
static int dw2102_tuner_attach(struct dvb_usb_adapter *adap)
{
dvb_attach(dvb_pll_attach, adap->fe, 0x60,
@@ -1073,6 +1123,7 @@ static struct usb_device_id dw2102_table[] = {
{USB_DEVICE(0x9022, USB_PID_TEVII_S630)},
{USB_DEVICE(0x3011, USB_PID_PROF_1100)},
{USB_DEVICE(0x9022, USB_PID_TEVII_S660)},
+ {USB_DEVICE(0x3034, 0x7500)},
{ }
};
@@ -1387,9 +1438,30 @@ static struct dvb_usb_device_properties s6x0_properties = {
}
};
+struct dvb_usb_device_properties *p7500;
+static struct dvb_usb_device_description d7500 = {
+ "Prof 7500 USB DVB-S2",
+ {&dw2102_table[9], NULL},
+ {NULL},
+};
+
static int dw2102_probe(struct usb_interface *intf,
const struct usb_device_id *id)
{
+
+ p7500 = kzalloc(sizeof(struct dvb_usb_device_properties), GFP_KERNEL);
+ if (!p7500)
+ return -ENOMEM;
+ /* copy default structure */
+ memcpy(p7500, &s6x0_properties,
+ sizeof(struct dvb_usb_device_properties));
+ /* fill only different fields */
+ p7500->firmware = "dvb-usb-p7500.fw";
+ p7500->devices[0] = d7500;
+ p7500->rc_key_map = tbs_rc_keys;
+ p7500->rc_key_map_size = ARRAY_SIZE(tbs_rc_keys);
+ p7500->adapter->frontend_attach = prof_7500_frontend_attach;
+
if (0 == dvb_usb_device_init(intf, &dw2102_properties,
THIS_MODULE, NULL, adapter_nr) ||
0 == dvb_usb_device_init(intf, &dw2104_properties,
@@ -1397,6 +1469,8 @@ static int dw2102_probe(struct usb_interface *intf,
0 == dvb_usb_device_init(intf, &dw3101_properties,
THIS_MODULE, NULL, adapter_nr) ||
0 == dvb_usb_device_init(intf, &s6x0_properties,
+ THIS_MODULE, NULL, adapter_nr) ||
+ 0 == dvb_usb_device_init(intf, p7500,
THIS_MODULE, NULL, adapter_nr))
return 0;
@@ -1431,6 +1505,6 @@ MODULE_AUTHOR("Igor M. Liplianin (c) liplianin@me.by");
MODULE_DESCRIPTION("Driver for DVBWorld DVB-S 2101, 2102, DVB-S2 2104,"
" DVB-C 3101 USB2.0,"
" TeVii S600, S630, S650, S660 USB2.0,"
- " Prof 1100 USB2.0 devices");
+ " Prof 1100, 7500 USB2.0 devices");
MODULE_VERSION("0.1");
MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/firewire/firedtv-1394.c b/drivers/media/dvb/firewire/firedtv-1394.c
index 7c5459c27b75..c3e0ec2dcfca 100644
--- a/drivers/media/dvb/firewire/firedtv-1394.c
+++ b/drivers/media/dvb/firewire/firedtv-1394.c
@@ -90,13 +90,14 @@ static inline struct node_entry *node_of(struct firedtv *fdtv)
return container_of(fdtv->device, struct unit_directory, device)->ne;
}
-static int node_lock(struct firedtv *fdtv, u64 addr, __be32 data[])
+static int node_lock(struct firedtv *fdtv, u64 addr, void *data)
{
+ quadlet_t *d = data;
int ret;
- ret = hpsb_node_lock(node_of(fdtv), addr, EXTCODE_COMPARE_SWAP,
- (__force quadlet_t *)&data[1], (__force quadlet_t)data[0]);
- data[0] = data[1];
+ ret = hpsb_node_lock(node_of(fdtv), addr,
+ EXTCODE_COMPARE_SWAP, &d[1], d[0]);
+ d[0] = d[1];
return ret;
}
@@ -192,9 +193,13 @@ static int node_probe(struct device *dev)
int kv_len, err;
void *kv_str;
- kv_len = (ud->model_name_kv->value.leaf.len - 2) * sizeof(quadlet_t);
- kv_str = CSR1212_TEXTUAL_DESCRIPTOR_LEAF_DATA(ud->model_name_kv);
-
+ if (ud->model_name_kv) {
+ kv_len = (ud->model_name_kv->value.leaf.len - 2) * 4;
+ kv_str = CSR1212_TEXTUAL_DESCRIPTOR_LEAF_DATA(ud->model_name_kv);
+ } else {
+ kv_len = 0;
+ kv_str = NULL;
+ }
fdtv = fdtv_alloc(dev, &fdtv_1394_backend, kv_str, kv_len);
if (!fdtv)
return -ENOMEM;
diff --git a/drivers/media/dvb/firewire/firedtv-avc.c b/drivers/media/dvb/firewire/firedtv-avc.c
index 50c42a4b972b..1b31bebc27d6 100644
--- a/drivers/media/dvb/firewire/firedtv-avc.c
+++ b/drivers/media/dvb/firewire/firedtv-avc.c
@@ -74,7 +74,6 @@
#define EN50221_TAG_CA_INFO 0x9f8031
struct avc_command_frame {
- int length;
u8 ctype;
u8 subunit;
u8 opcode;
@@ -82,13 +81,27 @@ struct avc_command_frame {
};
struct avc_response_frame {
- int length;
u8 response;
u8 subunit;
u8 opcode;
u8 operand[509];
};
+#define LAST_OPERAND (509 - 1)
+
+static inline void clear_operands(struct avc_command_frame *c, int from, int to)
+{
+ memset(&c->operand[from], 0, to - from + 1);
+}
+
+static void pad_operands(struct avc_command_frame *c, int from)
+{
+ int to = ALIGN(from, 4);
+
+ if (from <= to && to <= LAST_OPERAND)
+ clear_operands(c, from, to);
+}
+
#define AVC_DEBUG_READ_DESCRIPTOR 0x0001
#define AVC_DEBUG_DSIT 0x0002
#define AVC_DEBUG_DSD 0x0004
@@ -202,78 +215,65 @@ static void debug_pmt(char *msg, int length)
16, 1, msg, length, false);
}
-static int __avc_write(struct firedtv *fdtv,
- const struct avc_command_frame *c, struct avc_response_frame *r)
+static int avc_write(struct firedtv *fdtv)
{
int err, retry;
- if (r)
- fdtv->avc_reply_received = false;
+ fdtv->avc_reply_received = false;
for (retry = 0; retry < 6; retry++) {
if (unlikely(avc_debug))
- debug_fcp(&c->ctype, c->length);
+ debug_fcp(fdtv->avc_data, fdtv->avc_data_length);
err = fdtv->backend->write(fdtv, FCP_COMMAND_REGISTER,
- (void *)&c->ctype, c->length);
+ fdtv->avc_data, fdtv->avc_data_length);
if (err) {
- fdtv->avc_reply_received = true;
dev_err(fdtv->device, "FCP command write failed\n");
+
return err;
}
- if (!r)
- return 0;
-
/*
* AV/C specs say that answers should be sent within 150 ms.
* Time out after 200 ms.
*/
if (wait_event_timeout(fdtv->avc_wait,
fdtv->avc_reply_received,
- msecs_to_jiffies(200)) != 0) {
- r->length = fdtv->response_length;
- memcpy(&r->response, fdtv->response, r->length);
-
+ msecs_to_jiffies(200)) != 0)
return 0;
- }
}
dev_err(fdtv->device, "FCP response timed out\n");
+
return -ETIMEDOUT;
}
-static int avc_write(struct firedtv *fdtv,
- const struct avc_command_frame *c, struct avc_response_frame *r)
+static bool is_register_rc(struct avc_response_frame *r)
{
- int ret;
-
- if (mutex_lock_interruptible(&fdtv->avc_mutex))
- return -EINTR;
-
- ret = __avc_write(fdtv, c, r);
-
- mutex_unlock(&fdtv->avc_mutex);
- return ret;
+ return r->opcode == AVC_OPCODE_VENDOR &&
+ r->operand[0] == SFE_VENDOR_DE_COMPANYID_0 &&
+ r->operand[1] == SFE_VENDOR_DE_COMPANYID_1 &&
+ r->operand[2] == SFE_VENDOR_DE_COMPANYID_2 &&
+ r->operand[3] == SFE_VENDOR_OPCODE_REGISTER_REMOTE_CONTROL;
}
int avc_recv(struct firedtv *fdtv, void *data, size_t length)
{
- struct avc_response_frame *r =
- data - offsetof(struct avc_response_frame, response);
+ struct avc_response_frame *r = data;
if (unlikely(avc_debug))
debug_fcp(data, length);
- if (length >= 8 &&
- r->operand[0] == SFE_VENDOR_DE_COMPANYID_0 &&
- r->operand[1] == SFE_VENDOR_DE_COMPANYID_1 &&
- r->operand[2] == SFE_VENDOR_DE_COMPANYID_2 &&
- r->operand[3] == SFE_VENDOR_OPCODE_REGISTER_REMOTE_CONTROL) {
- if (r->response == AVC_RESPONSE_CHANGED) {
- fdtv_handle_rc(fdtv,
- r->operand[4] << 8 | r->operand[5]);
+ if (length >= 8 && is_register_rc(r)) {
+ switch (r->response) {
+ case AVC_RESPONSE_CHANGED:
+ fdtv_handle_rc(fdtv, r->operand[4] << 8 | r->operand[5]);
schedule_work(&fdtv->remote_ctrl_work);
- } else if (r->response != AVC_RESPONSE_INTERIM) {
+ break;
+ case AVC_RESPONSE_INTERIM:
+ if (is_register_rc((void *)fdtv->avc_data))
+ goto wake;
+ break;
+ default:
dev_info(fdtv->device,
"remote control result = %d\n", r->response);
}
@@ -285,9 +285,9 @@ int avc_recv(struct firedtv *fdtv, void *data, size_t length)
return -EIO;
}
- memcpy(fdtv->response, data, length);
- fdtv->response_length = length;
-
+ memcpy(fdtv->avc_data, data, length);
+ fdtv->avc_data_length = length;
+wake:
fdtv->avc_reply_received = true;
wake_up(&fdtv->avc_wait);
@@ -318,10 +318,11 @@ static int add_pid_filter(struct firedtv *fdtv, u8 *operand)
* tuning command for setting the relative LNB frequency
* (not supported by the AVC standard)
*/
-static void avc_tuner_tuneqpsk(struct firedtv *fdtv,
- struct dvb_frontend_parameters *params,
- struct avc_command_frame *c)
+static int avc_tuner_tuneqpsk(struct firedtv *fdtv,
+ struct dvb_frontend_parameters *params)
{
+ struct avc_command_frame *c = (void *)fdtv->avc_data;
+
c->opcode = AVC_OPCODE_VENDOR;
c->operand[0] = SFE_VENDOR_DE_COMPANYID_0;
@@ -370,16 +371,18 @@ static void avc_tuner_tuneqpsk(struct firedtv *fdtv,
c->operand[13] = 0x1;
c->operand[14] = 0xff;
c->operand[15] = 0xff;
- c->length = 20;
+
+ return 16;
} else {
- c->length = 16;
+ return 13;
}
}
-static void avc_tuner_dsd_dvb_c(struct firedtv *fdtv,
- struct dvb_frontend_parameters *params,
- struct avc_command_frame *c)
+static int avc_tuner_dsd_dvb_c(struct firedtv *fdtv,
+ struct dvb_frontend_parameters *params)
{
+ struct avc_command_frame *c = (void *)fdtv->avc_data;
+
c->opcode = AVC_OPCODE_DSD;
c->operand[0] = 0; /* source plug */
@@ -440,15 +443,14 @@ static void avc_tuner_dsd_dvb_c(struct firedtv *fdtv,
c->operand[20] = 0x00;
c->operand[21] = 0x00;
- /* Add PIDs to filter */
- c->length = ALIGN(22 + add_pid_filter(fdtv, &c->operand[22]) + 3, 4);
+ return 22 + add_pid_filter(fdtv, &c->operand[22]);
}
-static void avc_tuner_dsd_dvb_t(struct firedtv *fdtv,
- struct dvb_frontend_parameters *params,
- struct avc_command_frame *c)
+static int avc_tuner_dsd_dvb_t(struct firedtv *fdtv,
+ struct dvb_frontend_parameters *params)
{
struct dvb_ofdm_parameters *ofdm = &params->u.ofdm;
+ struct avc_command_frame *c = (void *)fdtv->avc_data;
c->opcode = AVC_OPCODE_DSD;
@@ -543,55 +545,58 @@ static void avc_tuner_dsd_dvb_t(struct firedtv *fdtv,
c->operand[15] = 0x00; /* network_ID[0] */
c->operand[16] = 0x00; /* network_ID[1] */
- /* Add PIDs to filter */
- c->length = ALIGN(17 + add_pid_filter(fdtv, &c->operand[17]) + 3, 4);
+ return 17 + add_pid_filter(fdtv, &c->operand[17]);
}
int avc_tuner_dsd(struct firedtv *fdtv,
struct dvb_frontend_parameters *params)
{
- char buffer[sizeof(struct avc_command_frame)];
- struct avc_command_frame *c = (void *)buffer;
- struct avc_response_frame *r = (void *)buffer; /* FIXME: unused */
+ struct avc_command_frame *c = (void *)fdtv->avc_data;
+ int pos, ret;
- memset(c, 0, sizeof(*c));
+ mutex_lock(&fdtv->avc_mutex);
c->ctype = AVC_CTYPE_CONTROL;
c->subunit = AVC_SUBUNIT_TYPE_TUNER | fdtv->subunit;
switch (fdtv->type) {
case FIREDTV_DVB_S:
- case FIREDTV_DVB_S2: avc_tuner_tuneqpsk(fdtv, params, c); break;
- case FIREDTV_DVB_C: avc_tuner_dsd_dvb_c(fdtv, params, c); break;
- case FIREDTV_DVB_T: avc_tuner_dsd_dvb_t(fdtv, params, c); break;
+ case FIREDTV_DVB_S2: pos = avc_tuner_tuneqpsk(fdtv, params); break;
+ case FIREDTV_DVB_C: pos = avc_tuner_dsd_dvb_c(fdtv, params); break;
+ case FIREDTV_DVB_T: pos = avc_tuner_dsd_dvb_t(fdtv, params); break;
default:
BUG();
}
+ pad_operands(c, pos);
- if (avc_write(fdtv, c, r) < 0)
- return -EIO;
-
- msleep(500);
+ fdtv->avc_data_length = ALIGN(3 + pos, 4);
+ ret = avc_write(fdtv);
#if 0
- /* FIXME: */
- /* u8 *status was an out-parameter of avc_tuner_dsd, unused by caller */
+ /*
+ * FIXME:
+ * u8 *status was an out-parameter of avc_tuner_dsd, unused by caller.
+ * Check for AVC_RESPONSE_ACCEPTED here instead?
+ */
if (status)
*status = r->operand[2];
#endif
- return 0;
+ mutex_unlock(&fdtv->avc_mutex);
+
+ if (ret == 0)
+ msleep(500);
+
+ return ret;
}
int avc_tuner_set_pids(struct firedtv *fdtv, unsigned char pidc, u16 pid[])
{
- char buffer[sizeof(struct avc_command_frame)];
- struct avc_command_frame *c = (void *)buffer;
- struct avc_response_frame *r = (void *)buffer; /* FIXME: unused */
- int pos, k;
+ struct avc_command_frame *c = (void *)fdtv->avc_data;
+ int ret, pos, k;
if (pidc > 16 && pidc != 0xff)
return -EINVAL;
- memset(c, 0, sizeof(*c));
+ mutex_lock(&fdtv->avc_mutex);
c->ctype = AVC_CTYPE_CONTROL;
c->subunit = AVC_SUBUNIT_TYPE_TUNER | fdtv->subunit;
@@ -614,24 +619,27 @@ int avc_tuner_set_pids(struct firedtv *fdtv, unsigned char pidc, u16 pid[])
c->operand[pos++] = 0x00; /* tableID */
c->operand[pos++] = 0x00; /* filter_length */
}
+ pad_operands(c, pos);
- c->length = ALIGN(3 + pos, 4);
+ fdtv->avc_data_length = ALIGN(3 + pos, 4);
+ ret = avc_write(fdtv);
- if (avc_write(fdtv, c, r) < 0)
- return -EIO;
+ /* FIXME: check response code? */
- msleep(50);
- return 0;
+ mutex_unlock(&fdtv->avc_mutex);
+
+ if (ret == 0)
+ msleep(50);
+
+ return ret;
}
int avc_tuner_get_ts(struct firedtv *fdtv)
{
- char buffer[sizeof(struct avc_command_frame)];
- struct avc_command_frame *c = (void *)buffer;
- struct avc_response_frame *r = (void *)buffer; /* FIXME: unused */
- int sl;
+ struct avc_command_frame *c = (void *)fdtv->avc_data;
+ int ret, sl;
- memset(c, 0, sizeof(*c));
+ mutex_lock(&fdtv->avc_mutex);
c->ctype = AVC_CTYPE_CONTROL;
c->subunit = AVC_SUBUNIT_TYPE_TUNER | fdtv->subunit;
@@ -646,26 +654,33 @@ int avc_tuner_get_ts(struct firedtv *fdtv)
c->operand[4] = 0x00; /* antenna number */
c->operand[5] = 0x0; /* system_specific_search_flags */
c->operand[6] = sl; /* system_specific_multiplex selection_length */
- c->operand[7] = 0x00; /* valid_flags [0] */
- c->operand[8] = 0x00; /* valid_flags [1] */
- c->operand[7 + sl] = 0x00; /* nr_of_dsit_sel_specs (always 0) */
+ /*
+ * operand[7]: valid_flags[0]
+ * operand[8]: valid_flags[1]
+ * operand[7 + sl]: nr_of_dsit_sel_specs (always 0)
+ */
+ clear_operands(c, 7, 24);
- c->length = fdtv->type == FIREDTV_DVB_T ? 24 : 28;
+ fdtv->avc_data_length = fdtv->type == FIREDTV_DVB_T ? 24 : 28;
+ ret = avc_write(fdtv);
- if (avc_write(fdtv, c, r) < 0)
- return -EIO;
+ /* FIXME: check response code? */
- msleep(250);
- return 0;
+ mutex_unlock(&fdtv->avc_mutex);
+
+ if (ret == 0)
+ msleep(250);
+
+ return ret;
}
int avc_identify_subunit(struct firedtv *fdtv)
{
- char buffer[sizeof(struct avc_command_frame)];
- struct avc_command_frame *c = (void *)buffer;
- struct avc_response_frame *r = (void *)buffer;
+ struct avc_command_frame *c = (void *)fdtv->avc_data;
+ struct avc_response_frame *r = (void *)fdtv->avc_data;
+ int ret;
- memset(c, 0, sizeof(*c));
+ mutex_lock(&fdtv->avc_mutex);
c->ctype = AVC_CTYPE_CONTROL;
c->subunit = AVC_SUBUNIT_TYPE_TUNER | fdtv->subunit;
@@ -678,31 +693,34 @@ int avc_identify_subunit(struct firedtv *fdtv)
c->operand[4] = 0x08; /* length lowbyte */
c->operand[5] = 0x00; /* offset highbyte */
c->operand[6] = 0x0d; /* offset lowbyte */
+ clear_operands(c, 7, 8); /* padding */
- c->length = 12;
-
- if (avc_write(fdtv, c, r) < 0)
- return -EIO;
+ fdtv->avc_data_length = 12;
+ ret = avc_write(fdtv);
+ if (ret < 0)
+ goto out;
if ((r->response != AVC_RESPONSE_STABLE &&
r->response != AVC_RESPONSE_ACCEPTED) ||
(r->operand[3] << 8) + r->operand[4] != 8) {
dev_err(fdtv->device, "cannot read subunit identifier\n");
- return -EINVAL;
+ ret = -EINVAL;
}
- return 0;
+out:
+ mutex_unlock(&fdtv->avc_mutex);
+
+ return ret;
}
#define SIZEOF_ANTENNA_INPUT_INFO 22
int avc_tuner_status(struct firedtv *fdtv, struct firedtv_tuner_status *stat)
{
- char buffer[sizeof(struct avc_command_frame)];
- struct avc_command_frame *c = (void *)buffer;
- struct avc_response_frame *r = (void *)buffer;
- int length;
+ struct avc_command_frame *c = (void *)fdtv->avc_data;
+ struct avc_response_frame *r = (void *)fdtv->avc_data;
+ int length, ret;
- memset(c, 0, sizeof(*c));
+ mutex_lock(&fdtv->avc_mutex);
c->ctype = AVC_CTYPE_CONTROL;
c->subunit = AVC_SUBUNIT_TYPE_TUNER | fdtv->subunit;
@@ -710,27 +728,30 @@ int avc_tuner_status(struct firedtv *fdtv, struct firedtv_tuner_status *stat)
c->operand[0] = DESCRIPTOR_TUNER_STATUS;
c->operand[1] = 0xff; /* read_result_status */
- c->operand[2] = 0x00; /* reserved */
- c->operand[3] = 0; /* SIZEOF_ANTENNA_INPUT_INFO >> 8; */
- c->operand[4] = 0; /* SIZEOF_ANTENNA_INPUT_INFO & 0xff; */
- c->operand[5] = 0x00;
- c->operand[6] = 0x00;
-
- c->length = 12;
-
- if (avc_write(fdtv, c, r) < 0)
- return -EIO;
+ /*
+ * operand[2]: reserved
+ * operand[3]: SIZEOF_ANTENNA_INPUT_INFO >> 8
+ * operand[4]: SIZEOF_ANTENNA_INPUT_INFO & 0xff
+ */
+ clear_operands(c, 2, 31);
+
+ fdtv->avc_data_length = 12;
+ ret = avc_write(fdtv);
+ if (ret < 0)
+ goto out;
if (r->response != AVC_RESPONSE_STABLE &&
r->response != AVC_RESPONSE_ACCEPTED) {
dev_err(fdtv->device, "cannot read tuner status\n");
- return -EINVAL;
+ ret = -EINVAL;
+ goto out;
}
length = r->operand[9];
if (r->operand[1] != 0x10 || length != SIZEOF_ANTENNA_INPUT_INFO) {
dev_err(fdtv->device, "got invalid tuner status\n");
- return -EINVAL;
+ ret = -EINVAL;
+ goto out;
}
stat->active_system = r->operand[10];
@@ -766,20 +787,21 @@ int avc_tuner_status(struct firedtv *fdtv, struct firedtv_tuner_status *stat)
stat->ca_dvb_flag = r->operand[31] >> 3 & 1;
stat->ca_error_flag = r->operand[31] >> 2 & 1;
stat->ca_initialization_status = r->operand[31] >> 1 & 1;
+out:
+ mutex_unlock(&fdtv->avc_mutex);
- return 0;
+ return ret;
}
int avc_lnb_control(struct firedtv *fdtv, char voltage, char burst,
char conttone, char nrdiseq,
struct dvb_diseqc_master_cmd *diseqcmd)
{
- char buffer[sizeof(struct avc_command_frame)];
- struct avc_command_frame *c = (void *)buffer;
- struct avc_response_frame *r = (void *)buffer;
- int i, j, k;
+ struct avc_command_frame *c = (void *)fdtv->avc_data;
+ struct avc_response_frame *r = (void *)fdtv->avc_data;
+ int pos, j, k, ret;
- memset(c, 0, sizeof(*c));
+ mutex_lock(&fdtv->avc_mutex);
c->ctype = AVC_CTYPE_CONTROL;
c->subunit = AVC_SUBUNIT_TYPE_TUNER | fdtv->subunit;
@@ -789,41 +811,41 @@ int avc_lnb_control(struct firedtv *fdtv, char voltage, char burst,
c->operand[1] = SFE_VENDOR_DE_COMPANYID_1;
c->operand[2] = SFE_VENDOR_DE_COMPANYID_2;
c->operand[3] = SFE_VENDOR_OPCODE_LNB_CONTROL;
-
c->operand[4] = voltage;
c->operand[5] = nrdiseq;
- i = 6;
-
+ pos = 6;
for (j = 0; j < nrdiseq; j++) {
- c->operand[i++] = diseqcmd[j].msg_len;
+ c->operand[pos++] = diseqcmd[j].msg_len;
for (k = 0; k < diseqcmd[j].msg_len; k++)
- c->operand[i++] = diseqcmd[j].msg[k];
+ c->operand[pos++] = diseqcmd[j].msg[k];
}
+ c->operand[pos++] = burst;
+ c->operand[pos++] = conttone;
+ pad_operands(c, pos);
- c->operand[i++] = burst;
- c->operand[i++] = conttone;
-
- c->length = ALIGN(3 + i, 4);
-
- if (avc_write(fdtv, c, r) < 0)
- return -EIO;
+ fdtv->avc_data_length = ALIGN(3 + pos, 4);
+ ret = avc_write(fdtv);
+ if (ret < 0)
+ goto out;
if (r->response != AVC_RESPONSE_ACCEPTED) {
dev_err(fdtv->device, "LNB control failed\n");
- return -EINVAL;
+ ret = -EINVAL;
}
+out:
+ mutex_unlock(&fdtv->avc_mutex);
- return 0;
+ return ret;
}
int avc_register_remote_control(struct firedtv *fdtv)
{
- char buffer[sizeof(struct avc_command_frame)];
- struct avc_command_frame *c = (void *)buffer;
+ struct avc_command_frame *c = (void *)fdtv->avc_data;
+ int ret;
- memset(c, 0, sizeof(*c));
+ mutex_lock(&fdtv->avc_mutex);
c->ctype = AVC_CTYPE_NOTIFY;
c->subunit = AVC_SUBUNIT_TYPE_UNIT | 7;
@@ -833,10 +855,16 @@ int avc_register_remote_control(struct firedtv *fdtv)
c->operand[1] = SFE_VENDOR_DE_COMPANYID_1;
c->operand[2] = SFE_VENDOR_DE_COMPANYID_2;
c->operand[3] = SFE_VENDOR_OPCODE_REGISTER_REMOTE_CONTROL;
+ c->operand[4] = 0; /* padding */
+
+ fdtv->avc_data_length = 8;
+ ret = avc_write(fdtv);
- c->length = 8;
+ /* FIXME: check response code? */
- return avc_write(fdtv, c, NULL);
+ mutex_unlock(&fdtv->avc_mutex);
+
+ return ret;
}
void avc_remote_ctrl_work(struct work_struct *work)
@@ -851,11 +879,10 @@ void avc_remote_ctrl_work(struct work_struct *work)
#if 0 /* FIXME: unused */
int avc_tuner_host2ca(struct firedtv *fdtv)
{
- char buffer[sizeof(struct avc_command_frame)];
- struct avc_command_frame *c = (void *)buffer;
- struct avc_response_frame *r = (void *)buffer; /* FIXME: unused */
+ struct avc_command_frame *c = (void *)fdtv->avc_data;
+ int ret;
- memset(c, 0, sizeof(*c));
+ mutex_lock(&fdtv->avc_mutex);
c->ctype = AVC_CTYPE_CONTROL;
c->subunit = AVC_SUBUNIT_TYPE_TUNER | fdtv->subunit;
@@ -867,15 +894,16 @@ int avc_tuner_host2ca(struct firedtv *fdtv)
c->operand[3] = SFE_VENDOR_OPCODE_HOST2CA;
c->operand[4] = 0; /* slot */
c->operand[5] = SFE_VENDOR_TAG_CA_APPLICATION_INFO; /* ca tag */
- c->operand[6] = 0; /* more/last */
- c->operand[7] = 0; /* length */
+ clear_operands(c, 6, 8);
- c->length = 12;
+ fdtv->avc_data_length = 12;
+ ret = avc_write(fdtv);
- if (avc_write(fdtv, c, r) < 0)
- return -EIO;
+ /* FIXME: check response code? */
- return 0;
+ mutex_unlock(&fdtv->avc_mutex);
+
+ return ret;
}
#endif
@@ -906,12 +934,11 @@ static int get_ca_object_length(struct avc_response_frame *r)
int avc_ca_app_info(struct firedtv *fdtv, char *app_info, unsigned int *len)
{
- char buffer[sizeof(struct avc_command_frame)];
- struct avc_command_frame *c = (void *)buffer;
- struct avc_response_frame *r = (void *)buffer;
- int pos;
+ struct avc_command_frame *c = (void *)fdtv->avc_data;
+ struct avc_response_frame *r = (void *)fdtv->avc_data;
+ int pos, ret;
- memset(c, 0, sizeof(*c));
+ mutex_lock(&fdtv->avc_mutex);
c->ctype = AVC_CTYPE_STATUS;
c->subunit = AVC_SUBUNIT_TYPE_TUNER | fdtv->subunit;
@@ -923,11 +950,12 @@ int avc_ca_app_info(struct firedtv *fdtv, char *app_info, unsigned int *len)
c->operand[3] = SFE_VENDOR_OPCODE_CA2HOST;
c->operand[4] = 0; /* slot */
c->operand[5] = SFE_VENDOR_TAG_CA_APPLICATION_INFO; /* ca tag */
+ clear_operands(c, 6, LAST_OPERAND);
- c->length = 12;
-
- if (avc_write(fdtv, c, r) < 0)
- return -EIO;
+ fdtv->avc_data_length = 12;
+ ret = avc_write(fdtv);
+ if (ret < 0)
+ goto out;
/* FIXME: check response code and validate response data */
@@ -939,18 +967,19 @@ int avc_ca_app_info(struct firedtv *fdtv, char *app_info, unsigned int *len)
app_info[4] = 0x01;
memcpy(&app_info[5], &r->operand[pos], 5 + r->operand[pos + 4]);
*len = app_info[3] + 4;
+out:
+ mutex_unlock(&fdtv->avc_mutex);
- return 0;
+ return ret;
}
int avc_ca_info(struct firedtv *fdtv, char *app_info, unsigned int *len)
{
- char buffer[sizeof(struct avc_command_frame)];
- struct avc_command_frame *c = (void *)buffer;
- struct avc_response_frame *r = (void *)buffer;
- int pos;
+ struct avc_command_frame *c = (void *)fdtv->avc_data;
+ struct avc_response_frame *r = (void *)fdtv->avc_data;
+ int pos, ret;
- memset(c, 0, sizeof(*c));
+ mutex_lock(&fdtv->avc_mutex);
c->ctype = AVC_CTYPE_STATUS;
c->subunit = AVC_SUBUNIT_TYPE_TUNER | fdtv->subunit;
@@ -962,11 +991,14 @@ int avc_ca_info(struct firedtv *fdtv, char *app_info, unsigned int *len)
c->operand[3] = SFE_VENDOR_OPCODE_CA2HOST;
c->operand[4] = 0; /* slot */
c->operand[5] = SFE_VENDOR_TAG_CA_APPLICATION_INFO; /* ca tag */
+ clear_operands(c, 6, LAST_OPERAND);
- c->length = 12;
+ fdtv->avc_data_length = 12;
+ ret = avc_write(fdtv);
+ if (ret < 0)
+ goto out;
- if (avc_write(fdtv, c, r) < 0)
- return -EIO;
+ /* FIXME: check response code and validate response data */
pos = get_ca_object_pos(r);
app_info[0] = (EN50221_TAG_CA_INFO >> 16) & 0xff;
@@ -976,17 +1008,18 @@ int avc_ca_info(struct firedtv *fdtv, char *app_info, unsigned int *len)
app_info[4] = r->operand[pos + 0];
app_info[5] = r->operand[pos + 1];
*len = app_info[3] + 4;
+out:
+ mutex_unlock(&fdtv->avc_mutex);
- return 0;
+ return ret;
}
int avc_ca_reset(struct firedtv *fdtv)
{
- char buffer[sizeof(struct avc_command_frame)];
- struct avc_command_frame *c = (void *)buffer;
- struct avc_response_frame *r = (void *)buffer; /* FIXME: unused */
+ struct avc_command_frame *c = (void *)fdtv->avc_data;
+ int ret;
- memset(c, 0, sizeof(*c));
+ mutex_lock(&fdtv->avc_mutex);
c->ctype = AVC_CTYPE_CONTROL;
c->subunit = AVC_SUBUNIT_TYPE_TUNER | fdtv->subunit;
@@ -1002,19 +1035,20 @@ int avc_ca_reset(struct firedtv *fdtv)
c->operand[7] = 1; /* length */
c->operand[8] = 0; /* force hardware reset */
- c->length = 12;
+ fdtv->avc_data_length = 12;
+ ret = avc_write(fdtv);
- if (avc_write(fdtv, c, r) < 0)
- return -EIO;
+ /* FIXME: check response code? */
- return 0;
+ mutex_unlock(&fdtv->avc_mutex);
+
+ return ret;
}
int avc_ca_pmt(struct firedtv *fdtv, char *msg, int length)
{
- char buffer[sizeof(struct avc_command_frame)];
- struct avc_command_frame *c = (void *)buffer;
- struct avc_response_frame *r = (void *)buffer;
+ struct avc_command_frame *c = (void *)fdtv->avc_data;
+ struct avc_response_frame *r = (void *)fdtv->avc_data;
int list_management;
int program_info_length;
int pmt_cmd_id;
@@ -1022,11 +1056,12 @@ int avc_ca_pmt(struct firedtv *fdtv, char *msg, int length)
int write_pos;
int es_info_length;
int crc32_csum;
+ int ret;
if (unlikely(avc_debug & AVC_DEBUG_APPLICATION_PMT))
debug_pmt(msg, length);
- memset(c, 0, sizeof(*c));
+ mutex_lock(&fdtv->avc_mutex);
c->ctype = AVC_CTYPE_CONTROL;
c->subunit = AVC_SUBUNIT_TYPE_TUNER | fdtv->subunit;
@@ -1058,7 +1093,7 @@ int avc_ca_pmt(struct firedtv *fdtv, char *msg, int length)
c->operand[12] = 0x02; /* Table id=2 */
c->operand[13] = 0x80; /* Section syntax + length */
- /* c->operand[14] = XXXprogram_info_length + 12; */
+
c->operand[15] = msg[1]; /* Program number */
c->operand[16] = msg[2];
c->operand[17] = 0x01; /* Version number=0 + current/next=1 */
@@ -1106,12 +1141,7 @@ int avc_ca_pmt(struct firedtv *fdtv, char *msg, int length)
write_pos += es_info_length;
}
}
-
- /* CRC */
- c->operand[write_pos++] = 0x00;
- c->operand[write_pos++] = 0x00;
- c->operand[write_pos++] = 0x00;
- c->operand[write_pos++] = 0x00;
+ write_pos += 4; /* CRC */
c->operand[7] = 0x82;
c->operand[8] = (write_pos - 10) >> 8;
@@ -1123,28 +1153,31 @@ int avc_ca_pmt(struct firedtv *fdtv, char *msg, int length)
c->operand[write_pos - 3] = (crc32_csum >> 16) & 0xff;
c->operand[write_pos - 2] = (crc32_csum >> 8) & 0xff;
c->operand[write_pos - 1] = (crc32_csum >> 0) & 0xff;
+ pad_operands(c, write_pos);
- c->length = ALIGN(3 + write_pos, 4);
-
- if (avc_write(fdtv, c, r) < 0)
- return -EIO;
+ fdtv->avc_data_length = ALIGN(3 + write_pos, 4);
+ ret = avc_write(fdtv);
+ if (ret < 0)
+ goto out;
if (r->response != AVC_RESPONSE_ACCEPTED) {
dev_err(fdtv->device,
"CA PMT failed with response 0x%x\n", r->response);
- return -EFAULT;
+ ret = -EFAULT;
}
+out:
+ mutex_unlock(&fdtv->avc_mutex);
- return 0;
+ return ret;
}
int avc_ca_get_time_date(struct firedtv *fdtv, int *interval)
{
- char buffer[sizeof(struct avc_command_frame)];
- struct avc_command_frame *c = (void *)buffer;
- struct avc_response_frame *r = (void *)buffer;
+ struct avc_command_frame *c = (void *)fdtv->avc_data;
+ struct avc_response_frame *r = (void *)fdtv->avc_data;
+ int ret;
- memset(c, 0, sizeof(*c));
+ mutex_lock(&fdtv->avc_mutex);
c->ctype = AVC_CTYPE_STATUS;
c->subunit = AVC_SUBUNIT_TYPE_TUNER | fdtv->subunit;
@@ -1156,28 +1189,28 @@ int avc_ca_get_time_date(struct firedtv *fdtv, int *interval)
c->operand[3] = SFE_VENDOR_OPCODE_CA2HOST;
c->operand[4] = 0; /* slot */
c->operand[5] = SFE_VENDOR_TAG_CA_DATE_TIME; /* ca tag */
- c->operand[6] = 0; /* more/last */
- c->operand[7] = 0; /* length */
+ clear_operands(c, 6, LAST_OPERAND);
- c->length = 12;
-
- if (avc_write(fdtv, c, r) < 0)
- return -EIO;
+ fdtv->avc_data_length = 12;
+ ret = avc_write(fdtv);
+ if (ret < 0)
+ goto out;
/* FIXME: check response code and validate response data */
*interval = r->operand[get_ca_object_pos(r)];
+out:
+ mutex_unlock(&fdtv->avc_mutex);
- return 0;
+ return ret;
}
int avc_ca_enter_menu(struct firedtv *fdtv)
{
- char buffer[sizeof(struct avc_command_frame)];
- struct avc_command_frame *c = (void *)buffer;
- struct avc_response_frame *r = (void *)buffer; /* FIXME: unused */
+ struct avc_command_frame *c = (void *)fdtv->avc_data;
+ int ret;
- memset(c, 0, sizeof(*c));
+ mutex_lock(&fdtv->avc_mutex);
c->ctype = AVC_CTYPE_STATUS;
c->subunit = AVC_SUBUNIT_TYPE_TUNER | fdtv->subunit;
@@ -1189,24 +1222,25 @@ int avc_ca_enter_menu(struct firedtv *fdtv)
c->operand[3] = SFE_VENDOR_OPCODE_HOST2CA;
c->operand[4] = 0; /* slot */
c->operand[5] = SFE_VENDOR_TAG_CA_ENTER_MENU;
- c->operand[6] = 0; /* more/last */
- c->operand[7] = 0; /* length */
+ clear_operands(c, 6, 8);
- c->length = 12;
+ fdtv->avc_data_length = 12;
+ ret = avc_write(fdtv);
- if (avc_write(fdtv, c, r) < 0)
- return -EIO;
+ /* FIXME: check response code? */
- return 0;
+ mutex_unlock(&fdtv->avc_mutex);
+
+ return ret;
}
int avc_ca_get_mmi(struct firedtv *fdtv, char *mmi_object, unsigned int *len)
{
- char buffer[sizeof(struct avc_command_frame)];
- struct avc_command_frame *c = (void *)buffer;
- struct avc_response_frame *r = (void *)buffer;
+ struct avc_command_frame *c = (void *)fdtv->avc_data;
+ struct avc_response_frame *r = (void *)fdtv->avc_data;
+ int ret;
- memset(c, 0, sizeof(*c));
+ mutex_lock(&fdtv->avc_mutex);
c->ctype = AVC_CTYPE_STATUS;
c->subunit = AVC_SUBUNIT_TYPE_TUNER | fdtv->subunit;
@@ -1218,20 +1252,21 @@ int avc_ca_get_mmi(struct firedtv *fdtv, char *mmi_object, unsigned int *len)
c->operand[3] = SFE_VENDOR_OPCODE_CA2HOST;
c->operand[4] = 0; /* slot */
c->operand[5] = SFE_VENDOR_TAG_CA_MMI;
- c->operand[6] = 0; /* more/last */
- c->operand[7] = 0; /* length */
+ clear_operands(c, 6, LAST_OPERAND);
- c->length = 12;
-
- if (avc_write(fdtv, c, r) < 0)
- return -EIO;
+ fdtv->avc_data_length = 12;
+ ret = avc_write(fdtv);
+ if (ret < 0)
+ goto out;
/* FIXME: check response code and validate response data */
*len = get_ca_object_length(r);
memcpy(mmi_object, &r->operand[get_ca_object_pos(r)], *len);
+out:
+ mutex_unlock(&fdtv->avc_mutex);
- return 0;
+ return ret;
}
#define CMP_OUTPUT_PLUG_CONTROL_REG_0 0xfffff0000904ULL
@@ -1240,14 +1275,14 @@ static int cmp_read(struct firedtv *fdtv, u64 addr, __be32 *data)
{
int ret;
- if (mutex_lock_interruptible(&fdtv->avc_mutex))
- return -EINTR;
+ mutex_lock(&fdtv->avc_mutex);
ret = fdtv->backend->read(fdtv, addr, data);
if (ret < 0)
dev_err(fdtv->device, "CMP: read I/O error\n");
mutex_unlock(&fdtv->avc_mutex);
+
return ret;
}
@@ -1255,14 +1290,19 @@ static int cmp_lock(struct firedtv *fdtv, u64 addr, __be32 data[])
{
int ret;
- if (mutex_lock_interruptible(&fdtv->avc_mutex))
- return -EINTR;
+ mutex_lock(&fdtv->avc_mutex);
+
+ /* data[] is stack-allocated and should not be DMA-mapped. */
+ memcpy(fdtv->avc_data, data, 8);
- ret = fdtv->backend->lock(fdtv, addr, data);
+ ret = fdtv->backend->lock(fdtv, addr, fdtv->avc_data);
if (ret < 0)
dev_err(fdtv->device, "CMP: lock I/O error\n");
+ else
+ memcpy(data, fdtv->avc_data, 8);
mutex_unlock(&fdtv->avc_mutex);
+
return ret;
}
diff --git a/drivers/media/dvb/firewire/firedtv-dvb.c b/drivers/media/dvb/firewire/firedtv-dvb.c
index fc9996c13e13..079e8c5b0475 100644
--- a/drivers/media/dvb/firewire/firedtv-dvb.c
+++ b/drivers/media/dvb/firewire/firedtv-dvb.c
@@ -277,7 +277,6 @@ struct firedtv *fdtv_alloc(struct device *dev,
mutex_init(&fdtv->avc_mutex);
init_waitqueue_head(&fdtv->avc_wait);
- fdtv->avc_reply_received = true;
mutex_init(&fdtv->demux_mutex);
INIT_WORK(&fdtv->remote_ctrl_work, avc_remote_ctrl_work);
diff --git a/drivers/media/dvb/firewire/firedtv-fw.c b/drivers/media/dvb/firewire/firedtv-fw.c
index 6223bf01efe9..75afe4f81e33 100644
--- a/drivers/media/dvb/firewire/firedtv-fw.c
+++ b/drivers/media/dvb/firewire/firedtv-fw.c
@@ -41,7 +41,7 @@ static int node_req(struct firedtv *fdtv, u64 addr, void *data, size_t len,
return rcode != RCODE_COMPLETE ? -EIO : 0;
}
-static int node_lock(struct firedtv *fdtv, u64 addr, __be32 data[])
+static int node_lock(struct firedtv *fdtv, u64 addr, void *data)
{
return node_req(fdtv, addr, data, 8, TCODE_LOCK_COMPARE_SWAP);
}
@@ -239,47 +239,18 @@ static const struct fw_address_region fcp_region = {
};
/* Adjust the template string if models with longer names appear. */
-#define MAX_MODEL_NAME_LEN ((int)DIV_ROUND_UP(sizeof("FireDTV ????"), 4))
-
-static size_t model_name(u32 *directory, __be32 *buffer)
-{
- struct fw_csr_iterator ci;
- int i, length, key, value, last_key = 0;
- u32 *block = NULL;
-
- fw_csr_iterator_init(&ci, directory);
- while (fw_csr_iterator_next(&ci, &key, &value)) {
- if (last_key == CSR_MODEL &&
- key == (CSR_DESCRIPTOR | CSR_LEAF))
- block = ci.p - 1 + value;
- last_key = key;
- }
-
- if (block == NULL)
- return 0;
-
- length = min((int)(block[0] >> 16) - 2, MAX_MODEL_NAME_LEN);
- if (length <= 0)
- return 0;
-
- /* fast-forward to text string */
- block += 3;
-
- for (i = 0; i < length; i++)
- buffer[i] = cpu_to_be32(block[i]);
-
- return length * 4;
-}
+#define MAX_MODEL_NAME_LEN sizeof("FireDTV ????")
static int node_probe(struct device *dev)
{
struct firedtv *fdtv;
- __be32 name[MAX_MODEL_NAME_LEN];
+ char name[MAX_MODEL_NAME_LEN];
int name_len, err;
- name_len = model_name(fw_unit(dev)->directory, name);
+ name_len = fw_csr_string(fw_unit(dev)->directory, CSR_MODEL,
+ name, sizeof(name));
- fdtv = fdtv_alloc(dev, &backend, (char *)name, name_len);
+ fdtv = fdtv_alloc(dev, &backend, name, name_len >= 0 ? name_len : 0);
if (!fdtv)
return -ENOMEM;
diff --git a/drivers/media/dvb/firewire/firedtv.h b/drivers/media/dvb/firewire/firedtv.h
index 35080dbb3c66..78cc28f36914 100644
--- a/drivers/media/dvb/firewire/firedtv.h
+++ b/drivers/media/dvb/firewire/firedtv.h
@@ -73,7 +73,7 @@ struct input_dev;
struct firedtv;
struct firedtv_backend {
- int (*lock)(struct firedtv *fdtv, u64 addr, __be32 data[]);
+ int (*lock)(struct firedtv *fdtv, u64 addr, void *data);
int (*read)(struct firedtv *fdtv, u64 addr, void *data);
int (*write)(struct firedtv *fdtv, u64 addr, void *data, size_t len);
int (*start_iso)(struct firedtv *fdtv);
@@ -114,8 +114,8 @@ struct firedtv {
unsigned long channel_active;
u16 channel_pid[16];
- size_t response_length;
- u8 response[512];
+ int avc_data_length;
+ u8 avc_data[512];
};
/* firedtv-1394.c */
diff --git a/drivers/media/dvb/frontends/Kconfig b/drivers/media/dvb/frontends/Kconfig
index a3b8b697349b..cd7f9b7cbffa 100644
--- a/drivers/media/dvb/frontends/Kconfig
+++ b/drivers/media/dvb/frontends/Kconfig
@@ -208,6 +208,14 @@ config DVB_DS3000
help
A DVB-S/S2 tuner module. Say Y when you want to support this frontend.
+config DVB_MB86A16
+ tristate "Fujitsu MB86A16 based"
+ depends on DVB_CORE && I2C
+ default m if DVB_FE_CUSTOMISE
+ help
+ A DVB-S/DSS Direct Conversion reveiver.
+ Say Y when you want to support this frontend.
+
comment "DVB-T (terrestrial) frontends"
depends on DVB_CORE
@@ -587,6 +595,17 @@ config DVB_ATBM8830
help
A DMB-TH tuner module. Say Y when you want to support this frontend.
+config DVB_TDA665x
+ tristate "TDA665x tuner"
+ depends on DVB_CORE && I2C
+ default m if DVB_FE_CUSTOMISE
+ help
+ Support for tuner modules based on Philips TDA6650/TDA6651 chips.
+ Say Y when you want to support this chip.
+
+ Currently supported tuners:
+ * Panasonic ENV57H12D5 (ET-50DT)
+
comment "Tools to develop new frontends"
config DVB_DUMMY_FE
diff --git a/drivers/media/dvb/frontends/Makefile b/drivers/media/dvb/frontends/Makefile
index 47575cc7b699..874e8ada4d1d 100644
--- a/drivers/media/dvb/frontends/Makefile
+++ b/drivers/media/dvb/frontends/Makefile
@@ -64,6 +64,7 @@ obj-$(CONFIG_DVB_TDA10048) += tda10048.o
obj-$(CONFIG_DVB_TUNER_CX24113) += cx24113.o
obj-$(CONFIG_DVB_S5H1411) += s5h1411.o
obj-$(CONFIG_DVB_LGS8GL5) += lgs8gl5.o
+obj-$(CONFIG_DVB_TDA665x) += tda665x.o
obj-$(CONFIG_DVB_LGS8GXX) += lgs8gxx.o
obj-$(CONFIG_DVB_ATBM8830) += atbm8830.o
obj-$(CONFIG_DVB_DUMMY_FE) += dvb_dummy_fe.o
@@ -80,3 +81,4 @@ obj-$(CONFIG_DVB_STV6110x) += stv6110x.o
obj-$(CONFIG_DVB_ISL6423) += isl6423.o
obj-$(CONFIG_DVB_EC100) += ec100.o
obj-$(CONFIG_DVB_DS3000) += ds3000.o
+obj-$(CONFIG_DVB_MB86A16) += mb86a16.o
diff --git a/drivers/media/dvb/frontends/atbm8830.c b/drivers/media/dvb/frontends/atbm8830.c
index 59881a5944eb..43aac2f85c2e 100644
--- a/drivers/media/dvb/frontends/atbm8830.c
+++ b/drivers/media/dvb/frontends/atbm8830.c
@@ -170,6 +170,19 @@ static int is_locked(struct atbm_state *priv, u8 *locked)
return 0;
}
+static int set_agc_config(struct atbm_state *priv,
+ u8 min, u8 max, u8 hold_loop)
+{
+ /* no effect if both min and max are zero */
+ if (!min && !max)
+ return 0;
+
+ atbm8830_write_reg(priv, REG_AGC_MIN, min);
+ atbm8830_write_reg(priv, REG_AGC_MAX, max);
+ atbm8830_write_reg(priv, REG_AGC_HOLD_LOOP, hold_loop);
+
+ return 0;
+}
static int set_static_channel_mode(struct atbm_state *priv)
{
@@ -227,6 +240,9 @@ static int atbm8830_init(struct dvb_frontend *fe)
/*Set IF frequency*/
set_if_freq(priv, cfg->if_freq);
+ /*Set AGC Config*/
+ set_agc_config(priv, cfg->agc_min, cfg->agc_max,
+ cfg->agc_hold_loop);
/*Set static channel mode*/
set_static_channel_mode(priv);
diff --git a/drivers/media/dvb/frontends/dib8000.c b/drivers/media/dvb/frontends/dib8000.c
index 6f6fa29d9ea4..2aa97dd6a8af 100644
--- a/drivers/media/dvb/frontends/dib8000.c
+++ b/drivers/media/dvb/frontends/dib8000.c
@@ -1999,6 +1999,8 @@ static int dib8000_set_frontend(struct dvb_frontend *fe, struct dvb_frontend_par
struct dib8000_state *state = fe->demodulator_priv;
int time, ret;
+ fe->dtv_property_cache.delivery_system = SYS_ISDBT;
+
dib8000_set_output_mode(state, OUTMODE_HIGH_Z);
if (fe->ops.tuner_ops.set_params)
diff --git a/drivers/media/dvb/frontends/dib8000.h b/drivers/media/dvb/frontends/dib8000.h
index d99619ae983c..b1ee20799639 100644
--- a/drivers/media/dvb/frontends/dib8000.h
+++ b/drivers/media/dvb/frontends/dib8000.h
@@ -100,7 +100,7 @@ static inline int dib8000_set_tune_state(struct dvb_frontend *fe, enum frontend_
static inline enum frontend_tune_state dib8000_get_tune_state(struct dvb_frontend *fe)
{
printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
- return CT_SHUTDOWN,
+ return CT_SHUTDOWN;
}
static inline void dib8000_pwm_agc_reset(struct dvb_frontend *fe)
{
diff --git a/drivers/media/dvb/frontends/lgdt3305.h b/drivers/media/dvb/frontends/lgdt3305.h
index 4fa6e52d1fe8..9cb11c9cae53 100644
--- a/drivers/media/dvb/frontends/lgdt3305.h
+++ b/drivers/media/dvb/frontends/lgdt3305.h
@@ -54,13 +54,13 @@ struct lgdt3305_config {
u16 usref_qam256; /* default: 0x2a80 */
/* disable i2c repeater - 0:repeater enabled 1:repeater disabled */
- int deny_i2c_rptr:1;
+ unsigned int deny_i2c_rptr:1;
/* spectral inversion - 0:disabled 1:enabled */
- int spectral_inversion:1;
+ unsigned int spectral_inversion:1;
/* use RF AGC loop - 0:disabled 1:enabled */
- int rf_agc_loop:1;
+ unsigned int rf_agc_loop:1;
enum lgdt3305_mpeg_mode mpeg_mode;
enum lgdt3305_tp_clock_edge tpclk_edge;
diff --git a/drivers/media/dvb/frontends/mb86a16.c b/drivers/media/dvb/frontends/mb86a16.c
new file mode 100644
index 000000000000..d05f7500e0c5
--- /dev/null
+++ b/drivers/media/dvb/frontends/mb86a16.c
@@ -0,0 +1,1878 @@
+/*
+ Fujitsu MB86A16 DVB-S/DSS DC Receiver driver
+
+ Copyright (C) Manu Abraham (abraham.manu@gmail.com)
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+
+#include "dvb_frontend.h"
+#include "mb86a16.h"
+#include "mb86a16_priv.h"
+
+unsigned int verbose = 5;
+module_param(verbose, int, 0644);
+
+#define ABS(x) ((x) < 0 ? (-x) : (x))
+
+struct mb86a16_state {
+ struct i2c_adapter *i2c_adap;
+ const struct mb86a16_config *config;
+ struct dvb_frontend frontend;
+
+ /* tuning parameters */
+ int frequency;
+ int srate;
+
+ /* Internal stuff */
+ int master_clk;
+ int deci;
+ int csel;
+ int rsel;
+};
+
+#define MB86A16_ERROR 0
+#define MB86A16_NOTICE 1
+#define MB86A16_INFO 2
+#define MB86A16_DEBUG 3
+
+#define dprintk(x, y, z, format, arg...) do { \
+ if (z) { \
+ if ((x > MB86A16_ERROR) && (x > y)) \
+ printk(KERN_ERR "%s: " format "\n", __func__, ##arg); \
+ else if ((x > MB86A16_NOTICE) && (x > y)) \
+ printk(KERN_NOTICE "%s: " format "\n", __func__, ##arg); \
+ else if ((x > MB86A16_INFO) && (x > y)) \
+ printk(KERN_INFO "%s: " format "\n", __func__, ##arg); \
+ else if ((x > MB86A16_DEBUG) && (x > y)) \
+ printk(KERN_DEBUG "%s: " format "\n", __func__, ##arg); \
+ } else { \
+ if (x > y) \
+ printk(format, ##arg); \
+ } \
+} while (0)
+
+#define TRACE_IN dprintk(verbose, MB86A16_DEBUG, 1, "-->()")
+#define TRACE_OUT dprintk(verbose, MB86A16_DEBUG, 1, "()-->")
+
+static int mb86a16_write(struct mb86a16_state *state, u8 reg, u8 val)
+{
+ int ret;
+ u8 buf[] = { reg, val };
+
+ struct i2c_msg msg = {
+ .addr = state->config->demod_address,
+ .flags = 0,
+ .buf = buf,
+ .len = 2
+ };
+
+ dprintk(verbose, MB86A16_DEBUG, 1,
+ "writing to [0x%02x],Reg[0x%02x],Data[0x%02x]",
+ state->config->demod_address, buf[0], buf[1]);
+
+ ret = i2c_transfer(state->i2c_adap, &msg, 1);
+
+ return (ret != 1) ? -EREMOTEIO : 0;
+}
+
+static int mb86a16_read(struct mb86a16_state *state, u8 reg, u8 *val)
+{
+ int ret;
+ u8 b0[] = { reg };
+ u8 b1[] = { 0 };
+
+ struct i2c_msg msg[] = {
+ {
+ .addr = state->config->demod_address,
+ .flags = 0,
+ .buf = b0,
+ .len = 1
+ }, {
+ .addr = state->config->demod_address,
+ .flags = I2C_M_RD,
+ .buf = b1,
+ .len = 1
+ }
+ };
+ ret = i2c_transfer(state->i2c_adap, msg, 2);
+ if (ret != 2) {
+ dprintk(verbose, MB86A16_ERROR, 1, "read error(reg=0x%02x, ret=0x%i)",
+ reg, ret);
+
+ return -EREMOTEIO;
+ }
+ *val = b1[0];
+
+ return ret;
+}
+
+static int CNTM_set(struct mb86a16_state *state,
+ unsigned char timint1,
+ unsigned char timint2,
+ unsigned char cnext)
+{
+ unsigned char val;
+
+ val = (timint1 << 4) | (timint2 << 2) | cnext;
+ if (mb86a16_write(state, MB86A16_CNTMR, val) < 0)
+ goto err;
+
+ return 0;
+
+err:
+ dprintk(verbose, MB86A16_ERROR, 1, "I2C transfer error");
+ return -EREMOTEIO;
+}
+
+static int smrt_set(struct mb86a16_state *state, int rate)
+{
+ int tmp ;
+ int m ;
+ unsigned char STOFS0, STOFS1;
+
+ m = 1 << state->deci;
+ tmp = (8192 * state->master_clk - 2 * m * rate * 8192 + state->master_clk / 2) / state->master_clk;
+
+ STOFS0 = tmp & 0x0ff;
+ STOFS1 = (tmp & 0xf00) >> 8;
+
+ if (mb86a16_write(state, MB86A16_SRATE1, (state->deci << 2) |
+ (state->csel << 1) |
+ state->rsel) < 0)
+ goto err;
+ if (mb86a16_write(state, MB86A16_SRATE2, STOFS0) < 0)
+ goto err;
+ if (mb86a16_write(state, MB86A16_SRATE3, STOFS1) < 0)
+ goto err;
+
+ return 0;
+err:
+ dprintk(verbose, MB86A16_ERROR, 1, "I2C transfer error");
+ return -1;
+}
+
+static int srst(struct mb86a16_state *state)
+{
+ if (mb86a16_write(state, MB86A16_RESET, 0x04) < 0)
+ goto err;
+
+ return 0;
+err:
+ dprintk(verbose, MB86A16_ERROR, 1, "I2C transfer error");
+ return -EREMOTEIO;
+
+}
+
+static int afcex_data_set(struct mb86a16_state *state,
+ unsigned char AFCEX_L,
+ unsigned char AFCEX_H)
+{
+ if (mb86a16_write(state, MB86A16_AFCEXL, AFCEX_L) < 0)
+ goto err;
+ if (mb86a16_write(state, MB86A16_AFCEXH, AFCEX_H) < 0)
+ goto err;
+
+ return 0;
+err:
+ dprintk(verbose, MB86A16_ERROR, 1, "I2C transfer error");
+
+ return -1;
+}
+
+static int afcofs_data_set(struct mb86a16_state *state,
+ unsigned char AFCEX_L,
+ unsigned char AFCEX_H)
+{
+ if (mb86a16_write(state, 0x58, AFCEX_L) < 0)
+ goto err;
+ if (mb86a16_write(state, 0x59, AFCEX_H) < 0)
+ goto err;
+
+ return 0;
+err:
+ dprintk(verbose, MB86A16_ERROR, 1, "I2C transfer error");
+ return -EREMOTEIO;
+}
+
+static int stlp_set(struct mb86a16_state *state,
+ unsigned char STRAS,
+ unsigned char STRBS)
+{
+ if (mb86a16_write(state, MB86A16_STRFILTCOEF1, (STRBS << 3) | (STRAS)) < 0)
+ goto err;
+
+ return 0;
+err:
+ dprintk(verbose, MB86A16_ERROR, 1, "I2C transfer error");
+ return -EREMOTEIO;
+}
+
+static int Vi_set(struct mb86a16_state *state, unsigned char ETH, unsigned char VIA)
+{
+ if (mb86a16_write(state, MB86A16_VISET2, 0x04) < 0)
+ goto err;
+ if (mb86a16_write(state, MB86A16_VISET3, 0xf5) < 0)
+ goto err;
+
+ return 0;
+err:
+ dprintk(verbose, MB86A16_ERROR, 1, "I2C transfer error");
+ return -EREMOTEIO;
+}
+
+static int initial_set(struct mb86a16_state *state)
+{
+ if (stlp_set(state, 5, 7))
+ goto err;
+
+ udelay(100);
+ if (afcex_data_set(state, 0, 0))
+ goto err;
+
+ udelay(100);
+ if (afcofs_data_set(state, 0, 0))
+ goto err;
+
+ udelay(100);
+ if (mb86a16_write(state, MB86A16_CRLFILTCOEF1, 0x16) < 0)
+ goto err;
+ if (mb86a16_write(state, 0x2f, 0x21) < 0)
+ goto err;
+ if (mb86a16_write(state, MB86A16_VIMAG, 0x38) < 0)
+ goto err;
+ if (mb86a16_write(state, MB86A16_FAGCS1, 0x00) < 0)
+ goto err;
+ if (mb86a16_write(state, MB86A16_FAGCS2, 0x1c) < 0)
+ goto err;
+ if (mb86a16_write(state, MB86A16_FAGCS3, 0x20) < 0)
+ goto err;
+ if (mb86a16_write(state, MB86A16_FAGCS4, 0x1e) < 0)
+ goto err;
+ if (mb86a16_write(state, MB86A16_FAGCS5, 0x23) < 0)
+ goto err;
+ if (mb86a16_write(state, 0x54, 0xff) < 0)
+ goto err;
+ if (mb86a16_write(state, MB86A16_TSOUT, 0x00) < 0)
+ goto err;
+
+ return 0;
+
+err:
+ dprintk(verbose, MB86A16_ERROR, 1, "I2C transfer error");
+ return -EREMOTEIO;
+}
+
+static int S01T_set(struct mb86a16_state *state,
+ unsigned char s1t,
+ unsigned s0t)
+{
+ if (mb86a16_write(state, 0x33, (s1t << 3) | s0t) < 0)
+ goto err;
+
+ return 0;
+err:
+ dprintk(verbose, MB86A16_ERROR, 1, "I2C transfer error");
+ return -EREMOTEIO;
+}
+
+
+static int EN_set(struct mb86a16_state *state,
+ int cren,
+ int afcen)
+{
+ unsigned char val;
+
+ val = 0x7a | (cren << 7) | (afcen << 2);
+ if (mb86a16_write(state, 0x49, val) < 0)
+ goto err;
+
+ return 0;
+err:
+ dprintk(verbose, MB86A16_ERROR, 1, "I2C transfer error");
+ return -EREMOTEIO;
+}
+
+static int AFCEXEN_set(struct mb86a16_state *state,
+ int afcexen,
+ int smrt)
+{
+ unsigned char AFCA ;
+
+ if (smrt > 18875)
+ AFCA = 4;
+ else if (smrt > 9375)
+ AFCA = 3;
+ else if (smrt > 2250)
+ AFCA = 2;
+ else
+ AFCA = 1;
+
+ if (mb86a16_write(state, 0x2a, 0x02 | (afcexen << 5) | (AFCA << 2)) < 0)
+ goto err;
+
+ return 0;
+
+err:
+ dprintk(verbose, MB86A16_ERROR, 1, "I2C transfer error");
+ return -EREMOTEIO;
+}
+
+static int DAGC_data_set(struct mb86a16_state *state,
+ unsigned char DAGCA,
+ unsigned char DAGCW)
+{
+ if (mb86a16_write(state, 0x2d, (DAGCA << 3) | DAGCW) < 0)
+ goto err;
+
+ return 0;
+
+err:
+ dprintk(verbose, MB86A16_ERROR, 1, "I2C transfer error");
+ return -EREMOTEIO;
+}
+
+static void smrt_info_get(struct mb86a16_state *state, int rate)
+{
+ if (rate >= 37501) {
+ state->deci = 0; state->csel = 0; state->rsel = 0;
+ } else if (rate >= 30001) {
+ state->deci = 0; state->csel = 0; state->rsel = 1;
+ } else if (rate >= 26251) {
+ state->deci = 0; state->csel = 1; state->rsel = 0;
+ } else if (rate >= 22501) {
+ state->deci = 0; state->csel = 1; state->rsel = 1;
+ } else if (rate >= 18751) {
+ state->deci = 1; state->csel = 0; state->rsel = 0;
+ } else if (rate >= 15001) {
+ state->deci = 1; state->csel = 0; state->rsel = 1;
+ } else if (rate >= 13126) {
+ state->deci = 1; state->csel = 1; state->rsel = 0;
+ } else if (rate >= 11251) {
+ state->deci = 1; state->csel = 1; state->rsel = 1;
+ } else if (rate >= 9376) {
+ state->deci = 2; state->csel = 0; state->rsel = 0;
+ } else if (rate >= 7501) {
+ state->deci = 2; state->csel = 0; state->rsel = 1;
+ } else if (rate >= 6563) {
+ state->deci = 2; state->csel = 1; state->rsel = 0;
+ } else if (rate >= 5626) {
+ state->deci = 2; state->csel = 1; state->rsel = 1;
+ } else if (rate >= 4688) {
+ state->deci = 3; state->csel = 0; state->rsel = 0;
+ } else if (rate >= 3751) {
+ state->deci = 3; state->csel = 0; state->rsel = 1;
+ } else if (rate >= 3282) {
+ state->deci = 3; state->csel = 1; state->rsel = 0;
+ } else if (rate >= 2814) {
+ state->deci = 3; state->csel = 1; state->rsel = 1;
+ } else if (rate >= 2344) {
+ state->deci = 4; state->csel = 0; state->rsel = 0;
+ } else if (rate >= 1876) {
+ state->deci = 4; state->csel = 0; state->rsel = 1;
+ } else if (rate >= 1641) {
+ state->deci = 4; state->csel = 1; state->rsel = 0;
+ } else if (rate >= 1407) {
+ state->deci = 4; state->csel = 1; state->rsel = 1;
+ } else if (rate >= 1172) {
+ state->deci = 5; state->csel = 0; state->rsel = 0;
+ } else if (rate >= 939) {
+ state->deci = 5; state->csel = 0; state->rsel = 1;
+ } else if (rate >= 821) {
+ state->deci = 5; state->csel = 1; state->rsel = 0;
+ } else {
+ state->deci = 5; state->csel = 1; state->rsel = 1;
+ }
+
+ if (state->csel == 0)
+ state->master_clk = 92000;
+ else
+ state->master_clk = 61333;
+
+}
+
+static int signal_det(struct mb86a16_state *state,
+ int smrt,
+ unsigned char *SIG)
+{
+
+ int ret ;
+ int smrtd ;
+ int wait_sym ;
+
+ u32 wait_t;
+ unsigned char S[3] ;
+ int i ;
+
+ if (*SIG > 45) {
+ if (CNTM_set(state, 2, 1, 2) < 0) {
+ dprintk(verbose, MB86A16_ERROR, 1, "CNTM set Error");
+ return -1;
+ }
+ wait_sym = 40000;
+ } else {
+ if (CNTM_set(state, 3, 1, 2) < 0) {
+ dprintk(verbose, MB86A16_ERROR, 1, "CNTM set Error");
+ return -1;
+ }
+ wait_sym = 80000;
+ }
+ for (i = 0; i < 3; i++) {
+ if (i == 0)
+ smrtd = smrt * 98 / 100;
+ else if (i == 1)
+ smrtd = smrt;
+ else
+ smrtd = smrt * 102 / 100;
+ smrt_info_get(state, smrtd);
+ smrt_set(state, smrtd);
+ srst(state);
+ wait_t = (wait_sym + 99 * smrtd / 100) / smrtd;
+ if (wait_t == 0)
+ wait_t = 1;
+ msleep_interruptible(10);
+ if (mb86a16_read(state, 0x37, &(S[i])) != 2) {
+ dprintk(verbose, MB86A16_ERROR, 1, "I2C transfer error");
+ return -EREMOTEIO;
+ }
+ }
+ if ((S[1] > S[0] * 112 / 100) &&
+ (S[1] > S[2] * 112 / 100)) {
+
+ ret = 1;
+ } else {
+ ret = 0;
+ }
+ *SIG = S[1];
+
+ if (CNTM_set(state, 0, 1, 2) < 0) {
+ dprintk(verbose, MB86A16_ERROR, 1, "CNTM set Error");
+ return -1;
+ }
+
+ return ret;
+}
+
+static int rf_val_set(struct mb86a16_state *state,
+ int f,
+ int smrt,
+ unsigned char R)
+{
+ unsigned char C, F, B;
+ int M;
+ unsigned char rf_val[5];
+ int ack = -1;
+
+ if (smrt > 37750)
+ C = 1;
+ else if (smrt > 18875)
+ C = 2;
+ else if (smrt > 5500)
+ C = 3;
+ else
+ C = 4;
+
+ if (smrt > 30500)
+ F = 3;
+ else if (smrt > 9375)
+ F = 1;
+ else if (smrt > 4625)
+ F = 0;
+ else
+ F = 2;
+
+ if (f < 1060)
+ B = 0;
+ else if (f < 1175)
+ B = 1;
+ else if (f < 1305)
+ B = 2;
+ else if (f < 1435)
+ B = 3;
+ else if (f < 1570)
+ B = 4;
+ else if (f < 1715)
+ B = 5;
+ else if (f < 1845)
+ B = 6;
+ else if (f < 1980)
+ B = 7;
+ else if (f < 2080)
+ B = 8;
+ else
+ B = 9;
+
+ M = f * (1 << R) / 2;
+
+ rf_val[0] = 0x01 | (C << 3) | (F << 1);
+ rf_val[1] = (R << 5) | ((M & 0x1f000) >> 12);
+ rf_val[2] = (M & 0x00ff0) >> 4;
+ rf_val[3] = ((M & 0x0000f) << 4) | B;
+
+ /* Frequency Set */
+ if (mb86a16_write(state, 0x21, rf_val[0]) < 0)
+ ack = 0;
+ if (mb86a16_write(state, 0x22, rf_val[1]) < 0)
+ ack = 0;
+ if (mb86a16_write(state, 0x23, rf_val[2]) < 0)
+ ack = 0;
+ if (mb86a16_write(state, 0x24, rf_val[3]) < 0)
+ ack = 0;
+ if (mb86a16_write(state, 0x25, 0x01) < 0)
+ ack = 0;
+ if (ack == 0) {
+ dprintk(verbose, MB86A16_ERROR, 1, "RF Setup - I2C transfer error");
+ return -EREMOTEIO;
+ }
+
+ return 0;
+}
+
+static int afcerr_chk(struct mb86a16_state *state)
+{
+ unsigned char AFCM_L, AFCM_H ;
+ int AFCM ;
+ int afcm, afcerr ;
+
+ if (mb86a16_read(state, 0x0e, &AFCM_L) != 2)
+ goto err;
+ if (mb86a16_read(state, 0x0f, &AFCM_H) != 2)
+ goto err;
+
+ AFCM = (AFCM_H << 8) + AFCM_L;
+
+ if (AFCM > 2048)
+ afcm = AFCM - 4096;
+ else
+ afcm = AFCM;
+ afcerr = afcm * state->master_clk / 8192;
+
+ return afcerr;
+
+err:
+ dprintk(verbose, MB86A16_ERROR, 1, "I2C transfer error");
+ return -EREMOTEIO;
+}
+
+static int dagcm_val_get(struct mb86a16_state *state)
+{
+ int DAGCM;
+ unsigned char DAGCM_H, DAGCM_L;
+
+ if (mb86a16_read(state, 0x45, &DAGCM_L) != 2)
+ goto err;
+ if (mb86a16_read(state, 0x46, &DAGCM_H) != 2)
+ goto err;
+
+ DAGCM = (DAGCM_H << 8) + DAGCM_L;
+
+ return DAGCM;
+
+err:
+ dprintk(verbose, MB86A16_ERROR, 1, "I2C transfer error");
+ return -EREMOTEIO;
+}
+
+static int mb86a16_read_status(struct dvb_frontend *fe, fe_status_t *status)
+{
+ u8 stat, stat2;
+ struct mb86a16_state *state = fe->demodulator_priv;
+
+ *status = 0;
+
+ if (mb86a16_read(state, MB86A16_SIG1, &stat) != 2)
+ goto err;
+ if (mb86a16_read(state, MB86A16_SIG2, &stat2) != 2)
+ goto err;
+ if ((stat > 25) && (stat2 > 25))
+ *status |= FE_HAS_SIGNAL;
+ if ((stat > 45) && (stat2 > 45))
+ *status |= FE_HAS_CARRIER;
+
+ if (mb86a16_read(state, MB86A16_STATUS, &stat) != 2)
+ goto err;
+
+ if (stat & 0x01)
+ *status |= FE_HAS_SYNC;
+ if (stat & 0x01)
+ *status |= FE_HAS_VITERBI;
+
+ if (mb86a16_read(state, MB86A16_FRAMESYNC, &stat) != 2)
+ goto err;
+
+ if ((stat & 0x0f) && (*status & FE_HAS_VITERBI))
+ *status |= FE_HAS_LOCK;
+
+ return 0;
+
+err:
+ dprintk(verbose, MB86A16_ERROR, 1, "I2C transfer error");
+ return -EREMOTEIO;
+}
+
+static int sync_chk(struct mb86a16_state *state,
+ unsigned char *VIRM)
+{
+ unsigned char val;
+ int sync;
+
+ if (mb86a16_read(state, 0x0d, &val) != 2)
+ goto err;
+
+ dprintk(verbose, MB86A16_INFO, 1, "Status = %02x,", val);
+ sync = val & 0x01;
+ *VIRM = (val & 0x1c) >> 2;
+
+ return sync;
+err:
+ dprintk(verbose, MB86A16_ERROR, 1, "I2C transfer error");
+ return -EREMOTEIO;
+
+}
+
+static int freqerr_chk(struct mb86a16_state *state,
+ int fTP,
+ int smrt,
+ int unit)
+{
+ unsigned char CRM, AFCML, AFCMH;
+ unsigned char temp1, temp2, temp3;
+ int crm, afcm, AFCM;
+ int crrerr, afcerr; /* kHz */
+ int frqerr; /* MHz */
+ int afcen, afcexen = 0;
+ int R, M, fOSC, fOSC_OFS;
+
+ if (mb86a16_read(state, 0x43, &CRM) != 2)
+ goto err;
+
+ if (CRM > 127)
+ crm = CRM - 256;
+ else
+ crm = CRM;
+
+ crrerr = smrt * crm / 256;
+ if (mb86a16_read(state, 0x49, &temp1) != 2)
+ goto err;
+
+ afcen = (temp1 & 0x04) >> 2;
+ if (afcen == 0) {
+ if (mb86a16_read(state, 0x2a, &temp1) != 2)
+ goto err;
+ afcexen = (temp1 & 0x20) >> 5;
+ }
+
+ if (afcen == 1) {
+ if (mb86a16_read(state, 0x0e, &AFCML) != 2)
+ goto err;
+ if (mb86a16_read(state, 0x0f, &AFCMH) != 2)
+ goto err;
+ } else if (afcexen == 1) {
+ if (mb86a16_read(state, 0x2b, &AFCML) != 2)
+ goto err;
+ if (mb86a16_read(state, 0x2c, &AFCMH) != 2)
+ goto err;
+ }
+ if ((afcen == 1) || (afcexen == 1)) {
+ smrt_info_get(state, smrt);
+ AFCM = ((AFCMH & 0x01) << 8) + AFCML;
+ if (AFCM > 255)
+ afcm = AFCM - 512;
+ else
+ afcm = AFCM;
+
+ afcerr = afcm * state->master_clk / 8192;
+ } else
+ afcerr = 0;
+
+ if (mb86a16_read(state, 0x22, &temp1) != 2)
+ goto err;
+ if (mb86a16_read(state, 0x23, &temp2) != 2)
+ goto err;
+ if (mb86a16_read(state, 0x24, &temp3) != 2)
+ goto err;
+
+ R = (temp1 & 0xe0) >> 5;
+ M = ((temp1 & 0x1f) << 12) + (temp2 << 4) + (temp3 >> 4);
+ if (R == 0)
+ fOSC = 2 * M;
+ else
+ fOSC = M;
+
+ fOSC_OFS = fOSC - fTP;
+
+ if (unit == 0) { /* MHz */
+ if (crrerr + afcerr + fOSC_OFS * 1000 >= 0)
+ frqerr = (crrerr + afcerr + fOSC_OFS * 1000 + 500) / 1000;
+ else
+ frqerr = (crrerr + afcerr + fOSC_OFS * 1000 - 500) / 1000;
+ } else { /* kHz */
+ frqerr = crrerr + afcerr + fOSC_OFS * 1000;
+ }
+
+ return frqerr;
+err:
+ dprintk(verbose, MB86A16_ERROR, 1, "I2C transfer error");
+ return -EREMOTEIO;
+}
+
+static unsigned char vco_dev_get(struct mb86a16_state *state, int smrt)
+{
+ unsigned char R;
+
+ if (smrt > 9375)
+ R = 0;
+ else
+ R = 1;
+
+ return R;
+}
+
+static void swp_info_get(struct mb86a16_state *state,
+ int fOSC_start,
+ int smrt,
+ int v, int R,
+ int swp_ofs,
+ int *fOSC,
+ int *afcex_freq,
+ unsigned char *AFCEX_L,
+ unsigned char *AFCEX_H)
+{
+ int AFCEX ;
+ int crnt_swp_freq ;
+
+ crnt_swp_freq = fOSC_start * 1000 + v * swp_ofs;
+
+ if (R == 0)
+ *fOSC = (crnt_swp_freq + 1000) / 2000 * 2;
+ else
+ *fOSC = (crnt_swp_freq + 500) / 1000;
+
+ if (*fOSC >= crnt_swp_freq)
+ *afcex_freq = *fOSC * 1000 - crnt_swp_freq;
+ else
+ *afcex_freq = crnt_swp_freq - *fOSC * 1000;
+
+ AFCEX = *afcex_freq * 8192 / state->master_clk;
+ *AFCEX_L = AFCEX & 0x00ff;
+ *AFCEX_H = (AFCEX & 0x0f00) >> 8;
+}
+
+
+static int swp_freq_calcuation(struct mb86a16_state *state, int i, int v, int *V, int vmax, int vmin,
+ int SIGMIN, int fOSC, int afcex_freq, int swp_ofs, unsigned char *SIG1)
+{
+ int swp_freq ;
+
+ if ((i % 2 == 1) && (v <= vmax)) {
+ /* positive v (case 1) */
+ if ((v - 1 == vmin) &&
+ (*(V + 30 + v) >= 0) &&
+ (*(V + 30 + v - 1) >= 0) &&
+ (*(V + 30 + v - 1) > *(V + 30 + v)) &&
+ (*(V + 30 + v - 1) > SIGMIN)) {
+
+ swp_freq = fOSC * 1000 + afcex_freq - swp_ofs;
+ *SIG1 = *(V + 30 + v - 1);
+ } else if ((v == vmax) &&
+ (*(V + 30 + v) >= 0) &&
+ (*(V + 30 + v - 1) >= 0) &&
+ (*(V + 30 + v) > *(V + 30 + v - 1)) &&
+ (*(V + 30 + v) > SIGMIN)) {
+ /* (case 2) */
+ swp_freq = fOSC * 1000 + afcex_freq;
+ *SIG1 = *(V + 30 + v);
+ } else if ((*(V + 30 + v) > 0) &&
+ (*(V + 30 + v - 1) > 0) &&
+ (*(V + 30 + v - 2) > 0) &&
+ (*(V + 30 + v - 3) > 0) &&
+ (*(V + 30 + v - 1) > *(V + 30 + v)) &&
+ (*(V + 30 + v - 2) > *(V + 30 + v - 3)) &&
+ ((*(V + 30 + v - 1) > SIGMIN) ||
+ (*(V + 30 + v - 2) > SIGMIN))) {
+ /* (case 3) */
+ if (*(V + 30 + v - 1) >= *(V + 30 + v - 2)) {
+ swp_freq = fOSC * 1000 + afcex_freq - swp_ofs;
+ *SIG1 = *(V + 30 + v - 1);
+ } else {
+ swp_freq = fOSC * 1000 + afcex_freq - swp_ofs * 2;
+ *SIG1 = *(V + 30 + v - 2);
+ }
+ } else if ((v == vmax) &&
+ (*(V + 30 + v) >= 0) &&
+ (*(V + 30 + v - 1) >= 0) &&
+ (*(V + 30 + v - 2) >= 0) &&
+ (*(V + 30 + v) > *(V + 30 + v - 2)) &&
+ (*(V + 30 + v - 1) > *(V + 30 + v - 2)) &&
+ ((*(V + 30 + v) > SIGMIN) ||
+ (*(V + 30 + v - 1) > SIGMIN))) {
+ /* (case 4) */
+ if (*(V + 30 + v) >= *(V + 30 + v - 1)) {
+ swp_freq = fOSC * 1000 + afcex_freq;
+ *SIG1 = *(V + 30 + v);
+ } else {
+ swp_freq = fOSC * 1000 + afcex_freq - swp_ofs;
+ *SIG1 = *(V + 30 + v - 1);
+ }
+ } else {
+ swp_freq = -1 ;
+ }
+ } else if ((i % 2 == 0) && (v >= vmin)) {
+ /* Negative v (case 1) */
+ if ((*(V + 30 + v) > 0) &&
+ (*(V + 30 + v + 1) > 0) &&
+ (*(V + 30 + v + 2) > 0) &&
+ (*(V + 30 + v + 1) > *(V + 30 + v)) &&
+ (*(V + 30 + v + 1) > *(V + 30 + v + 2)) &&
+ (*(V + 30 + v + 1) > SIGMIN)) {
+
+ swp_freq = fOSC * 1000 + afcex_freq + swp_ofs;
+ *SIG1 = *(V + 30 + v + 1);
+ } else if ((v + 1 == vmax) &&
+ (*(V + 30 + v) >= 0) &&
+ (*(V + 30 + v + 1) >= 0) &&
+ (*(V + 30 + v + 1) > *(V + 30 + v)) &&
+ (*(V + 30 + v + 1) > SIGMIN)) {
+ /* (case 2) */
+ swp_freq = fOSC * 1000 + afcex_freq + swp_ofs;
+ *SIG1 = *(V + 30 + v);
+ } else if ((v == vmin) &&
+ (*(V + 30 + v) > 0) &&
+ (*(V + 30 + v + 1) > 0) &&
+ (*(V + 30 + v + 2) > 0) &&
+ (*(V + 30 + v) > *(V + 30 + v + 1)) &&
+ (*(V + 30 + v) > *(V + 30 + v + 2)) &&
+ (*(V + 30 + v) > SIGMIN)) {
+ /* (case 3) */
+ swp_freq = fOSC * 1000 + afcex_freq;
+ *SIG1 = *(V + 30 + v);
+ } else if ((*(V + 30 + v) >= 0) &&
+ (*(V + 30 + v + 1) >= 0) &&
+ (*(V + 30 + v + 2) >= 0) &&
+ (*(V + 30 + v + 3) >= 0) &&
+ (*(V + 30 + v + 1) > *(V + 30 + v)) &&
+ (*(V + 30 + v + 2) > *(V + 30 + v + 3)) &&
+ ((*(V + 30 + v + 1) > SIGMIN) ||
+ (*(V + 30 + v + 2) > SIGMIN))) {
+ /* (case 4) */
+ if (*(V + 30 + v + 1) >= *(V + 30 + v + 2)) {
+ swp_freq = fOSC * 1000 + afcex_freq + swp_ofs;
+ *SIG1 = *(V + 30 + v + 1);
+ } else {
+ swp_freq = fOSC * 1000 + afcex_freq + swp_ofs * 2;
+ *SIG1 = *(V + 30 + v + 2);
+ }
+ } else if ((*(V + 30 + v) >= 0) &&
+ (*(V + 30 + v + 1) >= 0) &&
+ (*(V + 30 + v + 2) >= 0) &&
+ (*(V + 30 + v + 3) >= 0) &&
+ (*(V + 30 + v) > *(V + 30 + v + 2)) &&
+ (*(V + 30 + v + 1) > *(V + 30 + v + 2)) &&
+ (*(V + 30 + v) > *(V + 30 + v + 3)) &&
+ (*(V + 30 + v + 1) > *(V + 30 + v + 3)) &&
+ ((*(V + 30 + v) > SIGMIN) ||
+ (*(V + 30 + v + 1) > SIGMIN))) {
+ /* (case 5) */
+ if (*(V + 30 + v) >= *(V + 30 + v + 1)) {
+ swp_freq = fOSC * 1000 + afcex_freq;
+ *SIG1 = *(V + 30 + v);
+ } else {
+ swp_freq = fOSC * 1000 + afcex_freq + swp_ofs;
+ *SIG1 = *(V + 30 + v + 1);
+ }
+ } else if ((v + 2 == vmin) &&
+ (*(V + 30 + v) >= 0) &&
+ (*(V + 30 + v + 1) >= 0) &&
+ (*(V + 30 + v + 2) >= 0) &&
+ (*(V + 30 + v + 1) > *(V + 30 + v)) &&
+ (*(V + 30 + v + 2) > *(V + 30 + v)) &&
+ ((*(V + 30 + v + 1) > SIGMIN) ||
+ (*(V + 30 + v + 2) > SIGMIN))) {
+ /* (case 6) */
+ if (*(V + 30 + v + 1) >= *(V + 30 + v + 2)) {
+ swp_freq = fOSC * 1000 + afcex_freq + swp_ofs;
+ *SIG1 = *(V + 30 + v + 1);
+ } else {
+ swp_freq = fOSC * 1000 + afcex_freq + swp_ofs * 2;
+ *SIG1 = *(V + 30 + v + 2);
+ }
+ } else if ((vmax == 0) && (vmin == 0) && (*(V + 30 + v) > SIGMIN)) {
+ swp_freq = fOSC * 1000;
+ *SIG1 = *(V + 30 + v);
+ } else
+ swp_freq = -1;
+ } else
+ swp_freq = -1;
+
+ return swp_freq;
+}
+
+static void swp_info_get2(struct mb86a16_state *state,
+ int smrt,
+ int R,
+ int swp_freq,
+ int *afcex_freq,
+ int *fOSC,
+ unsigned char *AFCEX_L,
+ unsigned char *AFCEX_H)
+{
+ int AFCEX ;
+
+ if (R == 0)
+ *fOSC = (swp_freq + 1000) / 2000 * 2;
+ else
+ *fOSC = (swp_freq + 500) / 1000;
+
+ if (*fOSC >= swp_freq)
+ *afcex_freq = *fOSC * 1000 - swp_freq;
+ else
+ *afcex_freq = swp_freq - *fOSC * 1000;
+
+ AFCEX = *afcex_freq * 8192 / state->master_clk;
+ *AFCEX_L = AFCEX & 0x00ff;
+ *AFCEX_H = (AFCEX & 0x0f00) >> 8;
+}
+
+static void afcex_info_get(struct mb86a16_state *state,
+ int afcex_freq,
+ unsigned char *AFCEX_L,
+ unsigned char *AFCEX_H)
+{
+ int AFCEX ;
+
+ AFCEX = afcex_freq * 8192 / state->master_clk;
+ *AFCEX_L = AFCEX & 0x00ff;
+ *AFCEX_H = (AFCEX & 0x0f00) >> 8;
+}
+
+static int SEQ_set(struct mb86a16_state *state, unsigned char loop)
+{
+ /* SLOCK0 = 0 */
+ if (mb86a16_write(state, 0x32, 0x02 | (loop << 2)) < 0) {
+ dprintk(verbose, MB86A16_ERROR, 1, "I2C transfer error");
+ return -EREMOTEIO;
+ }
+
+ return 0;
+}
+
+static int iq_vt_set(struct mb86a16_state *state, unsigned char IQINV)
+{
+ /* Viterbi Rate, IQ Settings */
+ if (mb86a16_write(state, 0x06, 0xdf | (IQINV << 5)) < 0) {
+ dprintk(verbose, MB86A16_ERROR, 1, "I2C transfer error");
+ return -EREMOTEIO;
+ }
+
+ return 0;
+}
+
+static int FEC_srst(struct mb86a16_state *state)
+{
+ if (mb86a16_write(state, MB86A16_RESET, 0x02) < 0) {
+ dprintk(verbose, MB86A16_ERROR, 1, "I2C transfer error");
+ return -EREMOTEIO;
+ }
+
+ return 0;
+}
+
+static int S2T_set(struct mb86a16_state *state, unsigned char S2T)
+{
+ if (mb86a16_write(state, 0x34, 0x70 | S2T) < 0) {
+ dprintk(verbose, MB86A16_ERROR, 1, "I2C transfer error");
+ return -EREMOTEIO;
+ }
+
+ return 0;
+}
+
+static int S45T_set(struct mb86a16_state *state, unsigned char S4T, unsigned char S5T)
+{
+ if (mb86a16_write(state, 0x35, 0x00 | (S5T << 4) | S4T) < 0) {
+ dprintk(verbose, MB86A16_ERROR, 1, "I2C transfer error");
+ return -EREMOTEIO;
+ }
+
+ return 0;
+}
+
+
+static int mb86a16_set_fe(struct mb86a16_state *state)
+{
+ u8 agcval, cnmval;
+
+ int i, j;
+ int fOSC = 0;
+ int fOSC_start = 0;
+ int wait_t;
+ int fcp;
+ int swp_ofs;
+ int V[60];
+ u8 SIG1MIN;
+
+ unsigned char CREN, AFCEN, AFCEXEN;
+ unsigned char SIG1;
+ unsigned char TIMINT1, TIMINT2, TIMEXT;
+ unsigned char S0T, S1T;
+ unsigned char S2T;
+/* unsigned char S2T, S3T; */
+ unsigned char S4T, S5T;
+ unsigned char AFCEX_L, AFCEX_H;
+ unsigned char R;
+ unsigned char VIRM;
+ unsigned char ETH, VIA;
+ unsigned char junk;
+
+ int loop;
+ int ftemp;
+ int v, vmax, vmin;
+ int vmax_his, vmin_his;
+ int swp_freq, prev_swp_freq[20];
+ int prev_freq_num;
+ int signal_dupl;
+ int afcex_freq;
+ int signal;
+ int afcerr;
+ int temp_freq, delta_freq;
+ int dagcm[4];
+ int smrt_d;
+/* int freq_err; */
+ int n;
+ int ret = -1;
+ int sync;
+
+ dprintk(verbose, MB86A16_INFO, 1, "freq=%d Mhz, symbrt=%d Ksps", state->frequency, state->srate);
+
+ fcp = 3000;
+ swp_ofs = state->srate / 4;
+
+ for (i = 0; i < 60; i++)
+ V[i] = -1;
+
+ for (i = 0; i < 20; i++)
+ prev_swp_freq[i] = 0;
+
+ SIG1MIN = 25;
+
+ for (n = 0; ((n < 3) && (ret == -1)); n++) {
+ SEQ_set(state, 0);
+ iq_vt_set(state, 0);
+
+ CREN = 0;
+ AFCEN = 0;
+ AFCEXEN = 1;
+ TIMINT1 = 0;
+ TIMINT2 = 1;
+ TIMEXT = 2;
+ S1T = 0;
+ S0T = 0;
+
+ if (initial_set(state) < 0) {
+ dprintk(verbose, MB86A16_ERROR, 1, "initial set failed");
+ return -1;
+ }
+ if (DAGC_data_set(state, 3, 2) < 0) {
+ dprintk(verbose, MB86A16_ERROR, 1, "DAGC data set error");
+ return -1;
+ }
+ if (EN_set(state, CREN, AFCEN) < 0) {
+ dprintk(verbose, MB86A16_ERROR, 1, "EN set error");
+ return -1; /* (0, 0) */
+ }
+ if (AFCEXEN_set(state, AFCEXEN, state->srate) < 0) {
+ dprintk(verbose, MB86A16_ERROR, 1, "AFCEXEN set error");
+ return -1; /* (1, smrt) = (1, symbolrate) */
+ }
+ if (CNTM_set(state, TIMINT1, TIMINT2, TIMEXT) < 0) {
+ dprintk(verbose, MB86A16_ERROR, 1, "CNTM set error");
+ return -1; /* (0, 1, 2) */
+ }
+ if (S01T_set(state, S1T, S0T) < 0) {
+ dprintk(verbose, MB86A16_ERROR, 1, "S01T set error");
+ return -1; /* (0, 0) */
+ }
+ smrt_info_get(state, state->srate);
+ if (smrt_set(state, state->srate) < 0) {
+ dprintk(verbose, MB86A16_ERROR, 1, "smrt info get error");
+ return -1;
+ }
+
+ R = vco_dev_get(state, state->srate);
+ if (R == 1)
+ fOSC_start = state->frequency;
+
+ else if (R == 0) {
+ if (state->frequency % 2 == 0) {
+ fOSC_start = state->frequency;
+ } else {
+ fOSC_start = state->frequency + 1;
+ if (fOSC_start > 2150)
+ fOSC_start = state->frequency - 1;
+ }
+ }
+ loop = 1;
+ ftemp = fOSC_start * 1000;
+ vmax = 0 ;
+ while (loop == 1) {
+ ftemp = ftemp + swp_ofs;
+ vmax++;
+
+ /* Upper bound */
+ if (ftemp > 2150000) {
+ loop = 0;
+ vmax--;
+ } else {
+ if ((ftemp == 2150000) ||
+ (ftemp - state->frequency * 1000 >= fcp + state->srate / 4))
+ loop = 0;
+ }
+ }
+
+ loop = 1;
+ ftemp = fOSC_start * 1000;
+ vmin = 0 ;
+ while (loop == 1) {
+ ftemp = ftemp - swp_ofs;
+ vmin--;
+
+ /* Lower bound */
+ if (ftemp < 950000) {
+ loop = 0;
+ vmin++;
+ } else {
+ if ((ftemp == 950000) ||
+ (state->frequency * 1000 - ftemp >= fcp + state->srate / 4))
+ loop = 0;
+ }
+ }
+
+ wait_t = (8000 + state->srate / 2) / state->srate;
+ if (wait_t == 0)
+ wait_t = 1;
+
+ i = 0;
+ j = 0;
+ prev_freq_num = 0;
+ loop = 1;
+ signal = 0;
+ vmax_his = 0;
+ vmin_his = 0;
+ v = 0;
+
+ while (loop == 1) {
+ swp_info_get(state, fOSC_start, state->srate,
+ v, R, swp_ofs, &fOSC,
+ &afcex_freq, &AFCEX_L, &AFCEX_H);
+
+ udelay(100);
+ if (rf_val_set(state, fOSC, state->srate, R) < 0) {
+ dprintk(verbose, MB86A16_ERROR, 1, "rf val set error");
+ return -1;
+ }
+ udelay(100);
+ if (afcex_data_set(state, AFCEX_L, AFCEX_H) < 0) {
+ dprintk(verbose, MB86A16_ERROR, 1, "afcex data set error");
+ return -1;
+ }
+ if (srst(state) < 0) {
+ dprintk(verbose, MB86A16_ERROR, 1, "srst error");
+ return -1;
+ }
+ msleep_interruptible(wait_t);
+
+ if (mb86a16_read(state, 0x37, &SIG1) != 2) {
+ dprintk(verbose, MB86A16_ERROR, 1, "I2C transfer error");
+ return -1;
+ }
+ V[30 + v] = SIG1 ;
+ swp_freq = swp_freq_calcuation(state, i, v, V, vmax, vmin,
+ SIG1MIN, fOSC, afcex_freq,
+ swp_ofs, &SIG1); /* changed */
+
+ signal_dupl = 0;
+ for (j = 0; j < prev_freq_num; j++) {
+ if ((ABS(prev_swp_freq[j] - swp_freq)) < (swp_ofs * 3 / 2)) {
+ signal_dupl = 1;
+ dprintk(verbose, MB86A16_INFO, 1, "Probably Duplicate Signal, j = %d", j);
+ }
+ }
+ if ((signal_dupl == 0) && (swp_freq > 0) && (ABS(swp_freq - state->frequency * 1000) < fcp + state->srate / 6)) {
+ dprintk(verbose, MB86A16_DEBUG, 1, "------ Signal detect ------ [swp_freq=[%07d, srate=%05d]]", swp_freq, state->srate);
+ prev_swp_freq[prev_freq_num] = swp_freq;
+ prev_freq_num++;
+ swp_info_get2(state, state->srate, R, swp_freq,
+ &afcex_freq, &fOSC,
+ &AFCEX_L, &AFCEX_H);
+
+ if (rf_val_set(state, fOSC, state->srate, R) < 0) {
+ dprintk(verbose, MB86A16_ERROR, 1, "rf val set error");
+ return -1;
+ }
+ if (afcex_data_set(state, AFCEX_L, AFCEX_H) < 0) {
+ dprintk(verbose, MB86A16_ERROR, 1, "afcex data set error");
+ return -1;
+ }
+ signal = signal_det(state, state->srate, &SIG1);
+ if (signal == 1) {
+ dprintk(verbose, MB86A16_ERROR, 1, "***** Signal Found *****");
+ loop = 0;
+ } else {
+ dprintk(verbose, MB86A16_ERROR, 1, "!!!!! No signal !!!!!, try again...");
+ smrt_info_get(state, state->srate);
+ if (smrt_set(state, state->srate) < 0) {
+ dprintk(verbose, MB86A16_ERROR, 1, "smrt set error");
+ return -1;
+ }
+ }
+ }
+ if (v > vmax)
+ vmax_his = 1 ;
+ if (v < vmin)
+ vmin_his = 1 ;
+ i++;
+
+ if ((i % 2 == 1) && (vmax_his == 1))
+ i++;
+ if ((i % 2 == 0) && (vmin_his == 1))
+ i++;
+
+ if (i % 2 == 1)
+ v = (i + 1) / 2;
+ else
+ v = -i / 2;
+
+ if ((vmax_his == 1) && (vmin_his == 1))
+ loop = 0 ;
+ }
+
+ if (signal == 1) {
+ dprintk(verbose, MB86A16_INFO, 1, " Start Freq Error Check");
+ S1T = 7 ;
+ S0T = 1 ;
+ CREN = 0 ;
+ AFCEN = 1 ;
+ AFCEXEN = 0 ;
+
+ if (S01T_set(state, S1T, S0T) < 0) {
+ dprintk(verbose, MB86A16_ERROR, 1, "S01T set error");
+ return -1;
+ }
+ smrt_info_get(state, state->srate);
+ if (smrt_set(state, state->srate) < 0) {
+ dprintk(verbose, MB86A16_ERROR, 1, "smrt set error");
+ return -1;
+ }
+ if (EN_set(state, CREN, AFCEN) < 0) {
+ dprintk(verbose, MB86A16_ERROR, 1, "EN set error");
+ return -1;
+ }
+ if (AFCEXEN_set(state, AFCEXEN, state->srate) < 0) {
+ dprintk(verbose, MB86A16_ERROR, 1, "AFCEXEN set error");
+ return -1;
+ }
+ afcex_info_get(state, afcex_freq, &AFCEX_L, &AFCEX_H);
+ if (afcofs_data_set(state, AFCEX_L, AFCEX_H) < 0) {
+ dprintk(verbose, MB86A16_ERROR, 1, "AFCOFS data set error");
+ return -1;
+ }
+ if (srst(state) < 0) {
+ dprintk(verbose, MB86A16_ERROR, 1, "srst error");
+ return -1;
+ }
+ /* delay 4~200 */
+ wait_t = 200000 / state->master_clk + 200000 / state->srate;
+ msleep(wait_t);
+ afcerr = afcerr_chk(state);
+ if (afcerr == -1)
+ return -1;
+
+ swp_freq = fOSC * 1000 + afcerr ;
+ AFCEXEN = 1 ;
+ if (state->srate >= 1500)
+ smrt_d = state->srate / 3;
+ else
+ smrt_d = state->srate / 2;
+ smrt_info_get(state, smrt_d);
+ if (smrt_set(state, smrt_d) < 0) {
+ dprintk(verbose, MB86A16_ERROR, 1, "smrt set error");
+ return -1;
+ }
+ if (AFCEXEN_set(state, AFCEXEN, smrt_d) < 0) {
+ dprintk(verbose, MB86A16_ERROR, 1, "AFCEXEN set error");
+ return -1;
+ }
+ R = vco_dev_get(state, smrt_d);
+ if (DAGC_data_set(state, 2, 0) < 0) {
+ dprintk(verbose, MB86A16_ERROR, 1, "DAGC data set error");
+ return -1;
+ }
+ for (i = 0; i < 3; i++) {
+ temp_freq = swp_freq + (i - 1) * state->srate / 8;
+ swp_info_get2(state, smrt_d, R, temp_freq, &afcex_freq, &fOSC, &AFCEX_L, &AFCEX_H);
+ if (rf_val_set(state, fOSC, smrt_d, R) < 0) {
+ dprintk(verbose, MB86A16_ERROR, 1, "rf val set error");
+ return -1;
+ }
+ if (afcex_data_set(state, AFCEX_L, AFCEX_H) < 0) {
+ dprintk(verbose, MB86A16_ERROR, 1, "afcex data set error");
+ return -1;
+ }
+ wait_t = 200000 / state->master_clk + 40000 / smrt_d;
+ msleep(wait_t);
+ dagcm[i] = dagcm_val_get(state);
+ }
+ if ((dagcm[0] > dagcm[1]) &&
+ (dagcm[0] > dagcm[2]) &&
+ (dagcm[0] - dagcm[1] > 2 * (dagcm[2] - dagcm[1]))) {
+
+ temp_freq = swp_freq - 2 * state->srate / 8;
+ swp_info_get2(state, smrt_d, R, temp_freq, &afcex_freq, &fOSC, &AFCEX_L, &AFCEX_H);
+ if (rf_val_set(state, fOSC, smrt_d, R) < 0) {
+ dprintk(verbose, MB86A16_ERROR, 1, "rf val set error");
+ return -1;
+ }
+ if (afcex_data_set(state, AFCEX_L, AFCEX_H) < 0) {
+ dprintk(verbose, MB86A16_ERROR, 1, "afcex data set");
+ return -1;
+ }
+ wait_t = 200000 / state->master_clk + 40000 / smrt_d;
+ msleep(wait_t);
+ dagcm[3] = dagcm_val_get(state);
+ if (dagcm[3] > dagcm[1])
+ delta_freq = (dagcm[2] - dagcm[0] + dagcm[1] - dagcm[3]) * state->srate / 300;
+ else
+ delta_freq = 0;
+ } else if ((dagcm[2] > dagcm[1]) &&
+ (dagcm[2] > dagcm[0]) &&
+ (dagcm[2] - dagcm[1] > 2 * (dagcm[0] - dagcm[1]))) {
+
+ temp_freq = swp_freq + 2 * state->srate / 8;
+ swp_info_get2(state, smrt_d, R, temp_freq, &afcex_freq, &fOSC, &AFCEX_L, &AFCEX_H);
+ if (rf_val_set(state, fOSC, smrt_d, R) < 0) {
+ dprintk(verbose, MB86A16_ERROR, 1, "rf val set");
+ return -1;
+ }
+ if (afcex_data_set(state, AFCEX_L, AFCEX_H) < 0) {
+ dprintk(verbose, MB86A16_ERROR, 1, "afcex data set");
+ return -1;
+ }
+ wait_t = 200000 / state->master_clk + 40000 / smrt_d;
+ msleep(wait_t);
+ dagcm[3] = dagcm_val_get(state);
+ if (dagcm[3] > dagcm[1])
+ delta_freq = (dagcm[2] - dagcm[0] + dagcm[3] - dagcm[1]) * state->srate / 300;
+ else
+ delta_freq = 0 ;
+
+ } else {
+ delta_freq = 0 ;
+ }
+ dprintk(verbose, MB86A16_INFO, 1, "SWEEP Frequency = %d", swp_freq);
+ swp_freq += delta_freq;
+ dprintk(verbose, MB86A16_INFO, 1, "Adjusting .., DELTA Freq = %d, SWEEP Freq=%d", delta_freq, swp_freq);
+ if (ABS(state->frequency * 1000 - swp_freq) > 3800) {
+ dprintk(verbose, MB86A16_INFO, 1, "NO -- SIGNAL !");
+ } else {
+
+ S1T = 0;
+ S0T = 3;
+ CREN = 1;
+ AFCEN = 0;
+ AFCEXEN = 1;
+
+ if (S01T_set(state, S1T, S0T) < 0) {
+ dprintk(verbose, MB86A16_ERROR, 1, "S01T set error");
+ return -1;
+ }
+ if (DAGC_data_set(state, 0, 0) < 0) {
+ dprintk(verbose, MB86A16_ERROR, 1, "DAGC data set error");
+ return -1;
+ }
+ R = vco_dev_get(state, state->srate);
+ smrt_info_get(state, state->srate);
+ if (smrt_set(state, state->srate) < 0) {
+ dprintk(verbose, MB86A16_ERROR, 1, "smrt set error");
+ return -1;
+ }
+ if (EN_set(state, CREN, AFCEN) < 0) {
+ dprintk(verbose, MB86A16_ERROR, 1, "EN set error");
+ return -1;
+ }
+ if (AFCEXEN_set(state, AFCEXEN, state->srate) < 0) {
+ dprintk(verbose, MB86A16_ERROR, 1, "AFCEXEN set error");
+ return -1;
+ }
+ swp_info_get2(state, state->srate, R, swp_freq, &afcex_freq, &fOSC, &AFCEX_L, &AFCEX_H);
+ if (rf_val_set(state, fOSC, state->srate, R) < 0) {
+ dprintk(verbose, MB86A16_ERROR, 1, "rf val set error");
+ return -1;
+ }
+ if (afcex_data_set(state, AFCEX_L, AFCEX_H) < 0) {
+ dprintk(verbose, MB86A16_ERROR, 1, "afcex data set error");
+ return -1;
+ }
+ if (srst(state) < 0) {
+ dprintk(verbose, MB86A16_ERROR, 1, "srst error");
+ return -1;
+ }
+ wait_t = 7 + (10000 + state->srate / 2) / state->srate;
+ if (wait_t == 0)
+ wait_t = 1;
+ msleep_interruptible(wait_t);
+ if (mb86a16_read(state, 0x37, &SIG1) != 2) {
+ dprintk(verbose, MB86A16_ERROR, 1, "I2C transfer error");
+ return -EREMOTEIO;
+ }
+
+ if (SIG1 > 110) {
+ S2T = 4; S4T = 1; S5T = 6; ETH = 4; VIA = 6;
+ wait_t = 7 + (917504 + state->srate / 2) / state->srate;
+ } else if (SIG1 > 105) {
+ S2T = 4; S4T = 2; S5T = 8; ETH = 7; VIA = 2;
+ wait_t = 7 + (1048576 + state->srate / 2) / state->srate;
+ } else if (SIG1 > 85) {
+ S2T = 5; S4T = 2; S5T = 8; ETH = 7; VIA = 2;
+ wait_t = 7 + (1310720 + state->srate / 2) / state->srate;
+ } else if (SIG1 > 65) {
+ S2T = 6; S4T = 2; S5T = 8; ETH = 7; VIA = 2;
+ wait_t = 7 + (1572864 + state->srate / 2) / state->srate;
+ } else {
+ S2T = 7; S4T = 2; S5T = 8; ETH = 7; VIA = 2;
+ wait_t = 7 + (2097152 + state->srate / 2) / state->srate;
+ }
+ wait_t *= 2; /* FOS */
+ S2T_set(state, S2T);
+ S45T_set(state, S4T, S5T);
+ Vi_set(state, ETH, VIA);
+ srst(state);
+ msleep_interruptible(wait_t);
+ sync = sync_chk(state, &VIRM);
+ dprintk(verbose, MB86A16_INFO, 1, "-------- Viterbi=[%d] SYNC=[%d] ---------", VIRM, sync);
+ if (VIRM) {
+ if (VIRM == 4) {
+ /* 5/6 */
+ if (SIG1 > 110)
+ wait_t = (786432 + state->srate / 2) / state->srate;
+ else
+ wait_t = (1572864 + state->srate / 2) / state->srate;
+ if (state->srate < 5000)
+ /* FIXME ! , should be a long wait ! */
+ msleep_interruptible(wait_t);
+ else
+ msleep_interruptible(wait_t);
+
+ if (sync_chk(state, &junk) == 0) {
+ iq_vt_set(state, 1);
+ FEC_srst(state);
+ }
+ }
+ /* 1/2, 2/3, 3/4, 7/8 */
+ if (SIG1 > 110)
+ wait_t = (786432 + state->srate / 2) / state->srate;
+ else
+ wait_t = (1572864 + state->srate / 2) / state->srate;
+ msleep_interruptible(wait_t);
+ SEQ_set(state, 1);
+ } else {
+ dprintk(verbose, MB86A16_INFO, 1, "NO -- SYNC");
+ SEQ_set(state, 1);
+ ret = -1;
+ }
+ }
+ } else {
+ dprintk(verbose, MB86A16_INFO, 1, "NO -- SIGNAL");
+ ret = -1;
+ }
+
+ sync = sync_chk(state, &junk);
+ if (sync) {
+ dprintk(verbose, MB86A16_INFO, 1, "******* SYNC *******");
+ freqerr_chk(state, state->frequency, state->srate, 1);
+ ret = 0;
+ break;
+ }
+ }
+
+ mb86a16_read(state, 0x15, &agcval);
+ mb86a16_read(state, 0x26, &cnmval);
+ dprintk(verbose, MB86A16_INFO, 1, "AGC = %02x CNM = %02x", agcval, cnmval);
+
+ return ret;
+}
+
+static int mb86a16_send_diseqc_msg(struct dvb_frontend *fe,
+ struct dvb_diseqc_master_cmd *cmd)
+{
+ struct mb86a16_state *state = fe->demodulator_priv;
+ int i;
+ u8 regs;
+
+ if (mb86a16_write(state, MB86A16_DCC1, MB86A16_DCC1_DISTA) < 0)
+ goto err;
+ if (mb86a16_write(state, MB86A16_DCCOUT, 0x00) < 0)
+ goto err;
+ if (mb86a16_write(state, MB86A16_TONEOUT2, 0x04) < 0)
+ goto err;
+
+ regs = 0x18;
+
+ if (cmd->msg_len > 5 || cmd->msg_len < 4)
+ return -EINVAL;
+
+ for (i = 0; i < cmd->msg_len; i++) {
+ if (mb86a16_write(state, regs, cmd->msg[i]) < 0)
+ goto err;
+
+ regs++;
+ }
+ i += 0x90;
+
+ msleep_interruptible(10);
+
+ if (mb86a16_write(state, MB86A16_DCC1, i) < 0)
+ goto err;
+ if (mb86a16_write(state, MB86A16_DCCOUT, MB86A16_DCCOUT_DISEN) < 0)
+ goto err;
+
+ return 0;
+
+err:
+ dprintk(verbose, MB86A16_ERROR, 1, "I2C transfer error");
+ return -EREMOTEIO;
+}
+
+static int mb86a16_send_diseqc_burst(struct dvb_frontend *fe, fe_sec_mini_cmd_t burst)
+{
+ struct mb86a16_state *state = fe->demodulator_priv;
+
+ switch (burst) {
+ case SEC_MINI_A:
+ if (mb86a16_write(state, MB86A16_DCC1, MB86A16_DCC1_DISTA |
+ MB86A16_DCC1_TBEN |
+ MB86A16_DCC1_TBO) < 0)
+ goto err;
+ if (mb86a16_write(state, MB86A16_DCCOUT, MB86A16_DCCOUT_DISEN) < 0)
+ goto err;
+ break;
+ case SEC_MINI_B:
+ if (mb86a16_write(state, MB86A16_DCC1, MB86A16_DCC1_DISTA |
+ MB86A16_DCC1_TBEN) < 0)
+ goto err;
+ if (mb86a16_write(state, MB86A16_DCCOUT, MB86A16_DCCOUT_DISEN) < 0)
+ goto err;
+ break;
+ }
+
+ return 0;
+err:
+ dprintk(verbose, MB86A16_ERROR, 1, "I2C transfer error");
+ return -EREMOTEIO;
+}
+
+static int mb86a16_set_tone(struct dvb_frontend *fe, fe_sec_tone_mode_t tone)
+{
+ struct mb86a16_state *state = fe->demodulator_priv;
+
+ switch (tone) {
+ case SEC_TONE_ON:
+ if (mb86a16_write(state, MB86A16_TONEOUT2, 0x00) < 0)
+ goto err;
+ if (mb86a16_write(state, MB86A16_DCC1, MB86A16_DCC1_DISTA |
+ MB86A16_DCC1_CTOE) < 0)
+
+ goto err;
+ if (mb86a16_write(state, MB86A16_DCCOUT, MB86A16_DCCOUT_DISEN) < 0)
+ goto err;
+ break;
+ case SEC_TONE_OFF:
+ if (mb86a16_write(state, MB86A16_TONEOUT2, 0x04) < 0)
+ goto err;
+ if (mb86a16_write(state, MB86A16_DCC1, MB86A16_DCC1_DISTA) < 0)
+ goto err;
+ if (mb86a16_write(state, MB86A16_DCCOUT, 0x00) < 0)
+ goto err;
+ break;
+ default:
+ return -EINVAL;
+ }
+ return 0;
+
+err:
+ dprintk(verbose, MB86A16_ERROR, 1, "I2C transfer error");
+ return -EREMOTEIO;
+}
+
+static enum dvbfe_search mb86a16_search(struct dvb_frontend *fe,
+ struct dvb_frontend_parameters *p)
+{
+ struct mb86a16_state *state = fe->demodulator_priv;
+
+ state->frequency = p->frequency / 1000;
+ state->srate = p->u.qpsk.symbol_rate / 1000;
+
+ if (!mb86a16_set_fe(state)) {
+ dprintk(verbose, MB86A16_ERROR, 1, "Succesfully acquired LOCK");
+ return DVBFE_ALGO_SEARCH_SUCCESS;
+ }
+
+ dprintk(verbose, MB86A16_ERROR, 1, "Lock acquisition failed!");
+ return DVBFE_ALGO_SEARCH_FAILED;
+}
+
+static void mb86a16_release(struct dvb_frontend *fe)
+{
+ struct mb86a16_state *state = fe->demodulator_priv;
+ kfree(state);
+}
+
+static int mb86a16_init(struct dvb_frontend *fe)
+{
+ return 0;
+}
+
+static int mb86a16_sleep(struct dvb_frontend *fe)
+{
+ return 0;
+}
+
+static int mb86a16_read_ber(struct dvb_frontend *fe, u32 *ber)
+{
+ u8 ber_mon, ber_tab, ber_lsb, ber_mid, ber_msb, ber_tim, ber_rst;
+ u32 timer;
+
+ struct mb86a16_state *state = fe->demodulator_priv;
+
+ *ber = 0;
+ if (mb86a16_read(state, MB86A16_BERMON, &ber_mon) != 2)
+ goto err;
+ if (mb86a16_read(state, MB86A16_BERTAB, &ber_tab) != 2)
+ goto err;
+ if (mb86a16_read(state, MB86A16_BERLSB, &ber_lsb) != 2)
+ goto err;
+ if (mb86a16_read(state, MB86A16_BERMID, &ber_mid) != 2)
+ goto err;
+ if (mb86a16_read(state, MB86A16_BERMSB, &ber_msb) != 2)
+ goto err;
+ /* BER monitor invalid when BER_EN = 0 */
+ if (ber_mon & 0x04) {
+ /* coarse, fast calculation */
+ *ber = ber_tab & 0x1f;
+ dprintk(verbose, MB86A16_DEBUG, 1, "BER coarse=[0x%02x]", *ber);
+ if (ber_mon & 0x01) {
+ /*
+ * BER_SEL = 1, The monitored BER is the estimated
+ * value with a Reed-Solomon decoder error amount at
+ * the deinterleaver output.
+ * monitored BER is expressed as a 20 bit output in total
+ */
+ ber_rst = ber_mon >> 3;
+ *ber = (((ber_msb << 8) | ber_mid) << 8) | ber_lsb;
+ if (ber_rst == 0)
+ timer = 12500000;
+ if (ber_rst == 1)
+ timer = 25000000;
+ if (ber_rst == 2)
+ timer = 50000000;
+ if (ber_rst == 3)
+ timer = 100000000;
+
+ *ber /= timer;
+ dprintk(verbose, MB86A16_DEBUG, 1, "BER fine=[0x%02x]", *ber);
+ } else {
+ /*
+ * BER_SEL = 0, The monitored BER is the estimated
+ * value with a Viterbi decoder error amount at the
+ * QPSK demodulator output.
+ * monitored BER is expressed as a 24 bit output in total
+ */
+ ber_tim = ber_mon >> 1;
+ *ber = (((ber_msb << 8) | ber_mid) << 8) | ber_lsb;
+ if (ber_tim == 0)
+ timer = 16;
+ if (ber_tim == 1)
+ timer = 24;
+
+ *ber /= 2 ^ timer;
+ dprintk(verbose, MB86A16_DEBUG, 1, "BER fine=[0x%02x]", *ber);
+ }
+ }
+ return 0;
+err:
+ dprintk(verbose, MB86A16_ERROR, 1, "I2C transfer error");
+ return -EREMOTEIO;
+}
+
+static int mb86a16_read_signal_strength(struct dvb_frontend *fe, u16 *strength)
+{
+ u8 agcm = 0;
+ struct mb86a16_state *state = fe->demodulator_priv;
+
+ *strength = 0;
+ if (mb86a16_read(state, MB86A16_AGCM, &agcm) != 2) {
+ dprintk(verbose, MB86A16_ERROR, 1, "I2C transfer error");
+ return -EREMOTEIO;
+ }
+
+ *strength = ((0xff - agcm) * 100) / 256;
+ dprintk(verbose, MB86A16_DEBUG, 1, "Signal strength=[%d %%]", (u8) *strength);
+ *strength = (0xffff - 0xff) + agcm;
+
+ return 0;
+}
+
+struct cnr {
+ u8 cn_reg;
+ u8 cn_val;
+};
+
+static const struct cnr cnr_tab[] = {
+ { 35, 2 },
+ { 40, 3 },
+ { 50, 4 },
+ { 60, 5 },
+ { 70, 6 },
+ { 80, 7 },
+ { 92, 8 },
+ { 103, 9 },
+ { 115, 10 },
+ { 138, 12 },
+ { 162, 15 },
+ { 180, 18 },
+ { 185, 19 },
+ { 189, 20 },
+ { 195, 22 },
+ { 199, 24 },
+ { 201, 25 },
+ { 202, 26 },
+ { 203, 27 },
+ { 205, 28 },
+ { 208, 30 }
+};
+
+static int mb86a16_read_snr(struct dvb_frontend *fe, u16 *snr)
+{
+ struct mb86a16_state *state = fe->demodulator_priv;
+ int i = 0;
+ int low_tide = 2, high_tide = 30, q_level;
+ u8 cn;
+
+ *snr = 0;
+ if (mb86a16_read(state, 0x26, &cn) != 2) {
+ dprintk(verbose, MB86A16_ERROR, 1, "I2C transfer error");
+ return -EREMOTEIO;
+ }
+
+ for (i = 0; i < ARRAY_SIZE(cnr_tab); i++) {
+ if (cn < cnr_tab[i].cn_reg) {
+ *snr = cnr_tab[i].cn_val;
+ break;
+ }
+ }
+ q_level = (*snr * 100) / (high_tide - low_tide);
+ dprintk(verbose, MB86A16_ERROR, 1, "SNR (Quality) = [%d dB], Level=%d %%", *snr, q_level);
+ *snr = (0xffff - 0xff) + *snr;
+
+ return 0;
+}
+
+static int mb86a16_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks)
+{
+ u8 dist;
+ struct mb86a16_state *state = fe->demodulator_priv;
+
+ if (mb86a16_read(state, MB86A16_DISTMON, &dist) != 2) {
+ dprintk(verbose, MB86A16_ERROR, 1, "I2C transfer error");
+ return -EREMOTEIO;
+ }
+ *ucblocks = dist;
+
+ return 0;
+}
+
+static enum dvbfe_algo mb86a16_frontend_algo(struct dvb_frontend *fe)
+{
+ return DVBFE_ALGO_CUSTOM;
+}
+
+static struct dvb_frontend_ops mb86a16_ops = {
+ .info = {
+ .name = "Fujitsu MB86A16 DVB-S",
+ .type = FE_QPSK,
+ .frequency_min = 950000,
+ .frequency_max = 2150000,
+ .frequency_stepsize = 3000,
+ .frequency_tolerance = 0,
+ .symbol_rate_min = 1000000,
+ .symbol_rate_max = 45000000,
+ .symbol_rate_tolerance = 500,
+ .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_QPSK |
+ FE_CAN_FEC_AUTO
+ },
+ .release = mb86a16_release,
+
+ .get_frontend_algo = mb86a16_frontend_algo,
+ .search = mb86a16_search,
+ .read_status = mb86a16_read_status,
+ .init = mb86a16_init,
+ .sleep = mb86a16_sleep,
+ .read_status = mb86a16_read_status,
+
+ .read_ber = mb86a16_read_ber,
+ .read_signal_strength = mb86a16_read_signal_strength,
+ .read_snr = mb86a16_read_snr,
+ .read_ucblocks = mb86a16_read_ucblocks,
+
+ .diseqc_send_master_cmd = mb86a16_send_diseqc_msg,
+ .diseqc_send_burst = mb86a16_send_diseqc_burst,
+ .set_tone = mb86a16_set_tone,
+};
+
+struct dvb_frontend *mb86a16_attach(const struct mb86a16_config *config,
+ struct i2c_adapter *i2c_adap)
+{
+ u8 dev_id = 0;
+ struct mb86a16_state *state = NULL;
+
+ state = kmalloc(sizeof(struct mb86a16_state), GFP_KERNEL);
+ if (state == NULL)
+ goto error;
+
+ state->config = config;
+ state->i2c_adap = i2c_adap;
+
+ mb86a16_read(state, 0x7f, &dev_id);
+ if (dev_id != 0xfe)
+ goto error;
+
+ memcpy(&state->frontend.ops, &mb86a16_ops, sizeof(struct dvb_frontend_ops));
+ state->frontend.demodulator_priv = state;
+ state->frontend.ops.set_voltage = state->config->set_voltage;
+
+ return &state->frontend;
+error:
+ kfree(state);
+ return NULL;
+}
+EXPORT_SYMBOL(mb86a16_attach);
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Manu Abraham");
diff --git a/drivers/media/dvb/frontends/mb86a16.h b/drivers/media/dvb/frontends/mb86a16.h
new file mode 100644
index 000000000000..6ea8c376394f
--- /dev/null
+++ b/drivers/media/dvb/frontends/mb86a16.h
@@ -0,0 +1,52 @@
+/*
+ Fujitsu MB86A16 DVB-S/DSS DC Receiver driver
+
+ Copyright (C) Manu Abraham (abraham.manu@gmail.com)
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#ifndef __MB86A16_H
+#define __MB86A16_H
+
+#include <linux/dvb/frontend.h>
+#include "dvb_frontend.h"
+
+
+struct mb86a16_config {
+ u8 demod_address;
+
+ int (*set_voltage)(struct dvb_frontend *fe, fe_sec_voltage_t voltage);
+};
+
+
+
+#if defined(CONFIG_DVB_MB86A16) || (defined(CONFIG_DVB_MB86A16_MODULE) && defined(MODULE))
+
+extern struct dvb_frontend *mb86a16_attach(const struct mb86a16_config *config,
+ struct i2c_adapter *i2c_adap);
+
+#else
+
+static inline struct dvb_frontend *mb86a16_attach(const struct mb86a16_config *config,
+ struct i2c_adapter *i2c_adap)
+{
+ printk(KERN_WARNING "%s: Driver disabled by Kconfig\n", __func__);
+ return NULL;
+}
+
+#endif /* CONFIG_DVB_MB86A16 */
+
+#endif /* __MB86A16_H */
diff --git a/drivers/media/dvb/frontends/mb86a16_priv.h b/drivers/media/dvb/frontends/mb86a16_priv.h
new file mode 100644
index 000000000000..360a35acfe84
--- /dev/null
+++ b/drivers/media/dvb/frontends/mb86a16_priv.h
@@ -0,0 +1,151 @@
+/*
+ Fujitsu MB86A16 DVB-S/DSS DC Receiver driver
+
+ Copyright (C) Manu Abraham (abraham.manu@gmail.com)
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#ifndef __MB86A16_PRIV_H
+#define __MB86A16_PRIV_H
+
+#define MB86A16_TSOUT 0x00
+#define MB86A16_TSOUT_HIZSEL (0x01 << 5)
+#define MB86A16_TSOUT_HIZCNTI (0x01 << 4)
+#define MB86A16_TSOUT_MODE (0x01 << 3)
+#define MB86A16_TSOUT_ORDER (0x01 << 2)
+#define MB86A16_TSOUT_ERROR (0x01 << 1)
+#define Mb86A16_TSOUT_EDGE (0x01 << 0)
+
+#define MB86A16_FEC 0x01
+#define MB86A16_FEC_FSYNC (0x01 << 5)
+#define MB86A16_FEC_PCKB8 (0x01 << 4)
+#define MB86A16_FEC_DVDS (0x01 << 3)
+#define MB86A16_FEC_EREN (0x01 << 2)
+#define Mb86A16_FEC_RSEN (0x01 << 1)
+#define MB86A16_FEC_DIEN (0x01 << 0)
+
+#define MB86A16_AGC 0x02
+#define MB86A16_AGC_AGMD (0x01 << 6)
+#define MB86A16_AGC_AGCW (0x0f << 2)
+#define MB86A16_AGC_AGCP (0x01 << 1)
+#define MB86A16_AGC_AGCR (0x01 << 0)
+
+#define MB86A16_SRATE1 0x03
+#define MB86A16_SRATE1_DECI (0x07 << 2)
+#define MB86A16_SRATE1_CSEL (0x01 << 1)
+#define MB86A16_SRATE1_RSEL (0x01 << 0)
+
+#define MB86A16_SRATE2 0x04
+#define MB86A16_SRATE2_STOFSL (0xff << 0)
+
+#define MB86A16_SRATE3 0x05
+#define MB86A16_SRATE2_STOFSH (0xff << 0)
+
+#define MB86A16_VITERBI 0x06
+#define MB86A16_FRAMESYNC 0x07
+#define MB86A16_CRLFILTCOEF1 0x08
+#define MB86A16_CRLFILTCOEF2 0x09
+#define MB86A16_STRFILTCOEF1 0x0a
+#define MB86A16_STRFILTCOEF2 0x0b
+#define MB86A16_RESET 0x0c
+#define MB86A16_STATUS 0x0d
+#define MB86A16_AFCML 0x0e
+#define MB86A16_AFCMH 0x0f
+#define MB86A16_BERMON 0x10
+#define MB86A16_BERTAB 0x11
+#define MB86A16_BERLSB 0x12
+#define MB86A16_BERMID 0x13
+#define MB86A16_BERMSB 0x14
+#define MB86A16_AGCM 0x15
+
+#define MB86A16_DCC1 0x16
+#define MB86A16_DCC1_DISTA (0x01 << 7)
+#define MB86A16_DCC1_PRTY (0x01 << 6)
+#define MB86A16_DCC1_CTOE (0x01 << 5)
+#define MB86A16_DCC1_TBEN (0x01 << 4)
+#define MB86A16_DCC1_TBO (0x01 << 3)
+#define MB86A16_DCC1_NUM (0x07 << 0)
+
+#define MB86A16_DCC2 0x17
+#define MB86A16_DCC2_DCBST (0x01 << 0)
+
+#define MB86A16_DCC3 0x18
+#define MB86A16_DCC3_CODE0 (0xff << 0)
+
+#define MB86A16_DCC4 0x19
+#define MB86A16_DCC4_CODE1 (0xff << 0)
+
+#define MB86A16_DCC5 0x1a
+#define MB86A16_DCC5_CODE2 (0xff << 0)
+
+#define MB86A16_DCC6 0x1b
+#define MB86A16_DCC6_CODE3 (0xff << 0)
+
+#define MB86A16_DCC7 0x1c
+#define MB86A16_DCC7_CODE4 (0xff << 0)
+
+#define MB86A16_DCC8 0x1d
+#define MB86A16_DCC8_CODE5 (0xff << 0)
+
+#define MB86A16_DCCOUT 0x1e
+#define MB86A16_DCCOUT_DISEN (0x01 << 0)
+
+#define MB86A16_TONEOUT1 0x1f
+#define MB86A16_TONE_TDIVL (0xff << 0)
+
+#define MB86A16_TONEOUT2 0x20
+#define MB86A16_TONE_TMD (0x03 << 2)
+#define MB86A16_TONE_TDIVH (0x03 << 0)
+
+#define MB86A16_FREQ1 0x21
+#define MB86A16_FREQ2 0x22
+#define MB86A16_FREQ3 0x23
+#define MB86A16_FREQ4 0x24
+#define MB86A16_FREQSET 0x25
+#define MB86A16_CNM 0x26
+#define MB86A16_PORT0 0x27
+#define MB86A16_PORT1 0x28
+#define MB86A16_DRCFILT 0x29
+#define MB86A16_AFC 0x2a
+#define MB86A16_AFCEXL 0x2b
+#define MB86A16_AFCEXH 0x2c
+#define MB86A16_DAGC 0x2d
+#define MB86A16_SEQMODE 0x32
+#define MB86A16_S0S1T 0x33
+#define MB86A16_S2S3T 0x34
+#define MB86A16_S4S5T 0x35
+#define MB86A16_CNTMR 0x36
+#define MB86A16_SIG1 0x37
+#define MB86A16_SIG2 0x38
+#define MB86A16_VIMAG 0x39
+#define MB86A16_VISET1 0x3a
+#define MB86A16_VISET2 0x3b
+#define MB86A16_VISET3 0x3c
+#define MB86A16_FAGCS1 0x3d
+#define MB86A16_FAGCS2 0x3e
+#define MB86A16_FAGCS3 0x3f
+#define MB86A16_FAGCS4 0x40
+#define MB86A16_FAGCS5 0x41
+#define MB86A16_FAGCS6 0x42
+#define MB86A16_CRM 0x43
+#define MB86A16_STRM 0x44
+#define MB86A16_DAGCML 0x45
+#define MB86A16_DAGCMH 0x46
+#define MB86A16_QPSKTST 0x49
+#define MB86A16_DISTMON 0x52
+#define MB86A16_VERSION 0x7f
+
+#endif /* __MB86A16_PRIV_H */
diff --git a/drivers/media/dvb/frontends/stv0900.h b/drivers/media/dvb/frontends/stv0900.h
index 29c3fa85c227..e3e35d1ce838 100644
--- a/drivers/media/dvb/frontends/stv0900.h
+++ b/drivers/media/dvb/frontends/stv0900.h
@@ -49,6 +49,8 @@ struct stv0900_config {
u8 tun2_maddress;
u8 tun1_adc;/* 1 for stv6110, 2 for stb6100 */
u8 tun2_adc;
+ u8 tun1_type;/* for now 3 for stb6100 auto, else - software */
+ u8 tun2_type;
/* Set device param to start dma */
int (*set_ts_params)(struct dvb_frontend *fe, int is_punctured);
};
diff --git a/drivers/media/dvb/frontends/stv0900_core.c b/drivers/media/dvb/frontends/stv0900_core.c
index 8762c86044a5..115dc01c2234 100644
--- a/drivers/media/dvb/frontends/stv0900_core.c
+++ b/drivers/media/dvb/frontends/stv0900_core.c
@@ -567,6 +567,46 @@ void stv0900_set_bandwidth(struct dvb_frontend *fe, u32 bandwidth)
}
}
+u32 stv0900_get_freq_auto(struct stv0900_internal *intp, int demod)
+{
+ u32 freq, round;
+ /* Formulat :
+ Tuner_Frequency(MHz) = Regs / 64
+ Tuner_granularity(MHz) = Regs / 2048
+ real_Tuner_Frequency = Tuner_Frequency(MHz) - Tuner_granularity(MHz)
+ */
+ freq = (stv0900_get_bits(intp, TUN_RFFREQ2) << 10) +
+ (stv0900_get_bits(intp, TUN_RFFREQ1) << 2) +
+ stv0900_get_bits(intp, TUN_RFFREQ0);
+
+ freq = (freq * 1000) / 64;
+
+ round = (stv0900_get_bits(intp, TUN_RFRESTE1) >> 2) +
+ stv0900_get_bits(intp, TUN_RFRESTE0);
+
+ round = (round * 1000) / 2048;
+
+ return freq + round;
+}
+
+void stv0900_set_tuner_auto(struct stv0900_internal *intp, u32 Frequency,
+ u32 Bandwidth, int demod)
+{
+ u32 tunerFrequency;
+ /* Formulat:
+ Tuner_frequency_reg= Frequency(MHz)*64
+ */
+ tunerFrequency = (Frequency * 64) / 1000;
+
+ stv0900_write_bits(intp, TUN_RFFREQ2, (tunerFrequency >> 10));
+ stv0900_write_bits(intp, TUN_RFFREQ1, (tunerFrequency >> 2) & 0xff);
+ stv0900_write_bits(intp, TUN_RFFREQ0, (tunerFrequency & 0x03));
+ /* Low Pass Filter = BW /2 (MHz)*/
+ stv0900_write_bits(intp, TUN_BW, Bandwidth / 2000000);
+ /* Tuner Write trig */
+ stv0900_write_reg(intp, TNRLD, 1);
+}
+
static s32 stv0900_get_rf_level(struct stv0900_internal *intp,
const struct stv0900_table *lookup,
enum fe_stv0900_demod_num demod)
@@ -1329,7 +1369,6 @@ static enum fe_stv0900_error stv0900_init_internal(struct dvb_frontend *fe,
enum fe_stv0900_error error = STV0900_NO_ERROR;
enum fe_stv0900_error demodError = STV0900_NO_ERROR;
struct stv0900_internal *intp = NULL;
-
int selosci, i;
struct stv0900_inode *temp_int = find_inode(state->i2c_adap,
@@ -1404,6 +1443,27 @@ static enum fe_stv0900_error stv0900_init_internal(struct dvb_frontend *fe,
stv0900_write_bits(intp, F0900_P1_RST_HWARE, 0);
}
+ intp->tuner_type[0] = p_init->tuner1_type;
+ intp->tuner_type[1] = p_init->tuner2_type;
+ /* tuner init */
+ switch (p_init->tuner1_type) {
+ case 3: /*FE_AUTO_STB6100:*/
+ stv0900_write_reg(intp, R0900_P1_TNRCFG, 0x3c);
+ stv0900_write_reg(intp, R0900_P1_TNRCFG2, 0x86);
+ stv0900_write_reg(intp, R0900_P1_TNRCFG3, 0x18);
+ stv0900_write_reg(intp, R0900_P1_TNRXTAL, 27); /* 27MHz */
+ stv0900_write_reg(intp, R0900_P1_TNRSTEPS, 0x05);
+ stv0900_write_reg(intp, R0900_P1_TNRGAIN, 0x17);
+ stv0900_write_reg(intp, R0900_P1_TNRADJ, 0x1f);
+ stv0900_write_reg(intp, R0900_P1_TNRCTL2, 0x0);
+ stv0900_write_bits(intp, F0900_P1_TUN_TYPE, 3);
+ break;
+ /* case FE_SW_TUNER: */
+ default:
+ stv0900_write_bits(intp, F0900_P1_TUN_TYPE, 6);
+ break;
+ }
+
stv0900_write_bits(intp, F0900_P1_TUN_MADDRESS, p_init->tun1_maddress);
switch (p_init->tuner1_adc) {
case 1:
@@ -1413,6 +1473,27 @@ static enum fe_stv0900_error stv0900_init_internal(struct dvb_frontend *fe,
break;
}
+ stv0900_write_reg(intp, R0900_P1_TNRLD, 1); /* hw tuner */
+
+ /* tuner init */
+ switch (p_init->tuner2_type) {
+ case 3: /*FE_AUTO_STB6100:*/
+ stv0900_write_reg(intp, R0900_P2_TNRCFG, 0x3c);
+ stv0900_write_reg(intp, R0900_P2_TNRCFG2, 0x86);
+ stv0900_write_reg(intp, R0900_P2_TNRCFG3, 0x18);
+ stv0900_write_reg(intp, R0900_P2_TNRXTAL, 27); /* 27MHz */
+ stv0900_write_reg(intp, R0900_P2_TNRSTEPS, 0x05);
+ stv0900_write_reg(intp, R0900_P2_TNRGAIN, 0x17);
+ stv0900_write_reg(intp, R0900_P2_TNRADJ, 0x1f);
+ stv0900_write_reg(intp, R0900_P2_TNRCTL2, 0x0);
+ stv0900_write_bits(intp, F0900_P2_TUN_TYPE, 3);
+ break;
+ /* case FE_SW_TUNER: */
+ default:
+ stv0900_write_bits(intp, F0900_P2_TUN_TYPE, 6);
+ break;
+ }
+
stv0900_write_bits(intp, F0900_P2_TUN_MADDRESS, p_init->tun2_maddress);
switch (p_init->tuner2_adc) {
case 1:
@@ -1422,6 +1503,8 @@ static enum fe_stv0900_error stv0900_init_internal(struct dvb_frontend *fe,
break;
}
+ stv0900_write_reg(intp, R0900_P2_TNRLD, 1); /* hw tuner */
+
stv0900_write_bits(intp, F0900_P1_TUN_IQSWAP, p_init->tun1_iq_inv);
stv0900_write_bits(intp, F0900_P2_TUN_IQSWAP, p_init->tun2_iq_inv);
stv0900_set_mclk(intp, 135000000);
@@ -1824,10 +1907,12 @@ struct dvb_frontend *stv0900_attach(const struct stv0900_config *config,
init_params.tun1_maddress = config->tun1_maddress;
init_params.tun1_iq_inv = STV0900_IQ_NORMAL;
init_params.tuner1_adc = config->tun1_adc;
+ init_params.tuner1_type = config->tun1_type;
init_params.path2_ts_clock = config->path2_mode;
init_params.ts_config = config->ts_config_regs;
init_params.tun2_maddress = config->tun2_maddress;
init_params.tuner2_adc = config->tun2_adc;
+ init_params.tuner2_type = config->tun2_type;
init_params.tun2_iq_inv = STV0900_IQ_SWAPPED;
err_stv0900 = stv0900_init_internal(&state->frontend,
diff --git a/drivers/media/dvb/frontends/stv0900_priv.h b/drivers/media/dvb/frontends/stv0900_priv.h
index d8ba8a984abe..b62b0f0a4fef 100644
--- a/drivers/media/dvb/frontends/stv0900_priv.h
+++ b/drivers/media/dvb/frontends/stv0900_priv.h
@@ -247,6 +247,7 @@ struct stv0900_init_params{
u8 tun1_maddress;
int tuner1_adc;
+ int tuner1_type;
/* IQ from the tuner1 to the demod */
enum stv0900_iq_inversion tun1_iq_inv;
@@ -254,6 +255,7 @@ struct stv0900_init_params{
u8 tun2_maddress;
int tuner2_adc;
+ int tuner2_type;
/* IQ from the tuner2 to the demod */
enum stv0900_iq_inversion tun2_iq_inv;
@@ -309,6 +311,8 @@ struct stv0900_internal{
s32 bw[2];
s32 symbol_rate[2];
s32 srch_range[2];
+ /* for software/auto tuner */
+ int tuner_type[2];
/* algorithm for search Blind, Cold or Warm*/
enum fe_stv0900_search_algo srch_algo[2];
@@ -394,4 +398,11 @@ extern enum
fe_stv0900_tracking_standard stv0900_get_standard(struct dvb_frontend *fe,
enum fe_stv0900_demod_num demod);
+extern u32
+stv0900_get_freq_auto(struct stv0900_internal *intp, int demod);
+
+extern void
+stv0900_set_tuner_auto(struct stv0900_internal *intp, u32 Frequency,
+ u32 Bandwidth, int demod);
+
#endif
diff --git a/drivers/media/dvb/frontends/stv0900_reg.h b/drivers/media/dvb/frontends/stv0900_reg.h
index 7b8edf192e97..731afe93a823 100644
--- a/drivers/media/dvb/frontends/stv0900_reg.h
+++ b/drivers/media/dvb/frontends/stv0900_reg.h
@@ -3174,17 +3174,21 @@ extern s32 shiftx(s32 x, int demod, s32 shift);
#define R0900_P1_TNRRF1 0xf4e9
#define TNRRF1 REGx(R0900_P1_TNRRF1)
#define F0900_P1_TUN_RFFREQ2 0xf4e900ff
+#define TUN_RFFREQ2 FLDx(F0900_P1_TUN_RFFREQ2)
/*P1_TNRRF0*/
#define R0900_P1_TNRRF0 0xf4ea
#define TNRRF0 REGx(R0900_P1_TNRRF0)
#define F0900_P1_TUN_RFFREQ1 0xf4ea00ff
+#define TUN_RFFREQ1 FLDx(F0900_P1_TUN_RFFREQ1)
/*P1_TNRBW*/
#define R0900_P1_TNRBW 0xf4eb
#define TNRBW REGx(R0900_P1_TNRBW)
#define F0900_P1_TUN_RFFREQ0 0xf4eb00c0
+#define TUN_RFFREQ0 FLDx(F0900_P1_TUN_RFFREQ0)
#define F0900_P1_TUN_BW 0xf4eb003f
+#define TUN_BW FLDx(F0900_P1_TUN_BW)
/*P1_TNRADJ*/
#define R0900_P1_TNRADJ 0xf4ec
@@ -3234,11 +3238,13 @@ extern s32 shiftx(s32 x, int demod, s32 shift);
#define F0900_P1_TUN_I2CLOCKED 0xf4f60010
#define F0900_P1_TUN_PROGDONE 0xf4f6000c
#define F0900_P1_TUN_RFRESTE1 0xf4f60003
+#define TUN_RFRESTE1 FLDx(F0900_P1_TUN_RFRESTE1)
/*P1_TNRRESTE*/
#define R0900_P1_TNRRESTE 0xf4f7
#define TNRRESTE REGx(R0900_P1_TNRRESTE)
#define F0900_P1_TUN_RFRESTE0 0xf4f700ff
+#define TUN_RFRESTE0 FLDx(F0900_P1_TUN_RFRESTE0)
/*P1_SMAPCOEF7*/
#define R0900_P1_SMAPCOEF7 0xf500
diff --git a/drivers/media/dvb/frontends/stv0900_sw.c b/drivers/media/dvb/frontends/stv0900_sw.c
index b8da87fa637f..5161c2884426 100644
--- a/drivers/media/dvb/frontends/stv0900_sw.c
+++ b/drivers/media/dvb/frontends/stv0900_sw.c
@@ -606,7 +606,12 @@ static int stv0900_get_demod_cold_lock(struct dvb_frontend *fe,
tuner_freq -= (current_step * currier_step);
if (intp->chip_id <= 0x20) {
- stv0900_set_tuner(fe, tuner_freq, intp->bw[d]);
+ if (intp->tuner_type[d] == 3)
+ stv0900_set_tuner_auto(intp, tuner_freq,
+ intp->bw[d], demod);
+ else
+ stv0900_set_tuner(fe, tuner_freq, intp->bw[d]);
+
stv0900_write_reg(intp, DMDISTATE, 0x1c);
stv0900_write_reg(intp, CFRINIT1, 0);
stv0900_write_reg(intp, CFRINIT0, 0);
@@ -976,8 +981,16 @@ static void stv0900_track_optimization(struct dvb_frontend *fe)
intp->rolloff) + 10000000;
if ((intp->chip_id >= 0x20) || (blind_tun_sw == 1)) {
- if (intp->srch_algo[demod] != STV0900_WARM_START)
- stv0900_set_bandwidth(fe, intp->bw[demod]);
+ if (intp->srch_algo[demod] != STV0900_WARM_START) {
+ if (intp->tuner_type[demod] == 3)
+ stv0900_set_tuner_auto(intp,
+ intp->freq[demod],
+ intp->bw[demod],
+ demod);
+ else
+ stv0900_set_bandwidth(fe,
+ intp->bw[demod]);
+ }
}
if ((intp->srch_algo[demod] == STV0900_BLIND_SEARCH) ||
@@ -1202,7 +1215,11 @@ fe_stv0900_signal_type stv0900_get_signal_params(struct dvb_frontend *fe)
}
result->standard = stv0900_get_standard(fe, d);
- result->frequency = stv0900_get_tuner_freq(fe);
+ if (intp->tuner_type[demod] == 3)
+ result->frequency = stv0900_get_freq_auto(intp, d);
+ else
+ result->frequency = stv0900_get_tuner_freq(fe);
+
offsetFreq = stv0900_get_carr_freq(intp, intp->mclk, d) / 1000;
result->frequency += offsetFreq;
result->symbol_rate = stv0900_get_symbol_rate(intp, intp->mclk, d);
@@ -1239,7 +1256,11 @@ fe_stv0900_signal_type stv0900_get_signal_params(struct dvb_frontend *fe)
if ((intp->srch_algo[d] == STV0900_BLIND_SEARCH) ||
(intp->symbol_rate[d] < 10000000)) {
offsetFreq = result->frequency - intp->freq[d];
- intp->freq[d] = stv0900_get_tuner_freq(fe);
+ if (intp->tuner_type[demod] == 3)
+ intp->freq[d] = stv0900_get_freq_auto(intp, d);
+ else
+ intp->freq[d] = stv0900_get_tuner_freq(fe);
+
if (ABS(offsetFreq) <= ((intp->srch_range[d] / 2000) + 500))
range = STV0900_RANGEOK;
else if (ABS(offsetFreq) <=
@@ -1481,7 +1502,12 @@ static u32 stv0900_search_srate_coarse(struct dvb_frontend *fe)
else
tuner_freq -= (current_step * currier_step);
- stv0900_set_tuner(fe, tuner_freq, intp->bw[demod]);
+ if (intp->tuner_type[demod] == 3)
+ stv0900_set_tuner_auto(intp, tuner_freq,
+ intp->bw[demod], demod);
+ else
+ stv0900_set_tuner(fe, tuner_freq,
+ intp->bw[demod]);
}
}
@@ -1875,7 +1901,11 @@ enum fe_stv0900_signal_type stv0900_algo(struct dvb_frontend *fe)
}
- stv0900_set_tuner(fe, intp->freq[demod], intp->bw[demod]);
+ if (intp->tuner_type[demod] == 3)
+ stv0900_set_tuner_auto(intp, intp->freq[demod],
+ intp->bw[demod], demod);
+ else
+ stv0900_set_tuner(fe, intp->freq[demod], intp->bw[demod]);
agc1_power = MAKEWORD(stv0900_get_bits(intp, AGCIQ_VALUE1),
stv0900_get_bits(intp, AGCIQ_VALUE0));
diff --git a/drivers/media/dvb/frontends/tda10021.c b/drivers/media/dvb/frontends/tda10021.c
index 6c1dbf9288d8..6ca533ea0f0e 100644
--- a/drivers/media/dvb/frontends/tda10021.c
+++ b/drivers/media/dvb/frontends/tda10021.c
@@ -426,6 +426,10 @@ struct dvb_frontend* tda10021_attach(const struct tda1002x_config* config,
id = tda10021_readreg(state, 0x1a);
if ((id & 0xf0) != 0x70) goto error;
+ /* Don't claim TDA10023 */
+ if (id == 0x7d)
+ goto error;
+
printk("TDA10021: i2c-addr = 0x%02x, id = 0x%02x\n",
state->config->demod_address, id);
diff --git a/drivers/media/dvb/frontends/tda665x.c b/drivers/media/dvb/frontends/tda665x.c
new file mode 100644
index 000000000000..87d52739c828
--- /dev/null
+++ b/drivers/media/dvb/frontends/tda665x.c
@@ -0,0 +1,257 @@
+/*
+ TDA665x tuner driver
+ Copyright (C) Manu Abraham (abraham.manu@gmail.com)
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+
+#include "dvb_frontend.h"
+#include "tda665x.h"
+
+struct tda665x_state {
+ struct dvb_frontend *fe;
+ struct i2c_adapter *i2c;
+ const struct tda665x_config *config;
+
+ u32 frequency;
+ u32 bandwidth;
+};
+
+static int tda665x_read(struct tda665x_state *state, u8 *buf)
+{
+ const struct tda665x_config *config = state->config;
+ int err = 0;
+ struct i2c_msg msg = { .addr = config->addr, .flags = I2C_M_RD, .buf = buf, .len = 2 };
+
+ err = i2c_transfer(state->i2c, &msg, 1);
+ if (err != 1)
+ goto exit;
+
+ return err;
+exit:
+ printk(KERN_ERR "%s: I/O Error err=<%d>\n", __func__, err);
+ return err;
+}
+
+static int tda665x_write(struct tda665x_state *state, u8 *buf, u8 length)
+{
+ const struct tda665x_config *config = state->config;
+ int err = 0;
+ struct i2c_msg msg = { .addr = config->addr, .flags = 0, .buf = buf, .len = length };
+
+ err = i2c_transfer(state->i2c, &msg, 1);
+ if (err != 1)
+ goto exit;
+
+ return err;
+exit:
+ printk(KERN_ERR "%s: I/O Error err=<%d>\n", __func__, err);
+ return err;
+}
+
+static int tda665x_get_state(struct dvb_frontend *fe,
+ enum tuner_param param,
+ struct tuner_state *tstate)
+{
+ struct tda665x_state *state = fe->tuner_priv;
+ int err = 0;
+
+ switch (param) {
+ case DVBFE_TUNER_FREQUENCY:
+ tstate->frequency = state->frequency;
+ break;
+ case DVBFE_TUNER_BANDWIDTH:
+ break;
+ default:
+ printk(KERN_ERR "%s: Unknown parameter (param=%d)\n", __func__, param);
+ err = -EINVAL;
+ break;
+ }
+
+ return err;
+}
+
+static int tda665x_get_status(struct dvb_frontend *fe, u32 *status)
+{
+ struct tda665x_state *state = fe->tuner_priv;
+ u8 result = 0;
+ int err = 0;
+
+ *status = 0;
+
+ err = tda665x_read(state, &result);
+ if (err < 0)
+ goto exit;
+
+ if ((result >> 6) & 0x01) {
+ printk(KERN_DEBUG "%s: Tuner Phase Locked\n", __func__);
+ *status = 1;
+ }
+
+ return err;
+exit:
+ printk(KERN_ERR "%s: I/O Error\n", __func__);
+ return err;
+}
+
+static int tda665x_set_state(struct dvb_frontend *fe,
+ enum tuner_param param,
+ struct tuner_state *tstate)
+{
+ struct tda665x_state *state = fe->tuner_priv;
+ const struct tda665x_config *config = state->config;
+ u32 frequency, status = 0;
+ u8 buf[4];
+ int err = 0;
+
+ if (param & DVBFE_TUNER_FREQUENCY) {
+
+ frequency = tstate->frequency;
+ if ((frequency < config->frequency_max) || (frequency > config->frequency_min)) {
+ printk(KERN_ERR "%s: Frequency beyond limits, frequency=%d\n", __func__, frequency);
+ return -EINVAL;
+ }
+
+ frequency += config->frequency_offst;
+ frequency *= config->ref_multiplier;
+ frequency += config->ref_divider >> 1;
+ frequency /= config->ref_divider;
+
+ buf[0] = (u8) (frequency & 0x7f00) >> 8;
+ buf[1] = (u8) (frequency & 0x00ff) >> 0;
+ buf[2] = 0x80 | 0x40 | 0x02;
+ buf[3] = 0x00;
+
+ /* restore frequency */
+ frequency = tstate->frequency;
+
+ if (frequency < 153000000) {
+ /* VHF-L */
+ buf[3] |= 0x01; /* fc, Low Band, 47 - 153 MHz */
+ if (frequency < 68000000)
+ buf[3] |= 0x40; /* 83uA */
+ if (frequency < 1040000000)
+ buf[3] |= 0x60; /* 122uA */
+ if (frequency < 1250000000)
+ buf[3] |= 0x80; /* 163uA */
+ else
+ buf[3] |= 0xa0; /* 254uA */
+ } else if (frequency < 438000000) {
+ /* VHF-H */
+ buf[3] |= 0x02; /* fc, Mid Band, 153 - 438 MHz */
+ if (frequency < 230000000)
+ buf[3] |= 0x40;
+ if (frequency < 300000000)
+ buf[3] |= 0x60;
+ else
+ buf[3] |= 0x80;
+ } else {
+ /* UHF */
+ buf[3] |= 0x04; /* fc, High Band, 438 - 862 MHz */
+ if (frequency < 470000000)
+ buf[3] |= 0x60;
+ if (frequency < 526000000)
+ buf[3] |= 0x80;
+ else
+ buf[3] |= 0xa0;
+ }
+
+ /* Set params */
+ err = tda665x_write(state, buf, 5);
+ if (err < 0)
+ goto exit;
+
+ /* sleep for some time */
+ printk(KERN_DEBUG "%s: Waiting to Phase LOCK\n", __func__);
+ msleep(20);
+ /* check status */
+ err = tda665x_get_status(fe, &status);
+ if (err < 0)
+ goto exit;
+
+ if (status == 1) {
+ printk(KERN_DEBUG "%s: Tuner Phase locked: status=%d\n", __func__, status);
+ state->frequency = frequency; /* cache successful state */
+ } else {
+ printk(KERN_ERR "%s: No Phase lock: status=%d\n", __func__, status);
+ }
+ } else {
+ printk(KERN_ERR "%s: Unknown parameter (param=%d)\n", __func__, param);
+ return -EINVAL;
+ }
+
+ return 0;
+exit:
+ printk(KERN_ERR "%s: I/O Error\n", __func__);
+ return err;
+}
+
+static int tda665x_release(struct dvb_frontend *fe)
+{
+ struct tda665x_state *state = fe->tuner_priv;
+
+ fe->tuner_priv = NULL;
+ kfree(state);
+ return 0;
+}
+
+static struct dvb_tuner_ops tda665x_ops = {
+
+ .set_state = tda665x_set_state,
+ .get_state = tda665x_get_state,
+ .get_status = tda665x_get_status,
+ .release = tda665x_release
+};
+
+struct dvb_frontend *tda665x_attach(struct dvb_frontend *fe,
+ const struct tda665x_config *config,
+ struct i2c_adapter *i2c)
+{
+ struct tda665x_state *state = NULL;
+ struct dvb_tuner_info *info;
+
+ state = kzalloc(sizeof(struct tda665x_state), GFP_KERNEL);
+ if (state == NULL)
+ goto exit;
+
+ state->config = config;
+ state->i2c = i2c;
+ state->fe = fe;
+ fe->tuner_priv = state;
+ fe->ops.tuner_ops = tda665x_ops;
+ info = &fe->ops.tuner_ops.info;
+
+ memcpy(info->name, config->name, sizeof(config->name));
+ info->frequency_min = config->frequency_min;
+ info->frequency_max = config->frequency_max;
+ info->frequency_step = config->frequency_offst;
+
+ printk(KERN_DEBUG "%s: Attaching TDA665x (%s) tuner\n", __func__, info->name);
+
+ return fe;
+
+exit:
+ kfree(state);
+ return NULL;
+}
+EXPORT_SYMBOL(tda665x_attach);
+
+MODULE_DESCRIPTION("TDA665x driver");
+MODULE_AUTHOR("Manu Abraham");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/frontends/tda665x.h b/drivers/media/dvb/frontends/tda665x.h
new file mode 100644
index 000000000000..ec7927aa75ae
--- /dev/null
+++ b/drivers/media/dvb/frontends/tda665x.h
@@ -0,0 +1,52 @@
+/*
+ TDA665x tuner driver
+ Copyright (C) Manu Abraham (abraham.manu@gmail.com)
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#ifndef __TDA665x_H
+#define __TDA665x_H
+
+struct tda665x_config {
+ char name[128];
+
+ u8 addr;
+ u32 frequency_min;
+ u32 frequency_max;
+ u32 frequency_offst;
+ u32 ref_multiplier;
+ u32 ref_divider;
+};
+
+#if defined(CONFIG_DVB_TDA665x) || (defined(CONFIG_DVB_TDA665x_MODULE) && defined(MODULE))
+
+extern struct dvb_frontend *tda665x_attach(struct dvb_frontend *fe,
+ const struct tda665x_config *config,
+ struct i2c_adapter *i2c);
+
+#else
+
+static inline struct dvb_frontend *tda665x_attach(struct dvb_frontend *fe,
+ const struct tda665x_config *config,
+ struct i2c_adapter *i2c)
+{
+ printk(KERN_WARNING "%s: Driver disabled by Kconfig\n", __func__);
+ return NULL;
+}
+
+#endif /* CONFIG_DVB_TDA665x */
+
+#endif /* __TDA665x_H */
diff --git a/drivers/media/dvb/mantis/Kconfig b/drivers/media/dvb/mantis/Kconfig
new file mode 100644
index 000000000000..f9219cd7bb0c
--- /dev/null
+++ b/drivers/media/dvb/mantis/Kconfig
@@ -0,0 +1,32 @@
+config MANTIS_CORE
+ tristate "Mantis/Hopper PCI bridge based devices"
+ depends on PCI && I2C
+
+ help
+ Support for PCI cards based on the Mantis and Hopper PCi bridge.
+
+ Say Y if you own such a device and want to use it.
+
+config DVB_MANTIS
+ tristate "MANTIS based cards"
+ depends on MANTIS_CORE && DVB_CORE && PCI && I2C
+ select DVB_MB86A16
+ select DVB_ZL10353
+ select DVB_STV0299
+ select DVB_PLL
+ help
+ Support for PCI cards based on the Mantis PCI bridge.
+ Say Y when you have a Mantis based DVB card and want to use it.
+
+ If unsure say N.
+
+config DVB_HOPPER
+ tristate "HOPPER based cards"
+ depends on MANTIS_CORE && DVB_CORE && PCI && I2C
+ select DVB_ZL10353
+ select DVB_PLL
+ help
+ Support for PCI cards based on the Hopper PCI bridge.
+ Say Y when you have a Hopper based DVB card and want to use it.
+
+ If unsure say N
diff --git a/drivers/media/dvb/mantis/Makefile b/drivers/media/dvb/mantis/Makefile
new file mode 100644
index 000000000000..98dc5cd258ac
--- /dev/null
+++ b/drivers/media/dvb/mantis/Makefile
@@ -0,0 +1,28 @@
+mantis_core-objs := mantis_ioc.o \
+ mantis_uart.o \
+ mantis_dma.o \
+ mantis_pci.o \
+ mantis_i2c.o \
+ mantis_dvb.o \
+ mantis_evm.o \
+ mantis_hif.o \
+ mantis_ca.o \
+ mantis_pcmcia.o \
+ mantis_input.o
+
+mantis-objs := mantis_cards.o \
+ mantis_vp1033.o \
+ mantis_vp1034.o \
+ mantis_vp1041.o \
+ mantis_vp2033.o \
+ mantis_vp2040.o \
+ mantis_vp3030.o
+
+hopper-objs := hopper_cards.o \
+ hopper_vp3028.o
+
+obj-$(CONFIG_MANTIS_CORE) += mantis_core.o
+obj-$(CONFIG_DVB_MANTIS) += mantis.o
+obj-$(CONFIG_DVB_HOPPER) += hopper.o
+
+EXTRA_CFLAGS = -Idrivers/media/dvb/dvb-core/ -Idrivers/media/dvb/frontends/
diff --git a/drivers/media/dvb/mantis/hopper_cards.c b/drivers/media/dvb/mantis/hopper_cards.c
new file mode 100644
index 000000000000..d073c61e3c0d
--- /dev/null
+++ b/drivers/media/dvb/mantis/hopper_cards.c
@@ -0,0 +1,275 @@
+/*
+ Hopper PCI bridge driver
+
+ Copyright (C) Manu Abraham (abraham.manu@gmail.com)
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/kernel.h>
+#include <linux/pci.h>
+#include <asm/irq.h>
+#include <linux/interrupt.h>
+
+#include "dmxdev.h"
+#include "dvbdev.h"
+#include "dvb_demux.h"
+#include "dvb_frontend.h"
+#include "dvb_net.h"
+
+#include "mantis_common.h"
+#include "hopper_vp3028.h"
+#include "mantis_dma.h"
+#include "mantis_dvb.h"
+#include "mantis_uart.h"
+#include "mantis_ioc.h"
+#include "mantis_pci.h"
+#include "mantis_i2c.h"
+#include "mantis_reg.h"
+
+static unsigned int verbose;
+module_param(verbose, int, 0644);
+MODULE_PARM_DESC(verbose, "verbose startup messages, default is 1 (yes)");
+
+#define DRIVER_NAME "Hopper"
+
+static char *label[10] = {
+ "DMA",
+ "IRQ-0",
+ "IRQ-1",
+ "OCERR",
+ "PABRT",
+ "RIPRR",
+ "PPERR",
+ "FTRGT",
+ "RISCI",
+ "RACK"
+};
+
+static int devs;
+
+static irqreturn_t hopper_irq_handler(int irq, void *dev_id)
+{
+ u32 stat = 0, mask = 0, lstat = 0, mstat = 0;
+ u32 rst_stat = 0, rst_mask = 0;
+
+ struct mantis_pci *mantis;
+ struct mantis_ca *ca;
+
+ mantis = (struct mantis_pci *) dev_id;
+ if (unlikely(mantis == NULL)) {
+ dprintk(MANTIS_ERROR, 1, "Mantis == NULL");
+ return IRQ_NONE;
+ }
+ ca = mantis->mantis_ca;
+
+ stat = mmread(MANTIS_INT_STAT);
+ mask = mmread(MANTIS_INT_MASK);
+ mstat = lstat = stat & ~MANTIS_INT_RISCSTAT;
+ if (!(stat & mask))
+ return IRQ_NONE;
+
+ rst_mask = MANTIS_GPIF_WRACK |
+ MANTIS_GPIF_OTHERR |
+ MANTIS_SBUF_WSTO |
+ MANTIS_GPIF_EXTIRQ;
+
+ rst_stat = mmread(MANTIS_GPIF_STATUS);
+ rst_stat &= rst_mask;
+ mmwrite(rst_stat, MANTIS_GPIF_STATUS);
+
+ mantis->mantis_int_stat = stat;
+ mantis->mantis_int_mask = mask;
+ dprintk(MANTIS_DEBUG, 0, "\n-- Stat=<%02x> Mask=<%02x> --", stat, mask);
+ if (stat & MANTIS_INT_RISCEN) {
+ dprintk(MANTIS_DEBUG, 0, "<%s>", label[0]);
+ }
+ if (stat & MANTIS_INT_IRQ0) {
+ dprintk(MANTIS_DEBUG, 0, "<%s>", label[1]);
+ mantis->gpif_status = rst_stat;
+ wake_up(&ca->hif_write_wq);
+ schedule_work(&ca->hif_evm_work);
+ }
+ if (stat & MANTIS_INT_IRQ1) {
+ dprintk(MANTIS_DEBUG, 0, "<%s>", label[2]);
+ schedule_work(&mantis->uart_work);
+ }
+ if (stat & MANTIS_INT_OCERR) {
+ dprintk(MANTIS_DEBUG, 0, "<%s>", label[3]);
+ }
+ if (stat & MANTIS_INT_PABORT) {
+ dprintk(MANTIS_DEBUG, 0, "<%s>", label[4]);
+ }
+ if (stat & MANTIS_INT_RIPERR) {
+ dprintk(MANTIS_DEBUG, 0, "<%s>", label[5]);
+ }
+ if (stat & MANTIS_INT_PPERR) {
+ dprintk(MANTIS_DEBUG, 0, "<%s>", label[6]);
+ }
+ if (stat & MANTIS_INT_FTRGT) {
+ dprintk(MANTIS_DEBUG, 0, "<%s>", label[7]);
+ }
+ if (stat & MANTIS_INT_RISCI) {
+ dprintk(MANTIS_DEBUG, 0, "<%s>", label[8]);
+ mantis->finished_block = (stat & MANTIS_INT_RISCSTAT) >> 28;
+ tasklet_schedule(&mantis->tasklet);
+ }
+ if (stat & MANTIS_INT_I2CDONE) {
+ dprintk(MANTIS_DEBUG, 0, "<%s>", label[9]);
+ wake_up(&mantis->i2c_wq);
+ }
+ mmwrite(stat, MANTIS_INT_STAT);
+ stat &= ~(MANTIS_INT_RISCEN | MANTIS_INT_I2CDONE |
+ MANTIS_INT_I2CRACK | MANTIS_INT_PCMCIA7 |
+ MANTIS_INT_PCMCIA6 | MANTIS_INT_PCMCIA5 |
+ MANTIS_INT_PCMCIA4 | MANTIS_INT_PCMCIA3 |
+ MANTIS_INT_PCMCIA2 | MANTIS_INT_PCMCIA1 |
+ MANTIS_INT_PCMCIA0 | MANTIS_INT_IRQ1 |
+ MANTIS_INT_IRQ0 | MANTIS_INT_OCERR |
+ MANTIS_INT_PABORT | MANTIS_INT_RIPERR |
+ MANTIS_INT_PPERR | MANTIS_INT_FTRGT |
+ MANTIS_INT_RISCI);
+
+ if (stat)
+ dprintk(MANTIS_DEBUG, 0, "<Unknown> Stat=<%02x> Mask=<%02x>", stat, mask);
+
+ dprintk(MANTIS_DEBUG, 0, "\n");
+ return IRQ_HANDLED;
+}
+
+static int __devinit hopper_pci_probe(struct pci_dev *pdev, const struct pci_device_id *pci_id)
+{
+ struct mantis_pci *mantis;
+ struct mantis_hwconfig *config;
+ int err = 0;
+
+ mantis = kzalloc(sizeof(struct mantis_pci), GFP_KERNEL);
+ if (mantis == NULL) {
+ printk(KERN_ERR "%s ERROR: Out of memory\n", __func__);
+ err = -ENOMEM;
+ goto fail0;
+ }
+
+ mantis->num = devs;
+ mantis->verbose = verbose;
+ mantis->pdev = pdev;
+ config = (struct mantis_hwconfig *) pci_id->driver_data;
+ config->irq_handler = &hopper_irq_handler;
+ mantis->hwconfig = config;
+
+ err = mantis_pci_init(mantis);
+ if (err) {
+ dprintk(MANTIS_ERROR, 1, "ERROR: Mantis PCI initialization failed <%d>", err);
+ goto fail1;
+ }
+
+ err = mantis_stream_control(mantis, STREAM_TO_HIF);
+ if (err < 0) {
+ dprintk(MANTIS_ERROR, 1, "ERROR: Mantis stream control failed <%d>", err);
+ goto fail1;
+ }
+
+ err = mantis_i2c_init(mantis);
+ if (err < 0) {
+ dprintk(MANTIS_ERROR, 1, "ERROR: Mantis I2C initialization failed <%d>", err);
+ goto fail2;
+ }
+
+ err = mantis_get_mac(mantis);
+ if (err < 0) {
+ dprintk(MANTIS_ERROR, 1, "ERROR: Mantis MAC address read failed <%d>", err);
+ goto fail2;
+ }
+
+ err = mantis_dma_init(mantis);
+ if (err < 0) {
+ dprintk(MANTIS_ERROR, 1, "ERROR: Mantis DMA initialization failed <%d>", err);
+ goto fail3;
+ }
+
+ err = mantis_dvb_init(mantis);
+ if (err < 0) {
+ dprintk(MANTIS_ERROR, 1, "ERROR: Mantis DVB initialization failed <%d>", err);
+ goto fail4;
+ }
+ devs++;
+
+ return err;
+
+fail4:
+ dprintk(MANTIS_ERROR, 1, "ERROR: Mantis DMA exit! <%d>", err);
+ mantis_dma_exit(mantis);
+
+fail3:
+ dprintk(MANTIS_ERROR, 1, "ERROR: Mantis I2C exit! <%d>", err);
+ mantis_i2c_exit(mantis);
+
+fail2:
+ dprintk(MANTIS_ERROR, 1, "ERROR: Mantis PCI exit! <%d>", err);
+ mantis_pci_exit(mantis);
+
+fail1:
+ dprintk(MANTIS_ERROR, 1, "ERROR: Mantis free! <%d>", err);
+ kfree(mantis);
+
+fail0:
+ return err;
+}
+
+static void __devexit hopper_pci_remove(struct pci_dev *pdev)
+{
+ struct mantis_pci *mantis = pci_get_drvdata(pdev);
+
+ if (mantis) {
+ mantis_dvb_exit(mantis);
+ mantis_dma_exit(mantis);
+ mantis_i2c_exit(mantis);
+ mantis_pci_exit(mantis);
+ kfree(mantis);
+ }
+ return;
+
+}
+
+static struct pci_device_id hopper_pci_table[] = {
+ MAKE_ENTRY(TWINHAN_TECHNOLOGIES, MANTIS_VP_3028_DVB_T, &vp3028_config),
+ { }
+};
+
+static struct pci_driver hopper_pci_driver = {
+ .name = DRIVER_NAME,
+ .id_table = hopper_pci_table,
+ .probe = hopper_pci_probe,
+ .remove = hopper_pci_remove,
+};
+
+static int __devinit hopper_init(void)
+{
+ return pci_register_driver(&hopper_pci_driver);
+}
+
+static void __devexit hopper_exit(void)
+{
+ return pci_unregister_driver(&hopper_pci_driver);
+}
+
+module_init(hopper_init);
+module_exit(hopper_exit);
+
+MODULE_DESCRIPTION("HOPPER driver");
+MODULE_AUTHOR("Manu Abraham");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/mantis/hopper_vp3028.c b/drivers/media/dvb/mantis/hopper_vp3028.c
new file mode 100644
index 000000000000..96674c78e86b
--- /dev/null
+++ b/drivers/media/dvb/mantis/hopper_vp3028.c
@@ -0,0 +1,88 @@
+/*
+ Hopper VP-3028 driver
+
+ Copyright (C) Manu Abraham (abraham.manu@gmail.com)
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include <linux/signal.h>
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+
+#include "dmxdev.h"
+#include "dvbdev.h"
+#include "dvb_demux.h"
+#include "dvb_frontend.h"
+#include "dvb_net.h"
+
+#include "zl10353.h"
+#include "mantis_common.h"
+#include "mantis_ioc.h"
+#include "mantis_dvb.h"
+#include "hopper_vp3028.h"
+
+struct zl10353_config hopper_vp3028_config = {
+ .demod_address = 0x0f,
+};
+
+#define MANTIS_MODEL_NAME "VP-3028"
+#define MANTIS_DEV_TYPE "DVB-T"
+
+static int vp3028_frontend_init(struct mantis_pci *mantis, struct dvb_frontend *fe)
+{
+ struct i2c_adapter *adapter = &mantis->adapter;
+ struct mantis_hwconfig *config = mantis->hwconfig;
+ int err = 0;
+
+ gpio_set_bits(mantis, config->reset, 0);
+ msleep(100);
+ err = mantis_frontend_power(mantis, POWER_ON);
+ msleep(100);
+ gpio_set_bits(mantis, config->reset, 1);
+
+ err = mantis_frontend_power(mantis, POWER_ON);
+ if (err == 0) {
+ msleep(250);
+ dprintk(MANTIS_ERROR, 1, "Probing for 10353 (DVB-T)");
+ fe = zl10353_attach(&hopper_vp3028_config, adapter);
+
+ if (!fe)
+ return -1;
+ } else {
+ dprintk(MANTIS_ERROR, 1, "Frontend on <%s> POWER ON failed! <%d>",
+ adapter->name,
+ err);
+
+ return -EIO;
+ }
+ dprintk(MANTIS_ERROR, 1, "Done!");
+
+ return 0;
+}
+
+struct mantis_hwconfig vp3028_config = {
+ .model_name = MANTIS_MODEL_NAME,
+ .dev_type = MANTIS_DEV_TYPE,
+ .ts_size = MANTIS_TS_188,
+
+ .baud_rate = MANTIS_BAUD_9600,
+ .parity = MANTIS_PARITY_NONE,
+ .bytes = 0,
+
+ .frontend_init = vp3028_frontend_init,
+ .power = GPIF_A00,
+ .reset = GPIF_A03,
+};
diff --git a/drivers/media/dvb/mantis/hopper_vp3028.h b/drivers/media/dvb/mantis/hopper_vp3028.h
new file mode 100644
index 000000000000..57239498bc87
--- /dev/null
+++ b/drivers/media/dvb/mantis/hopper_vp3028.h
@@ -0,0 +1,30 @@
+/*
+ Hopper VP-3028 driver
+
+ Copyright (C) Manu Abraham (abraham.manu@gmail.com)
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#ifndef __MANTIS_VP3028_H
+#define __MANTIS_VP3028_H
+
+#include "mantis_common.h"
+
+#define MANTIS_VP_3028_DVB_T 0x0028
+
+extern struct mantis_hwconfig vp3028_config;
+
+#endif /* __MANTIS_VP3028_H */
diff --git a/drivers/media/dvb/mantis/mantis_ca.c b/drivers/media/dvb/mantis/mantis_ca.c
new file mode 100644
index 000000000000..403ce043d00e
--- /dev/null
+++ b/drivers/media/dvb/mantis/mantis_ca.c
@@ -0,0 +1,207 @@
+/*
+ Mantis PCI bridge driver
+
+ Copyright (C) Manu Abraham (abraham.manu@gmail.com)
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include <linux/signal.h>
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+
+#include "dmxdev.h"
+#include "dvbdev.h"
+#include "dvb_demux.h"
+#include "dvb_frontend.h"
+#include "dvb_net.h"
+
+#include "mantis_common.h"
+#include "mantis_link.h"
+#include "mantis_hif.h"
+#include "mantis_reg.h"
+
+#include "mantis_ca.h"
+
+static int mantis_ca_read_attr_mem(struct dvb_ca_en50221 *en50221, int slot, int addr)
+{
+ struct mantis_ca *ca = en50221->data;
+ struct mantis_pci *mantis = ca->ca_priv;
+
+ dprintk(MANTIS_DEBUG, 1, "Slot(%d): Request Attribute Mem Read", slot);
+
+ if (slot != 0)
+ return -EINVAL;
+
+ return mantis_hif_read_mem(ca, addr);
+}
+
+static int mantis_ca_write_attr_mem(struct dvb_ca_en50221 *en50221, int slot, int addr, u8 data)
+{
+ struct mantis_ca *ca = en50221->data;
+ struct mantis_pci *mantis = ca->ca_priv;
+
+ dprintk(MANTIS_DEBUG, 1, "Slot(%d): Request Attribute Mem Write", slot);
+
+ if (slot != 0)
+ return -EINVAL;
+
+ return mantis_hif_write_mem(ca, addr, data);
+}
+
+static int mantis_ca_read_cam_ctl(struct dvb_ca_en50221 *en50221, int slot, u8 addr)
+{
+ struct mantis_ca *ca = en50221->data;
+ struct mantis_pci *mantis = ca->ca_priv;
+
+ dprintk(MANTIS_DEBUG, 1, "Slot(%d): Request CAM control Read", slot);
+
+ if (slot != 0)
+ return -EINVAL;
+
+ return mantis_hif_read_iom(ca, addr);
+}
+
+static int mantis_ca_write_cam_ctl(struct dvb_ca_en50221 *en50221, int slot, u8 addr, u8 data)
+{
+ struct mantis_ca *ca = en50221->data;
+ struct mantis_pci *mantis = ca->ca_priv;
+
+ dprintk(MANTIS_DEBUG, 1, "Slot(%d): Request CAM control Write", slot);
+
+ if (slot != 0)
+ return -EINVAL;
+
+ return mantis_hif_write_iom(ca, addr, data);
+}
+
+static int mantis_ca_slot_reset(struct dvb_ca_en50221 *en50221, int slot)
+{
+ struct mantis_ca *ca = en50221->data;
+ struct mantis_pci *mantis = ca->ca_priv;
+
+ dprintk(MANTIS_DEBUG, 1, "Slot(%d): Slot RESET", slot);
+ udelay(500); /* Wait.. */
+ mmwrite(0xda, MANTIS_PCMCIA_RESET); /* Leading edge assert */
+ udelay(500);
+ mmwrite(0x00, MANTIS_PCMCIA_RESET); /* Trailing edge deassert */
+ msleep(1000);
+ dvb_ca_en50221_camready_irq(&ca->en50221, 0);
+
+ return 0;
+}
+
+static int mantis_ca_slot_shutdown(struct dvb_ca_en50221 *en50221, int slot)
+{
+ struct mantis_ca *ca = en50221->data;
+ struct mantis_pci *mantis = ca->ca_priv;
+
+ dprintk(MANTIS_DEBUG, 1, "Slot(%d): Slot shutdown", slot);
+
+ return 0;
+}
+
+static int mantis_ts_control(struct dvb_ca_en50221 *en50221, int slot)
+{
+ struct mantis_ca *ca = en50221->data;
+ struct mantis_pci *mantis = ca->ca_priv;
+
+ dprintk(MANTIS_DEBUG, 1, "Slot(%d): TS control", slot);
+/* mantis_set_direction(mantis, 1); */ /* Enable TS through CAM */
+
+ return 0;
+}
+
+static int mantis_slot_status(struct dvb_ca_en50221 *en50221, int slot, int open)
+{
+ struct mantis_ca *ca = en50221->data;
+ struct mantis_pci *mantis = ca->ca_priv;
+
+ dprintk(MANTIS_DEBUG, 1, "Slot(%d): Poll Slot status", slot);
+
+ if (ca->slot_state == MODULE_INSERTED) {
+ dprintk(MANTIS_DEBUG, 1, "CA Module present and ready");
+ return DVB_CA_EN50221_POLL_CAM_PRESENT | DVB_CA_EN50221_POLL_CAM_READY;
+ } else {
+ dprintk(MANTIS_DEBUG, 1, "CA Module not present or not ready");
+ }
+
+ return 0;
+}
+
+int mantis_ca_init(struct mantis_pci *mantis)
+{
+ struct dvb_adapter *dvb_adapter = &mantis->dvb_adapter;
+ struct mantis_ca *ca;
+ int ca_flags = 0, result;
+
+ dprintk(MANTIS_DEBUG, 1, "Initializing Mantis CA");
+ ca = kzalloc(sizeof(struct mantis_ca), GFP_KERNEL);
+ if (!ca) {
+ dprintk(MANTIS_ERROR, 1, "Out of memory!, exiting ..");
+ result = -ENOMEM;
+ goto err;
+ }
+
+ ca->ca_priv = mantis;
+ mantis->mantis_ca = ca;
+ ca_flags = DVB_CA_EN50221_FLAG_IRQ_CAMCHANGE;
+ /* register CA interface */
+ ca->en50221.owner = THIS_MODULE;
+ ca->en50221.read_attribute_mem = mantis_ca_read_attr_mem;
+ ca->en50221.write_attribute_mem = mantis_ca_write_attr_mem;
+ ca->en50221.read_cam_control = mantis_ca_read_cam_ctl;
+ ca->en50221.write_cam_control = mantis_ca_write_cam_ctl;
+ ca->en50221.slot_reset = mantis_ca_slot_reset;
+ ca->en50221.slot_shutdown = mantis_ca_slot_shutdown;
+ ca->en50221.slot_ts_enable = mantis_ts_control;
+ ca->en50221.poll_slot_status = mantis_slot_status;
+ ca->en50221.data = ca;
+
+ mutex_init(&ca->ca_lock);
+
+ init_waitqueue_head(&ca->hif_data_wq);
+ init_waitqueue_head(&ca->hif_opdone_wq);
+ init_waitqueue_head(&ca->hif_write_wq);
+
+ dprintk(MANTIS_ERROR, 1, "Registering EN50221 device");
+ result = dvb_ca_en50221_init(dvb_adapter, &ca->en50221, ca_flags, 1);
+ if (result != 0) {
+ dprintk(MANTIS_ERROR, 1, "EN50221: Initialization failed <%d>", result);
+ goto err;
+ }
+ dprintk(MANTIS_ERROR, 1, "Registered EN50221 device");
+ mantis_evmgr_init(ca);
+ return 0;
+err:
+ kfree(ca);
+ return result;
+}
+EXPORT_SYMBOL_GPL(mantis_ca_init);
+
+void mantis_ca_exit(struct mantis_pci *mantis)
+{
+ struct mantis_ca *ca = mantis->mantis_ca;
+
+ dprintk(MANTIS_DEBUG, 1, "Mantis CA exit");
+
+ mantis_evmgr_exit(ca);
+ dprintk(MANTIS_ERROR, 1, "Unregistering EN50221 device");
+ if (ca)
+ dvb_ca_en50221_release(&ca->en50221);
+
+ kfree(ca);
+}
+EXPORT_SYMBOL_GPL(mantis_ca_exit);
diff --git a/drivers/media/dvb/mantis/mantis_ca.h b/drivers/media/dvb/mantis/mantis_ca.h
new file mode 100644
index 000000000000..dc63e55f7eca
--- /dev/null
+++ b/drivers/media/dvb/mantis/mantis_ca.h
@@ -0,0 +1,27 @@
+/*
+ Mantis PCI bridge driver
+
+ Copyright (C) Manu Abraham (abraham.manu@gmail.com)
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#ifndef __MANTIS_CA_H
+#define __MANTIS_CA_H
+
+extern int mantis_ca_init(struct mantis_pci *mantis);
+extern void mantis_ca_exit(struct mantis_pci *mantis);
+
+#endif /* __MANTIS_CA_H */
diff --git a/drivers/media/dvb/mantis/mantis_cards.c b/drivers/media/dvb/mantis/mantis_cards.c
new file mode 100644
index 000000000000..16f1708fd3bc
--- /dev/null
+++ b/drivers/media/dvb/mantis/mantis_cards.c
@@ -0,0 +1,305 @@
+/*
+ Mantis PCI bridge driver
+
+ Copyright (C) Manu Abraham (abraham.manu@gmail.com)
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/kernel.h>
+#include <linux/pci.h>
+#include <asm/irq.h>
+#include <linux/interrupt.h>
+
+#include "dmxdev.h"
+#include "dvbdev.h"
+#include "dvb_demux.h"
+#include "dvb_frontend.h"
+#include "dvb_net.h"
+
+#include "mantis_common.h"
+
+#include "mantis_vp1033.h"
+#include "mantis_vp1034.h"
+#include "mantis_vp1041.h"
+#include "mantis_vp2033.h"
+#include "mantis_vp2040.h"
+#include "mantis_vp3030.h"
+
+#include "mantis_dma.h"
+#include "mantis_ca.h"
+#include "mantis_dvb.h"
+#include "mantis_uart.h"
+#include "mantis_ioc.h"
+#include "mantis_pci.h"
+#include "mantis_i2c.h"
+#include "mantis_reg.h"
+
+static unsigned int verbose;
+module_param(verbose, int, 0644);
+MODULE_PARM_DESC(verbose, "verbose startup messages, default is 1 (yes)");
+
+static int devs;
+
+#define DRIVER_NAME "Mantis"
+
+static char *label[10] = {
+ "DMA",
+ "IRQ-0",
+ "IRQ-1",
+ "OCERR",
+ "PABRT",
+ "RIPRR",
+ "PPERR",
+ "FTRGT",
+ "RISCI",
+ "RACK"
+};
+
+static irqreturn_t mantis_irq_handler(int irq, void *dev_id)
+{
+ u32 stat = 0, mask = 0, lstat = 0, mstat = 0;
+ u32 rst_stat = 0, rst_mask = 0;
+
+ struct mantis_pci *mantis;
+ struct mantis_ca *ca;
+
+ mantis = (struct mantis_pci *) dev_id;
+ if (unlikely(mantis == NULL)) {
+ dprintk(MANTIS_ERROR, 1, "Mantis == NULL");
+ return IRQ_NONE;
+ }
+ ca = mantis->mantis_ca;
+
+ stat = mmread(MANTIS_INT_STAT);
+ mask = mmread(MANTIS_INT_MASK);
+ mstat = lstat = stat & ~MANTIS_INT_RISCSTAT;
+ if (!(stat & mask))
+ return IRQ_NONE;
+
+ rst_mask = MANTIS_GPIF_WRACK |
+ MANTIS_GPIF_OTHERR |
+ MANTIS_SBUF_WSTO |
+ MANTIS_GPIF_EXTIRQ;
+
+ rst_stat = mmread(MANTIS_GPIF_STATUS);
+ rst_stat &= rst_mask;
+ mmwrite(rst_stat, MANTIS_GPIF_STATUS);
+
+ mantis->mantis_int_stat = stat;
+ mantis->mantis_int_mask = mask;
+ dprintk(MANTIS_DEBUG, 0, "\n-- Stat=<%02x> Mask=<%02x> --", stat, mask);
+ if (stat & MANTIS_INT_RISCEN) {
+ dprintk(MANTIS_DEBUG, 0, "<%s>", label[0]);
+ }
+ if (stat & MANTIS_INT_IRQ0) {
+ dprintk(MANTIS_DEBUG, 0, "<%s>", label[1]);
+ mantis->gpif_status = rst_stat;
+ wake_up(&ca->hif_write_wq);
+ schedule_work(&ca->hif_evm_work);
+ }
+ if (stat & MANTIS_INT_IRQ1) {
+ dprintk(MANTIS_DEBUG, 0, "<%s>", label[2]);
+ schedule_work(&mantis->uart_work);
+ }
+ if (stat & MANTIS_INT_OCERR) {
+ dprintk(MANTIS_DEBUG, 0, "<%s>", label[3]);
+ }
+ if (stat & MANTIS_INT_PABORT) {
+ dprintk(MANTIS_DEBUG, 0, "<%s>", label[4]);
+ }
+ if (stat & MANTIS_INT_RIPERR) {
+ dprintk(MANTIS_DEBUG, 0, "<%s>", label[5]);
+ }
+ if (stat & MANTIS_INT_PPERR) {
+ dprintk(MANTIS_DEBUG, 0, "<%s>", label[6]);
+ }
+ if (stat & MANTIS_INT_FTRGT) {
+ dprintk(MANTIS_DEBUG, 0, "<%s>", label[7]);
+ }
+ if (stat & MANTIS_INT_RISCI) {
+ dprintk(MANTIS_DEBUG, 0, "<%s>", label[8]);
+ mantis->finished_block = (stat & MANTIS_INT_RISCSTAT) >> 28;
+ tasklet_schedule(&mantis->tasklet);
+ }
+ if (stat & MANTIS_INT_I2CDONE) {
+ dprintk(MANTIS_DEBUG, 0, "<%s>", label[9]);
+ wake_up(&mantis->i2c_wq);
+ }
+ mmwrite(stat, MANTIS_INT_STAT);
+ stat &= ~(MANTIS_INT_RISCEN | MANTIS_INT_I2CDONE |
+ MANTIS_INT_I2CRACK | MANTIS_INT_PCMCIA7 |
+ MANTIS_INT_PCMCIA6 | MANTIS_INT_PCMCIA5 |
+ MANTIS_INT_PCMCIA4 | MANTIS_INT_PCMCIA3 |
+ MANTIS_INT_PCMCIA2 | MANTIS_INT_PCMCIA1 |
+ MANTIS_INT_PCMCIA0 | MANTIS_INT_IRQ1 |
+ MANTIS_INT_IRQ0 | MANTIS_INT_OCERR |
+ MANTIS_INT_PABORT | MANTIS_INT_RIPERR |
+ MANTIS_INT_PPERR | MANTIS_INT_FTRGT |
+ MANTIS_INT_RISCI);
+
+ if (stat)
+ dprintk(MANTIS_DEBUG, 0, "<Unknown> Stat=<%02x> Mask=<%02x>", stat, mask);
+
+ dprintk(MANTIS_DEBUG, 0, "\n");
+ return IRQ_HANDLED;
+}
+
+static int __devinit mantis_pci_probe(struct pci_dev *pdev, const struct pci_device_id *pci_id)
+{
+ struct mantis_pci *mantis;
+ struct mantis_hwconfig *config;
+ int err = 0;
+
+ mantis = kzalloc(sizeof(struct mantis_pci), GFP_KERNEL);
+ if (mantis == NULL) {
+ printk(KERN_ERR "%s ERROR: Out of memory\n", __func__);
+ err = -ENOMEM;
+ goto fail0;
+ }
+
+ mantis->num = devs;
+ mantis->verbose = verbose;
+ mantis->pdev = pdev;
+ config = (struct mantis_hwconfig *) pci_id->driver_data;
+ config->irq_handler = &mantis_irq_handler;
+ mantis->hwconfig = config;
+
+ err = mantis_pci_init(mantis);
+ if (err) {
+ dprintk(MANTIS_ERROR, 1, "ERROR: Mantis PCI initialization failed <%d>", err);
+ goto fail1;
+ }
+
+ err = mantis_stream_control(mantis, STREAM_TO_HIF);
+ if (err < 0) {
+ dprintk(MANTIS_ERROR, 1, "ERROR: Mantis stream control failed <%d>", err);
+ goto fail1;
+ }
+
+ err = mantis_i2c_init(mantis);
+ if (err < 0) {
+ dprintk(MANTIS_ERROR, 1, "ERROR: Mantis I2C initialization failed <%d>", err);
+ goto fail2;
+ }
+
+ err = mantis_get_mac(mantis);
+ if (err < 0) {
+ dprintk(MANTIS_ERROR, 1, "ERROR: Mantis MAC address read failed <%d>", err);
+ goto fail2;
+ }
+
+ err = mantis_dma_init(mantis);
+ if (err < 0) {
+ dprintk(MANTIS_ERROR, 1, "ERROR: Mantis DMA initialization failed <%d>", err);
+ goto fail3;
+ }
+
+ err = mantis_dvb_init(mantis);
+ if (err < 0) {
+ dprintk(MANTIS_ERROR, 1, "ERROR: Mantis DVB initialization failed <%d>", err);
+ goto fail4;
+ }
+ err = mantis_uart_init(mantis);
+ if (err < 0) {
+ dprintk(MANTIS_ERROR, 1, "ERROR: Mantis UART initialization failed <%d>", err);
+ goto fail6;
+ }
+
+ devs++;
+
+ return err;
+
+
+ dprintk(MANTIS_ERROR, 1, "ERROR: Mantis UART exit! <%d>", err);
+ mantis_uart_exit(mantis);
+
+fail6:
+fail4:
+ dprintk(MANTIS_ERROR, 1, "ERROR: Mantis DMA exit! <%d>", err);
+ mantis_dma_exit(mantis);
+
+fail3:
+ dprintk(MANTIS_ERROR, 1, "ERROR: Mantis I2C exit! <%d>", err);
+ mantis_i2c_exit(mantis);
+
+fail2:
+ dprintk(MANTIS_ERROR, 1, "ERROR: Mantis PCI exit! <%d>", err);
+ mantis_pci_exit(mantis);
+
+fail1:
+ dprintk(MANTIS_ERROR, 1, "ERROR: Mantis free! <%d>", err);
+ kfree(mantis);
+
+fail0:
+ return err;
+}
+
+static void __devexit mantis_pci_remove(struct pci_dev *pdev)
+{
+ struct mantis_pci *mantis = pci_get_drvdata(pdev);
+
+ if (mantis) {
+
+ mantis_uart_exit(mantis);
+ mantis_dvb_exit(mantis);
+ mantis_dma_exit(mantis);
+ mantis_i2c_exit(mantis);
+ mantis_pci_exit(mantis);
+ kfree(mantis);
+ }
+ return;
+}
+
+static struct pci_device_id mantis_pci_table[] = {
+ MAKE_ENTRY(TWINHAN_TECHNOLOGIES, MANTIS_VP_1033_DVB_S, &vp1033_config),
+ MAKE_ENTRY(TWINHAN_TECHNOLOGIES, MANTIS_VP_1034_DVB_S, &vp1034_config),
+ MAKE_ENTRY(TWINHAN_TECHNOLOGIES, MANTIS_VP_1041_DVB_S2, &vp1041_config),
+ MAKE_ENTRY(TECHNISAT, SKYSTAR_HD2_10, &vp1041_config),
+ MAKE_ENTRY(TECHNISAT, SKYSTAR_HD2_20, &vp1041_config),
+ MAKE_ENTRY(TERRATEC, CINERGY_S2_PCI_HD, &vp1041_config),
+ MAKE_ENTRY(TWINHAN_TECHNOLOGIES, MANTIS_VP_2033_DVB_C, &vp2033_config),
+ MAKE_ENTRY(TWINHAN_TECHNOLOGIES, MANTIS_VP_2040_DVB_C, &vp2040_config),
+ MAKE_ENTRY(TECHNISAT, CABLESTAR_HD2, &vp2040_config),
+ MAKE_ENTRY(TERRATEC, CINERGY_C, &vp2033_config),
+ MAKE_ENTRY(TWINHAN_TECHNOLOGIES, MANTIS_VP_3030_DVB_T, &vp3030_config),
+ { }
+};
+
+static struct pci_driver mantis_pci_driver = {
+ .name = DRIVER_NAME,
+ .id_table = mantis_pci_table,
+ .probe = mantis_pci_probe,
+ .remove = mantis_pci_remove,
+};
+
+static int __devinit mantis_init(void)
+{
+ return pci_register_driver(&mantis_pci_driver);
+}
+
+static void __devexit mantis_exit(void)
+{
+ return pci_unregister_driver(&mantis_pci_driver);
+}
+
+module_init(mantis_init);
+module_exit(mantis_exit);
+
+MODULE_DESCRIPTION("MANTIS driver");
+MODULE_AUTHOR("Manu Abraham");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/mantis/mantis_common.h b/drivers/media/dvb/mantis/mantis_common.h
new file mode 100644
index 000000000000..d0b645a483c9
--- /dev/null
+++ b/drivers/media/dvb/mantis/mantis_common.h
@@ -0,0 +1,179 @@
+/*
+ Mantis PCI bridge driver
+
+ Copyright (C) Manu Abraham (abraham.manu@gmail.com)
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#ifndef __MANTIS_COMMON_H
+#define __MANTIS_COMMON_H
+
+#include <linux/mutex.h>
+#include <linux/workqueue.h>
+
+#include "mantis_uart.h"
+
+#include "mantis_link.h"
+
+#define MANTIS_ERROR 0
+#define MANTIS_NOTICE 1
+#define MANTIS_INFO 2
+#define MANTIS_DEBUG 3
+#define MANTIS_TMG 9
+
+#define dprintk(y, z, format, arg...) do { \
+ if (z) { \
+ if ((mantis->verbose > MANTIS_ERROR) && (mantis->verbose > y)) \
+ printk(KERN_ERR "%s (%d): " format "\n" , __func__ , mantis->num , ##arg); \
+ else if ((mantis->verbose > MANTIS_NOTICE) && (mantis->verbose > y)) \
+ printk(KERN_NOTICE "%s (%d): " format "\n" , __func__ , mantis->num , ##arg); \
+ else if ((mantis->verbose > MANTIS_INFO) && (mantis->verbose > y)) \
+ printk(KERN_INFO "%s (%d): " format "\n" , __func__ , mantis->num , ##arg); \
+ else if ((mantis->verbose > MANTIS_DEBUG) && (mantis->verbose > y)) \
+ printk(KERN_DEBUG "%s (%d): " format "\n" , __func__ , mantis->num , ##arg); \
+ else if ((mantis->verbose > MANTIS_TMG) && (mantis->verbose > y)) \
+ printk(KERN_DEBUG "%s (%d): " format "\n" , __func__ , mantis->num , ##arg); \
+ } else { \
+ if (mantis->verbose > y) \
+ printk(format , ##arg); \
+ } \
+} while(0)
+
+#define mwrite(dat, addr) writel((dat), addr)
+#define mread(addr) readl(addr)
+
+#define mmwrite(dat, addr) mwrite((dat), (mantis->mmio + (addr)))
+#define mmread(addr) mread(mantis->mmio + (addr))
+
+#define MANTIS_TS_188 0
+#define MANTIS_TS_204 1
+
+#define TWINHAN_TECHNOLOGIES 0x1822
+#define MANTIS 0x4e35
+
+#define TECHNISAT 0x1ae4
+#define TERRATEC 0x153b
+
+#define MAKE_ENTRY(__subven, __subdev, __configptr) { \
+ .vendor = TWINHAN_TECHNOLOGIES, \
+ .device = MANTIS, \
+ .subvendor = (__subven), \
+ .subdevice = (__subdev), \
+ .driver_data = (unsigned long) (__configptr) \
+}
+
+enum mantis_i2c_mode {
+ MANTIS_PAGE_MODE = 0,
+ MANTIS_BYTE_MODE,
+};
+
+struct mantis_pci;
+
+struct mantis_hwconfig {
+ char *model_name;
+ char *dev_type;
+ u32 ts_size;
+
+ enum mantis_baud baud_rate;
+ enum mantis_parity parity;
+ u32 bytes;
+
+ irqreturn_t (*irq_handler)(int irq, void *dev_id);
+ int (*frontend_init)(struct mantis_pci *mantis, struct dvb_frontend *fe);
+
+ u8 power;
+ u8 reset;
+
+ enum mantis_i2c_mode i2c_mode;
+};
+
+struct mantis_pci {
+ unsigned int verbose;
+
+ /* PCI stuff */
+ u16 vendor_id;
+ u16 device_id;
+ u16 subsystem_vendor;
+ u16 subsystem_device;
+
+ u8 latency;
+
+ struct pci_dev *pdev;
+
+ unsigned long mantis_addr;
+ void __iomem *mmio;
+
+ u8 irq;
+ u8 revision;
+
+ unsigned int num;
+
+ /* RISC Core */
+ u32 finished_block;
+ u32 last_block;
+ u32 line_bytes;
+ u32 line_count;
+ u32 risc_pos;
+ u8 *buf_cpu;
+ dma_addr_t buf_dma;
+ u32 *risc_cpu;
+ dma_addr_t risc_dma;
+
+ struct tasklet_struct tasklet;
+
+ struct i2c_adapter adapter;
+ int i2c_rc;
+ wait_queue_head_t i2c_wq;
+ struct mutex i2c_lock;
+
+ /* DVB stuff */
+ struct dvb_adapter dvb_adapter;
+ struct dvb_frontend *fe;
+ struct dvb_demux demux;
+ struct dmxdev dmxdev;
+ struct dmx_frontend fe_hw;
+ struct dmx_frontend fe_mem;
+ struct dvb_net dvbnet;
+
+ u8 feeds;
+
+ struct mantis_hwconfig *hwconfig;
+
+ u32 mantis_int_stat;
+ u32 mantis_int_mask;
+
+ /* board specific */
+ u8 mac_address[8];
+ u32 sub_vendor_id;
+ u32 sub_device_id;
+
+ /* A12 A13 A14 */
+ u32 gpio_status;
+
+ u32 gpif_status;
+
+ struct mantis_ca *mantis_ca;
+
+ wait_queue_head_t uart_wq;
+ struct work_struct uart_work;
+ spinlock_t uart_lock;
+
+ struct input_dev *rc;
+};
+
+#define MANTIS_HIF_STATUS (mantis->gpio_status)
+
+#endif /* __MANTIS_COMMON_H */
diff --git a/drivers/media/dvb/mantis/mantis_core.c b/drivers/media/dvb/mantis/mantis_core.c
new file mode 100644
index 000000000000..8113b23ce448
--- /dev/null
+++ b/drivers/media/dvb/mantis/mantis_core.c
@@ -0,0 +1,238 @@
+/*
+ Mantis PCI bridge driver
+
+ Copyright (C) Manu Abraham (abraham.manu@gmail.com)
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "mantis_common.h"
+#include "mantis_core.h"
+#include "mantis_vp1033.h"
+#include "mantis_vp1034.h"
+#include "mantis_vp1041.h"
+#include "mantis_vp2033.h"
+#include "mantis_vp2040.h"
+#include "mantis_vp3030.h"
+
+static int read_eeprom_byte(struct mantis_pci *mantis, u8 *data, u8 length)
+{
+ int err;
+ struct i2c_msg msg[] = {
+ {
+ .addr = 0x50,
+ .flags = 0,
+ .buf = data,
+ .len = 1
+ }, {
+ .addr = 0x50,
+ .flags = I2C_M_RD,
+ .buf = data,
+ .len = length
+ },
+ };
+
+ err = i2c_transfer(&mantis->adapter, msg, 2);
+ if (err < 0) {
+ dprintk(verbose, MANTIS_ERROR, 1,
+ "ERROR: i2c read: < err=%i d0=0x%02x d1=0x%02x >",
+ err, data[0], data[1]);
+
+ return err;
+ }
+
+ return 0;
+}
+
+static int write_eeprom_byte(struct mantis_pci *mantis, u8 *data, u8 length)
+{
+ int err;
+
+ struct i2c_msg msg = {
+ .addr = 0x50,
+ .flags = 0,
+ .buf = data,
+ .len = length
+ };
+
+ err = i2c_transfer(&mantis->adapter, &msg, 1);
+ if (err < 0) {
+ dprintk(verbose, MANTIS_ERROR, 1,
+ "ERROR: i2c write: < err=%i length=0x%02x d0=0x%02x, d1=0x%02x >",
+ err, length, data[0], data[1]);
+
+ return err;
+ }
+
+ return 0;
+}
+
+static int get_mac_address(struct mantis_pci *mantis)
+{
+ int err;
+
+ mantis->mac_address[0] = 0x08;
+ err = read_eeprom_byte(mantis, &mantis->mac_address[0], 6);
+ if (err < 0) {
+ dprintk(verbose, MANTIS_ERROR, 1, "Mantis EEPROM read error");
+
+ return err;
+ }
+ dprintk(verbose, MANTIS_ERROR, 0,
+ " MAC Address=[%02x:%02x:%02x:%02x:%02x:%02x]\n",
+ mantis->mac_address[0], mantis->mac_address[1],
+ mantis->mac_address[2], mantis->mac_address[3],
+ mantis->mac_address[4], mantis->mac_address[5]);
+
+ return 0;
+}
+
+#define MANTIS_MODEL_UNKNOWN "UNKNOWN"
+#define MANTIS_DEV_UNKNOWN "UNKNOWN"
+
+struct mantis_hwconfig unknown_device = {
+ .model_name = MANTIS_MODEL_UNKNOWN,
+ .dev_type = MANTIS_DEV_UNKNOWN,
+};
+
+static void mantis_load_config(struct mantis_pci *mantis)
+{
+ switch (mantis->subsystem_device) {
+ case MANTIS_VP_1033_DVB_S: /* VP-1033 */
+ mantis->hwconfig = &vp1033_mantis_config;
+ break;
+ case MANTIS_VP_1034_DVB_S: /* VP-1034 */
+ mantis->hwconfig = &vp1034_mantis_config;
+ break;
+ case MANTIS_VP_1041_DVB_S2: /* VP-1041 */
+ case TECHNISAT_SKYSTAR_HD2:
+ mantis->hwconfig = &vp1041_mantis_config;
+ break;
+ case MANTIS_VP_2033_DVB_C: /* VP-2033 */
+ mantis->hwconfig = &vp2033_mantis_config;
+ break;
+ case MANTIS_VP_2040_DVB_C: /* VP-2040 */
+ case TERRATEC_CINERGY_C_PCI: /* VP-2040 clone */
+ case TECHNISAT_CABLESTAR_HD2:
+ mantis->hwconfig = &vp2040_mantis_config;
+ break;
+ case MANTIS_VP_3030_DVB_T: /* VP-3030 */
+ mantis->hwconfig = &vp3030_mantis_config;
+ break;
+ default:
+ mantis->hwconfig = &unknown_device;
+ break;
+ }
+}
+
+int mantis_core_init(struct mantis_pci *mantis)
+{
+ int err = 0;
+
+ mantis_load_config(mantis);
+ dprintk(verbose, MANTIS_ERROR, 0, "found a %s PCI %s device on (%02x:%02x.%x),\n",
+ mantis->hwconfig->model_name, mantis->hwconfig->dev_type,
+ mantis->pdev->bus->number, PCI_SLOT(mantis->pdev->devfn), PCI_FUNC(mantis->pdev->devfn));
+ dprintk(verbose, MANTIS_ERROR, 0, " Mantis Rev %d [%04x:%04x], ",
+ mantis->revision,
+ mantis->subsystem_vendor, mantis->subsystem_device);
+ dprintk(verbose, MANTIS_ERROR, 0,
+ "irq: %d, latency: %d\n memory: 0x%lx, mmio: 0x%p\n",
+ mantis->pdev->irq, mantis->latency,
+ mantis->mantis_addr, mantis->mantis_mmio);
+
+ err = mantis_i2c_init(mantis);
+ if (err < 0) {
+ dprintk(verbose, MANTIS_ERROR, 1, "Mantis I2C init failed");
+ return err;
+ }
+ err = get_mac_address(mantis);
+ if (err < 0) {
+ dprintk(verbose, MANTIS_ERROR, 1, "get MAC address failed");
+ return err;
+ }
+ err = mantis_dma_init(mantis);
+ if (err < 0) {
+ dprintk(verbose, MANTIS_ERROR, 1, "Mantis DMA init failed");
+ return err;
+ }
+ err = mantis_dvb_init(mantis);
+ if (err < 0) {
+ dprintk(verbose, MANTIS_DEBUG, 1, "Mantis DVB init failed");
+ return err;
+ }
+ err = mantis_uart_init(mantis);
+ if (err < 0) {
+ dprintk(verbose, MANTIS_DEBUG, 1, "Mantis UART init failed");
+ return err;
+ }
+
+ return 0;
+}
+
+int mantis_core_exit(struct mantis_pci *mantis)
+{
+ mantis_dma_stop(mantis);
+ dprintk(verbose, MANTIS_ERROR, 1, "DMA engine stopping");
+
+ mantis_uart_exit(mantis);
+ dprintk(verbose, MANTIS_ERROR, 1, "UART exit failed");
+
+ if (mantis_dma_exit(mantis) < 0)
+ dprintk(verbose, MANTIS_ERROR, 1, "DMA exit failed");
+ if (mantis_dvb_exit(mantis) < 0)
+ dprintk(verbose, MANTIS_ERROR, 1, "DVB exit failed");
+ if (mantis_i2c_exit(mantis) < 0)
+ dprintk(verbose, MANTIS_ERROR, 1, "I2C adapter delete.. failed");
+
+ return 0;
+}
+
+/* Turn the given bit on or off. */
+void gpio_set_bits(struct mantis_pci *mantis, u32 bitpos, u8 value)
+{
+ u32 cur;
+
+ cur = mmread(MANTIS_GPIF_ADDR);
+ if (value)
+ mantis->gpio_status = cur | (1 << bitpos);
+ else
+ mantis->gpio_status = cur & (~(1 << bitpos));
+
+ mmwrite(mantis->gpio_status, MANTIS_GPIF_ADDR);
+ mmwrite(0x00, MANTIS_GPIF_DOUT);
+ udelay(100);
+}
+
+/* direction = 0 , no CI passthrough ; 1 , CI passthrough */
+void mantis_set_direction(struct mantis_pci *mantis, int direction)
+{
+ u32 reg;
+
+ reg = mmread(0x28);
+ dprintk(verbose, MANTIS_DEBUG, 1, "TS direction setup");
+ if (direction == 0x01) {
+ /* to CI */
+ reg |= 0x04;
+ mmwrite(reg, 0x28);
+ reg &= 0xff - 0x04;
+ mmwrite(reg, 0x28);
+ } else {
+ reg &= 0xff - 0x04;
+ mmwrite(reg, 0x28);
+ reg |= 0x04;
+ mmwrite(reg, 0x28);
+ }
+}
diff --git a/drivers/media/dvb/mantis/mantis_core.h b/drivers/media/dvb/mantis/mantis_core.h
new file mode 100644
index 000000000000..833ee42e694e
--- /dev/null
+++ b/drivers/media/dvb/mantis/mantis_core.h
@@ -0,0 +1,57 @@
+/*
+ Mantis PCI bridge driver
+
+ Copyright (C) Manu Abraham (abraham.manu@gmail.com)
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#ifndef __MANTIS_CORE_H
+#define __MANTIS_CORE_H
+
+#include "mantis_common.h"
+
+
+#define FE_TYPE_SAT 0
+#define FE_TYPE_CAB 1
+#define FE_TYPE_TER 2
+
+#define FE_TYPE_TS204 0
+#define FE_TYPE_TS188 1
+
+
+struct vendorname {
+ u8 *sub_vendor_name;
+ u32 sub_vendor_id;
+};
+
+struct devicetype {
+ u8 *sub_device_name;
+ u32 sub_device_id;
+ u8 device_type;
+ u32 type_flags;
+};
+
+
+extern int mantis_dma_init(struct mantis_pci *mantis);
+extern int mantis_dma_exit(struct mantis_pci *mantis);
+extern void mantis_dma_start(struct mantis_pci *mantis);
+extern void mantis_dma_stop(struct mantis_pci *mantis);
+extern int mantis_i2c_init(struct mantis_pci *mantis);
+extern int mantis_i2c_exit(struct mantis_pci *mantis);
+extern int mantis_core_init(struct mantis_pci *mantis);
+extern int mantis_core_exit(struct mantis_pci *mantis);
+
+#endif /* __MANTIS_CORE_H */
diff --git a/drivers/media/dvb/mantis/mantis_dma.c b/drivers/media/dvb/mantis/mantis_dma.c
new file mode 100644
index 000000000000..46202a4012aa
--- /dev/null
+++ b/drivers/media/dvb/mantis/mantis_dma.c
@@ -0,0 +1,256 @@
+/*
+ Mantis PCI bridge driver
+
+ Copyright (C) Manu Abraham (abraham.manu@gmail.com)
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include <linux/kernel.h>
+#include <asm/page.h>
+#include <linux/vmalloc.h>
+#include <linux/pci.h>
+
+#include <asm/irq.h>
+#include <linux/signal.h>
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+
+#include "dmxdev.h"
+#include "dvbdev.h"
+#include "dvb_demux.h"
+#include "dvb_frontend.h"
+#include "dvb_net.h"
+
+#include "mantis_common.h"
+#include "mantis_reg.h"
+#include "mantis_dma.h"
+
+#define RISC_WRITE (0x01 << 28)
+#define RISC_JUMP (0x07 << 28)
+#define RISC_IRQ (0x01 << 24)
+
+#define RISC_STATUS(status) ((((~status) & 0x0f) << 20) | ((status & 0x0f) << 16))
+#define RISC_FLUSH() (mantis->risc_pos = 0)
+#define RISC_INSTR(opcode) (mantis->risc_cpu[mantis->risc_pos++] = cpu_to_le32(opcode))
+
+#define MANTIS_BUF_SIZE (64 * 1024)
+#define MANTIS_BLOCK_BYTES (MANTIS_BUF_SIZE >> 4)
+#define MANTIS_BLOCK_COUNT (1 << 4)
+#define MANTIS_RISC_SIZE PAGE_SIZE
+
+int mantis_dma_exit(struct mantis_pci *mantis)
+{
+ if (mantis->buf_cpu) {
+ dprintk(MANTIS_ERROR, 1,
+ "DMA=0x%lx cpu=0x%p size=%d",
+ (unsigned long) mantis->buf_dma,
+ mantis->buf_cpu,
+ MANTIS_BUF_SIZE);
+
+ pci_free_consistent(mantis->pdev, MANTIS_BUF_SIZE,
+ mantis->buf_cpu, mantis->buf_dma);
+
+ mantis->buf_cpu = NULL;
+ }
+ if (mantis->risc_cpu) {
+ dprintk(MANTIS_ERROR, 1,
+ "RISC=0x%lx cpu=0x%p size=%lx",
+ (unsigned long) mantis->risc_dma,
+ mantis->risc_cpu,
+ MANTIS_RISC_SIZE);
+
+ pci_free_consistent(mantis->pdev, MANTIS_RISC_SIZE,
+ mantis->risc_cpu, mantis->risc_dma);
+
+ mantis->risc_cpu = NULL;
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(mantis_dma_exit);
+
+static inline int mantis_alloc_buffers(struct mantis_pci *mantis)
+{
+ if (!mantis->buf_cpu) {
+ mantis->buf_cpu = pci_alloc_consistent(mantis->pdev,
+ MANTIS_BUF_SIZE,
+ &mantis->buf_dma);
+ if (!mantis->buf_cpu) {
+ dprintk(MANTIS_ERROR, 1,
+ "DMA buffer allocation failed");
+
+ goto err;
+ }
+ dprintk(MANTIS_ERROR, 1,
+ "DMA=0x%lx cpu=0x%p size=%d",
+ (unsigned long) mantis->buf_dma,
+ mantis->buf_cpu, MANTIS_BUF_SIZE);
+ }
+ if (!mantis->risc_cpu) {
+ mantis->risc_cpu = pci_alloc_consistent(mantis->pdev,
+ MANTIS_RISC_SIZE,
+ &mantis->risc_dma);
+
+ if (!mantis->risc_cpu) {
+ dprintk(MANTIS_ERROR, 1,
+ "RISC program allocation failed");
+
+ mantis_dma_exit(mantis);
+
+ goto err;
+ }
+ dprintk(MANTIS_ERROR, 1,
+ "RISC=0x%lx cpu=0x%p size=%lx",
+ (unsigned long) mantis->risc_dma,
+ mantis->risc_cpu, MANTIS_RISC_SIZE);
+ }
+
+ return 0;
+err:
+ dprintk(MANTIS_ERROR, 1, "Out of memory (?) .....");
+ return -ENOMEM;
+}
+
+static inline int mantis_calc_lines(struct mantis_pci *mantis)
+{
+ mantis->line_bytes = MANTIS_BLOCK_BYTES;
+ mantis->line_count = MANTIS_BLOCK_COUNT;
+
+ while (mantis->line_bytes > 4095) {
+ mantis->line_bytes >>= 1;
+ mantis->line_count <<= 1;
+ }
+
+ dprintk(MANTIS_DEBUG, 1, "Mantis RISC block bytes=[%d], line bytes=[%d], line count=[%d]",
+ MANTIS_BLOCK_BYTES, mantis->line_bytes, mantis->line_count);
+
+ if (mantis->line_count > 255) {
+ dprintk(MANTIS_ERROR, 1, "Buffer size error");
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+int mantis_dma_init(struct mantis_pci *mantis)
+{
+ int err = 0;
+
+ dprintk(MANTIS_DEBUG, 1, "Mantis DMA init");
+ if (mantis_alloc_buffers(mantis) < 0) {
+ dprintk(MANTIS_ERROR, 1, "Error allocating DMA buffer");
+
+ /* Stop RISC Engine */
+ mmwrite(0, MANTIS_DMA_CTL);
+
+ goto err;
+ }
+ err = mantis_calc_lines(mantis);
+ if (err < 0) {
+ dprintk(MANTIS_ERROR, 1, "Mantis calc lines failed");
+
+ goto err;
+ }
+
+ return 0;
+err:
+ return err;
+}
+EXPORT_SYMBOL_GPL(mantis_dma_init);
+
+static inline void mantis_risc_program(struct mantis_pci *mantis)
+{
+ u32 buf_pos = 0;
+ u32 line;
+
+ dprintk(MANTIS_DEBUG, 1, "Mantis create RISC program");
+ RISC_FLUSH();
+
+ dprintk(MANTIS_DEBUG, 1, "risc len lines %u, bytes per line %u",
+ mantis->line_count, mantis->line_bytes);
+
+ for (line = 0; line < mantis->line_count; line++) {
+ dprintk(MANTIS_DEBUG, 1, "RISC PROG line=[%d]", line);
+ if (!(buf_pos % MANTIS_BLOCK_BYTES)) {
+ RISC_INSTR(RISC_WRITE |
+ RISC_IRQ |
+ RISC_STATUS(((buf_pos / MANTIS_BLOCK_BYTES) +
+ (MANTIS_BLOCK_COUNT - 1)) %
+ MANTIS_BLOCK_COUNT) |
+ mantis->line_bytes);
+ } else {
+ RISC_INSTR(RISC_WRITE | mantis->line_bytes);
+ }
+ RISC_INSTR(mantis->buf_dma + buf_pos);
+ buf_pos += mantis->line_bytes;
+ }
+ RISC_INSTR(RISC_JUMP);
+ RISC_INSTR(mantis->risc_dma);
+}
+
+void mantis_dma_start(struct mantis_pci *mantis)
+{
+ dprintk(MANTIS_DEBUG, 1, "Mantis Start DMA engine");
+
+ mantis_risc_program(mantis);
+ mmwrite(mantis->risc_dma, MANTIS_RISC_START);
+ mmwrite(mmread(MANTIS_GPIF_ADDR) | MANTIS_GPIF_HIFRDWRN, MANTIS_GPIF_ADDR);
+
+ mmwrite(0, MANTIS_DMA_CTL);
+ mantis->last_block = mantis->finished_block = 0;
+
+ mmwrite(mmread(MANTIS_INT_MASK) | MANTIS_INT_RISCI, MANTIS_INT_MASK);
+
+ mmwrite(MANTIS_FIFO_EN | MANTIS_DCAP_EN
+ | MANTIS_RISC_EN, MANTIS_DMA_CTL);
+
+}
+
+void mantis_dma_stop(struct mantis_pci *mantis)
+{
+ u32 stat = 0, mask = 0;
+
+ stat = mmread(MANTIS_INT_STAT);
+ mask = mmread(MANTIS_INT_MASK);
+ dprintk(MANTIS_DEBUG, 1, "Mantis Stop DMA engine");
+
+ mmwrite((mmread(MANTIS_GPIF_ADDR) & (~(MANTIS_GPIF_HIFRDWRN))), MANTIS_GPIF_ADDR);
+
+ mmwrite((mmread(MANTIS_DMA_CTL) & ~(MANTIS_FIFO_EN |
+ MANTIS_DCAP_EN |
+ MANTIS_RISC_EN)), MANTIS_DMA_CTL);
+
+ mmwrite(mmread(MANTIS_INT_STAT), MANTIS_INT_STAT);
+
+ mmwrite(mmread(MANTIS_INT_MASK) & ~(MANTIS_INT_RISCI |
+ MANTIS_INT_RISCEN), MANTIS_INT_MASK);
+}
+
+
+void mantis_dma_xfer(unsigned long data)
+{
+ struct mantis_pci *mantis = (struct mantis_pci *) data;
+ struct mantis_hwconfig *config = mantis->hwconfig;
+
+ while (mantis->last_block != mantis->finished_block) {
+ dprintk(MANTIS_DEBUG, 1, "last block=[%d] finished block=[%d]",
+ mantis->last_block, mantis->finished_block);
+
+ (config->ts_size ? dvb_dmx_swfilter_204 : dvb_dmx_swfilter)
+ (&mantis->demux, &mantis->buf_cpu[mantis->last_block * MANTIS_BLOCK_BYTES], MANTIS_BLOCK_BYTES);
+ mantis->last_block = (mantis->last_block + 1) % MANTIS_BLOCK_COUNT;
+ }
+}
diff --git a/drivers/media/dvb/mantis/mantis_dma.h b/drivers/media/dvb/mantis/mantis_dma.h
new file mode 100644
index 000000000000..6be00fa82094
--- /dev/null
+++ b/drivers/media/dvb/mantis/mantis_dma.h
@@ -0,0 +1,30 @@
+/*
+ Mantis PCI bridge driver
+
+ Copyright (C) Manu Abraham (abraham.manu@gmail.com)
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#ifndef __MANTIS_DMA_H
+#define __MANTIS_DMA_H
+
+extern int mantis_dma_init(struct mantis_pci *mantis);
+extern int mantis_dma_exit(struct mantis_pci *mantis);
+extern void mantis_dma_start(struct mantis_pci *mantis);
+extern void mantis_dma_stop(struct mantis_pci *mantis);
+extern void mantis_dma_xfer(unsigned long data);
+
+#endif /* __MANTIS_DMA_H */
diff --git a/drivers/media/dvb/mantis/mantis_dvb.c b/drivers/media/dvb/mantis/mantis_dvb.c
new file mode 100644
index 000000000000..99d82eec3b03
--- /dev/null
+++ b/drivers/media/dvb/mantis/mantis_dvb.c
@@ -0,0 +1,296 @@
+/*
+ Mantis PCI bridge driver
+ Copyright (C) Manu Abraham (abraham.manu@gmail.com)
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include <linux/kernel.h>
+#include <linux/bitops.h>
+
+#include <linux/signal.h>
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+#include <linux/pci.h>
+#include <linux/i2c.h>
+
+#include "dmxdev.h"
+#include "dvbdev.h"
+#include "dvb_demux.h"
+#include "dvb_frontend.h"
+#include "dvb_net.h"
+
+#include "mantis_common.h"
+#include "mantis_dma.h"
+#include "mantis_ca.h"
+#include "mantis_ioc.h"
+#include "mantis_dvb.h"
+
+DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
+
+int mantis_frontend_power(struct mantis_pci *mantis, enum mantis_power power)
+{
+ struct mantis_hwconfig *config = mantis->hwconfig;
+
+ switch (power) {
+ case POWER_ON:
+ dprintk(MANTIS_DEBUG, 1, "Power ON");
+ gpio_set_bits(mantis, config->power, POWER_ON);
+ msleep(100);
+ gpio_set_bits(mantis, config->power, POWER_ON);
+ msleep(100);
+ break;
+
+ case POWER_OFF:
+ dprintk(MANTIS_DEBUG, 1, "Power OFF");
+ gpio_set_bits(mantis, config->power, POWER_OFF);
+ msleep(100);
+ break;
+
+ default:
+ dprintk(MANTIS_DEBUG, 1, "Unknown state <%02x>", power);
+ return -1;
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(mantis_frontend_power);
+
+void mantis_frontend_soft_reset(struct mantis_pci *mantis)
+{
+ struct mantis_hwconfig *config = mantis->hwconfig;
+
+ dprintk(MANTIS_DEBUG, 1, "Frontend RESET");
+ gpio_set_bits(mantis, config->reset, 0);
+ msleep(100);
+ gpio_set_bits(mantis, config->reset, 0);
+ msleep(100);
+ gpio_set_bits(mantis, config->reset, 1);
+ msleep(100);
+ gpio_set_bits(mantis, config->reset, 1);
+ msleep(100);
+
+ return;
+}
+EXPORT_SYMBOL_GPL(mantis_frontend_soft_reset);
+
+static int mantis_frontend_shutdown(struct mantis_pci *mantis)
+{
+ int err;
+
+ mantis_frontend_soft_reset(mantis);
+ err = mantis_frontend_power(mantis, POWER_OFF);
+ if (err != 0) {
+ dprintk(MANTIS_ERROR, 1, "Frontend POWER OFF failed! <%d>", err);
+ return 1;
+ }
+
+ return 0;
+}
+
+static int mantis_dvb_start_feed(struct dvb_demux_feed *dvbdmxfeed)
+{
+ struct dvb_demux *dvbdmx = dvbdmxfeed->demux;
+ struct mantis_pci *mantis = dvbdmx->priv;
+
+ dprintk(MANTIS_DEBUG, 1, "Mantis DVB Start feed");
+ if (!dvbdmx->dmx.frontend) {
+ dprintk(MANTIS_DEBUG, 1, "no frontend ?");
+ return -EINVAL;
+ }
+
+ mantis->feeds++;
+ dprintk(MANTIS_DEBUG, 1, "mantis start feed, feeds=%d", mantis->feeds);
+
+ if (mantis->feeds == 1) {
+ dprintk(MANTIS_DEBUG, 1, "mantis start feed & dma");
+ mantis_dma_start(mantis);
+ }
+
+ return mantis->feeds;
+}
+
+static int mantis_dvb_stop_feed(struct dvb_demux_feed *dvbdmxfeed)
+{
+ struct dvb_demux *dvbdmx = dvbdmxfeed->demux;
+ struct mantis_pci *mantis = dvbdmx->priv;
+
+ dprintk(MANTIS_DEBUG, 1, "Mantis DVB Stop feed");
+ if (!dvbdmx->dmx.frontend) {
+ dprintk(MANTIS_DEBUG, 1, "no frontend ?");
+ return -EINVAL;
+ }
+
+ mantis->feeds--;
+ if (mantis->feeds == 0) {
+ dprintk(MANTIS_DEBUG, 1, "mantis stop feed and dma");
+ mantis_dma_stop(mantis);
+ }
+
+ return 0;
+}
+
+int __devinit mantis_dvb_init(struct mantis_pci *mantis)
+{
+ struct mantis_hwconfig *config = mantis->hwconfig;
+ int result = -1;
+
+ dprintk(MANTIS_DEBUG, 1, "dvb_register_adapter");
+
+ result = dvb_register_adapter(&mantis->dvb_adapter,
+ "Mantis DVB adapter",
+ THIS_MODULE,
+ &mantis->pdev->dev,
+ adapter_nr);
+
+ if (result < 0) {
+
+ dprintk(MANTIS_ERROR, 1, "Error registering adapter");
+ return -ENODEV;
+ }
+
+ mantis->dvb_adapter.priv = mantis;
+ mantis->demux.dmx.capabilities = DMX_TS_FILTERING |
+ DMX_SECTION_FILTERING |
+ DMX_MEMORY_BASED_FILTERING;
+
+ mantis->demux.priv = mantis;
+ mantis->demux.filternum = 256;
+ mantis->demux.feednum = 256;
+ mantis->demux.start_feed = mantis_dvb_start_feed;
+ mantis->demux.stop_feed = mantis_dvb_stop_feed;
+ mantis->demux.write_to_decoder = NULL;
+
+ dprintk(MANTIS_DEBUG, 1, "dvb_dmx_init");
+ result = dvb_dmx_init(&mantis->demux);
+ if (result < 0) {
+ dprintk(MANTIS_ERROR, 1, "dvb_dmx_init failed, ERROR=%d", result);
+
+ goto err0;
+ }
+
+ mantis->dmxdev.filternum = 256;
+ mantis->dmxdev.demux = &mantis->demux.dmx;
+ mantis->dmxdev.capabilities = 0;
+ dprintk(MANTIS_DEBUG, 1, "dvb_dmxdev_init");
+
+ result = dvb_dmxdev_init(&mantis->dmxdev, &mantis->dvb_adapter);
+ if (result < 0) {
+
+ dprintk(MANTIS_ERROR, 1, "dvb_dmxdev_init failed, ERROR=%d", result);
+ goto err1;
+ }
+
+ mantis->fe_hw.source = DMX_FRONTEND_0;
+ result = mantis->demux.dmx.add_frontend(&mantis->demux.dmx, &mantis->fe_hw);
+ if (result < 0) {
+
+ dprintk(MANTIS_ERROR, 1, "dvb_dmx_init failed, ERROR=%d", result);
+ goto err2;
+ }
+
+ mantis->fe_mem.source = DMX_MEMORY_FE;
+ result = mantis->demux.dmx.add_frontend(&mantis->demux.dmx, &mantis->fe_mem);
+ if (result < 0) {
+ dprintk(MANTIS_ERROR, 1, "dvb_dmx_init failed, ERROR=%d", result);
+ goto err3;
+ }
+
+ result = mantis->demux.dmx.connect_frontend(&mantis->demux.dmx, &mantis->fe_hw);
+ if (result < 0) {
+ dprintk(MANTIS_ERROR, 1, "dvb_dmx_init failed, ERROR=%d", result);
+ goto err4;
+ }
+
+ dvb_net_init(&mantis->dvb_adapter, &mantis->dvbnet, &mantis->demux.dmx);
+ tasklet_init(&mantis->tasklet, mantis_dma_xfer, (unsigned long) mantis);
+ if (mantis->hwconfig) {
+ result = config->frontend_init(mantis, mantis->fe);
+ if (result < 0) {
+ dprintk(MANTIS_ERROR, 1, "!!! NO Frontends found !!!");
+ goto err5;
+ } else {
+ if (mantis->fe == NULL) {
+ dprintk(MANTIS_ERROR, 1, "FE <NULL>");
+ goto err5;
+ }
+
+ if (dvb_register_frontend(&mantis->dvb_adapter, mantis->fe)) {
+ dprintk(MANTIS_ERROR, 1, "ERROR: Frontend registration failed");
+
+ if (mantis->fe->ops.release)
+ mantis->fe->ops.release(mantis->fe);
+
+ mantis->fe = NULL;
+ goto err5;
+ }
+ }
+ }
+
+ return 0;
+
+ /* Error conditions .. */
+err5:
+ tasklet_kill(&mantis->tasklet);
+ dvb_net_release(&mantis->dvbnet);
+ dvb_unregister_frontend(mantis->fe);
+ dvb_frontend_detach(mantis->fe);
+err4:
+ mantis->demux.dmx.remove_frontend(&mantis->demux.dmx, &mantis->fe_mem);
+
+err3:
+ mantis->demux.dmx.remove_frontend(&mantis->demux.dmx, &mantis->fe_hw);
+
+err2:
+ dvb_dmxdev_release(&mantis->dmxdev);
+
+err1:
+ dvb_dmx_release(&mantis->demux);
+
+err0:
+ dvb_unregister_adapter(&mantis->dvb_adapter);
+
+ return result;
+}
+EXPORT_SYMBOL_GPL(mantis_dvb_init);
+
+int __devexit mantis_dvb_exit(struct mantis_pci *mantis)
+{
+ int err;
+
+ if (mantis->fe) {
+ /* mantis_ca_exit(mantis); */
+ err = mantis_frontend_shutdown(mantis);
+ if (err != 0)
+ dprintk(MANTIS_ERROR, 1, "Frontend exit while POWER ON! <%d>", err);
+ dvb_unregister_frontend(mantis->fe);
+ dvb_frontend_detach(mantis->fe);
+ }
+
+ tasklet_kill(&mantis->tasklet);
+ dvb_net_release(&mantis->dvbnet);
+
+ mantis->demux.dmx.remove_frontend(&mantis->demux.dmx, &mantis->fe_mem);
+ mantis->demux.dmx.remove_frontend(&mantis->demux.dmx, &mantis->fe_hw);
+
+ dvb_dmxdev_release(&mantis->dmxdev);
+ dvb_dmx_release(&mantis->demux);
+
+ dprintk(MANTIS_DEBUG, 1, "dvb_unregister_adapter");
+ dvb_unregister_adapter(&mantis->dvb_adapter);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(mantis_dvb_exit);
diff --git a/drivers/media/dvb/mantis/mantis_dvb.h b/drivers/media/dvb/mantis/mantis_dvb.h
new file mode 100644
index 000000000000..464199db304e
--- /dev/null
+++ b/drivers/media/dvb/mantis/mantis_dvb.h
@@ -0,0 +1,35 @@
+/*
+ Mantis PCI bridge driver
+
+ Copyright (C) Manu Abraham (abraham.manu@gmail.com)
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#ifndef __MANTIS_DVB_H
+#define __MANTIS_DVB_H
+
+enum mantis_power {
+ POWER_OFF = 0,
+ POWER_ON = 1
+};
+
+extern int mantis_frontend_power(struct mantis_pci *mantis, enum mantis_power power);
+extern void mantis_frontend_soft_reset(struct mantis_pci *mantis);
+
+extern int mantis_dvb_init(struct mantis_pci *mantis);
+extern int mantis_dvb_exit(struct mantis_pci *mantis);
+
+#endif /* __MANTIS_DVB_H */
diff --git a/drivers/media/dvb/mantis/mantis_evm.c b/drivers/media/dvb/mantis/mantis_evm.c
new file mode 100644
index 000000000000..a7b369a439d6
--- /dev/null
+++ b/drivers/media/dvb/mantis/mantis_evm.c
@@ -0,0 +1,117 @@
+/*
+ Mantis PCI bridge driver
+
+ Copyright (C) Manu Abraham (abraham.manu@gmail.com)
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include <linux/kernel.h>
+
+#include <linux/signal.h>
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+
+#include "dmxdev.h"
+#include "dvbdev.h"
+#include "dvb_demux.h"
+#include "dvb_frontend.h"
+#include "dvb_net.h"
+
+#include "mantis_common.h"
+#include "mantis_link.h"
+#include "mantis_hif.h"
+#include "mantis_reg.h"
+
+static void mantis_hifevm_work(struct work_struct *work)
+{
+ struct mantis_ca *ca = container_of(work, struct mantis_ca, hif_evm_work);
+ struct mantis_pci *mantis = ca->ca_priv;
+
+ u32 gpif_stat, gpif_mask;
+
+ gpif_stat = mmread(MANTIS_GPIF_STATUS);
+ gpif_mask = mmread(MANTIS_GPIF_IRQCFG);
+
+ if (gpif_stat & MANTIS_GPIF_DETSTAT) {
+ if (gpif_stat & MANTIS_CARD_PLUGIN) {
+ dprintk(MANTIS_DEBUG, 1, "Event Mgr: Adapter(%d) Slot(0): CAM Plugin", mantis->num);
+ mmwrite(0xdada0000, MANTIS_CARD_RESET);
+ mantis_event_cam_plugin(ca);
+ dvb_ca_en50221_camchange_irq(&ca->en50221,
+ 0,
+ DVB_CA_EN50221_CAMCHANGE_INSERTED);
+ }
+ } else {
+ if (gpif_stat & MANTIS_CARD_PLUGOUT) {
+ dprintk(MANTIS_DEBUG, 1, "Event Mgr: Adapter(%d) Slot(0): CAM Unplug", mantis->num);
+ mmwrite(0xdada0000, MANTIS_CARD_RESET);
+ mantis_event_cam_unplug(ca);
+ dvb_ca_en50221_camchange_irq(&ca->en50221,
+ 0,
+ DVB_CA_EN50221_CAMCHANGE_REMOVED);
+ }
+ }
+
+ if (mantis->gpif_status & MANTIS_GPIF_EXTIRQ)
+ dprintk(MANTIS_DEBUG, 1, "Event Mgr: Adapter(%d) Slot(0): Ext IRQ", mantis->num);
+
+ if (mantis->gpif_status & MANTIS_SBUF_WSTO)
+ dprintk(MANTIS_DEBUG, 1, "Event Mgr: Adapter(%d) Slot(0): Smart Buffer Timeout", mantis->num);
+
+ if (mantis->gpif_status & MANTIS_GPIF_OTHERR)
+ dprintk(MANTIS_DEBUG, 1, "Event Mgr: Adapter(%d) Slot(0): Alignment Error", mantis->num);
+
+ if (gpif_stat & MANTIS_SBUF_OVFLW)
+ dprintk(MANTIS_DEBUG, 1, "Event Mgr: Adapter(%d) Slot(0): Smart Buffer Overflow", mantis->num);
+
+ if (gpif_stat & MANTIS_GPIF_BRRDY)
+ dprintk(MANTIS_DEBUG, 1, "Event Mgr: Adapter(%d) Slot(0): Smart Buffer Read Ready", mantis->num);
+
+ if (gpif_stat & MANTIS_GPIF_INTSTAT)
+ dprintk(MANTIS_DEBUG, 1, "Event Mgr: Adapter(%d) Slot(0): GPIF IRQ", mantis->num);
+
+ if (gpif_stat & MANTIS_SBUF_EMPTY)
+ dprintk(MANTIS_DEBUG, 1, "Event Mgr: Adapter(%d) Slot(0): Smart Buffer Empty", mantis->num);
+
+ if (gpif_stat & MANTIS_SBUF_OPDONE) {
+ dprintk(MANTIS_DEBUG, 1, "Event Mgr: Adapter(%d) Slot(0): Smart Buffer operation complete", mantis->num);
+ ca->sbuf_status = MANTIS_SBUF_DATA_AVAIL;
+ ca->hif_event = MANTIS_SBUF_OPDONE;
+ wake_up(&ca->hif_opdone_wq);
+ }
+}
+
+int mantis_evmgr_init(struct mantis_ca *ca)
+{
+ struct mantis_pci *mantis = ca->ca_priv;
+
+ dprintk(MANTIS_DEBUG, 1, "Initializing Mantis Host I/F Event manager");
+ INIT_WORK(&ca->hif_evm_work, mantis_hifevm_work);
+ mantis_pcmcia_init(ca);
+ schedule_work(&ca->hif_evm_work);
+ mantis_hif_init(ca);
+ return 0;
+}
+
+void mantis_evmgr_exit(struct mantis_ca *ca)
+{
+ struct mantis_pci *mantis = ca->ca_priv;
+
+ dprintk(MANTIS_DEBUG, 1, "Mantis Host I/F Event manager exiting");
+ flush_scheduled_work();
+ mantis_hif_exit(ca);
+ mantis_pcmcia_exit(ca);
+}
diff --git a/drivers/media/dvb/mantis/mantis_hif.c b/drivers/media/dvb/mantis/mantis_hif.c
new file mode 100644
index 000000000000..7477dac628b4
--- /dev/null
+++ b/drivers/media/dvb/mantis/mantis_hif.c
@@ -0,0 +1,240 @@
+/*
+ Mantis PCI bridge driver
+
+ Copyright (C) Manu Abraham (abraham.manu@gmail.com)
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include <linux/kernel.h>
+#include <linux/signal.h>
+#include <linux/sched.h>
+
+#include <linux/signal.h>
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+
+#include "dmxdev.h"
+#include "dvbdev.h"
+#include "dvb_demux.h"
+#include "dvb_frontend.h"
+#include "dvb_net.h"
+
+#include "mantis_common.h"
+
+#include "mantis_hif.h"
+#include "mantis_link.h" /* temporary due to physical layer stuff */
+
+#include "mantis_reg.h"
+
+
+static int mantis_hif_sbuf_opdone_wait(struct mantis_ca *ca)
+{
+ struct mantis_pci *mantis = ca->ca_priv;
+ int rc = 0;
+
+ if (wait_event_timeout(ca->hif_opdone_wq,
+ ca->hif_event & MANTIS_SBUF_OPDONE,
+ msecs_to_jiffies(500)) == -ERESTARTSYS) {
+
+ dprintk(MANTIS_ERROR, 1, "Adapter(%d) Slot(0): Smart buffer operation timeout !", mantis->num);
+ rc = -EREMOTEIO;
+ }
+ dprintk(MANTIS_DEBUG, 1, "Smart Buffer Operation complete");
+ ca->hif_event &= ~MANTIS_SBUF_OPDONE;
+ return rc;
+}
+
+static int mantis_hif_write_wait(struct mantis_ca *ca)
+{
+ struct mantis_pci *mantis = ca->ca_priv;
+ u32 opdone = 0, timeout = 0;
+ int rc = 0;
+
+ if (wait_event_timeout(ca->hif_write_wq,
+ mantis->gpif_status & MANTIS_GPIF_WRACK,
+ msecs_to_jiffies(500)) == -ERESTARTSYS) {
+
+ dprintk(MANTIS_ERROR, 1, "Adapter(%d) Slot(0): Write ACK timed out !", mantis->num);
+ rc = -EREMOTEIO;
+ }
+ dprintk(MANTIS_DEBUG, 1, "Write Acknowledged");
+ mantis->gpif_status &= ~MANTIS_GPIF_WRACK;
+ while (!opdone) {
+ opdone = (mmread(MANTIS_GPIF_STATUS) & MANTIS_SBUF_OPDONE);
+ udelay(500);
+ timeout++;
+ if (timeout > 100) {
+ dprintk(MANTIS_ERROR, 1, "Adater(%d) Slot(0): Write operation timed out!", mantis->num);
+ rc = -ETIMEDOUT;
+ break;
+ }
+ }
+ dprintk(MANTIS_DEBUG, 1, "HIF Write success");
+ return rc;
+}
+
+
+int mantis_hif_read_mem(struct mantis_ca *ca, u32 addr)
+{
+ struct mantis_pci *mantis = ca->ca_priv;
+ u32 hif_addr = 0, data, count = 4;
+
+ dprintk(MANTIS_DEBUG, 1, "Adapter(%d) Slot(0): Request HIF Mem Read", mantis->num);
+ mutex_lock(&ca->ca_lock);
+ hif_addr &= ~MANTIS_GPIF_PCMCIAREG;
+ hif_addr &= ~MANTIS_GPIF_PCMCIAIOM;
+ hif_addr |= MANTIS_HIF_STATUS;
+ hif_addr |= addr;
+
+ mmwrite(hif_addr, MANTIS_GPIF_BRADDR);
+ mmwrite(count, MANTIS_GPIF_BRBYTES);
+ udelay(20);
+ mmwrite(hif_addr | MANTIS_GPIF_HIFRDWRN, MANTIS_GPIF_ADDR);
+
+ if (mantis_hif_sbuf_opdone_wait(ca) != 0) {
+ dprintk(MANTIS_ERROR, 1, "Adapter(%d) Slot(0): GPIF Smart Buffer operation failed", mantis->num);
+ mutex_unlock(&ca->ca_lock);
+ return -EREMOTEIO;
+ }
+ data = mmread(MANTIS_GPIF_DIN);
+ mutex_unlock(&ca->ca_lock);
+ dprintk(MANTIS_DEBUG, 1, "Mem Read: 0x%02x", data);
+ return (data >> 24) & 0xff;
+}
+
+int mantis_hif_write_mem(struct mantis_ca *ca, u32 addr, u8 data)
+{
+ struct mantis_slot *slot = ca->slot;
+ struct mantis_pci *mantis = ca->ca_priv;
+ u32 hif_addr = 0;
+
+ dprintk(MANTIS_DEBUG, 1, "Adapter(%d) Slot(0): Request HIF Mem Write", mantis->num);
+ mutex_lock(&ca->ca_lock);
+ hif_addr &= ~MANTIS_GPIF_HIFRDWRN;
+ hif_addr &= ~MANTIS_GPIF_PCMCIAREG;
+ hif_addr &= ~MANTIS_GPIF_PCMCIAIOM;
+ hif_addr |= MANTIS_HIF_STATUS;
+ hif_addr |= addr;
+
+ mmwrite(slot->slave_cfg, MANTIS_GPIF_CFGSLA); /* Slot0 alone for now */
+ mmwrite(hif_addr, MANTIS_GPIF_ADDR);
+ mmwrite(data, MANTIS_GPIF_DOUT);
+
+ if (mantis_hif_write_wait(ca) != 0) {
+ dprintk(MANTIS_ERROR, 1, "Adapter(%d) Slot(0): HIF Smart Buffer operation failed", mantis->num);
+ mutex_unlock(&ca->ca_lock);
+ return -EREMOTEIO;
+ }
+ dprintk(MANTIS_DEBUG, 1, "Mem Write: (0x%02x to 0x%02x)", data, addr);
+ mutex_unlock(&ca->ca_lock);
+
+ return 0;
+}
+
+int mantis_hif_read_iom(struct mantis_ca *ca, u32 addr)
+{
+ struct mantis_pci *mantis = ca->ca_priv;
+ u32 data, hif_addr = 0;
+
+ dprintk(MANTIS_DEBUG, 1, "Adapter(%d) Slot(0): Request HIF I/O Read", mantis->num);
+ mutex_lock(&ca->ca_lock);
+ hif_addr &= ~MANTIS_GPIF_PCMCIAREG;
+ hif_addr |= MANTIS_GPIF_PCMCIAIOM;
+ hif_addr |= MANTIS_HIF_STATUS;
+ hif_addr |= addr;
+
+ mmwrite(hif_addr, MANTIS_GPIF_BRADDR);
+ mmwrite(1, MANTIS_GPIF_BRBYTES);
+ udelay(20);
+ mmwrite(hif_addr | MANTIS_GPIF_HIFRDWRN, MANTIS_GPIF_ADDR);
+
+ if (mantis_hif_sbuf_opdone_wait(ca) != 0) {
+ dprintk(MANTIS_ERROR, 1, "Adapter(%d) Slot(0): HIF Smart Buffer operation failed", mantis->num);
+ mutex_unlock(&ca->ca_lock);
+ return -EREMOTEIO;
+ }
+ data = mmread(MANTIS_GPIF_DIN);
+ dprintk(MANTIS_DEBUG, 1, "I/O Read: 0x%02x", data);
+ udelay(50);
+ mutex_unlock(&ca->ca_lock);
+
+ return (u8) data;
+}
+
+int mantis_hif_write_iom(struct mantis_ca *ca, u32 addr, u8 data)
+{
+ struct mantis_pci *mantis = ca->ca_priv;
+ u32 hif_addr = 0;
+
+ dprintk(MANTIS_DEBUG, 1, "Adapter(%d) Slot(0): Request HIF I/O Write", mantis->num);
+ mutex_lock(&ca->ca_lock);
+ hif_addr &= ~MANTIS_GPIF_PCMCIAREG;
+ hif_addr &= ~MANTIS_GPIF_HIFRDWRN;
+ hif_addr |= MANTIS_GPIF_PCMCIAIOM;
+ hif_addr |= MANTIS_HIF_STATUS;
+ hif_addr |= addr;
+
+ mmwrite(hif_addr, MANTIS_GPIF_ADDR);
+ mmwrite(data, MANTIS_GPIF_DOUT);
+
+ if (mantis_hif_write_wait(ca) != 0) {
+ dprintk(MANTIS_ERROR, 1, "Adapter(%d) Slot(0): HIF Smart Buffer operation failed", mantis->num);
+ mutex_unlock(&ca->ca_lock);
+ return -EREMOTEIO;
+ }
+ dprintk(MANTIS_DEBUG, 1, "I/O Write: (0x%02x to 0x%02x)", data, addr);
+ mutex_unlock(&ca->ca_lock);
+ udelay(50);
+
+ return 0;
+}
+
+int mantis_hif_init(struct mantis_ca *ca)
+{
+ struct mantis_slot *slot = ca->slot;
+ struct mantis_pci *mantis = ca->ca_priv;
+ u32 irqcfg;
+
+ slot[0].slave_cfg = 0x70773028;
+ dprintk(MANTIS_ERROR, 1, "Adapter(%d) Initializing Mantis Host Interface", mantis->num);
+
+ mutex_lock(&ca->ca_lock);
+ irqcfg = mmread(MANTIS_GPIF_IRQCFG);
+ irqcfg = MANTIS_MASK_BRRDY |
+ MANTIS_MASK_WRACK |
+ MANTIS_MASK_EXTIRQ |
+ MANTIS_MASK_WSTO |
+ MANTIS_MASK_OTHERR |
+ MANTIS_MASK_OVFLW;
+
+ mmwrite(irqcfg, MANTIS_GPIF_IRQCFG);
+ mutex_unlock(&ca->ca_lock);
+
+ return 0;
+}
+
+void mantis_hif_exit(struct mantis_ca *ca)
+{
+ struct mantis_pci *mantis = ca->ca_priv;
+ u32 irqcfg;
+
+ dprintk(MANTIS_ERROR, 1, "Adapter(%d) Exiting Mantis Host Interface", mantis->num);
+ mutex_lock(&ca->ca_lock);
+ irqcfg = mmread(MANTIS_GPIF_IRQCFG);
+ irqcfg &= ~MANTIS_MASK_BRRDY;
+ mmwrite(irqcfg, MANTIS_GPIF_IRQCFG);
+ mutex_unlock(&ca->ca_lock);
+}
diff --git a/drivers/media/dvb/mantis/mantis_hif.h b/drivers/media/dvb/mantis/mantis_hif.h
new file mode 100644
index 000000000000..9094f9ed2362
--- /dev/null
+++ b/drivers/media/dvb/mantis/mantis_hif.h
@@ -0,0 +1,29 @@
+/*
+ Mantis PCI bridge driver
+
+ Copyright (C) Manu Abraham (abraham.manu@gmail.com)
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#ifndef __MANTIS_HIF_H
+#define __MANTIS_HIF_H
+
+#define MANTIS_HIF_MEMRD 1
+#define MANTIS_HIF_MEMWR 2
+#define MANTIS_HIF_IOMRD 3
+#define MANTIS_HIF_IOMWR 4
+
+#endif /* __MANTIS_HIF_H */
diff --git a/drivers/media/dvb/mantis/mantis_i2c.c b/drivers/media/dvb/mantis/mantis_i2c.c
new file mode 100644
index 000000000000..7870bcf9689a
--- /dev/null
+++ b/drivers/media/dvb/mantis/mantis_i2c.c
@@ -0,0 +1,267 @@
+/*
+ Mantis PCI bridge driver
+
+ Copyright (C) Manu Abraham (abraham.manu@gmail.com)
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include <asm/io.h>
+#include <linux/ioport.h>
+#include <linux/pci.h>
+#include <linux/i2c.h>
+
+#include "dmxdev.h"
+#include "dvbdev.h"
+#include "dvb_demux.h"
+#include "dvb_frontend.h"
+#include "dvb_net.h"
+
+#include "mantis_common.h"
+#include "mantis_reg.h"
+#include "mantis_i2c.h"
+
+#define TRIALS 10000
+
+static int mantis_i2c_read(struct mantis_pci *mantis, const struct i2c_msg *msg)
+{
+ u32 rxd, i, stat, trials;
+
+ dprintk(MANTIS_INFO, 0, " %s: Address=[0x%02x] <R>[ ",
+ __func__, msg->addr);
+
+ for (i = 0; i < msg->len; i++) {
+ rxd = (msg->addr << 25) | (1 << 24)
+ | MANTIS_I2C_RATE_3
+ | MANTIS_I2C_STOP
+ | MANTIS_I2C_PGMODE;
+
+ if (i == (msg->len - 1))
+ rxd &= ~MANTIS_I2C_STOP;
+
+ mmwrite(MANTIS_INT_I2CDONE, MANTIS_INT_STAT);
+ mmwrite(rxd, MANTIS_I2CDATA_CTL);
+
+ /* wait for xfer completion */
+ for (trials = 0; trials < TRIALS; trials++) {
+ stat = mmread(MANTIS_INT_STAT);
+ if (stat & MANTIS_INT_I2CDONE)
+ break;
+ }
+
+ dprintk(MANTIS_TMG, 0, "I2CDONE: trials=%d\n", trials);
+
+ /* wait for xfer completion */
+ for (trials = 0; trials < TRIALS; trials++) {
+ stat = mmread(MANTIS_INT_STAT);
+ if (stat & MANTIS_INT_I2CRACK)
+ break;
+ }
+
+ dprintk(MANTIS_TMG, 0, "I2CRACK: trials=%d\n", trials);
+
+ rxd = mmread(MANTIS_I2CDATA_CTL);
+ msg->buf[i] = (u8)((rxd >> 8) & 0xFF);
+ dprintk(MANTIS_INFO, 0, "%02x ", msg->buf[i]);
+ }
+ dprintk(MANTIS_INFO, 0, "]\n");
+
+ return 0;
+}
+
+static int mantis_i2c_write(struct mantis_pci *mantis, const struct i2c_msg *msg)
+{
+ int i;
+ u32 txd = 0, stat, trials;
+
+ dprintk(MANTIS_INFO, 0, " %s: Address=[0x%02x] <W>[ ",
+ __func__, msg->addr);
+
+ for (i = 0; i < msg->len; i++) {
+ dprintk(MANTIS_INFO, 0, "%02x ", msg->buf[i]);
+ txd = (msg->addr << 25) | (msg->buf[i] << 8)
+ | MANTIS_I2C_RATE_3
+ | MANTIS_I2C_STOP
+ | MANTIS_I2C_PGMODE;
+
+ if (i == (msg->len - 1))
+ txd &= ~MANTIS_I2C_STOP;
+
+ mmwrite(MANTIS_INT_I2CDONE, MANTIS_INT_STAT);
+ mmwrite(txd, MANTIS_I2CDATA_CTL);
+
+ /* wait for xfer completion */
+ for (trials = 0; trials < TRIALS; trials++) {
+ stat = mmread(MANTIS_INT_STAT);
+ if (stat & MANTIS_INT_I2CDONE)
+ break;
+ }
+
+ dprintk(MANTIS_TMG, 0, "I2CDONE: trials=%d\n", trials);
+
+ /* wait for xfer completion */
+ for (trials = 0; trials < TRIALS; trials++) {
+ stat = mmread(MANTIS_INT_STAT);
+ if (stat & MANTIS_INT_I2CRACK)
+ break;
+ }
+
+ dprintk(MANTIS_TMG, 0, "I2CRACK: trials=%d\n", trials);
+ }
+ dprintk(MANTIS_INFO, 0, "]\n");
+
+ return 0;
+}
+
+static int mantis_i2c_xfer(struct i2c_adapter *adapter, struct i2c_msg *msgs, int num)
+{
+ int ret = 0, i = 0, trials;
+ u32 stat, data, txd;
+ struct mantis_pci *mantis;
+ struct mantis_hwconfig *config;
+
+ mantis = i2c_get_adapdata(adapter);
+ BUG_ON(!mantis);
+ config = mantis->hwconfig;
+ BUG_ON(!config);
+
+ dprintk(MANTIS_DEBUG, 1, "Messages:%d", num);
+ mutex_lock(&mantis->i2c_lock);
+
+ while (i < num) {
+ /* Byte MODE */
+ if ((config->i2c_mode & MANTIS_BYTE_MODE) &&
+ ((i + 1) < num) &&
+ (msgs[i].len < 2) &&
+ (msgs[i + 1].len < 2) &&
+ (msgs[i + 1].flags & I2C_M_RD)) {
+
+ dprintk(MANTIS_DEBUG, 0, " Byte MODE:\n");
+
+ /* Read operation */
+ txd = msgs[i].addr << 25 | (0x1 << 24)
+ | (msgs[i].buf[0] << 16)
+ | MANTIS_I2C_RATE_3;
+
+ mmwrite(txd, MANTIS_I2CDATA_CTL);
+ /* wait for xfer completion */
+ for (trials = 0; trials < TRIALS; trials++) {
+ stat = mmread(MANTIS_INT_STAT);
+ if (stat & MANTIS_INT_I2CDONE)
+ break;
+ }
+
+ /* check for xfer completion */
+ if (stat & MANTIS_INT_I2CDONE) {
+ /* check xfer was acknowledged */
+ if (stat & MANTIS_INT_I2CRACK) {
+ data = mmread(MANTIS_I2CDATA_CTL);
+ msgs[i + 1].buf[0] = (data >> 8) & 0xff;
+ dprintk(MANTIS_DEBUG, 0, " Byte <%d> RXD=0x%02x [%02x]\n", 0x0, data, msgs[i + 1].buf[0]);
+ } else {
+ /* I/O error */
+ dprintk(MANTIS_ERROR, 1, " I/O error, LINE:%d", __LINE__);
+ ret = -EIO;
+ break;
+ }
+ } else {
+ /* I/O error */
+ dprintk(MANTIS_ERROR, 1, " I/O error, LINE:%d", __LINE__);
+ ret = -EIO;
+ break;
+ }
+ i += 2; /* Write/Read operation in one go */
+ }
+
+ if (i < num) {
+ if (msgs[i].flags & I2C_M_RD)
+ ret = mantis_i2c_read(mantis, &msgs[i]);
+ else
+ ret = mantis_i2c_write(mantis, &msgs[i]);
+
+ i++;
+ if (ret < 0)
+ goto bail_out;
+ }
+
+ }
+
+ mutex_unlock(&mantis->i2c_lock);
+
+ return num;
+
+bail_out:
+ mutex_unlock(&mantis->i2c_lock);
+ return ret;
+}
+
+static u32 mantis_i2c_func(struct i2c_adapter *adapter)
+{
+ return I2C_FUNC_SMBUS_EMUL;
+}
+
+static struct i2c_algorithm mantis_algo = {
+ .master_xfer = mantis_i2c_xfer,
+ .functionality = mantis_i2c_func,
+};
+
+int __devinit mantis_i2c_init(struct mantis_pci *mantis)
+{
+ u32 intstat, intmask;
+ struct i2c_adapter *i2c_adapter = &mantis->adapter;
+ struct pci_dev *pdev = mantis->pdev;
+
+ init_waitqueue_head(&mantis->i2c_wq);
+ mutex_init(&mantis->i2c_lock);
+ strncpy(i2c_adapter->name, "Mantis I2C", sizeof(i2c_adapter->name));
+ i2c_set_adapdata(i2c_adapter, mantis);
+
+ i2c_adapter->owner = THIS_MODULE;
+ i2c_adapter->class = I2C_CLASS_TV_DIGITAL;
+ i2c_adapter->algo = &mantis_algo;
+ i2c_adapter->algo_data = NULL;
+ i2c_adapter->timeout = 500;
+ i2c_adapter->retries = 3;
+ i2c_adapter->dev.parent = &pdev->dev;
+
+ mantis->i2c_rc = i2c_add_adapter(i2c_adapter);
+ if (mantis->i2c_rc < 0)
+ return mantis->i2c_rc;
+
+ dprintk(MANTIS_DEBUG, 1, "Initializing I2C ..");
+
+ intstat = mmread(MANTIS_INT_STAT);
+ intmask = mmread(MANTIS_INT_MASK);
+ mmwrite(intstat, MANTIS_INT_STAT);
+ dprintk(MANTIS_DEBUG, 1, "Disabling I2C interrupt");
+ intmask = mmread(MANTIS_INT_MASK);
+ mmwrite((intmask & ~MANTIS_INT_I2CDONE), MANTIS_INT_MASK);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(mantis_i2c_init);
+
+int mantis_i2c_exit(struct mantis_pci *mantis)
+{
+ u32 intmask;
+
+ dprintk(MANTIS_DEBUG, 1, "Disabling I2C interrupt");
+ intmask = mmread(MANTIS_INT_MASK);
+ mmwrite((intmask & ~MANTIS_INT_I2CDONE), MANTIS_INT_MASK);
+
+ dprintk(MANTIS_DEBUG, 1, "Removing I2C adapter");
+ return i2c_del_adapter(&mantis->adapter);
+}
+EXPORT_SYMBOL_GPL(mantis_i2c_exit);
diff --git a/drivers/media/dvb/mantis/mantis_i2c.h b/drivers/media/dvb/mantis/mantis_i2c.h
new file mode 100644
index 000000000000..1342df2faed8
--- /dev/null
+++ b/drivers/media/dvb/mantis/mantis_i2c.h
@@ -0,0 +1,30 @@
+/*
+ Mantis PCI bridge driver
+
+ Copyright (C) Manu Abraham (abraham.manu@gmail.com)
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#ifndef __MANTIS_I2C_H
+#define __MANTIS_I2C_H
+
+#define I2C_STOP (1 << 0)
+#define I2C_READ (1 << 1)
+
+extern int mantis_i2c_init(struct mantis_pci *mantis);
+extern int mantis_i2c_exit(struct mantis_pci *mantis);
+
+#endif /* __MANTIS_I2C_H */
diff --git a/drivers/media/dvb/mantis/mantis_input.c b/drivers/media/dvb/mantis/mantis_input.c
new file mode 100644
index 000000000000..4675a3b53c7d
--- /dev/null
+++ b/drivers/media/dvb/mantis/mantis_input.c
@@ -0,0 +1,148 @@
+/*
+ Mantis PCI bridge driver
+
+ Copyright (C) Manu Abraham (abraham.manu@gmail.com)
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include <linux/input.h>
+#include <media/ir-common.h>
+#include <linux/pci.h>
+
+#include "dmxdev.h"
+#include "dvbdev.h"
+#include "dvb_demux.h"
+#include "dvb_frontend.h"
+#include "dvb_net.h"
+
+#include "mantis_common.h"
+#include "mantis_reg.h"
+#include "mantis_uart.h"
+
+static struct ir_scancode mantis_ir_table[] = {
+ { 0x29, KEY_POWER },
+ { 0x28, KEY_FAVORITES },
+ { 0x30, KEY_TEXT },
+ { 0x17, KEY_INFO }, /* Preview */
+ { 0x23, KEY_EPG },
+ { 0x3b, KEY_F22 }, /* Record List */
+ { 0x3c, KEY_1 },
+ { 0x3e, KEY_2 },
+ { 0x39, KEY_3 },
+ { 0x36, KEY_4 },
+ { 0x22, KEY_5 },
+ { 0x20, KEY_6 },
+ { 0x32, KEY_7 },
+ { 0x26, KEY_8 },
+ { 0x24, KEY_9 },
+ { 0x2a, KEY_0 },
+
+ { 0x33, KEY_CANCEL },
+ { 0x2c, KEY_BACK },
+ { 0x15, KEY_CLEAR },
+ { 0x3f, KEY_TAB },
+ { 0x10, KEY_ENTER },
+ { 0x14, KEY_UP },
+ { 0x0d, KEY_RIGHT },
+ { 0x0e, KEY_DOWN },
+ { 0x11, KEY_LEFT },
+
+ { 0x21, KEY_VOLUMEUP },
+ { 0x35, KEY_VOLUMEDOWN },
+ { 0x3d, KEY_CHANNELDOWN },
+ { 0x3a, KEY_CHANNELUP },
+ { 0x2e, KEY_RECORD },
+ { 0x2b, KEY_PLAY },
+ { 0x13, KEY_PAUSE },
+ { 0x25, KEY_STOP },
+
+ { 0x1f, KEY_REWIND },
+ { 0x2d, KEY_FASTFORWARD },
+ { 0x1e, KEY_PREVIOUS }, /* Replay |< */
+ { 0x1d, KEY_NEXT }, /* Skip >| */
+
+ { 0x0b, KEY_CAMERA }, /* Capture */
+ { 0x0f, KEY_LANGUAGE }, /* SAP */
+ { 0x18, KEY_MODE }, /* PIP */
+ { 0x12, KEY_ZOOM }, /* Full screen */
+ { 0x1c, KEY_SUBTITLE },
+ { 0x2f, KEY_MUTE },
+ { 0x16, KEY_F20 }, /* L/R */
+ { 0x38, KEY_F21 }, /* Hibernate */
+
+ { 0x37, KEY_SWITCHVIDEOMODE }, /* A/V */
+ { 0x31, KEY_AGAIN }, /* Recall */
+ { 0x1a, KEY_KPPLUS }, /* Zoom+ */
+ { 0x19, KEY_KPMINUS }, /* Zoom- */
+ { 0x27, KEY_RED },
+ { 0x0C, KEY_GREEN },
+ { 0x01, KEY_YELLOW },
+ { 0x00, KEY_BLUE },
+};
+
+struct ir_scancode_table ir_mantis = {
+ .scan = mantis_ir_table,
+ .size = ARRAY_SIZE(mantis_ir_table),
+};
+EXPORT_SYMBOL_GPL(ir_mantis);
+
+int mantis_input_init(struct mantis_pci *mantis)
+{
+ struct input_dev *rc;
+ struct ir_input_state rc_state;
+ char name[80], dev[80];
+ int err;
+
+ rc = input_allocate_device();
+ if (!rc) {
+ dprintk(MANTIS_ERROR, 1, "Input device allocate failed");
+ return -ENOMEM;
+ }
+
+ sprintf(name, "Mantis %s IR receiver", mantis->hwconfig->model_name);
+ sprintf(dev, "pci-%s/ir0", pci_name(mantis->pdev));
+
+ rc->name = name;
+ rc->phys = dev;
+
+ ir_input_init(rc, &rc_state, IR_TYPE_OTHER);
+
+ rc->id.bustype = BUS_PCI;
+ rc->id.vendor = mantis->vendor_id;
+ rc->id.product = mantis->device_id;
+ rc->id.version = 1;
+ rc->dev = mantis->pdev->dev;
+
+ err = ir_input_register(rc, &ir_mantis, NULL);
+ if (err) {
+ dprintk(MANTIS_ERROR, 1, "IR device registration failed, ret = %d", err);
+ input_free_device(rc);
+ return -ENODEV;
+ }
+
+ mantis->rc = rc;
+
+ return 0;
+}
+
+int mantis_exit(struct mantis_pci *mantis)
+{
+ struct input_dev *rc = mantis->rc;
+
+ ir_input_unregister(rc);
+
+ return 0;
+}
diff --git a/drivers/media/dvb/mantis/mantis_ioc.c b/drivers/media/dvb/mantis/mantis_ioc.c
new file mode 100644
index 000000000000..de148ded52d8
--- /dev/null
+++ b/drivers/media/dvb/mantis/mantis_ioc.c
@@ -0,0 +1,130 @@
+/*
+ Mantis PCI bridge driver
+
+ Copyright (C) Manu Abraham (abraham.manu@gmail.com)
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include <linux/kernel.h>
+#include <linux/i2c.h>
+
+#include <linux/signal.h>
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+
+#include "dmxdev.h"
+#include "dvbdev.h"
+#include "dvb_demux.h"
+#include "dvb_frontend.h"
+#include "dvb_net.h"
+
+#include "mantis_common.h"
+#include "mantis_reg.h"
+#include "mantis_ioc.h"
+
+static int read_eeprom_bytes(struct mantis_pci *mantis, u8 reg, u8 *data, u8 length)
+{
+ struct i2c_adapter *adapter = &mantis->adapter;
+ int err;
+ u8 buf = reg;
+
+ struct i2c_msg msg[] = {
+ { .addr = 0x50, .flags = 0, .buf = &buf, .len = 1 },
+ { .addr = 0x50, .flags = I2C_M_RD, .buf = data, .len = length },
+ };
+
+ err = i2c_transfer(adapter, msg, 2);
+ if (err < 0) {
+ dprintk(MANTIS_ERROR, 1, "ERROR: i2c read: < err=%i d0=0x%02x d1=0x%02x >",
+ err, data[0], data[1]);
+
+ return err;
+ }
+
+ return 0;
+}
+int mantis_get_mac(struct mantis_pci *mantis)
+{
+ int err;
+ u8 mac_addr[6] = {0};
+
+ err = read_eeprom_bytes(mantis, 0x08, mac_addr, 6);
+ if (err < 0) {
+ dprintk(MANTIS_ERROR, 1, "ERROR: Mantis EEPROM read error <%d>", err);
+
+ return err;
+ }
+
+ dprintk(MANTIS_ERROR, 0,
+ " MAC Address=[%02x:%02x:%02x:%02x:%02x:%02x]\n",
+ mac_addr[0],
+ mac_addr[1],
+ mac_addr[2],
+ mac_addr[3],
+ mac_addr[4],
+ mac_addr[5]);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(mantis_get_mac);
+
+/* Turn the given bit on or off. */
+void gpio_set_bits(struct mantis_pci *mantis, u32 bitpos, u8 value)
+{
+ u32 cur;
+
+ dprintk(MANTIS_DEBUG, 1, "Set Bit <%d> to <%d>", bitpos, value);
+ cur = mmread(MANTIS_GPIF_ADDR);
+ if (value)
+ mantis->gpio_status = cur | (1 << bitpos);
+ else
+ mantis->gpio_status = cur & (~(1 << bitpos));
+
+ dprintk(MANTIS_DEBUG, 1, "GPIO Value <%02x>", mantis->gpio_status);
+ mmwrite(mantis->gpio_status, MANTIS_GPIF_ADDR);
+ mmwrite(0x00, MANTIS_GPIF_DOUT);
+}
+EXPORT_SYMBOL_GPL(gpio_set_bits);
+
+int mantis_stream_control(struct mantis_pci *mantis, enum mantis_stream_control stream_ctl)
+{
+ u32 reg;
+
+ reg = mmread(MANTIS_CONTROL);
+ switch (stream_ctl) {
+ case STREAM_TO_HIF:
+ dprintk(MANTIS_DEBUG, 1, "Set stream to HIF");
+ reg &= 0xff - MANTIS_BYPASS;
+ mmwrite(reg, MANTIS_CONTROL);
+ reg |= MANTIS_BYPASS;
+ mmwrite(reg, MANTIS_CONTROL);
+ break;
+
+ case STREAM_TO_CAM:
+ dprintk(MANTIS_DEBUG, 1, "Set stream to CAM");
+ reg |= MANTIS_BYPASS;
+ mmwrite(reg, MANTIS_CONTROL);
+ reg &= 0xff - MANTIS_BYPASS;
+ mmwrite(reg, MANTIS_CONTROL);
+ break;
+ default:
+ dprintk(MANTIS_ERROR, 1, "Unknown MODE <%02x>", stream_ctl);
+ return -1;
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(mantis_stream_control);
diff --git a/drivers/media/dvb/mantis/mantis_ioc.h b/drivers/media/dvb/mantis/mantis_ioc.h
new file mode 100644
index 000000000000..188fe5a81614
--- /dev/null
+++ b/drivers/media/dvb/mantis/mantis_ioc.h
@@ -0,0 +1,51 @@
+/*
+ Mantis PCI bridge driver
+
+ Copyright (C) Manu Abraham (abraham.manu@gmail.com)
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#ifndef __MANTIS_IOC_H
+#define __MANTIS_IOC_H
+
+#define GPIF_A00 0x00
+#define GPIF_A01 0x01
+#define GPIF_A02 0x02
+#define GPIF_A03 0x03
+#define GPIF_A04 0x04
+#define GPIF_A05 0x05
+#define GPIF_A06 0x06
+#define GPIF_A07 0x07
+#define GPIF_A08 0x08
+#define GPIF_A09 0x09
+#define GPIF_A10 0x0a
+#define GPIF_A11 0x0b
+
+#define GPIF_A12 0x0c
+#define GPIF_A13 0x0d
+#define GPIF_A14 0x0e
+
+enum mantis_stream_control {
+ STREAM_TO_HIF = 0,
+ STREAM_TO_CAM
+};
+
+extern int mantis_get_mac(struct mantis_pci *mantis);
+extern void gpio_set_bits(struct mantis_pci *mantis, u32 bitpos, u8 value);
+
+extern int mantis_stream_control(struct mantis_pci *mantis, enum mantis_stream_control stream_ctl);
+
+#endif /* __MANTIS_IOC_H */
diff --git a/drivers/media/dvb/mantis/mantis_link.h b/drivers/media/dvb/mantis/mantis_link.h
new file mode 100644
index 000000000000..2a814774a001
--- /dev/null
+++ b/drivers/media/dvb/mantis/mantis_link.h
@@ -0,0 +1,83 @@
+/*
+ Mantis PCI bridge driver
+
+ Copyright (C) Manu Abraham (abraham.manu@gmail.com)
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#ifndef __MANTIS_LINK_H
+#define __MANTIS_LINK_H
+
+#include <linux/mutex.h>
+#include <linux/workqueue.h>
+#include "dvb_ca_en50221.h"
+
+enum mantis_sbuf_status {
+ MANTIS_SBUF_DATA_AVAIL = 1,
+ MANTIS_SBUF_DATA_EMPTY = 2,
+ MANTIS_SBUF_DATA_OVFLW = 3
+};
+
+struct mantis_slot {
+ u32 timeout;
+ u32 slave_cfg;
+ u32 bar;
+};
+
+/* Physical layer */
+enum mantis_slot_state {
+ MODULE_INSERTED = 3,
+ MODULE_XTRACTED = 4
+};
+
+struct mantis_ca {
+ struct mantis_slot slot[4];
+
+ struct work_struct hif_evm_work;
+
+ u32 hif_event;
+ wait_queue_head_t hif_opdone_wq;
+ wait_queue_head_t hif_brrdyw_wq;
+ wait_queue_head_t hif_data_wq;
+ wait_queue_head_t hif_write_wq; /* HIF Write op */
+
+ enum mantis_sbuf_status sbuf_status;
+
+ enum mantis_slot_state slot_state;
+
+ void *ca_priv;
+
+ struct dvb_ca_en50221 en50221;
+ struct mutex ca_lock;
+};
+
+/* CA */
+extern void mantis_event_cam_plugin(struct mantis_ca *ca);
+extern void mantis_event_cam_unplug(struct mantis_ca *ca);
+extern int mantis_pcmcia_init(struct mantis_ca *ca);
+extern void mantis_pcmcia_exit(struct mantis_ca *ca);
+extern int mantis_evmgr_init(struct mantis_ca *ca);
+extern void mantis_evmgr_exit(struct mantis_ca *ca);
+
+/* HIF */
+extern int mantis_hif_init(struct mantis_ca *ca);
+extern void mantis_hif_exit(struct mantis_ca *ca);
+extern int mantis_hif_read_mem(struct mantis_ca *ca, u32 addr);
+extern int mantis_hif_write_mem(struct mantis_ca *ca, u32 addr, u8 data);
+extern int mantis_hif_read_iom(struct mantis_ca *ca, u32 addr);
+extern int mantis_hif_write_iom(struct mantis_ca *ca, u32 addr, u8 data);
+
+#endif /* __MANTIS_LINK_H */
diff --git a/drivers/media/dvb/mantis/mantis_pci.c b/drivers/media/dvb/mantis/mantis_pci.c
new file mode 100644
index 000000000000..6c7534af6b44
--- /dev/null
+++ b/drivers/media/dvb/mantis/mantis_pci.c
@@ -0,0 +1,177 @@
+/*
+ Mantis PCI bridge driver
+
+ Copyright (C) Manu Abraham (abraham.manu@gmail.com)
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/kernel.h>
+#include <asm/io.h>
+#include <asm/pgtable.h>
+#include <asm/page.h>
+#include <linux/kmod.h>
+#include <linux/vmalloc.h>
+#include <linux/init.h>
+#include <linux/device.h>
+#include <linux/pci.h>
+
+#include <asm/irq.h>
+#include <linux/signal.h>
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+
+#include "dmxdev.h"
+#include "dvbdev.h"
+#include "dvb_demux.h"
+#include "dvb_frontend.h"
+#include "dvb_net.h"
+
+#include <asm/irq.h>
+#include <linux/signal.h>
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+
+#include "mantis_common.h"
+#include "mantis_reg.h"
+#include "mantis_pci.h"
+
+#define DRIVER_NAME "Mantis Core"
+
+int __devinit mantis_pci_init(struct mantis_pci *mantis)
+{
+ u8 revision, latency;
+ struct mantis_hwconfig *config = mantis->hwconfig;
+ struct pci_dev *pdev = mantis->pdev;
+ int err, ret = 0;
+
+ dprintk(MANTIS_ERROR, 0, "found a %s PCI %s device on (%02x:%02x.%x),\n",
+ config->model_name,
+ config->dev_type,
+ mantis->pdev->bus->number,
+ PCI_SLOT(mantis->pdev->devfn),
+ PCI_FUNC(mantis->pdev->devfn));
+
+ err = pci_enable_device(pdev);
+ if (err != 0) {
+ ret = -ENODEV;
+ dprintk(MANTIS_ERROR, 1, "ERROR: PCI enable failed <%i>", err);
+ goto fail0;
+ }
+
+ err = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32));
+ if (err != 0) {
+ dprintk(MANTIS_ERROR, 1, "ERROR: Unable to obtain 32 bit DMA <%i>", err);
+ ret = -ENOMEM;
+ goto fail1;
+ }
+
+ pci_set_master(pdev);
+
+ if (!request_mem_region(pci_resource_start(pdev, 0),
+ pci_resource_len(pdev, 0),
+ DRIVER_NAME)) {
+
+ dprintk(MANTIS_ERROR, 1, "ERROR: BAR0 Request failed !");
+ ret = -ENODEV;
+ goto fail1;
+ }
+
+ mantis->mmio = ioremap(pci_resource_start(pdev, 0),
+ pci_resource_len(pdev, 0));
+
+ if (!mantis->mmio) {
+ dprintk(MANTIS_ERROR, 1, "ERROR: BAR0 remap failed !");
+ ret = -ENODEV;
+ goto fail2;
+ }
+
+ pci_read_config_byte(pdev, PCI_LATENCY_TIMER, &latency);
+ pci_read_config_byte(pdev, PCI_CLASS_REVISION, &revision);
+ mantis->latency = latency;
+ mantis->revision = revision;
+
+ dprintk(MANTIS_ERROR, 0, " Mantis Rev %d [%04x:%04x], ",
+ mantis->revision,
+ mantis->pdev->subsystem_vendor,
+ mantis->pdev->subsystem_device);
+
+ dprintk(MANTIS_ERROR, 0,
+ "irq: %d, latency: %d\n memory: 0x%lx, mmio: 0x%p\n",
+ mantis->pdev->irq,
+ mantis->latency,
+ mantis->mantis_addr,
+ mantis->mmio);
+
+ err = request_irq(pdev->irq,
+ config->irq_handler,
+ IRQF_SHARED,
+ DRIVER_NAME,
+ mantis);
+
+ if (err != 0) {
+
+ dprintk(MANTIS_ERROR, 1, "ERROR: IRQ registration failed ! <%d>", err);
+ ret = -ENODEV;
+ goto fail3;
+ }
+
+ pci_set_drvdata(pdev, mantis);
+ return ret;
+
+ /* Error conditions */
+fail3:
+ dprintk(MANTIS_ERROR, 1, "ERROR: <%d> I/O unmap", ret);
+ if (mantis->mmio)
+ iounmap(mantis->mmio);
+
+fail2:
+ dprintk(MANTIS_ERROR, 1, "ERROR: <%d> releasing regions", ret);
+ release_mem_region(pci_resource_start(pdev, 0),
+ pci_resource_len(pdev, 0));
+
+fail1:
+ dprintk(MANTIS_ERROR, 1, "ERROR: <%d> disabling device", ret);
+ pci_disable_device(pdev);
+
+fail0:
+ dprintk(MANTIS_ERROR, 1, "ERROR: <%d> exiting", ret);
+ pci_set_drvdata(pdev, NULL);
+ return ret;
+}
+EXPORT_SYMBOL_GPL(mantis_pci_init);
+
+void mantis_pci_exit(struct mantis_pci *mantis)
+{
+ struct pci_dev *pdev = mantis->pdev;
+
+ dprintk(MANTIS_NOTICE, 1, " mem: 0x%p", mantis->mmio);
+ free_irq(pdev->irq, mantis);
+ if (mantis->mmio) {
+ iounmap(mantis->mmio);
+ release_mem_region(pci_resource_start(pdev, 0),
+ pci_resource_len(pdev, 0));
+ }
+
+ pci_disable_device(pdev);
+ pci_set_drvdata(pdev, NULL);
+}
+EXPORT_SYMBOL_GPL(mantis_pci_exit);
+
+MODULE_DESCRIPTION("Mantis PCI DTV bridge driver");
+MODULE_AUTHOR("Manu Abraham");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/mantis/mantis_pci.h b/drivers/media/dvb/mantis/mantis_pci.h
new file mode 100644
index 000000000000..65f004519086
--- /dev/null
+++ b/drivers/media/dvb/mantis/mantis_pci.h
@@ -0,0 +1,27 @@
+/*
+ Mantis PCI bridge driver
+
+ Copyright (C) Manu Abraham (abraham.manu@gmail.com)
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#ifndef __MANTIS_PCI_H
+#define __MANTIS_PCI_H
+
+extern int mantis_pci_init(struct mantis_pci *mantis);
+extern void mantis_pci_exit(struct mantis_pci *mantis);
+
+#endif /* __MANTIS_PCI_H */
diff --git a/drivers/media/dvb/mantis/mantis_pcmcia.c b/drivers/media/dvb/mantis/mantis_pcmcia.c
new file mode 100644
index 000000000000..5cb545b913f6
--- /dev/null
+++ b/drivers/media/dvb/mantis/mantis_pcmcia.c
@@ -0,0 +1,120 @@
+/*
+ Mantis PCI bridge driver
+
+ Copyright (C) Manu Abraham (abraham.manu@gmail.com)
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include <linux/kernel.h>
+
+#include <linux/signal.h>
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+
+#include "dmxdev.h"
+#include "dvbdev.h"
+#include "dvb_demux.h"
+#include "dvb_frontend.h"
+#include "dvb_net.h"
+
+#include "mantis_common.h"
+#include "mantis_link.h" /* temporary due to physical layer stuff */
+#include "mantis_reg.h"
+
+/*
+ * If Slot state is already PLUG_IN event and we are called
+ * again, definitely it is jitter alone
+ */
+void mantis_event_cam_plugin(struct mantis_ca *ca)
+{
+ struct mantis_pci *mantis = ca->ca_priv;
+
+ u32 gpif_irqcfg;
+
+ if (ca->slot_state == MODULE_XTRACTED) {
+ dprintk(MANTIS_DEBUG, 1, "Event: CAM Plugged IN: Adapter(%d) Slot(0)", mantis->num);
+ udelay(50);
+ mmwrite(0xda000000, MANTIS_CARD_RESET);
+ gpif_irqcfg = mmread(MANTIS_GPIF_IRQCFG);
+ gpif_irqcfg |= MANTIS_MASK_PLUGOUT;
+ gpif_irqcfg &= ~MANTIS_MASK_PLUGIN;
+ mmwrite(gpif_irqcfg, MANTIS_GPIF_IRQCFG);
+ udelay(500);
+ ca->slot_state = MODULE_INSERTED;
+ }
+ udelay(100);
+}
+
+/*
+ * If Slot state is already UN_PLUG event and we are called
+ * again, definitely it is jitter alone
+ */
+void mantis_event_cam_unplug(struct mantis_ca *ca)
+{
+ struct mantis_pci *mantis = ca->ca_priv;
+
+ u32 gpif_irqcfg;
+
+ if (ca->slot_state == MODULE_INSERTED) {
+ dprintk(MANTIS_DEBUG, 1, "Event: CAM Unplugged: Adapter(%d) Slot(0)", mantis->num);
+ udelay(50);
+ mmwrite(0x00da0000, MANTIS_CARD_RESET);
+ gpif_irqcfg = mmread(MANTIS_GPIF_IRQCFG);
+ gpif_irqcfg |= MANTIS_MASK_PLUGIN;
+ gpif_irqcfg &= ~MANTIS_MASK_PLUGOUT;
+ mmwrite(gpif_irqcfg, MANTIS_GPIF_IRQCFG);
+ udelay(500);
+ ca->slot_state = MODULE_XTRACTED;
+ }
+ udelay(100);
+}
+
+int mantis_pcmcia_init(struct mantis_ca *ca)
+{
+ struct mantis_pci *mantis = ca->ca_priv;
+
+ u32 gpif_stat, card_stat;
+
+ mmwrite(mmread(MANTIS_INT_MASK) | MANTIS_INT_IRQ0, MANTIS_INT_MASK);
+ gpif_stat = mmread(MANTIS_GPIF_STATUS);
+ card_stat = mmread(MANTIS_GPIF_IRQCFG);
+
+ if (gpif_stat & MANTIS_GPIF_DETSTAT) {
+ dprintk(MANTIS_DEBUG, 1, "CAM found on Adapter(%d) Slot(0)", mantis->num);
+ mmwrite(card_stat | MANTIS_MASK_PLUGOUT, MANTIS_GPIF_IRQCFG);
+ ca->slot_state = MODULE_INSERTED;
+ dvb_ca_en50221_camchange_irq(&ca->en50221,
+ 0,
+ DVB_CA_EN50221_CAMCHANGE_INSERTED);
+ } else {
+ dprintk(MANTIS_DEBUG, 1, "Empty Slot on Adapter(%d) Slot(0)", mantis->num);
+ mmwrite(card_stat | MANTIS_MASK_PLUGIN, MANTIS_GPIF_IRQCFG);
+ ca->slot_state = MODULE_XTRACTED;
+ dvb_ca_en50221_camchange_irq(&ca->en50221,
+ 0,
+ DVB_CA_EN50221_CAMCHANGE_REMOVED);
+ }
+
+ return 0;
+}
+
+void mantis_pcmcia_exit(struct mantis_ca *ca)
+{
+ struct mantis_pci *mantis = ca->ca_priv;
+
+ mmwrite(mmread(MANTIS_GPIF_STATUS) & (~MANTIS_CARD_PLUGOUT | ~MANTIS_CARD_PLUGIN), MANTIS_GPIF_STATUS);
+ mmwrite(mmread(MANTIS_INT_MASK) & ~MANTIS_INT_IRQ0, MANTIS_INT_MASK);
+}
diff --git a/drivers/media/dvb/mantis/mantis_reg.h b/drivers/media/dvb/mantis/mantis_reg.h
new file mode 100644
index 000000000000..7761f9dc7fe0
--- /dev/null
+++ b/drivers/media/dvb/mantis/mantis_reg.h
@@ -0,0 +1,197 @@
+/*
+ Mantis PCI bridge driver
+
+ Copyright (C) Manu Abraham (abraham.manu@gmail.com)
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#ifndef __MANTIS_REG_H
+#define __MANTIS_REG_H
+
+/* Interrupts */
+#define MANTIS_INT_STAT 0x00
+#define MANTIS_INT_MASK 0x04
+
+#define MANTIS_INT_RISCSTAT (0x0f << 28)
+#define MANTIS_INT_RISCEN (0x01 << 27)
+#define MANTIS_INT_I2CRACK (0x01 << 26)
+
+/* #define MANTIS_INT_GPIF (0xff << 12) */
+
+#define MANTIS_INT_PCMCIA7 (0x01 << 19)
+#define MANTIS_INT_PCMCIA6 (0x01 << 18)
+#define MANTIS_INT_PCMCIA5 (0x01 << 17)
+#define MANTIS_INT_PCMCIA4 (0x01 << 16)
+#define MANTIS_INT_PCMCIA3 (0x01 << 15)
+#define MANTIS_INT_PCMCIA2 (0x01 << 14)
+#define MANTIS_INT_PCMCIA1 (0x01 << 13)
+#define MANTIS_INT_PCMCIA0 (0x01 << 12)
+#define MANTIS_INT_IRQ1 (0x01 << 11)
+#define MANTIS_INT_IRQ0 (0x01 << 10)
+#define MANTIS_INT_OCERR (0x01 << 8)
+#define MANTIS_INT_PABORT (0x01 << 7)
+#define MANTIS_INT_RIPERR (0x01 << 6)
+#define MANTIS_INT_PPERR (0x01 << 5)
+#define MANTIS_INT_FTRGT (0x01 << 3)
+#define MANTIS_INT_RISCI (0x01 << 1)
+#define MANTIS_INT_I2CDONE (0x01 << 0)
+
+/* DMA */
+#define MANTIS_DMA_CTL 0x08
+#define MANTIS_GPIF_RD (0xff << 24)
+#define MANTIS_GPIF_WR (0xff << 16)
+#define MANTIS_CPU_DO (0x01 << 10)
+#define MANTIS_DRV_DO (0x01 << 9)
+#define MANTIS_I2C_RD (0x01 << 7)
+#define MANTIS_I2C_WR (0x01 << 6)
+#define MANTIS_DCAP_MODE (0x01 << 5)
+#define MANTIS_FIFO_TP_4 (0x00 << 3)
+#define MANTIS_FIFO_TP_8 (0x01 << 3)
+#define MANTIS_FIFO_TP_16 (0x02 << 3)
+#define MANTIS_FIFO_EN (0x01 << 2)
+#define MANTIS_DCAP_EN (0x01 << 1)
+#define MANTIS_RISC_EN (0x01 << 0)
+
+/* DEBUG */
+#define MANTIS_DEBUGREG 0x0c
+#define MANTIS_DATINV (0x0e << 7)
+#define MANTIS_TOP_DEBUGSEL (0x07 << 4)
+#define MANTIS_PCMCIA_DEBUGSEL (0x0f << 0)
+
+#define MANTIS_RISC_START 0x10
+#define MANTIS_RISC_PC 0x14
+
+/* I2C */
+#define MANTIS_I2CDATA_CTL 0x18
+#define MANTIS_I2C_RATE_1 (0x00 << 6)
+#define MANTIS_I2C_RATE_2 (0x01 << 6)
+#define MANTIS_I2C_RATE_3 (0x02 << 6)
+#define MANTIS_I2C_RATE_4 (0x03 << 6)
+#define MANTIS_I2C_STOP (0x01 << 5)
+#define MANTIS_I2C_PGMODE (0x01 << 3)
+
+/* DATA */
+#define MANTIS_CMD_DATA_R1 0x20
+#define MANTIS_CMD_DATA_3 (0xff << 24)
+#define MANTIS_CMD_DATA_2 (0xff << 16)
+#define MANTIS_CMD_DATA_1 (0xff << 8)
+#define MANTIS_CMD_DATA_0 (0xff << 0)
+
+#define MANTIS_CMD_DATA_R2 0x24
+#define MANTIS_CMD_DATA_7 (0xff << 24)
+#define MANTIS_CMD_DATA_6 (0xff << 16)
+#define MANTIS_CMD_DATA_5 (0xff << 8)
+#define MANTIS_CMD_DATA_4 (0xff << 0)
+
+#define MANTIS_CONTROL 0x28
+#define MANTIS_DET (0x01 << 7)
+#define MANTIS_DAT_CF_EN (0x01 << 6)
+#define MANTIS_ACS (0x03 << 4)
+#define MANTIS_VCCEN (0x01 << 3)
+#define MANTIS_BYPASS (0x01 << 2)
+#define MANTIS_MRST (0x01 << 1)
+#define MANTIS_CRST_INT (0x01 << 0)
+
+#define MANTIS_GPIF_CFGSLA 0x84
+#define MANTIS_GPIF_WAITSMPL (0x07 << 28)
+#define MANTIS_GPIF_BYTEADDRSUB (0x01 << 25)
+#define MANTIS_GPIF_WAITPOL (0x01 << 24)
+#define MANTIS_GPIF_NCDELAY (0x07 << 20)
+#define MANTIS_GPIF_RW2CSDELAY (0x07 << 16)
+#define MANTIS_GPIF_SLFTIMEDMODE (0x01 << 15)
+#define MANTIS_GPIF_SLFTIMEDDELY (0x7f << 8)
+#define MANTIS_GPIF_DEVTYPE (0x07 << 4)
+#define MANTIS_GPIF_BIGENDIAN (0x01 << 3)
+#define MANTIS_GPIF_FETCHCMD (0x03 << 1)
+#define MANTIS_GPIF_HWORDDEV (0x01 << 0)
+
+#define MANTIS_GPIF_WSTOPER 0x90
+#define MANTIS_GPIF_WSTOPERWREN3 (0x01 << 31)
+#define MANTIS_GPIF_PARBOOTN (0x01 << 29)
+#define MANTIS_GPIF_WSTOPERSLID3 (0x1f << 24)
+#define MANTIS_GPIF_WSTOPERWREN2 (0x01 << 23)
+#define MANTIS_GPIF_WSTOPERSLID2 (0x1f << 16)
+#define MANTIS_GPIF_WSTOPERWREN1 (0x01 << 15)
+#define MANTIS_GPIF_WSTOPERSLID1 (0x1f << 8)
+#define MANTIS_GPIF_WSTOPERWREN0 (0x01 << 7)
+#define MANTIS_GPIF_WSTOPERSLID0 (0x1f << 0)
+
+#define MANTIS_GPIF_CS2RW 0x94
+#define MANTIS_GPIF_CS2RWWREN3 (0x01 << 31)
+#define MANTIS_GPIF_CS2RWDELY3 (0x3f << 24)
+#define MANTIS_GPIF_CS2RWWREN2 (0x01 << 23)
+#define MANTIS_GPIF_CS2RWDELY2 (0x3f << 16)
+#define MANTIS_GPIF_CS2RWWREN1 (0x01 << 15)
+#define MANTIS_GPIF_CS2RWDELY1 (0x3f << 8)
+#define MANTIS_GPIF_CS2RWWREN0 (0x01 << 7)
+#define MANTIS_GPIF_CS2RWDELY0 (0x3f << 0)
+
+#define MANTIS_GPIF_IRQCFG 0x98
+#define MANTIS_GPIF_IRQPOL (0x01 << 8)
+#define MANTIS_MASK_WRACK (0x01 << 7)
+#define MANTIS_MASK_BRRDY (0x01 << 6)
+#define MANTIS_MASK_OVFLW (0x01 << 5)
+#define MANTIS_MASK_OTHERR (0x01 << 4)
+#define MANTIS_MASK_WSTO (0x01 << 3)
+#define MANTIS_MASK_EXTIRQ (0x01 << 2)
+#define MANTIS_MASK_PLUGIN (0x01 << 1)
+#define MANTIS_MASK_PLUGOUT (0x01 << 0)
+
+#define MANTIS_GPIF_STATUS 0x9c
+#define MANTIS_SBUF_KILLOP (0x01 << 15)
+#define MANTIS_SBUF_OPDONE (0x01 << 14)
+#define MANTIS_SBUF_EMPTY (0x01 << 13)
+#define MANTIS_GPIF_DETSTAT (0x01 << 9)
+#define MANTIS_GPIF_INTSTAT (0x01 << 8)
+#define MANTIS_GPIF_WRACK (0x01 << 7)
+#define MANTIS_GPIF_BRRDY (0x01 << 6)
+#define MANTIS_SBUF_OVFLW (0x01 << 5)
+#define MANTIS_GPIF_OTHERR (0x01 << 4)
+#define MANTIS_SBUF_WSTO (0x01 << 3)
+#define MANTIS_GPIF_EXTIRQ (0x01 << 2)
+#define MANTIS_CARD_PLUGIN (0x01 << 1)
+#define MANTIS_CARD_PLUGOUT (0x01 << 0)
+
+#define MANTIS_GPIF_BRADDR 0xa0
+#define MANTIS_GPIF_PCMCIAREG (0x01 << 27)
+#define MANTIS_GPIF_PCMCIAIOM (0x01 << 26)
+#define MANTIS_GPIF_BR_ADDR (0xfffffff << 0)
+
+#define MANTIS_GPIF_BRBYTES 0xa4
+#define MANTIS_GPIF_BRCNT (0xfff << 0)
+
+#define MANTIS_PCMCIA_RESET 0xa8
+#define MANTIS_PCMCIA_RSTVAL (0xff << 0)
+
+#define MANTIS_CARD_RESET 0xac
+
+#define MANTIS_GPIF_ADDR 0xb0
+#define MANTIS_GPIF_HIFRDWRN (0x01 << 31)
+#define MANTIS_GPIF_PCMCIAREG (0x01 << 27)
+#define MANTIS_GPIF_PCMCIAIOM (0x01 << 26)
+#define MANTIS_GPIF_HIFADDR (0xfffffff << 0)
+
+#define MANTIS_GPIF_DOUT 0xb4
+#define MANTIS_GPIF_HIFDOUT (0xfffffff << 0)
+
+#define MANTIS_GPIF_DIN 0xb8
+#define MANTIS_GPIF_HIFDIN (0xfffffff << 0)
+
+#define MANTIS_GPIF_SPARE 0xbc
+#define MANTIS_GPIF_LOGICRD (0xffff << 16)
+#define MANTIS_GPIF_LOGICRW (0xffff << 0)
+
+#endif /* __MANTIS_REG_H */
diff --git a/drivers/media/dvb/mantis/mantis_uart.c b/drivers/media/dvb/mantis/mantis_uart.c
new file mode 100644
index 000000000000..7d2f2398fa8b
--- /dev/null
+++ b/drivers/media/dvb/mantis/mantis_uart.c
@@ -0,0 +1,186 @@
+/*
+ Mantis PCI bridge driver
+
+ Copyright (C) Manu Abraham (abraham.manu@gmail.com)
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include <linux/kernel.h>
+#include <linux/spinlock.h>
+
+#include <linux/signal.h>
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+
+#include "dmxdev.h"
+#include "dvbdev.h"
+#include "dvb_demux.h"
+#include "dvb_frontend.h"
+#include "dvb_net.h"
+
+#include "mantis_common.h"
+#include "mantis_reg.h"
+#include "mantis_uart.h"
+
+struct mantis_uart_params {
+ enum mantis_baud baud_rate;
+ enum mantis_parity parity;
+};
+
+static struct {
+ char string[7];
+} rates[5] = {
+ { "9600" },
+ { "19200" },
+ { "38400" },
+ { "57600" },
+ { "115200" }
+};
+
+static struct {
+ char string[5];
+} parity[3] = {
+ { "NONE" },
+ { "ODD" },
+ { "EVEN" }
+};
+
+#define UART_MAX_BUF 16
+
+int mantis_uart_read(struct mantis_pci *mantis, u8 *data)
+{
+ struct mantis_hwconfig *config = mantis->hwconfig;
+ u32 stat = 0, i;
+
+ /* get data */
+ for (i = 0; i < (config->bytes + 1); i++) {
+
+ stat = mmread(MANTIS_UART_STAT);
+
+ if (stat & MANTIS_UART_RXFIFO_FULL) {
+ dprintk(MANTIS_ERROR, 1, "RX Fifo FULL");
+ }
+ data[i] = mmread(MANTIS_UART_RXD) & 0x3f;
+
+ dprintk(MANTIS_DEBUG, 1, "Reading ... <%02x>", data[i] & 0x3f);
+
+ if (data[i] & (1 << 7)) {
+ dprintk(MANTIS_ERROR, 1, "UART framing error");
+ return -EINVAL;
+ }
+ if (data[i] & (1 << 6)) {
+ dprintk(MANTIS_ERROR, 1, "UART parity error");
+ return -EINVAL;
+ }
+ }
+
+ return 0;
+}
+
+static void mantis_uart_work(struct work_struct *work)
+{
+ struct mantis_pci *mantis = container_of(work, struct mantis_pci, uart_work);
+ struct mantis_hwconfig *config = mantis->hwconfig;
+ u8 buf[16];
+ int i;
+
+ mantis_uart_read(mantis, buf);
+
+ for (i = 0; i < (config->bytes + 1); i++)
+ dprintk(MANTIS_INFO, 1, "UART BUF:%d <%02x> ", i, buf[i]);
+
+ dprintk(MANTIS_DEBUG, 0, "\n");
+}
+
+static int mantis_uart_setup(struct mantis_pci *mantis,
+ struct mantis_uart_params *params)
+{
+ u32 reg;
+
+ mmwrite((mmread(MANTIS_UART_CTL) | (params->parity & 0x3)), MANTIS_UART_CTL);
+
+ reg = mmread(MANTIS_UART_BAUD);
+
+ switch (params->baud_rate) {
+ case MANTIS_BAUD_9600:
+ reg |= 0xd8;
+ break;
+ case MANTIS_BAUD_19200:
+ reg |= 0x6c;
+ break;
+ case MANTIS_BAUD_38400:
+ reg |= 0x36;
+ break;
+ case MANTIS_BAUD_57600:
+ reg |= 0x23;
+ break;
+ case MANTIS_BAUD_115200:
+ reg |= 0x11;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ mmwrite(reg, MANTIS_UART_BAUD);
+
+ return 0;
+}
+
+int mantis_uart_init(struct mantis_pci *mantis)
+{
+ struct mantis_hwconfig *config = mantis->hwconfig;
+ struct mantis_uart_params params;
+
+ /* default parity: */
+ params.baud_rate = config->baud_rate;
+ params.parity = config->parity;
+ dprintk(MANTIS_INFO, 1, "Initializing UART @ %sbps parity:%s",
+ rates[params.baud_rate].string,
+ parity[params.parity].string);
+
+ init_waitqueue_head(&mantis->uart_wq);
+ spin_lock_init(&mantis->uart_lock);
+
+ INIT_WORK(&mantis->uart_work, mantis_uart_work);
+
+ /* disable interrupt */
+ mmwrite(mmread(MANTIS_UART_CTL) & 0xffef, MANTIS_UART_CTL);
+
+ mantis_uart_setup(mantis, &params);
+
+ /* default 1 byte */
+ mmwrite((mmread(MANTIS_UART_BAUD) | (config->bytes << 8)), MANTIS_UART_BAUD);
+
+ /* flush buffer */
+ mmwrite((mmread(MANTIS_UART_CTL) | MANTIS_UART_RXFLUSH), MANTIS_UART_CTL);
+
+ /* enable interrupt */
+ mmwrite(mmread(MANTIS_INT_MASK) | 0x800, MANTIS_INT_MASK);
+ mmwrite(mmread(MANTIS_UART_CTL) | MANTIS_UART_RXINT, MANTIS_UART_CTL);
+
+ schedule_work(&mantis->uart_work);
+ dprintk(MANTIS_DEBUG, 1, "UART succesfully initialized");
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(mantis_uart_init);
+
+void mantis_uart_exit(struct mantis_pci *mantis)
+{
+ /* disable interrupt */
+ mmwrite(mmread(MANTIS_UART_CTL) & 0xffef, MANTIS_UART_CTL);
+}
+EXPORT_SYMBOL_GPL(mantis_uart_exit);
diff --git a/drivers/media/dvb/mantis/mantis_uart.h b/drivers/media/dvb/mantis/mantis_uart.h
new file mode 100644
index 000000000000..ffb62a0a5a13
--- /dev/null
+++ b/drivers/media/dvb/mantis/mantis_uart.h
@@ -0,0 +1,58 @@
+/*
+ Mantis PCI bridge driver
+
+ Copyright (C) Manu Abraham (abraham.manu@gmail.com)
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#ifndef __MANTIS_UART_H
+#define __MANTIS_UART_H
+
+#define MANTIS_UART_CTL 0xe0
+#define MANTIS_UART_RXINT (1 << 4)
+#define MANTIS_UART_RXFLUSH (1 << 2)
+
+#define MANTIS_UART_RXD 0xe8
+#define MANTIS_UART_BAUD 0xec
+
+#define MANTIS_UART_STAT 0xf0
+#define MANTIS_UART_RXFIFO_DATA (1 << 7)
+#define MANTIS_UART_RXFIFO_EMPTY (1 << 6)
+#define MANTIS_UART_RXFIFO_FULL (1 << 3)
+#define MANTIS_UART_FRAME_ERR (1 << 2)
+#define MANTIS_UART_PARITY_ERR (1 << 1)
+#define MANTIS_UART_RXTHRESH_INT (1 << 0)
+
+enum mantis_baud {
+ MANTIS_BAUD_9600 = 0,
+ MANTIS_BAUD_19200,
+ MANTIS_BAUD_38400,
+ MANTIS_BAUD_57600,
+ MANTIS_BAUD_115200
+};
+
+enum mantis_parity {
+ MANTIS_PARITY_NONE = 0,
+ MANTIS_PARITY_EVEN,
+ MANTIS_PARITY_ODD,
+};
+
+struct mantis_pci;
+
+extern int mantis_uart_init(struct mantis_pci *mantis);
+extern void mantis_uart_exit(struct mantis_pci *mantis);
+
+#endif /* __MANTIS_UART_H */
diff --git a/drivers/media/dvb/mantis/mantis_vp1033.c b/drivers/media/dvb/mantis/mantis_vp1033.c
new file mode 100644
index 000000000000..4a723bda0031
--- /dev/null
+++ b/drivers/media/dvb/mantis/mantis_vp1033.c
@@ -0,0 +1,212 @@
+/*
+ Mantis VP-1033 driver
+
+ Copyright (C) Manu Abraham (abraham.manu@gmail.com)
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include <linux/signal.h>
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+
+#include "dmxdev.h"
+#include "dvbdev.h"
+#include "dvb_demux.h"
+#include "dvb_frontend.h"
+#include "dvb_net.h"
+
+#include "stv0299.h"
+#include "mantis_common.h"
+#include "mantis_ioc.h"
+#include "mantis_dvb.h"
+#include "mantis_vp1033.h"
+#include "mantis_reg.h"
+
+u8 lgtdqcs001f_inittab[] = {
+ 0x01, 0x15,
+ 0x02, 0x00,
+ 0x03, 0x00,
+ 0x04, 0x2a,
+ 0x05, 0x85,
+ 0x06, 0x02,
+ 0x07, 0x00,
+ 0x08, 0x00,
+ 0x0c, 0x01,
+ 0x0d, 0x81,
+ 0x0e, 0x44,
+ 0x0f, 0x94,
+ 0x10, 0x3c,
+ 0x11, 0x84,
+ 0x12, 0xb9,
+ 0x13, 0xb5,
+ 0x14, 0x4f,
+ 0x15, 0xc9,
+ 0x16, 0x80,
+ 0x17, 0x36,
+ 0x18, 0xfb,
+ 0x19, 0xcf,
+ 0x1a, 0xbc,
+ 0x1c, 0x2b,
+ 0x1d, 0x27,
+ 0x1e, 0x00,
+ 0x1f, 0x0b,
+ 0x20, 0xa1,
+ 0x21, 0x60,
+ 0x22, 0x00,
+ 0x23, 0x00,
+ 0x28, 0x00,
+ 0x29, 0x28,
+ 0x2a, 0x14,
+ 0x2b, 0x0f,
+ 0x2c, 0x09,
+ 0x2d, 0x05,
+ 0x31, 0x1f,
+ 0x32, 0x19,
+ 0x33, 0xfc,
+ 0x34, 0x13,
+ 0xff, 0xff,
+};
+
+#define MANTIS_MODEL_NAME "VP-1033"
+#define MANTIS_DEV_TYPE "DVB-S/DSS"
+
+int lgtdqcs001f_tuner_set(struct dvb_frontend *fe,
+ struct dvb_frontend_parameters *params)
+{
+ struct mantis_pci *mantis = fe->dvb->priv;
+ struct i2c_adapter *adapter = &mantis->adapter;
+
+ u8 buf[4];
+ u32 div;
+
+
+ struct i2c_msg msg = {.addr = 0x61, .flags = 0, .buf = buf, .len = sizeof(buf)};
+
+ div = params->frequency / 250;
+
+ buf[0] = (div >> 8) & 0x7f;
+ buf[1] = div & 0xff;
+ buf[2] = 0x83;
+ buf[3] = 0xc0;
+
+ if (params->frequency < 1531000)
+ buf[3] |= 0x04;
+ else
+ buf[3] &= ~0x04;
+ if (i2c_transfer(adapter, &msg, 1) < 0) {
+ dprintk(MANTIS_ERROR, 1, "Write: I2C Transfer failed");
+ return -EIO;
+ }
+ msleep_interruptible(100);
+
+ return 0;
+}
+
+int lgtdqcs001f_set_symbol_rate(struct dvb_frontend *fe,
+ u32 srate, u32 ratio)
+{
+ u8 aclk = 0;
+ u8 bclk = 0;
+
+ if (srate < 1500000) {
+ aclk = 0xb7;
+ bclk = 0x47;
+ } else if (srate < 3000000) {
+ aclk = 0xb7;
+ bclk = 0x4b;
+ } else if (srate < 7000000) {
+ aclk = 0xb7;
+ bclk = 0x4f;
+ } else if (srate < 14000000) {
+ aclk = 0xb7;
+ bclk = 0x53;
+ } else if (srate < 30000000) {
+ aclk = 0xb6;
+ bclk = 0x53;
+ } else if (srate < 45000000) {
+ aclk = 0xb4;
+ bclk = 0x51;
+ }
+ stv0299_writereg(fe, 0x13, aclk);
+ stv0299_writereg(fe, 0x14, bclk);
+
+ stv0299_writereg(fe, 0x1f, (ratio >> 16) & 0xff);
+ stv0299_writereg(fe, 0x20, (ratio >> 8) & 0xff);
+ stv0299_writereg(fe, 0x21, ratio & 0xf0);
+
+ return 0;
+}
+
+struct stv0299_config lgtdqcs001f_config = {
+ .demod_address = 0x68,
+ .inittab = lgtdqcs001f_inittab,
+ .mclk = 88000000UL,
+ .invert = 0,
+ .skip_reinit = 0,
+ .volt13_op0_op1 = STV0299_VOLT13_OP0,
+ .min_delay_ms = 100,
+ .set_symbol_rate = lgtdqcs001f_set_symbol_rate,
+};
+
+static int vp1033_frontend_init(struct mantis_pci *mantis, struct dvb_frontend *fe)
+{
+ struct i2c_adapter *adapter = &mantis->adapter;
+
+ int err = 0;
+
+ err = mantis_frontend_power(mantis, POWER_ON);
+ if (err == 0) {
+ mantis_frontend_soft_reset(mantis);
+ msleep(250);
+
+ dprintk(MANTIS_ERROR, 1, "Probing for STV0299 (DVB-S)");
+ fe = stv0299_attach(&lgtdqcs001f_config, adapter);
+
+ if (fe) {
+ fe->ops.tuner_ops.set_params = lgtdqcs001f_tuner_set;
+ dprintk(MANTIS_ERROR, 1, "found STV0299 DVB-S frontend @ 0x%02x",
+ lgtdqcs001f_config.demod_address);
+
+ dprintk(MANTIS_ERROR, 1, "Mantis DVB-S STV0299 frontend attach success");
+ } else {
+ return -1;
+ }
+ } else {
+ dprintk(MANTIS_ERROR, 1, "Frontend on <%s> POWER ON failed! <%d>",
+ adapter->name,
+ err);
+
+ return -EIO;
+ }
+ mantis->fe = fe;
+ dprintk(MANTIS_ERROR, 1, "Done!");
+
+ return 0;
+}
+
+struct mantis_hwconfig vp1033_config = {
+ .model_name = MANTIS_MODEL_NAME,
+ .dev_type = MANTIS_DEV_TYPE,
+ .ts_size = MANTIS_TS_204,
+
+ .baud_rate = MANTIS_BAUD_9600,
+ .parity = MANTIS_PARITY_NONE,
+ .bytes = 0,
+
+ .frontend_init = vp1033_frontend_init,
+ .power = GPIF_A12,
+ .reset = GPIF_A13,
+};
diff --git a/drivers/media/dvb/mantis/mantis_vp1033.h b/drivers/media/dvb/mantis/mantis_vp1033.h
new file mode 100644
index 000000000000..7daaa1bf127d
--- /dev/null
+++ b/drivers/media/dvb/mantis/mantis_vp1033.h
@@ -0,0 +1,30 @@
+/*
+ Mantis VP-1033 driver
+
+ Copyright (C) Manu Abraham (abraham.manu@gmail.com)
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#ifndef __MANTIS_VP1033_H
+#define __MANTIS_VP1033_H
+
+#include "mantis_common.h"
+
+#define MANTIS_VP_1033_DVB_S 0x0016
+
+extern struct mantis_hwconfig vp1033_config;
+
+#endif /* __MANTIS_VP1033_H */
diff --git a/drivers/media/dvb/mantis/mantis_vp1034.c b/drivers/media/dvb/mantis/mantis_vp1034.c
new file mode 100644
index 000000000000..8e6ae558ee57
--- /dev/null
+++ b/drivers/media/dvb/mantis/mantis_vp1034.c
@@ -0,0 +1,119 @@
+/*
+ Mantis VP-1034 driver
+
+ Copyright (C) Manu Abraham (abraham.manu@gmail.com)
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include <linux/signal.h>
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+
+#include "dmxdev.h"
+#include "dvbdev.h"
+#include "dvb_demux.h"
+#include "dvb_frontend.h"
+#include "dvb_net.h"
+
+#include "mb86a16.h"
+#include "mantis_common.h"
+#include "mantis_ioc.h"
+#include "mantis_dvb.h"
+#include "mantis_vp1034.h"
+#include "mantis_reg.h"
+
+struct mb86a16_config vp1034_mb86a16_config = {
+ .demod_address = 0x08,
+ .set_voltage = vp1034_set_voltage,
+};
+
+#define MANTIS_MODEL_NAME "VP-1034"
+#define MANTIS_DEV_TYPE "DVB-S/DSS"
+
+int vp1034_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage)
+{
+ struct mantis_pci *mantis = fe->dvb->priv;
+
+ switch (voltage) {
+ case SEC_VOLTAGE_13:
+ dprintk(MANTIS_ERROR, 1, "Polarization=[13V]");
+ gpio_set_bits(mantis, 13, 1);
+ gpio_set_bits(mantis, 14, 0);
+ break;
+ case SEC_VOLTAGE_18:
+ dprintk(MANTIS_ERROR, 1, "Polarization=[18V]");
+ gpio_set_bits(mantis, 13, 1);
+ gpio_set_bits(mantis, 14, 1);
+ break;
+ case SEC_VOLTAGE_OFF:
+ dprintk(MANTIS_ERROR, 1, "Frontend (dummy) POWERDOWN");
+ break;
+ default:
+ dprintk(MANTIS_ERROR, 1, "Invalid = (%d)", (u32) voltage);
+ return -EINVAL;
+ }
+ mmwrite(0x00, MANTIS_GPIF_DOUT);
+
+ return 0;
+}
+
+static int vp1034_frontend_init(struct mantis_pci *mantis, struct dvb_frontend *fe)
+{
+ struct i2c_adapter *adapter = &mantis->adapter;
+
+ int err = 0;
+
+ err = mantis_frontend_power(mantis, POWER_ON);
+ if (err == 0) {
+ mantis_frontend_soft_reset(mantis);
+ msleep(250);
+
+ dprintk(MANTIS_ERROR, 1, "Probing for MB86A16 (DVB-S/DSS)");
+ fe = mb86a16_attach(&vp1034_mb86a16_config, adapter);
+ if (fe) {
+ dprintk(MANTIS_ERROR, 1,
+ "found MB86A16 DVB-S/DSS frontend @0x%02x",
+ vp1034_mb86a16_config.demod_address);
+
+ } else {
+ return -1;
+ }
+ } else {
+ dprintk(MANTIS_ERROR, 1, "Frontend on <%s> POWER ON failed! <%d>",
+ adapter->name,
+ err);
+
+ return -EIO;
+ }
+ mantis->fe = fe;
+ dprintk(MANTIS_ERROR, 1, "Done!");
+
+ return 0;
+}
+
+struct mantis_hwconfig vp1034_config = {
+ .model_name = MANTIS_MODEL_NAME,
+ .dev_type = MANTIS_DEV_TYPE,
+ .ts_size = MANTIS_TS_204,
+
+ .baud_rate = MANTIS_BAUD_9600,
+ .parity = MANTIS_PARITY_NONE,
+ .bytes = 0,
+
+ .frontend_init = vp1034_frontend_init,
+ .power = GPIF_A12,
+ .reset = GPIF_A13,
+};
diff --git a/drivers/media/dvb/mantis/mantis_vp1034.h b/drivers/media/dvb/mantis/mantis_vp1034.h
new file mode 100644
index 000000000000..323f38ef8e3d
--- /dev/null
+++ b/drivers/media/dvb/mantis/mantis_vp1034.h
@@ -0,0 +1,33 @@
+/*
+ Mantis VP-1034 driver
+
+ Copyright (C) Manu Abraham (abraham.manu@gmail.com)
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#ifndef __MANTIS_VP1034_H
+#define __MANTIS_VP1034_H
+
+#include "dvb_frontend.h"
+#include "mantis_common.h"
+
+
+#define MANTIS_VP_1034_DVB_S 0x0014
+
+extern struct mantis_hwconfig vp1034_config;
+extern int vp1034_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage);
+
+#endif /* __MANTIS_VP1034_H */
diff --git a/drivers/media/dvb/mantis/mantis_vp1041.c b/drivers/media/dvb/mantis/mantis_vp1041.c
new file mode 100644
index 000000000000..515346dd31d0
--- /dev/null
+++ b/drivers/media/dvb/mantis/mantis_vp1041.c
@@ -0,0 +1,358 @@
+/*
+ Mantis VP-1041 driver
+
+ Copyright (C) Manu Abraham (abraham.manu@gmail.com)
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include <linux/signal.h>
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+
+#include "dmxdev.h"
+#include "dvbdev.h"
+#include "dvb_demux.h"
+#include "dvb_frontend.h"
+#include "dvb_net.h"
+
+#include "mantis_common.h"
+#include "mantis_ioc.h"
+#include "mantis_dvb.h"
+#include "mantis_vp1041.h"
+#include "stb0899_reg.h"
+#include "stb0899_drv.h"
+#include "stb0899_cfg.h"
+#include "stb6100_cfg.h"
+#include "stb6100.h"
+#include "lnbp21.h"
+
+#define MANTIS_MODEL_NAME "VP-1041"
+#define MANTIS_DEV_TYPE "DSS/DVB-S/DVB-S2"
+
+static const struct stb0899_s1_reg vp1041_stb0899_s1_init_1[] = {
+
+ /* 0x0000000b, *//* SYSREG */
+ { STB0899_DEV_ID , 0x30 },
+ { STB0899_DISCNTRL1 , 0x32 },
+ { STB0899_DISCNTRL2 , 0x80 },
+ { STB0899_DISRX_ST0 , 0x04 },
+ { STB0899_DISRX_ST1 , 0x00 },
+ { STB0899_DISPARITY , 0x00 },
+ { STB0899_DISFIFO , 0x00 },
+ { STB0899_DISSTATUS , 0x20 },
+ { STB0899_DISF22 , 0x99 },
+ { STB0899_DISF22RX , 0xa8 },
+ /* SYSREG ? */
+ { STB0899_ACRPRESC , 0x11 },
+ { STB0899_ACRDIV1 , 0x0a },
+ { STB0899_ACRDIV2 , 0x05 },
+ { STB0899_DACR1 , 0x00 },
+ { STB0899_DACR2 , 0x00 },
+ { STB0899_OUTCFG , 0x00 },
+ { STB0899_MODECFG , 0x00 },
+ { STB0899_IRQSTATUS_3 , 0xfe },
+ { STB0899_IRQSTATUS_2 , 0x03 },
+ { STB0899_IRQSTATUS_1 , 0x7c },
+ { STB0899_IRQSTATUS_0 , 0xf4 },
+ { STB0899_IRQMSK_3 , 0xf3 },
+ { STB0899_IRQMSK_2 , 0xfc },
+ { STB0899_IRQMSK_1 , 0xff },
+ { STB0899_IRQMSK_0 , 0xff },
+ { STB0899_IRQCFG , 0x00 },
+ { STB0899_I2CCFG , 0x88 },
+ { STB0899_I2CRPT , 0x58 },
+ { STB0899_IOPVALUE5 , 0x00 },
+ { STB0899_IOPVALUE4 , 0x33 },
+ { STB0899_IOPVALUE3 , 0x6d },
+ { STB0899_IOPVALUE2 , 0x90 },
+ { STB0899_IOPVALUE1 , 0x60 },
+ { STB0899_IOPVALUE0 , 0x00 },
+ { STB0899_GPIO00CFG , 0x82 },
+ { STB0899_GPIO01CFG , 0x82 },
+ { STB0899_GPIO02CFG , 0x82 },
+ { STB0899_GPIO03CFG , 0x82 },
+ { STB0899_GPIO04CFG , 0x82 },
+ { STB0899_GPIO05CFG , 0x82 },
+ { STB0899_GPIO06CFG , 0x82 },
+ { STB0899_GPIO07CFG , 0x82 },
+ { STB0899_GPIO08CFG , 0x82 },
+ { STB0899_GPIO09CFG , 0x82 },
+ { STB0899_GPIO10CFG , 0x82 },
+ { STB0899_GPIO11CFG , 0x82 },
+ { STB0899_GPIO12CFG , 0x82 },
+ { STB0899_GPIO13CFG , 0x82 },
+ { STB0899_GPIO14CFG , 0x82 },
+ { STB0899_GPIO15CFG , 0x82 },
+ { STB0899_GPIO16CFG , 0x82 },
+ { STB0899_GPIO17CFG , 0x82 },
+ { STB0899_GPIO18CFG , 0x82 },
+ { STB0899_GPIO19CFG , 0x82 },
+ { STB0899_GPIO20CFG , 0x82 },
+ { STB0899_SDATCFG , 0xb8 },
+ { STB0899_SCLTCFG , 0xba },
+ { STB0899_AGCRFCFG , 0x1c }, /* 0x11 */
+ { STB0899_GPIO22 , 0x82 }, /* AGCBB2CFG */
+ { STB0899_GPIO21 , 0x91 }, /* AGCBB1CFG */
+ { STB0899_DIRCLKCFG , 0x82 },
+ { STB0899_CLKOUT27CFG , 0x7e },
+ { STB0899_STDBYCFG , 0x82 },
+ { STB0899_CS0CFG , 0x82 },
+ { STB0899_CS1CFG , 0x82 },
+ { STB0899_DISEQCOCFG , 0x20 },
+ { STB0899_GPIO32CFG , 0x82 },
+ { STB0899_GPIO33CFG , 0x82 },
+ { STB0899_GPIO34CFG , 0x82 },
+ { STB0899_GPIO35CFG , 0x82 },
+ { STB0899_GPIO36CFG , 0x82 },
+ { STB0899_GPIO37CFG , 0x82 },
+ { STB0899_GPIO38CFG , 0x82 },
+ { STB0899_GPIO39CFG , 0x82 },
+ { STB0899_NCOARSE , 0x17 }, /* 0x15 = 27 Mhz Clock, F/3 = 198MHz, F/6 = 99MHz */
+ { STB0899_SYNTCTRL , 0x02 }, /* 0x00 = CLK from CLKI, 0x02 = CLK from XTALI */
+ { STB0899_FILTCTRL , 0x00 },
+ { STB0899_SYSCTRL , 0x01 },
+ { STB0899_STOPCLK1 , 0x20 },
+ { STB0899_STOPCLK2 , 0x00 },
+ { STB0899_INTBUFSTATUS , 0x00 },
+ { STB0899_INTBUFCTRL , 0x0a },
+ { 0xffff , 0xff },
+};
+
+static const struct stb0899_s1_reg vp1041_stb0899_s1_init_3[] = {
+ { STB0899_DEMOD , 0x00 },
+ { STB0899_RCOMPC , 0xc9 },
+ { STB0899_AGC1CN , 0x01 },
+ { STB0899_AGC1REF , 0x10 },
+ { STB0899_RTC , 0x23 },
+ { STB0899_TMGCFG , 0x4e },
+ { STB0899_AGC2REF , 0x34 },
+ { STB0899_TLSR , 0x84 },
+ { STB0899_CFD , 0xf7 },
+ { STB0899_ACLC , 0x87 },
+ { STB0899_BCLC , 0x94 },
+ { STB0899_EQON , 0x41 },
+ { STB0899_LDT , 0xf1 },
+ { STB0899_LDT2 , 0xe3 },
+ { STB0899_EQUALREF , 0xb4 },
+ { STB0899_TMGRAMP , 0x10 },
+ { STB0899_TMGTHD , 0x30 },
+ { STB0899_IDCCOMP , 0xfd },
+ { STB0899_QDCCOMP , 0xff },
+ { STB0899_POWERI , 0x0c },
+ { STB0899_POWERQ , 0x0f },
+ { STB0899_RCOMP , 0x6c },
+ { STB0899_AGCIQIN , 0x80 },
+ { STB0899_AGC2I1 , 0x06 },
+ { STB0899_AGC2I2 , 0x00 },
+ { STB0899_TLIR , 0x30 },
+ { STB0899_RTF , 0x7f },
+ { STB0899_DSTATUS , 0x00 },
+ { STB0899_LDI , 0xbc },
+ { STB0899_CFRM , 0xea },
+ { STB0899_CFRL , 0x31 },
+ { STB0899_NIRM , 0x2b },
+ { STB0899_NIRL , 0x80 },
+ { STB0899_ISYMB , 0x1d },
+ { STB0899_QSYMB , 0xa6 },
+ { STB0899_SFRH , 0x2f },
+ { STB0899_SFRM , 0x68 },
+ { STB0899_SFRL , 0x40 },
+ { STB0899_SFRUPH , 0x2f },
+ { STB0899_SFRUPM , 0x68 },
+ { STB0899_SFRUPL , 0x40 },
+ { STB0899_EQUAI1 , 0x02 },
+ { STB0899_EQUAQ1 , 0xff },
+ { STB0899_EQUAI2 , 0x04 },
+ { STB0899_EQUAQ2 , 0x05 },
+ { STB0899_EQUAI3 , 0x02 },
+ { STB0899_EQUAQ3 , 0xfd },
+ { STB0899_EQUAI4 , 0x03 },
+ { STB0899_EQUAQ4 , 0x07 },
+ { STB0899_EQUAI5 , 0x08 },
+ { STB0899_EQUAQ5 , 0xf5 },
+ { STB0899_DSTATUS2 , 0x00 },
+ { STB0899_VSTATUS , 0x00 },
+ { STB0899_VERROR , 0x86 },
+ { STB0899_IQSWAP , 0x2a },
+ { STB0899_ECNT1M , 0x00 },
+ { STB0899_ECNT1L , 0x00 },
+ { STB0899_ECNT2M , 0x00 },
+ { STB0899_ECNT2L , 0x00 },
+ { STB0899_ECNT3M , 0x0a },
+ { STB0899_ECNT3L , 0xad },
+ { STB0899_FECAUTO1 , 0x06 },
+ { STB0899_FECM , 0x01 },
+ { STB0899_VTH12 , 0xb0 },
+ { STB0899_VTH23 , 0x7a },
+ { STB0899_VTH34 , 0x58 },
+ { STB0899_VTH56 , 0x38 },
+ { STB0899_VTH67 , 0x34 },
+ { STB0899_VTH78 , 0x24 },
+ { STB0899_PRVIT , 0xff },
+ { STB0899_VITSYNC , 0x19 },
+ { STB0899_RSULC , 0xb1 }, /* DVB = 0xb1, DSS = 0xa1 */
+ { STB0899_TSULC , 0x42 },
+ { STB0899_RSLLC , 0x41 },
+ { STB0899_TSLPL , 0x12 },
+ { STB0899_TSCFGH , 0x0c },
+ { STB0899_TSCFGM , 0x00 },
+ { STB0899_TSCFGL , 0x00 },
+ { STB0899_TSOUT , 0x69 }, /* 0x0d for CAM */
+ { STB0899_RSSYNCDEL , 0x00 },
+ { STB0899_TSINHDELH , 0x02 },
+ { STB0899_TSINHDELM , 0x00 },
+ { STB0899_TSINHDELL , 0x00 },
+ { STB0899_TSLLSTKM , 0x1b },
+ { STB0899_TSLLSTKL , 0xb3 },
+ { STB0899_TSULSTKM , 0x00 },
+ { STB0899_TSULSTKL , 0x00 },
+ { STB0899_PCKLENUL , 0xbc },
+ { STB0899_PCKLENLL , 0xcc },
+ { STB0899_RSPCKLEN , 0xbd },
+ { STB0899_TSSTATUS , 0x90 },
+ { STB0899_ERRCTRL1 , 0xb6 },
+ { STB0899_ERRCTRL2 , 0x95 },
+ { STB0899_ERRCTRL3 , 0x8d },
+ { STB0899_DMONMSK1 , 0x27 },
+ { STB0899_DMONMSK0 , 0x03 },
+ { STB0899_DEMAPVIT , 0x5c },
+ { STB0899_PLPARM , 0x19 },
+ { STB0899_PDELCTRL , 0x48 },
+ { STB0899_PDELCTRL2 , 0x00 },
+ { STB0899_BBHCTRL1 , 0x00 },
+ { STB0899_BBHCTRL2 , 0x00 },
+ { STB0899_HYSTTHRESH , 0x77 },
+ { STB0899_MATCSTM , 0x00 },
+ { STB0899_MATCSTL , 0x00 },
+ { STB0899_UPLCSTM , 0x00 },
+ { STB0899_UPLCSTL , 0x00 },
+ { STB0899_DFLCSTM , 0x00 },
+ { STB0899_DFLCSTL , 0x00 },
+ { STB0899_SYNCCST , 0x00 },
+ { STB0899_SYNCDCSTM , 0x00 },
+ { STB0899_SYNCDCSTL , 0x00 },
+ { STB0899_ISI_ENTRY , 0x00 },
+ { STB0899_ISI_BIT_EN , 0x00 },
+ { STB0899_MATSTRM , 0xf0 },
+ { STB0899_MATSTRL , 0x02 },
+ { STB0899_UPLSTRM , 0x45 },
+ { STB0899_UPLSTRL , 0x60 },
+ { STB0899_DFLSTRM , 0xe3 },
+ { STB0899_DFLSTRL , 0x00 },
+ { STB0899_SYNCSTR , 0x47 },
+ { STB0899_SYNCDSTRM , 0x05 },
+ { STB0899_SYNCDSTRL , 0x18 },
+ { STB0899_CFGPDELSTATUS1 , 0x19 },
+ { STB0899_CFGPDELSTATUS2 , 0x2b },
+ { STB0899_BBFERRORM , 0x00 },
+ { STB0899_BBFERRORL , 0x01 },
+ { STB0899_UPKTERRORM , 0x00 },
+ { STB0899_UPKTERRORL , 0x00 },
+ { 0xffff , 0xff },
+};
+
+struct stb0899_config vp1041_stb0899_config = {
+ .init_dev = vp1041_stb0899_s1_init_1,
+ .init_s2_demod = stb0899_s2_init_2,
+ .init_s1_demod = vp1041_stb0899_s1_init_3,
+ .init_s2_fec = stb0899_s2_init_4,
+ .init_tst = stb0899_s1_init_5,
+
+ .demod_address = 0x68, /* 0xd0 >> 1 */
+
+ .xtal_freq = 27000000,
+ .inversion = IQ_SWAP_ON, /* 1 */
+
+ .lo_clk = 76500000,
+ .hi_clk = 99000000,
+
+ .esno_ave = STB0899_DVBS2_ESNO_AVE,
+ .esno_quant = STB0899_DVBS2_ESNO_QUANT,
+ .avframes_coarse = STB0899_DVBS2_AVFRAMES_COARSE,
+ .avframes_fine = STB0899_DVBS2_AVFRAMES_FINE,
+ .miss_threshold = STB0899_DVBS2_MISS_THRESHOLD,
+ .uwp_threshold_acq = STB0899_DVBS2_UWP_THRESHOLD_ACQ,
+ .uwp_threshold_track = STB0899_DVBS2_UWP_THRESHOLD_TRACK,
+ .uwp_threshold_sof = STB0899_DVBS2_UWP_THRESHOLD_SOF,
+ .sof_search_timeout = STB0899_DVBS2_SOF_SEARCH_TIMEOUT,
+
+ .btr_nco_bits = STB0899_DVBS2_BTR_NCO_BITS,
+ .btr_gain_shift_offset = STB0899_DVBS2_BTR_GAIN_SHIFT_OFFSET,
+ .crl_nco_bits = STB0899_DVBS2_CRL_NCO_BITS,
+ .ldpc_max_iter = STB0899_DVBS2_LDPC_MAX_ITER,
+
+ .tuner_get_frequency = stb6100_get_frequency,
+ .tuner_set_frequency = stb6100_set_frequency,
+ .tuner_set_bandwidth = stb6100_set_bandwidth,
+ .tuner_get_bandwidth = stb6100_get_bandwidth,
+ .tuner_set_rfsiggain = NULL,
+};
+
+struct stb6100_config vp1041_stb6100_config = {
+ .tuner_address = 0x60,
+ .refclock = 27000000,
+};
+
+static int vp1041_frontend_init(struct mantis_pci *mantis, struct dvb_frontend *fe)
+{
+ struct i2c_adapter *adapter = &mantis->adapter;
+
+ int err = 0;
+
+ err = mantis_frontend_power(mantis, POWER_ON);
+ if (err == 0) {
+ mantis_frontend_soft_reset(mantis);
+ msleep(250);
+ mantis->fe = stb0899_attach(&vp1041_stb0899_config, adapter);
+ if (mantis->fe) {
+ dprintk(MANTIS_ERROR, 1,
+ "found STB0899 DVB-S/DVB-S2 frontend @0x%02x",
+ vp1041_stb0899_config.demod_address);
+
+ if (stb6100_attach(mantis->fe, &vp1041_stb6100_config, adapter)) {
+ if (!lnbp21_attach(mantis->fe, adapter, 0, 0))
+ dprintk(MANTIS_ERROR, 1, "No LNBP21 found!");
+ }
+ } else {
+ return -EREMOTEIO;
+ }
+ } else {
+ dprintk(MANTIS_ERROR, 1, "Frontend on <%s> POWER ON failed! <%d>",
+ adapter->name,
+ err);
+
+ return -EIO;
+ }
+
+
+ dprintk(MANTIS_ERROR, 1, "Done!");
+
+ return 0;
+}
+
+struct mantis_hwconfig vp1041_config = {
+ .model_name = MANTIS_MODEL_NAME,
+ .dev_type = MANTIS_DEV_TYPE,
+ .ts_size = MANTIS_TS_188,
+
+ .baud_rate = MANTIS_BAUD_9600,
+ .parity = MANTIS_PARITY_NONE,
+ .bytes = 0,
+
+ .frontend_init = vp1041_frontend_init,
+ .power = GPIF_A12,
+ .reset = GPIF_A13,
+};
diff --git a/drivers/media/dvb/mantis/mantis_vp1041.h b/drivers/media/dvb/mantis/mantis_vp1041.h
new file mode 100644
index 000000000000..1ae5b3de8081
--- /dev/null
+++ b/drivers/media/dvb/mantis/mantis_vp1041.h
@@ -0,0 +1,33 @@
+/*
+ Mantis VP-1041 driver
+
+ Copyright (C) Manu Abraham (abraham.manu@gmail.com)
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#ifndef __MANTIS_VP1041_H
+#define __MANTIS_VP1041_H
+
+#include "mantis_common.h"
+
+#define MANTIS_VP_1041_DVB_S2 0x0031
+#define SKYSTAR_HD2_10 0x0001
+#define SKYSTAR_HD2_20 0x0003
+#define CINERGY_S2_PCI_HD 0x1179
+
+extern struct mantis_hwconfig vp1041_config;
+
+#endif /* __MANTIS_VP1041_H */
diff --git a/drivers/media/dvb/mantis/mantis_vp2033.c b/drivers/media/dvb/mantis/mantis_vp2033.c
new file mode 100644
index 000000000000..10ce81790a8c
--- /dev/null
+++ b/drivers/media/dvb/mantis/mantis_vp2033.c
@@ -0,0 +1,187 @@
+/*
+ Mantis VP-2033 driver
+
+ Copyright (C) Manu Abraham (abraham.manu@gmail.com)
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include <linux/signal.h>
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+
+#include "dmxdev.h"
+#include "dvbdev.h"
+#include "dvb_demux.h"
+#include "dvb_frontend.h"
+#include "dvb_net.h"
+
+#include "tda1002x.h"
+#include "mantis_common.h"
+#include "mantis_ioc.h"
+#include "mantis_dvb.h"
+#include "mantis_vp2033.h"
+
+#define MANTIS_MODEL_NAME "VP-2033"
+#define MANTIS_DEV_TYPE "DVB-C"
+
+struct tda1002x_config vp2033_tda1002x_cu1216_config = {
+ .demod_address = 0x18 >> 1,
+ .invert = 1,
+};
+
+struct tda10023_config vp2033_tda10023_cu1216_config = {
+ .demod_address = 0x18 >> 1,
+ .invert = 1,
+};
+
+static u8 read_pwm(struct mantis_pci *mantis)
+{
+ struct i2c_adapter *adapter = &mantis->adapter;
+
+ u8 b = 0xff;
+ u8 pwm;
+ struct i2c_msg msg[] = {
+ {.addr = 0x50, .flags = 0, .buf = &b, .len = 1},
+ {.addr = 0x50, .flags = I2C_M_RD, .buf = &pwm, .len = 1}
+ };
+
+ if ((i2c_transfer(adapter, msg, 2) != 2)
+ || (pwm == 0xff))
+ pwm = 0x48;
+
+ return pwm;
+}
+
+static int tda1002x_cu1216_tuner_set(struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
+{
+ struct mantis_pci *mantis = fe->dvb->priv;
+ struct i2c_adapter *adapter = &mantis->adapter;
+
+ u8 buf[6];
+ struct i2c_msg msg = {.addr = 0x60, .flags = 0, .buf = buf, .len = sizeof(buf)};
+ int i;
+
+#define CU1216_IF 36125000
+#define TUNER_MUL 62500
+
+ u32 div = (params->frequency + CU1216_IF + TUNER_MUL / 2) / TUNER_MUL;
+
+ buf[0] = (div >> 8) & 0x7f;
+ buf[1] = div & 0xff;
+ buf[2] = 0xce;
+ buf[3] = (params->frequency < 150000000 ? 0x01 :
+ params->frequency < 445000000 ? 0x02 : 0x04);
+ buf[4] = 0xde;
+ buf[5] = 0x20;
+
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
+
+ if (i2c_transfer(adapter, &msg, 1) != 1)
+ return -EIO;
+
+ /* wait for the pll lock */
+ msg.flags = I2C_M_RD;
+ msg.len = 1;
+ for (i = 0; i < 20; i++) {
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
+
+ if (i2c_transfer(adapter, &msg, 1) == 1 && (buf[0] & 0x40))
+ break;
+
+ msleep(10);
+ }
+
+ /* switch the charge pump to the lower current */
+ msg.flags = 0;
+ msg.len = 2;
+ msg.buf = &buf[2];
+ buf[2] &= ~0x40;
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
+
+ if (i2c_transfer(adapter, &msg, 1) != 1)
+ return -EIO;
+
+ return 0;
+}
+
+static int vp2033_frontend_init(struct mantis_pci *mantis, struct dvb_frontend *fe)
+{
+ struct i2c_adapter *adapter = &mantis->adapter;
+
+ int err = 0;
+
+ err = mantis_frontend_power(mantis, POWER_ON);
+ if (err == 0) {
+ mantis_frontend_soft_reset(mantis);
+ msleep(250);
+
+ dprintk(MANTIS_ERROR, 1, "Probing for CU1216 (DVB-C)");
+ fe = tda10021_attach(&vp2033_tda1002x_cu1216_config,
+ adapter,
+ read_pwm(mantis));
+
+ if (fe) {
+ dprintk(MANTIS_ERROR, 1,
+ "found Philips CU1216 DVB-C frontend (TDA10021) @ 0x%02x",
+ vp2033_tda1002x_cu1216_config.demod_address);
+ } else {
+ fe = tda10023_attach(&vp2033_tda10023_cu1216_config,
+ adapter,
+ read_pwm(mantis));
+
+ if (fe) {
+ dprintk(MANTIS_ERROR, 1,
+ "found Philips CU1216 DVB-C frontend (TDA10023) @ 0x%02x",
+ vp2033_tda1002x_cu1216_config.demod_address);
+ }
+ }
+
+ if (fe) {
+ fe->ops.tuner_ops.set_params = tda1002x_cu1216_tuner_set;
+ dprintk(MANTIS_ERROR, 1, "Mantis DVB-C Philips CU1216 frontend attach success");
+ } else {
+ return -1;
+ }
+ } else {
+ dprintk(MANTIS_ERROR, 1, "Frontend on <%s> POWER ON failed! <%d>",
+ adapter->name,
+ err);
+
+ return -EIO;
+ }
+
+ mantis->fe = fe;
+ dprintk(MANTIS_DEBUG, 1, "Done!");
+
+ return 0;
+}
+
+struct mantis_hwconfig vp2033_config = {
+ .model_name = MANTIS_MODEL_NAME,
+ .dev_type = MANTIS_DEV_TYPE,
+ .ts_size = MANTIS_TS_204,
+
+ .baud_rate = MANTIS_BAUD_9600,
+ .parity = MANTIS_PARITY_NONE,
+ .bytes = 0,
+
+ .frontend_init = vp2033_frontend_init,
+ .power = GPIF_A12,
+ .reset = GPIF_A13,
+};
diff --git a/drivers/media/dvb/mantis/mantis_vp2033.h b/drivers/media/dvb/mantis/mantis_vp2033.h
new file mode 100644
index 000000000000..c55242b79d54
--- /dev/null
+++ b/drivers/media/dvb/mantis/mantis_vp2033.h
@@ -0,0 +1,30 @@
+/*
+ Mantis VP-2033 driver
+
+ Copyright (C) Manu Abraham (abraham.manu@gmail.com)
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#ifndef __MANTIS_VP2033_H
+#define __MANTIS_VP2033_H
+
+#include "mantis_common.h"
+
+#define MANTIS_VP_2033_DVB_C 0x0008
+
+extern struct mantis_hwconfig vp2033_config;
+
+#endif /* __MANTIS_VP2033_H */
diff --git a/drivers/media/dvb/mantis/mantis_vp2040.c b/drivers/media/dvb/mantis/mantis_vp2040.c
new file mode 100644
index 000000000000..a7ca233e800b
--- /dev/null
+++ b/drivers/media/dvb/mantis/mantis_vp2040.c
@@ -0,0 +1,186 @@
+/*
+ Mantis VP-2040 driver
+
+ Copyright (C) Manu Abraham (abraham.manu@gmail.com)
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include <linux/signal.h>
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+
+#include "dmxdev.h"
+#include "dvbdev.h"
+#include "dvb_demux.h"
+#include "dvb_frontend.h"
+#include "dvb_net.h"
+
+#include "tda1002x.h"
+#include "mantis_common.h"
+#include "mantis_ioc.h"
+#include "mantis_dvb.h"
+#include "mantis_vp2040.h"
+
+#define MANTIS_MODEL_NAME "VP-2040"
+#define MANTIS_DEV_TYPE "DVB-C"
+
+struct tda1002x_config vp2040_tda1002x_cu1216_config = {
+ .demod_address = 0x18 >> 1,
+ .invert = 1,
+};
+
+struct tda10023_config vp2040_tda10023_cu1216_config = {
+ .demod_address = 0x18 >> 1,
+ .invert = 1,
+};
+
+static int tda1002x_cu1216_tuner_set(struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
+{
+ struct mantis_pci *mantis = fe->dvb->priv;
+ struct i2c_adapter *adapter = &mantis->adapter;
+
+ u8 buf[6];
+ struct i2c_msg msg = {.addr = 0x60, .flags = 0, .buf = buf, .len = sizeof(buf)};
+ int i;
+
+#define CU1216_IF 36125000
+#define TUNER_MUL 62500
+
+ u32 div = (params->frequency + CU1216_IF + TUNER_MUL / 2) / TUNER_MUL;
+
+ buf[0] = (div >> 8) & 0x7f;
+ buf[1] = div & 0xff;
+ buf[2] = 0xce;
+ buf[3] = (params->frequency < 150000000 ? 0x01 :
+ params->frequency < 445000000 ? 0x02 : 0x04);
+ buf[4] = 0xde;
+ buf[5] = 0x20;
+
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
+
+ if (i2c_transfer(adapter, &msg, 1) != 1)
+ return -EIO;
+
+ /* wait for the pll lock */
+ msg.flags = I2C_M_RD;
+ msg.len = 1;
+ for (i = 0; i < 20; i++) {
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
+
+ if (i2c_transfer(adapter, &msg, 1) == 1 && (buf[0] & 0x40))
+ break;
+
+ msleep(10);
+ }
+
+ /* switch the charge pump to the lower current */
+ msg.flags = 0;
+ msg.len = 2;
+ msg.buf = &buf[2];
+ buf[2] &= ~0x40;
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
+
+ if (i2c_transfer(adapter, &msg, 1) != 1)
+ return -EIO;
+
+ return 0;
+}
+
+static u8 read_pwm(struct mantis_pci *mantis)
+{
+ struct i2c_adapter *adapter = &mantis->adapter;
+
+ u8 b = 0xff;
+ u8 pwm;
+ struct i2c_msg msg[] = {
+ {.addr = 0x50, .flags = 0, .buf = &b, .len = 1},
+ {.addr = 0x50, .flags = I2C_M_RD, .buf = &pwm, .len = 1}
+ };
+
+ if ((i2c_transfer(adapter, msg, 2) != 2)
+ || (pwm == 0xff))
+ pwm = 0x48;
+
+ return pwm;
+}
+
+static int vp2040_frontend_init(struct mantis_pci *mantis, struct dvb_frontend *fe)
+{
+ struct i2c_adapter *adapter = &mantis->adapter;
+
+ int err = 0;
+
+ err = mantis_frontend_power(mantis, POWER_ON);
+ if (err == 0) {
+ mantis_frontend_soft_reset(mantis);
+ msleep(250);
+
+ dprintk(MANTIS_ERROR, 1, "Probing for CU1216 (DVB-C)");
+ fe = tda10021_attach(&vp2040_tda1002x_cu1216_config,
+ adapter,
+ read_pwm(mantis));
+
+ if (fe) {
+ dprintk(MANTIS_ERROR, 1,
+ "found Philips CU1216 DVB-C frontend (TDA10021) @ 0x%02x",
+ vp2040_tda1002x_cu1216_config.demod_address);
+ } else {
+ fe = tda10023_attach(&vp2040_tda10023_cu1216_config,
+ adapter,
+ read_pwm(mantis));
+
+ if (fe) {
+ dprintk(MANTIS_ERROR, 1,
+ "found Philips CU1216 DVB-C frontend (TDA10023) @ 0x%02x",
+ vp2040_tda1002x_cu1216_config.demod_address);
+ }
+ }
+
+ if (fe) {
+ fe->ops.tuner_ops.set_params = tda1002x_cu1216_tuner_set;
+ dprintk(MANTIS_ERROR, 1, "Mantis DVB-C Philips CU1216 frontend attach success");
+ } else {
+ return -1;
+ }
+ } else {
+ dprintk(MANTIS_ERROR, 1, "Frontend on <%s> POWER ON failed! <%d>",
+ adapter->name,
+ err);
+
+ return -EIO;
+ }
+ mantis->fe = fe;
+ dprintk(MANTIS_DEBUG, 1, "Done!");
+
+ return 0;
+}
+
+struct mantis_hwconfig vp2040_config = {
+ .model_name = MANTIS_MODEL_NAME,
+ .dev_type = MANTIS_DEV_TYPE,
+ .ts_size = MANTIS_TS_204,
+
+ .baud_rate = MANTIS_BAUD_9600,
+ .parity = MANTIS_PARITY_NONE,
+ .bytes = 0,
+
+ .frontend_init = vp2040_frontend_init,
+ .power = GPIF_A12,
+ .reset = GPIF_A13,
+};
diff --git a/drivers/media/dvb/mantis/mantis_vp2040.h b/drivers/media/dvb/mantis/mantis_vp2040.h
new file mode 100644
index 000000000000..d125e219b685
--- /dev/null
+++ b/drivers/media/dvb/mantis/mantis_vp2040.h
@@ -0,0 +1,32 @@
+/*
+ Mantis VP-2040 driver
+
+ Copyright (C) Manu Abraham (abraham.manu@gmail.com)
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#ifndef __MANTIS_VP2040_H
+#define __MANTIS_VP2040_H
+
+#include "mantis_common.h"
+
+#define MANTIS_VP_2040_DVB_C 0x0043
+#define CINERGY_C 0x1178
+#define CABLESTAR_HD2 0x0002
+
+extern struct mantis_hwconfig vp2040_config;
+
+#endif /* __MANTIS_VP2040_H */
diff --git a/drivers/media/dvb/mantis/mantis_vp3028.c b/drivers/media/dvb/mantis/mantis_vp3028.c
new file mode 100644
index 000000000000..4155c838a18a
--- /dev/null
+++ b/drivers/media/dvb/mantis/mantis_vp3028.c
@@ -0,0 +1,38 @@
+/*
+ Mantis VP-3028 driver
+
+ Copyright (C) Manu Abraham (abraham.manu@gmail.com)
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "mantis_common.h"
+#include "mantis_vp3028.h"
+
+struct zl10353_config mantis_vp3028_config = {
+ .demod_address = 0x0f,
+};
+
+#define MANTIS_MODEL_NAME "VP-3028"
+#define MANTIS_DEV_TYPE "DVB-T"
+
+struct mantis_hwconfig vp3028_mantis_config = {
+ .model_name = MANTIS_MODEL_NAME,
+ .dev_type = MANTIS_DEV_TYPE,
+ .ts_size = MANTIS_TS_188,
+ .baud_rate = MANTIS_BAUD_9600,
+ .parity = MANTIS_PARITY_NONE,
+ .bytes = 0,
+};
diff --git a/drivers/media/dvb/mantis/mantis_vp3028.h b/drivers/media/dvb/mantis/mantis_vp3028.h
new file mode 100644
index 000000000000..b07be6adc522
--- /dev/null
+++ b/drivers/media/dvb/mantis/mantis_vp3028.h
@@ -0,0 +1,33 @@
+/*
+ Mantis VP-3028 driver
+
+ Copyright (C) Manu Abraham (abraham.manu@gmail.com)
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#ifndef __MANTIS_VP3028_H
+#define __MANTIS_VP3028_H
+
+#include "dvb_frontend.h"
+#include "mantis_common.h"
+#include "zl10353.h"
+
+#define MANTIS_VP_3028_DVB_T 0x0028
+
+extern struct zl10353_config mantis_vp3028_config;
+extern struct mantis_hwconfig vp3028_mantis_config;
+
+#endif /* __MANTIS_VP3028_H */
diff --git a/drivers/media/dvb/mantis/mantis_vp3030.c b/drivers/media/dvb/mantis/mantis_vp3030.c
new file mode 100644
index 000000000000..1f4334214953
--- /dev/null
+++ b/drivers/media/dvb/mantis/mantis_vp3030.c
@@ -0,0 +1,105 @@
+/*
+ Mantis VP-3030 driver
+
+ Copyright (C) Manu Abraham (abraham.manu@gmail.com)
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include <linux/signal.h>
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+
+#include "dmxdev.h"
+#include "dvbdev.h"
+#include "dvb_demux.h"
+#include "dvb_frontend.h"
+#include "dvb_net.h"
+
+#include "zl10353.h"
+#include "tda665x.h"
+#include "mantis_common.h"
+#include "mantis_ioc.h"
+#include "mantis_dvb.h"
+#include "mantis_vp3030.h"
+
+struct zl10353_config mantis_vp3030_config = {
+ .demod_address = 0x0f,
+};
+
+struct tda665x_config env57h12d5_config = {
+ .name = "ENV57H12D5 (ET-50DT)",
+ .addr = 0x60,
+ .frequency_min = 47000000,
+ .frequency_max = 862000000,
+ .frequency_offst = 3616667,
+ .ref_multiplier = 6, /* 1/6 MHz */
+ .ref_divider = 100000, /* 1/6 MHz */
+};
+
+#define MANTIS_MODEL_NAME "VP-3030"
+#define MANTIS_DEV_TYPE "DVB-T"
+
+
+static int vp3030_frontend_init(struct mantis_pci *mantis, struct dvb_frontend *fe)
+{
+ struct i2c_adapter *adapter = &mantis->adapter;
+ struct mantis_hwconfig *config = mantis->hwconfig;
+ int err = 0;
+
+ gpio_set_bits(mantis, config->reset, 0);
+ msleep(100);
+ err = mantis_frontend_power(mantis, POWER_ON);
+ msleep(100);
+ gpio_set_bits(mantis, config->reset, 1);
+
+ if (err == 0) {
+ msleep(250);
+ dprintk(MANTIS_ERROR, 1, "Probing for 10353 (DVB-T)");
+ fe = zl10353_attach(&mantis_vp3030_config, adapter);
+
+ if (!fe)
+ return -1;
+
+ tda665x_attach(fe, &env57h12d5_config, adapter);
+ } else {
+ dprintk(MANTIS_ERROR, 1, "Frontend on <%s> POWER ON failed! <%d>",
+ adapter->name,
+ err);
+
+ return -EIO;
+
+ }
+ mantis->fe = fe;
+ dprintk(MANTIS_ERROR, 1, "Done!");
+
+ return 0;
+}
+
+struct mantis_hwconfig vp3030_config = {
+ .model_name = MANTIS_MODEL_NAME,
+ .dev_type = MANTIS_DEV_TYPE,
+ .ts_size = MANTIS_TS_188,
+
+ .baud_rate = MANTIS_BAUD_9600,
+ .parity = MANTIS_PARITY_NONE,
+ .bytes = 0,
+
+ .frontend_init = vp3030_frontend_init,
+ .power = GPIF_A12,
+ .reset = GPIF_A13,
+
+ .i2c_mode = MANTIS_BYTE_MODE
+};
diff --git a/drivers/media/dvb/mantis/mantis_vp3030.h b/drivers/media/dvb/mantis/mantis_vp3030.h
new file mode 100644
index 000000000000..5f12c4266277
--- /dev/null
+++ b/drivers/media/dvb/mantis/mantis_vp3030.h
@@ -0,0 +1,30 @@
+/*
+ Mantis VP-3030 driver
+
+ Copyright (C) Manu Abraham (abraham.manu@gmail.com)
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#ifndef __MANTIS_VP3030_H
+#define __MANTIS_VP3030_H
+
+#include "mantis_common.h"
+
+#define MANTIS_VP_3030_DVB_T 0x0024
+
+extern struct mantis_hwconfig vp3030_config;
+
+#endif /* __MANTIS_VP3030_H */
diff --git a/drivers/media/dvb/siano/sms-cards.c b/drivers/media/dvb/siano/sms-cards.c
index 1067b22eb0c6..cff77e2eb557 100644
--- a/drivers/media/dvb/siano/sms-cards.c
+++ b/drivers/media/dvb/siano/sms-cards.c
@@ -62,6 +62,7 @@ static struct sms_board sms_boards[] = {
[SMS1XXX_BOARD_HAUPPAUGE_WINDHAM] = {
.name = "Hauppauge WinTV MiniStick",
.type = SMS_NOVA_B0,
+ .fw[DEVICE_MODE_ISDBT_BDA] = "sms1xxx-hcw-55xxx-isdbt-02.fw",
.fw[DEVICE_MODE_DVBT_BDA] = "sms1xxx-hcw-55xxx-dvbt-02.fw",
.board_cfg.leds_power = 26,
.board_cfg.led0 = 27,
diff --git a/drivers/media/dvb/siano/smscoreapi.h b/drivers/media/dvb/siano/smscoreapi.h
index eec18aaf5512..8ecadecaa9d0 100644
--- a/drivers/media/dvb/siano/smscoreapi.h
+++ b/drivers/media/dvb/siano/smscoreapi.h
@@ -212,6 +212,8 @@ struct smscore_device_t {
#define MSG_SMS_DAB_CHANNEL 607
#define MSG_SMS_GET_PID_FILTER_LIST_REQ 608
#define MSG_SMS_GET_PID_FILTER_LIST_RES 609
+#define MSG_SMS_GET_STATISTICS_RES 616
+#define MSG_SMS_GET_STATISTICS_REQ 615
#define MSG_SMS_HO_PER_SLICES_IND 630
#define MSG_SMS_SET_ANTENNA_CONFIG_REQ 651
#define MSG_SMS_SET_ANTENNA_CONFIG_RES 652
@@ -339,7 +341,7 @@ struct SmsFirmware_ST {
/* Statistics information returned as response for
* SmsHostApiGetStatistics_Req */
-struct SMSHOSTLIB_STATISTICS_S {
+struct SMSHOSTLIB_STATISTICS_ST {
u32 Reserved; /* Reserved */
/* Common parameters */
@@ -424,6 +426,79 @@ struct SMSHOSTLIB_STATISTICS_S {
u32 ReservedFields[10]; /* Reserved */
};
+struct SmsMsgStatisticsInfo_ST {
+ u32 RequestResult;
+
+ struct SMSHOSTLIB_STATISTICS_ST Stat;
+
+ /* Split the calc of the SNR in DAB */
+ u32 Signal; /* dB */
+ u32 Noise; /* dB */
+
+};
+
+struct SMSHOSTLIB_ISDBT_LAYER_STAT_ST {
+ /* Per-layer information */
+ u32 CodeRate; /* Code Rate from SMSHOSTLIB_CODE_RATE_ET,
+ * 255 means layer does not exist */
+ u32 Constellation; /* Constellation from SMSHOSTLIB_CONSTELLATION_ET,
+ * 255 means layer does not exist */
+ u32 BER; /* Post Viterbi BER [1E-5], 0xFFFFFFFF indicate N/A */
+ u32 BERErrorCount; /* Post Viterbi Error Bits Count */
+ u32 BERBitCount; /* Post Viterbi Total Bits Count */
+ u32 PreBER; /* Pre Viterbi BER [1E-5], 0xFFFFFFFF indicate N/A */
+ u32 TS_PER; /* Transport stream PER [%], 0xFFFFFFFF indicate N/A */
+ u32 ErrorTSPackets; /* Number of erroneous transport-stream packets */
+ u32 TotalTSPackets; /* Total number of transport-stream packets */
+ u32 TILdepthI; /* Time interleaver depth I parameter,
+ * 255 means layer does not exist */
+ u32 NumberOfSegments; /* Number of segments in layer A,
+ * 255 means layer does not exist */
+ u32 TMCCErrors; /* TMCC errors */
+};
+
+struct SMSHOSTLIB_STATISTICS_ISDBT_ST {
+ u32 StatisticsType; /* Enumerator identifying the type of the
+ * structure. Values are the same as
+ * SMSHOSTLIB_DEVICE_MODES_E
+ *
+ * This field MUST always be first in any
+ * statistics structure */
+
+ u32 FullSize; /* Total size of the structure returned by the modem.
+ * If the size requested by the host is smaller than
+ * FullSize, the struct will be truncated */
+
+ /* Common parameters */
+ u32 IsRfLocked; /* 0 - not locked, 1 - locked */
+ u32 IsDemodLocked; /* 0 - not locked, 1 - locked */
+ u32 IsExternalLNAOn; /* 0 - external LNA off, 1 - external LNA on */
+
+ /* Reception quality */
+ s32 SNR; /* dB */
+ s32 RSSI; /* dBm */
+ s32 InBandPwr; /* In band power in dBM */
+ s32 CarrierOffset; /* Carrier Offset in Hz */
+
+ /* Transmission parameters */
+ u32 Frequency; /* Frequency in Hz */
+ u32 Bandwidth; /* Bandwidth in MHz */
+ u32 TransmissionMode; /* ISDB-T transmission mode */
+ u32 ModemState; /* 0 - Acquisition, 1 - Locked */
+ u32 GuardInterval; /* Guard Interval, 1 divided by value */
+ u32 SystemType; /* ISDB-T system type (ISDB-T / ISDB-Tsb) */
+ u32 PartialReception; /* TRUE - partial reception, FALSE otherwise */
+ u32 NumOfLayers; /* Number of ISDB-T layers in the network */
+
+ /* Per-layer information */
+ /* Layers A, B and C */
+ struct SMSHOSTLIB_ISDBT_LAYER_STAT_ST LayerInfo[3];
+ /* Per-layer statistics, see SMSHOSTLIB_ISDBT_LAYER_STAT_ST */
+
+ /* Interface information */
+ u32 SmsToHostTxErrors; /* Total number of transmission errors. */
+};
+
struct PID_STATISTICS_DATA_S {
struct PID_BURST_S {
u32 size;
diff --git a/drivers/media/dvb/siano/smsdvb.c b/drivers/media/dvb/siano/smsdvb.c
index 68bf9fbd8fed..5f3939821ca3 100644
--- a/drivers/media/dvb/siano/smsdvb.c
+++ b/drivers/media/dvb/siano/smsdvb.c
@@ -116,6 +116,118 @@ static void sms_board_dvb3_event(struct smsdvb_client_t *client,
}
}
+
+static void smsdvb_update_dvb_stats(struct RECEPTION_STATISTICS_S *pReceptionData,
+ struct SMSHOSTLIB_STATISTICS_ST *p)
+{
+ if (sms_dbg & 2) {
+ printk(KERN_DEBUG "Reserved = %d", p->Reserved);
+ printk(KERN_DEBUG "IsRfLocked = %d", p->IsRfLocked);
+ printk(KERN_DEBUG "IsDemodLocked = %d", p->IsDemodLocked);
+ printk(KERN_DEBUG "IsExternalLNAOn = %d", p->IsExternalLNAOn);
+ printk(KERN_DEBUG "SNR = %d", p->SNR);
+ printk(KERN_DEBUG "BER = %d", p->BER);
+ printk(KERN_DEBUG "FIB_CRC = %d", p->FIB_CRC);
+ printk(KERN_DEBUG "TS_PER = %d", p->TS_PER);
+ printk(KERN_DEBUG "MFER = %d", p->MFER);
+ printk(KERN_DEBUG "RSSI = %d", p->RSSI);
+ printk(KERN_DEBUG "InBandPwr = %d", p->InBandPwr);
+ printk(KERN_DEBUG "CarrierOffset = %d", p->CarrierOffset);
+ printk(KERN_DEBUG "Frequency = %d", p->Frequency);
+ printk(KERN_DEBUG "Bandwidth = %d", p->Bandwidth);
+ printk(KERN_DEBUG "TransmissionMode = %d", p->TransmissionMode);
+ printk(KERN_DEBUG "ModemState = %d", p->ModemState);
+ printk(KERN_DEBUG "GuardInterval = %d", p->GuardInterval);
+ printk(KERN_DEBUG "CodeRate = %d", p->CodeRate);
+ printk(KERN_DEBUG "LPCodeRate = %d", p->LPCodeRate);
+ printk(KERN_DEBUG "Hierarchy = %d", p->Hierarchy);
+ printk(KERN_DEBUG "Constellation = %d", p->Constellation);
+ printk(KERN_DEBUG "BurstSize = %d", p->BurstSize);
+ printk(KERN_DEBUG "BurstDuration = %d", p->BurstDuration);
+ printk(KERN_DEBUG "BurstCycleTime = %d", p->BurstCycleTime);
+ printk(KERN_DEBUG "CalculatedBurstCycleTime = %d", p->CalculatedBurstCycleTime);
+ printk(KERN_DEBUG "NumOfRows = %d", p->NumOfRows);
+ printk(KERN_DEBUG "NumOfPaddCols = %d", p->NumOfPaddCols);
+ printk(KERN_DEBUG "NumOfPunctCols = %d", p->NumOfPunctCols);
+ printk(KERN_DEBUG "ErrorTSPackets = %d", p->ErrorTSPackets);
+ printk(KERN_DEBUG "TotalTSPackets = %d", p->TotalTSPackets);
+ printk(KERN_DEBUG "NumOfValidMpeTlbs = %d", p->NumOfValidMpeTlbs);
+ printk(KERN_DEBUG "NumOfInvalidMpeTlbs = %d", p->NumOfInvalidMpeTlbs);
+ printk(KERN_DEBUG "NumOfCorrectedMpeTlbs = %d", p->NumOfCorrectedMpeTlbs);
+ printk(KERN_DEBUG "BERErrorCount = %d", p->BERErrorCount);
+ printk(KERN_DEBUG "BERBitCount = %d", p->BERBitCount);
+ printk(KERN_DEBUG "SmsToHostTxErrors = %d", p->SmsToHostTxErrors);
+ printk(KERN_DEBUG "PreBER = %d", p->PreBER);
+ printk(KERN_DEBUG "CellId = %d", p->CellId);
+ printk(KERN_DEBUG "DvbhSrvIndHP = %d", p->DvbhSrvIndHP);
+ printk(KERN_DEBUG "DvbhSrvIndLP = %d", p->DvbhSrvIndLP);
+ printk(KERN_DEBUG "NumMPEReceived = %d", p->NumMPEReceived);
+ }
+
+ pReceptionData->IsDemodLocked = p->IsDemodLocked;
+
+ pReceptionData->SNR = p->SNR;
+ pReceptionData->BER = p->BER;
+ pReceptionData->BERErrorCount = p->BERErrorCount;
+ pReceptionData->InBandPwr = p->InBandPwr;
+ pReceptionData->ErrorTSPackets = p->ErrorTSPackets;
+};
+
+
+static void smsdvb_update_isdbt_stats(struct RECEPTION_STATISTICS_S *pReceptionData,
+ struct SMSHOSTLIB_STATISTICS_ISDBT_ST *p)
+{
+ int i;
+
+ if (sms_dbg & 2) {
+ printk(KERN_DEBUG "IsRfLocked = %d", p->IsRfLocked);
+ printk(KERN_DEBUG "IsDemodLocked = %d", p->IsDemodLocked);
+ printk(KERN_DEBUG "IsExternalLNAOn = %d", p->IsExternalLNAOn);
+ printk(KERN_DEBUG "SNR = %d", p->SNR);
+ printk(KERN_DEBUG "RSSI = %d", p->RSSI);
+ printk(KERN_DEBUG "InBandPwr = %d", p->InBandPwr);
+ printk(KERN_DEBUG "CarrierOffset = %d", p->CarrierOffset);
+ printk(KERN_DEBUG "Frequency = %d", p->Frequency);
+ printk(KERN_DEBUG "Bandwidth = %d", p->Bandwidth);
+ printk(KERN_DEBUG "TransmissionMode = %d", p->TransmissionMode);
+ printk(KERN_DEBUG "ModemState = %d", p->ModemState);
+ printk(KERN_DEBUG "GuardInterval = %d", p->GuardInterval);
+ printk(KERN_DEBUG "SystemType = %d", p->SystemType);
+ printk(KERN_DEBUG "PartialReception = %d", p->PartialReception);
+ printk(KERN_DEBUG "NumOfLayers = %d", p->NumOfLayers);
+ printk(KERN_DEBUG "SmsToHostTxErrors = %d", p->SmsToHostTxErrors);
+
+ for (i = 0; i < 3; i++) {
+ printk(KERN_DEBUG "%d: CodeRate = %d", i, p->LayerInfo[i].CodeRate);
+ printk(KERN_DEBUG "%d: Constellation = %d", i, p->LayerInfo[i].Constellation);
+ printk(KERN_DEBUG "%d: BER = %d", i, p->LayerInfo[i].BER);
+ printk(KERN_DEBUG "%d: BERErrorCount = %d", i, p->LayerInfo[i].BERErrorCount);
+ printk(KERN_DEBUG "%d: BERBitCount = %d", i, p->LayerInfo[i].BERBitCount);
+ printk(KERN_DEBUG "%d: PreBER = %d", i, p->LayerInfo[i].PreBER);
+ printk(KERN_DEBUG "%d: TS_PER = %d", i, p->LayerInfo[i].TS_PER);
+ printk(KERN_DEBUG "%d: ErrorTSPackets = %d", i, p->LayerInfo[i].ErrorTSPackets);
+ printk(KERN_DEBUG "%d: TotalTSPackets = %d", i, p->LayerInfo[i].TotalTSPackets);
+ printk(KERN_DEBUG "%d: TILdepthI = %d", i, p->LayerInfo[i].TILdepthI);
+ printk(KERN_DEBUG "%d: NumberOfSegments = %d", i, p->LayerInfo[i].NumberOfSegments);
+ printk(KERN_DEBUG "%d: TMCCErrors = %d", i, p->LayerInfo[i].TMCCErrors);
+ }
+ }
+
+ pReceptionData->IsDemodLocked = p->IsDemodLocked;
+
+ pReceptionData->SNR = p->SNR;
+ pReceptionData->InBandPwr = p->InBandPwr;
+
+ pReceptionData->ErrorTSPackets = 0;
+ pReceptionData->BER = 0;
+ pReceptionData->BERErrorCount = 0;
+ for (i = 0; i < 3; i++) {
+ pReceptionData->BER += p->LayerInfo[i].BER;
+ pReceptionData->BERErrorCount += p->LayerInfo[i].BERErrorCount;
+ pReceptionData->ErrorTSPackets += p->LayerInfo[i].ErrorTSPackets;
+ }
+}
+
static int smsdvb_onresponse(void *context, struct smscore_buffer_t *cb)
{
struct smsdvb_client_t *client = (struct smsdvb_client_t *) context;
@@ -134,6 +246,7 @@ static int smsdvb_onresponse(void *context, struct smscore_buffer_t *cb)
break;
case MSG_SMS_RF_TUNE_RES:
+ case MSG_SMS_ISDBT_TUNE_RES:
complete(&client->tune_done);
break;
@@ -217,6 +330,40 @@ static int smsdvb_onresponse(void *context, struct smscore_buffer_t *cb)
is_status_update = true;
break;
}
+ case MSG_SMS_GET_STATISTICS_RES: {
+ union {
+ struct SMSHOSTLIB_STATISTICS_ISDBT_ST isdbt;
+ struct SmsMsgStatisticsInfo_ST dvb;
+ } *p = (void *) (phdr + 1);
+ struct RECEPTION_STATISTICS_S *pReceptionData =
+ &client->sms_stat_dvb.ReceptionData;
+
+ sms_info("MSG_SMS_GET_STATISTICS_RES");
+
+ is_status_update = true;
+
+ switch (smscore_get_device_mode(client->coredev)) {
+ case DEVICE_MODE_ISDBT:
+ case DEVICE_MODE_ISDBT_BDA:
+ smsdvb_update_isdbt_stats(pReceptionData, &p->isdbt);
+ break;
+ default:
+ smsdvb_update_dvb_stats(pReceptionData, &p->dvb.Stat);
+ }
+ if (!pReceptionData->IsDemodLocked) {
+ pReceptionData->SNR = 0;
+ pReceptionData->BER = 0;
+ pReceptionData->BERErrorCount = 0;
+ pReceptionData->InBandPwr = 0;
+ pReceptionData->ErrorTSPackets = 0;
+ }
+
+ complete(&client->tune_done);
+ break;
+ }
+ default:
+ sms_info("Unhandled message %d", phdr->msgType);
+
}
smscore_putbuffer(client->coredev, cb);
@@ -233,10 +380,10 @@ static int smsdvb_onresponse(void *context, struct smscore_buffer_t *cb)
DVB3_EVENT_UNC_ERR);
} else {
- /*client->fe_status =
- (phdr->msgType == MSG_SMS_NO_SIGNAL_IND) ?
- 0 : FE_HAS_SIGNAL;*/
- client->fe_status = 0;
+ if (client->sms_stat_dvb.ReceptionData.IsRfLocked)
+ client->fe_status = FE_HAS_SIGNAL | FE_HAS_CARRIER;
+ else
+ client->fe_status = 0;
sms_board_dvb3_event(client, DVB3_EVENT_FE_UNLOCK);
}
}
@@ -325,6 +472,20 @@ static int smsdvb_sendrequest_and_wait(struct smsdvb_client_t *client,
0 : -ETIME;
}
+static int smsdvb_send_statistics_request(struct smsdvb_client_t *client)
+{
+ int rc;
+ struct SmsMsgHdr_ST Msg = { MSG_SMS_GET_STATISTICS_REQ,
+ DVBT_BDA_CONTROL_MSG_ID,
+ HIF_TASK,
+ sizeof(struct SmsMsgHdr_ST), 0 };
+
+ rc = smsdvb_sendrequest_and_wait(client, &Msg, sizeof(Msg),
+ &client->tune_done);
+
+ return rc;
+}
+
static inline int led_feedback(struct smsdvb_client_t *client)
{
if (client->fe_status & FE_HAS_LOCK)
@@ -337,33 +498,43 @@ static inline int led_feedback(struct smsdvb_client_t *client)
static int smsdvb_read_status(struct dvb_frontend *fe, fe_status_t *stat)
{
+ int rc;
struct smsdvb_client_t *client;
client = container_of(fe, struct smsdvb_client_t, frontend);
+ rc = smsdvb_send_statistics_request(client);
+
*stat = client->fe_status;
led_feedback(client);
- return 0;
+ return rc;
}
static int smsdvb_read_ber(struct dvb_frontend *fe, u32 *ber)
{
+ int rc;
struct smsdvb_client_t *client;
client = container_of(fe, struct smsdvb_client_t, frontend);
+ rc = smsdvb_send_statistics_request(client);
+
*ber = client->sms_stat_dvb.ReceptionData.BER;
led_feedback(client);
- return 0;
+ return rc;
}
static int smsdvb_read_signal_strength(struct dvb_frontend *fe, u16 *strength)
{
+ int rc;
+
struct smsdvb_client_t *client;
client = container_of(fe, struct smsdvb_client_t, frontend);
+ rc = smsdvb_send_statistics_request(client);
+
if (client->sms_stat_dvb.ReceptionData.InBandPwr < -95)
*strength = 0;
else if (client->sms_stat_dvb.ReceptionData.InBandPwr > -29)
@@ -375,31 +546,37 @@ static int smsdvb_read_signal_strength(struct dvb_frontend *fe, u16 *strength)
led_feedback(client);
- return 0;
+ return rc;
}
static int smsdvb_read_snr(struct dvb_frontend *fe, u16 *snr)
{
+ int rc;
struct smsdvb_client_t *client;
client = container_of(fe, struct smsdvb_client_t, frontend);
+ rc = smsdvb_send_statistics_request(client);
+
*snr = client->sms_stat_dvb.ReceptionData.SNR;
led_feedback(client);
- return 0;
+ return rc;
}
static int smsdvb_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks)
{
+ int rc;
struct smsdvb_client_t *client;
client = container_of(fe, struct smsdvb_client_t, frontend);
+ rc = smsdvb_send_statistics_request(client);
+
*ucblocks = client->sms_stat_dvb.ReceptionData.ErrorTSPackets;
led_feedback(client);
- return 0;
+ return rc;
}
static int smsdvb_get_tune_settings(struct dvb_frontend *fe,
@@ -413,9 +590,10 @@ static int smsdvb_get_tune_settings(struct dvb_frontend *fe,
return 0;
}
-static int smsdvb_set_frontend(struct dvb_frontend *fe,
- struct dvb_frontend_parameters *fep)
+static int smsdvb_dvbt_set_frontend(struct dvb_frontend *fe,
+ struct dvb_frontend_parameters *p)
{
+ struct dtv_frontend_properties *c = &fe->dtv_property_cache;
struct smsdvb_client_t *client =
container_of(fe, struct smsdvb_client_t, frontend);
@@ -429,24 +607,33 @@ static int smsdvb_set_frontend(struct dvb_frontend *fe,
client->fe_status = FE_HAS_SIGNAL;
client->event_fe_state = -1;
client->event_unc_state = -1;
+ fe->dtv_property_cache.delivery_system = SYS_DVBT;
Msg.Msg.msgSrcId = DVBT_BDA_CONTROL_MSG_ID;
Msg.Msg.msgDstId = HIF_TASK;
Msg.Msg.msgFlags = 0;
Msg.Msg.msgType = MSG_SMS_RF_TUNE_REQ;
Msg.Msg.msgLength = sizeof(Msg);
- Msg.Data[0] = fep->frequency;
+ Msg.Data[0] = c->frequency;
Msg.Data[2] = 12000000;
- sms_debug("freq %d band %d",
- fep->frequency, fep->u.ofdm.bandwidth);
+ sms_info("%s: freq %d band %d", __func__, c->frequency,
+ c->bandwidth_hz);
- switch (fep->u.ofdm.bandwidth) {
- case BANDWIDTH_8_MHZ: Msg.Data[1] = BW_8_MHZ; break;
- case BANDWIDTH_7_MHZ: Msg.Data[1] = BW_7_MHZ; break;
- case BANDWIDTH_6_MHZ: Msg.Data[1] = BW_6_MHZ; break;
- case BANDWIDTH_AUTO: return -EOPNOTSUPP;
- default: return -EINVAL;
+ switch (c->bandwidth_hz / 1000000) {
+ case 8:
+ Msg.Data[1] = BW_8_MHZ;
+ break;
+ case 7:
+ Msg.Data[1] = BW_7_MHZ;
+ break;
+ case 6:
+ Msg.Data[1] = BW_6_MHZ;
+ break;
+ case 0:
+ return -EOPNOTSUPP;
+ default:
+ return -EINVAL;
}
/* Disable LNA, if any. An error is returned if no LNA is present */
ret = sms_board_lna_control(client->coredev, 0);
@@ -470,6 +657,90 @@ static int smsdvb_set_frontend(struct dvb_frontend *fe,
&client->tune_done);
}
+static int smsdvb_isdbt_set_frontend(struct dvb_frontend *fe,
+ struct dvb_frontend_parameters *p)
+{
+ struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+ struct smsdvb_client_t *client =
+ container_of(fe, struct smsdvb_client_t, frontend);
+
+ struct {
+ struct SmsMsgHdr_ST Msg;
+ u32 Data[4];
+ } Msg;
+
+ fe->dtv_property_cache.delivery_system = SYS_ISDBT;
+
+ Msg.Msg.msgSrcId = DVBT_BDA_CONTROL_MSG_ID;
+ Msg.Msg.msgDstId = HIF_TASK;
+ Msg.Msg.msgFlags = 0;
+ Msg.Msg.msgType = MSG_SMS_ISDBT_TUNE_REQ;
+ Msg.Msg.msgLength = sizeof(Msg);
+
+ if (c->isdbt_sb_segment_idx == -1)
+ c->isdbt_sb_segment_idx = 0;
+
+ switch (c->isdbt_sb_segment_count) {
+ case 3:
+ Msg.Data[1] = BW_ISDBT_3SEG;
+ break;
+ case 1:
+ Msg.Data[1] = BW_ISDBT_1SEG;
+ break;
+ case 0: /* AUTO */
+ switch (c->bandwidth_hz / 1000000) {
+ case 8:
+ case 7:
+ c->isdbt_sb_segment_count = 3;
+ Msg.Data[1] = BW_ISDBT_3SEG;
+ break;
+ case 6:
+ c->isdbt_sb_segment_count = 1;
+ Msg.Data[1] = BW_ISDBT_1SEG;
+ break;
+ default: /* Assumes 6 MHZ bw */
+ c->isdbt_sb_segment_count = 1;
+ c->bandwidth_hz = 6000;
+ Msg.Data[1] = BW_ISDBT_1SEG;
+ break;
+ }
+ break;
+ default:
+ sms_info("Segment count %d not supported", c->isdbt_sb_segment_count);
+ return -EINVAL;
+ }
+
+ Msg.Data[0] = c->frequency;
+ Msg.Data[2] = 12000000;
+ Msg.Data[3] = c->isdbt_sb_segment_idx;
+
+ sms_info("%s: freq %d segwidth %d segindex %d\n", __func__,
+ c->frequency, c->isdbt_sb_segment_count,
+ c->isdbt_sb_segment_idx);
+
+ return smsdvb_sendrequest_and_wait(client, &Msg, sizeof(Msg),
+ &client->tune_done);
+}
+
+static int smsdvb_set_frontend(struct dvb_frontend *fe,
+ struct dvb_frontend_parameters *fep)
+{
+ struct smsdvb_client_t *client =
+ container_of(fe, struct smsdvb_client_t, frontend);
+ struct smscore_device_t *coredev = client->coredev;
+
+ switch (smscore_get_device_mode(coredev)) {
+ case DEVICE_MODE_DVBT:
+ case DEVICE_MODE_DVBT_BDA:
+ return smsdvb_dvbt_set_frontend(fe, fep);
+ case DEVICE_MODE_ISDBT:
+ case DEVICE_MODE_ISDBT_BDA:
+ return smsdvb_isdbt_set_frontend(fe, fep);
+ default:
+ return -EINVAL;
+ }
+}
+
static int smsdvb_get_frontend(struct dvb_frontend *fe,
struct dvb_frontend_parameters *fep)
{
@@ -557,13 +828,6 @@ static int smsdvb_hotplug(struct smscore_device_t *coredev,
/* device removal handled by onremove callback */
if (!arrival)
return 0;
-
- if (smscore_get_device_mode(coredev) != DEVICE_MODE_DVBT_BDA) {
- sms_err("SMS Device mode is not set for "
- "DVB operation.");
- return 0;
- }
-
client = kzalloc(sizeof(struct smsdvb_client_t), GFP_KERNEL);
if (!client) {
sms_err("kmalloc() failed");
diff --git a/drivers/media/dvb/ttpci/budget-ci.c b/drivers/media/dvb/ttpci/budget-ci.c
index 9782e0593733..49c2a817a06f 100644
--- a/drivers/media/dvb/ttpci/budget-ci.c
+++ b/drivers/media/dvb/ttpci/budget-ci.c
@@ -254,7 +254,7 @@ static int msp430_ir_init(struct budget_ci *budget_ci)
budget_ci->ir.timer_keyup.function = msp430_ir_keyup;
budget_ci->ir.timer_keyup.data = (unsigned long) &budget_ci->ir;
budget_ci->ir.last_raw = 0xffff; /* An impossible value */
- error = ir_input_register(input_dev, ir_codes);
+ error = ir_input_register(input_dev, ir_codes, NULL);
if (error) {
printk(KERN_ERR "budget_ci: could not init driver for IR device (code %d)\n", error);
return error;
diff --git a/drivers/media/video/bt8xx/bttv-input.c b/drivers/media/video/bt8xx/bttv-input.c
index 277a092e1214..b320dbd635aa 100644
--- a/drivers/media/video/bt8xx/bttv-input.c
+++ b/drivers/media/video/bt8xx/bttv-input.c
@@ -247,7 +247,7 @@ int bttv_input_init(struct bttv *btv)
struct card_ir *ir;
struct ir_scancode_table *ir_codes = NULL;
struct input_dev *input_dev;
- int ir_type = IR_TYPE_OTHER;
+ u64 ir_type = IR_TYPE_OTHER;
int err = -ENOMEM;
if (!btv->has_remote)
@@ -389,7 +389,7 @@ int bttv_input_init(struct bttv *btv)
bttv_ir_start(btv, ir);
/* all done */
- err = ir_input_register(btv->remote->dev, ir_codes);
+ err = ir_input_register(btv->remote->dev, ir_codes, NULL);
if (err)
goto err_out_stop;
diff --git a/drivers/media/video/cx231xx/cx231xx-input.c b/drivers/media/video/cx231xx/cx231xx-input.c
index 15826f98b688..c5771db3bfce 100644
--- a/drivers/media/video/cx231xx/cx231xx-input.c
+++ b/drivers/media/video/cx231xx/cx231xx-input.c
@@ -216,7 +216,7 @@ int cx231xx_ir_init(struct cx231xx *dev)
cx231xx_ir_start(ir);
/* all done */
- err = ir_input_register(ir->input, dev->board.ir_codes);
+ err = ir_input_register(ir->input, dev->board.ir_codes, NULL);
if (err)
goto err_out_stop;
diff --git a/drivers/media/video/cx23885/cx23885-dvb.c b/drivers/media/video/cx23885/cx23885-dvb.c
index e45d2df08138..ed99e93a5ac6 100644
--- a/drivers/media/video/cx23885/cx23885-dvb.c
+++ b/drivers/media/video/cx23885/cx23885-dvb.c
@@ -542,6 +542,9 @@ static struct atbm8830_config mygica_x8558pro_atbm8830_cfg1 = {
.osc_clk_freq = 30400, /* in kHz */
.if_freq = 0, /* zero IF */
.zif_swap_iq = 1,
+ .agc_min = 0x2E,
+ .agc_max = 0xFF,
+ .agc_hold_loop = 0,
};
static struct max2165_config mygic_x8558pro_max2165_cfg1 = {
@@ -558,6 +561,9 @@ static struct atbm8830_config mygica_x8558pro_atbm8830_cfg2 = {
.osc_clk_freq = 30400, /* in kHz */
.if_freq = 0, /* zero IF */
.zif_swap_iq = 1,
+ .agc_min = 0x2E,
+ .agc_max = 0xFF,
+ .agc_hold_loop = 0,
};
static struct max2165_config mygic_x8558pro_max2165_cfg2 = {
diff --git a/drivers/media/video/cx23885/cx23885-input.c b/drivers/media/video/cx23885/cx23885-input.c
index 768eec92ccf9..9c6620f86dca 100644
--- a/drivers/media/video/cx23885/cx23885-input.c
+++ b/drivers/media/video/cx23885/cx23885-input.c
@@ -397,7 +397,7 @@ int cx23885_input_init(struct cx23885_dev *dev)
dev->ir_input = ir;
cx23885_input_ir_start(dev);
- ret = ir_input_register(ir->dev, ir_codes);
+ ret = ir_input_register(ir->dev, ir_codes, NULL);
if (ret)
goto err_out_stop;
diff --git a/drivers/media/video/cx88/cx88-input.c b/drivers/media/video/cx88/cx88-input.c
index f9fda18b410c..de180d4d5a21 100644
--- a/drivers/media/video/cx88/cx88-input.c
+++ b/drivers/media/video/cx88/cx88-input.c
@@ -192,7 +192,7 @@ int cx88_ir_init(struct cx88_core *core, struct pci_dev *pci)
struct cx88_IR *ir;
struct input_dev *input_dev;
struct ir_scancode_table *ir_codes = NULL;
- int ir_type = IR_TYPE_OTHER;
+ u64 ir_type = IR_TYPE_OTHER;
int err = -ENOMEM;
ir = kzalloc(sizeof(*ir), GFP_KERNEL);
@@ -383,7 +383,7 @@ int cx88_ir_init(struct cx88_core *core, struct pci_dev *pci)
cx88_ir_start(core, ir);
/* all done */
- err = ir_input_register(ir->input, ir_codes);
+ err = ir_input_register(ir->input, ir_codes, NULL);
if (err)
goto err_out_stop;
diff --git a/drivers/media/video/em28xx/em28xx-input.c b/drivers/media/video/em28xx/em28xx-input.c
index af0d935c29be..69dcf0cc1f1e 100644
--- a/drivers/media/video/em28xx/em28xx-input.c
+++ b/drivers/media/video/em28xx/em28xx-input.c
@@ -75,6 +75,10 @@ struct em28xx_IR {
unsigned int repeat_interval;
int (*get_key)(struct em28xx_IR *, struct em28xx_ir_poll_result *);
+
+ /* IR device properties */
+
+ struct ir_dev_props props;
};
/**********************************************************
@@ -336,35 +340,28 @@ static void em28xx_ir_stop(struct em28xx_IR *ir)
cancel_delayed_work_sync(&ir->work);
}
-int em28xx_ir_init(struct em28xx *dev)
+int em28xx_ir_change_protocol(void *priv, u64 ir_type)
{
- struct em28xx_IR *ir;
- struct input_dev *input_dev;
- u8 ir_config;
- int err = -ENOMEM;
-
- if (dev->board.ir_codes == NULL) {
- /* No remote control support */
- return 0;
- }
-
- ir = kzalloc(sizeof(*ir), GFP_KERNEL);
- input_dev = input_allocate_device();
- if (!ir || !input_dev)
- goto err_out_free;
-
- ir->input = input_dev;
- ir_config = EM2874_IR_RC5;
+ int rc = 0;
+ struct em28xx_IR *ir = priv;
+ struct em28xx *dev = ir->dev;
+ u8 ir_config = EM2874_IR_RC5;
/* Adjust xclk based o IR table for RC5/NEC tables */
- if (dev->board.ir_codes->ir_type == IR_TYPE_RC5) {
+
+ dev->board.ir_codes->ir_type = IR_TYPE_OTHER;
+ if (ir_type == IR_TYPE_RC5) {
dev->board.xclk |= EM28XX_XCLK_IR_RC5_MODE;
ir->full_code = 1;
- } else if (dev->board.ir_codes->ir_type == IR_TYPE_NEC) {
+ } else if (ir_type == IR_TYPE_NEC) {
dev->board.xclk &= ~EM28XX_XCLK_IR_RC5_MODE;
ir_config = EM2874_IR_NEC;
ir->full_code = 1;
- }
+ } else
+ rc = -EINVAL;
+
+ dev->board.ir_codes->ir_type = ir_type;
+
em28xx_write_reg_bits(dev, EM28XX_R0F_XCLK, dev->board.xclk,
EM28XX_XCLK_IR_RC5_MODE);
@@ -380,9 +377,42 @@ int em28xx_ir_init(struct em28xx *dev)
break;
default:
printk("Unrecognized em28xx chip id: IR not supported\n");
- goto err_out_free;
+ rc = -EINVAL;
}
+ return rc;
+}
+
+int em28xx_ir_init(struct em28xx *dev)
+{
+ struct em28xx_IR *ir;
+ struct input_dev *input_dev;
+ int err = -ENOMEM;
+
+ if (dev->board.ir_codes == NULL) {
+ /* No remote control support */
+ return 0;
+ }
+
+ ir = kzalloc(sizeof(*ir), GFP_KERNEL);
+ input_dev = input_allocate_device();
+ if (!ir || !input_dev)
+ goto err_out_free;
+
+ /* record handles to ourself */
+ ir->dev = dev;
+ dev->ir = ir;
+
+ ir->input = input_dev;
+
+ /*
+ * em2874 supports more protocols. For now, let's just announce
+ * the two protocols that were already tested
+ */
+ ir->props.allowed_protos = IR_TYPE_RC5 | IR_TYPE_NEC;
+ ir->props.priv = ir;
+ ir->props.change_protocol = em28xx_ir_change_protocol;
+
/* This is how often we ask the chip for IR information */
ir->polling = 100; /* ms */
@@ -393,6 +423,8 @@ int em28xx_ir_init(struct em28xx *dev)
usb_make_path(dev->udev, ir->phys, sizeof(ir->phys));
strlcat(ir->phys, "/input0", sizeof(ir->phys));
+ /* Set IR protocol */
+ em28xx_ir_change_protocol(ir, dev->board.ir_codes->ir_type);
err = ir_input_init(input_dev, &ir->ir, IR_TYPE_OTHER);
if (err < 0)
goto err_out_free;
@@ -405,14 +437,13 @@ int em28xx_ir_init(struct em28xx *dev)
input_dev->id.product = le16_to_cpu(dev->udev->descriptor.idProduct);
input_dev->dev.parent = &dev->udev->dev;
- /* record handles to ourself */
- ir->dev = dev;
- dev->ir = ir;
+
em28xx_ir_start(ir);
/* all done */
- err = ir_input_register(ir->input, dev->board.ir_codes);
+ err = ir_input_register(ir->input, dev->board.ir_codes,
+ &ir->props);
if (err)
goto err_out_stop;
diff --git a/drivers/media/video/gspca/gspca.c b/drivers/media/video/gspca/gspca.c
index e930a67d526b..bd6214d4ab3b 100644
--- a/drivers/media/video/gspca/gspca.c
+++ b/drivers/media/video/gspca/gspca.c
@@ -1815,6 +1815,8 @@ static int vidioc_qbuf(struct file *file, void *priv,
/* put the buffer in the 'queued' queue */
i = gspca_dev->fr_q;
gspca_dev->fr_queue[i] = index;
+ if (gspca_dev->fr_i == i)
+ gspca_dev->cur_frame = frame;
gspca_dev->fr_q = (i + 1) % gspca_dev->nframes;
PDEBUG(D_FRAM, "qbuf q:%d i:%d o:%d",
gspca_dev->fr_q,
diff --git a/drivers/media/video/gspca/ov534.c b/drivers/media/video/gspca/ov534.c
index 4dbb882c83dc..0a6b8f07a69d 100644
--- a/drivers/media/video/gspca/ov534.c
+++ b/drivers/media/video/gspca/ov534.c
@@ -1533,7 +1533,7 @@ static void setexposure_96(struct gspca_dev *gspca_dev)
static void setsharpness_96(struct gspca_dev *gspca_dev)
{
struct sd *sd = (struct sd *) gspca_dev;
- u8 val;
+ s8 val;
val = sd->sharpness;
if (val < 0) { /* auto */
diff --git a/drivers/media/video/gspca/sunplus.c b/drivers/media/video/gspca/sunplus.c
index 716df6b15fc5..53e85725f36d 100644
--- a/drivers/media/video/gspca/sunplus.c
+++ b/drivers/media/video/gspca/sunplus.c
@@ -1336,6 +1336,7 @@ static const __devinitdata struct usb_device_id device_table[] = {
{USB_DEVICE(0x04fc, 0x5330), BS(SPCA533, 0)},
{USB_DEVICE(0x04fc, 0x5360), BS(SPCA536, 0)},
{USB_DEVICE(0x04fc, 0xffff), BS(SPCA504B, 0)},
+ {USB_DEVICE(0x052b, 0x1507), BS(SPCA533, MegapixV4)},
{USB_DEVICE(0x052b, 0x1513), BS(SPCA533, MegapixV4)},
{USB_DEVICE(0x052b, 0x1803), BS(SPCA533, MegaImageVI)},
{USB_DEVICE(0x0546, 0x3155), BS(SPCA533, 0)},
diff --git a/drivers/media/video/ir-kbd-i2c.c b/drivers/media/video/ir-kbd-i2c.c
index b86e35386cee..094e21dbb14f 100644
--- a/drivers/media/video/ir-kbd-i2c.c
+++ b/drivers/media/video/ir-kbd-i2c.c
@@ -299,7 +299,7 @@ static int ir_probe(struct i2c_client *client, const struct i2c_device_id *id)
{
struct ir_scancode_table *ir_codes = NULL;
const char *name = NULL;
- int ir_type = 0;
+ u64 ir_type = 0;
struct IR_i2c *ir;
struct input_dev *input_dev;
struct i2c_adapter *adap = client->adapter;
@@ -446,7 +446,7 @@ static int ir_probe(struct i2c_client *client, const struct i2c_device_id *id)
input_dev->name = ir->name;
input_dev->phys = ir->phys;
- err = ir_input_register(ir->input, ir->ir_codes);
+ err = ir_input_register(ir->input, ir->ir_codes, NULL);
if (err)
goto err_out_free;
diff --git a/drivers/media/video/saa7134/saa7134-input.c b/drivers/media/video/saa7134/saa7134-input.c
index f8e985989ca0..a4eaf1b75d70 100644
--- a/drivers/media/video/saa7134/saa7134-input.c
+++ b/drivers/media/video/saa7134/saa7134-input.c
@@ -460,7 +460,7 @@ int saa7134_input_init1(struct saa7134_dev *dev)
int polling = 0;
int rc5_gpio = 0;
int nec_gpio = 0;
- int ir_type = IR_TYPE_OTHER;
+ u64 ir_type = IR_TYPE_OTHER;
int err;
if (dev->has_remote != SAA7134_REMOTE_GPIO)
@@ -728,7 +728,7 @@ int saa7134_input_init1(struct saa7134_dev *dev)
dev->remote = ir;
saa7134_ir_start(dev, ir);
- err = ir_input_register(ir->dev, ir_codes);
+ err = ir_input_register(ir->dev, ir_codes, NULL);
if (err)
goto err_out_stop;
diff --git a/drivers/media/video/uvc/uvc_ctrl.c b/drivers/media/video/uvc/uvc_ctrl.c
index 0469d7a876a8..ec8ef8c5560a 100644
--- a/drivers/media/video/uvc/uvc_ctrl.c
+++ b/drivers/media/video/uvc/uvc_ctrl.c
@@ -1393,7 +1393,7 @@ uvc_ctrl_prune_entity(struct uvc_device *dev, struct uvc_entity *entity)
size = entity->processing.bControlSize;
for (i = 0; i < ARRAY_SIZE(blacklist); ++i) {
- if (!usb_match_id(dev->intf, &blacklist[i].id))
+ if (!usb_match_one_id(dev->intf, &blacklist[i].id))
continue;
if (blacklist[i].index >= 8 * size ||
diff --git a/drivers/media/video/uvc/uvc_driver.c b/drivers/media/video/uvc/uvc_driver.c
index 391cccca7ffc..fc7db17afb29 100644
--- a/drivers/media/video/uvc/uvc_driver.c
+++ b/drivers/media/video/uvc/uvc_driver.c
@@ -43,8 +43,9 @@
#define DRIVER_VERSION "v0.1.0"
#endif
+unsigned int uvc_clock_param = CLOCK_MONOTONIC;
unsigned int uvc_no_drop_param;
-static unsigned int uvc_quirks_param;
+static unsigned int uvc_quirks_param = -1;
unsigned int uvc_trace_param;
unsigned int uvc_timeout_param = UVC_CTRL_STREAMING_TIMEOUT;
@@ -59,6 +60,11 @@ static struct uvc_format_desc uvc_fmts[] = {
.fcc = V4L2_PIX_FMT_YUYV,
},
{
+ .name = "YUV 4:2:2 (YUYV)",
+ .guid = UVC_GUID_FORMAT_YUY2_ISIGHT,
+ .fcc = V4L2_PIX_FMT_YUYV,
+ },
+ {
.name = "YUV 4:2:0 (NV12)",
.guid = UVC_GUID_FORMAT_NV12,
.fcc = V4L2_PIX_FMT_NV12,
@@ -1750,7 +1756,8 @@ static int uvc_probe(struct usb_interface *intf,
dev->udev = usb_get_dev(udev);
dev->intf = usb_get_intf(intf);
dev->intfnum = intf->cur_altsetting->desc.bInterfaceNumber;
- dev->quirks = id->driver_info | uvc_quirks_param;
+ dev->quirks = (uvc_quirks_param == -1)
+ ? id->driver_info : uvc_quirks_param;
if (udev->product != NULL)
strlcpy(dev->name, udev->product, sizeof dev->name);
@@ -1773,9 +1780,9 @@ static int uvc_probe(struct usb_interface *intf,
le16_to_cpu(udev->descriptor.idVendor),
le16_to_cpu(udev->descriptor.idProduct));
- if (uvc_quirks_param != 0) {
- uvc_printk(KERN_INFO, "Forcing device quirks 0x%x by module "
- "parameter for testing purpose.\n", uvc_quirks_param);
+ if (dev->quirks != id->driver_info) {
+ uvc_printk(KERN_INFO, "Forcing device quirks to 0x%x by module "
+ "parameter for testing purpose.\n", dev->quirks);
uvc_printk(KERN_INFO, "Please report required quirks to the "
"linux-uvc-devel mailing list.\n");
}
@@ -1892,6 +1899,45 @@ static int uvc_reset_resume(struct usb_interface *intf)
}
/* ------------------------------------------------------------------------
+ * Module parameters
+ */
+
+static int uvc_clock_param_get(char *buffer, struct kernel_param *kp)
+{
+ if (uvc_clock_param == CLOCK_MONOTONIC)
+ return sprintf(buffer, "CLOCK_MONOTONIC");
+ else
+ return sprintf(buffer, "CLOCK_REALTIME");
+}
+
+static int uvc_clock_param_set(const char *val, struct kernel_param *kp)
+{
+ if (strncasecmp(val, "clock_", strlen("clock_")) == 0)
+ val += strlen("clock_");
+
+ if (strcasecmp(val, "monotonic") == 0)
+ uvc_clock_param = CLOCK_MONOTONIC;
+ else if (strcasecmp(val, "realtime") == 0)
+ uvc_clock_param = CLOCK_REALTIME;
+ else
+ return -EINVAL;
+
+ return 0;
+}
+
+module_param_call(clock, uvc_clock_param_set, uvc_clock_param_get,
+ &uvc_clock_param, S_IRUGO|S_IWUSR);
+MODULE_PARM_DESC(clock, "Video buffers timestamp clock");
+module_param_named(nodrop, uvc_no_drop_param, uint, S_IRUGO|S_IWUSR);
+MODULE_PARM_DESC(nodrop, "Don't drop incomplete frames");
+module_param_named(quirks, uvc_quirks_param, uint, S_IRUGO|S_IWUSR);
+MODULE_PARM_DESC(quirks, "Forced device quirks");
+module_param_named(trace, uvc_trace_param, uint, S_IRUGO|S_IWUSR);
+MODULE_PARM_DESC(trace, "Trace level bitmask");
+module_param_named(timeout, uvc_timeout_param, uint, S_IRUGO|S_IWUSR);
+MODULE_PARM_DESC(timeout, "Streaming control requests timeout");
+
+/* ------------------------------------------------------------------------
* Driver initialization and cleanup
*/
@@ -2197,15 +2243,6 @@ static void __exit uvc_cleanup(void)
module_init(uvc_init);
module_exit(uvc_cleanup);
-module_param_named(nodrop, uvc_no_drop_param, uint, S_IRUGO|S_IWUSR);
-MODULE_PARM_DESC(nodrop, "Don't drop incomplete frames");
-module_param_named(quirks, uvc_quirks_param, uint, S_IRUGO|S_IWUSR);
-MODULE_PARM_DESC(quirks, "Forced device quirks");
-module_param_named(trace, uvc_trace_param, uint, S_IRUGO|S_IWUSR);
-MODULE_PARM_DESC(trace, "Trace level bitmask");
-module_param_named(timeout, uvc_timeout_param, uint, S_IRUGO|S_IWUSR);
-MODULE_PARM_DESC(timeout, "Streaming control requests timeout");
-
MODULE_AUTHOR(DRIVER_AUTHOR);
MODULE_DESCRIPTION(DRIVER_DESC);
MODULE_LICENSE("GPL");
diff --git a/drivers/media/video/uvc/uvc_queue.c b/drivers/media/video/uvc/uvc_queue.c
index f854698c4061..4a925a31b0e0 100644
--- a/drivers/media/video/uvc/uvc_queue.c
+++ b/drivers/media/video/uvc/uvc_queue.c
@@ -59,9 +59,9 @@
* returns immediately.
*
* When the buffer is full, the completion handler removes it from the irq
- * queue, marks it as ready (UVC_BUF_STATE_DONE) and wakes its wait queue.
+ * queue, marks it as done (UVC_BUF_STATE_DONE) and wakes its wait queue.
* At that point, any process waiting on the buffer will be woken up. If a
- * process tries to dequeue a buffer after it has been marked ready, the
+ * process tries to dequeue a buffer after it has been marked done, the
* dequeing will succeed immediately.
*
* 2. Buffers are queued, user is waiting on a buffer and the device gets
@@ -201,6 +201,7 @@ static void __uvc_query_buffer(struct uvc_buffer *buf,
break;
case UVC_BUF_STATE_QUEUED:
case UVC_BUF_STATE_ACTIVE:
+ case UVC_BUF_STATE_READY:
v4l2_buf->flags |= V4L2_BUF_FLAG_QUEUED;
break;
case UVC_BUF_STATE_IDLE:
@@ -295,13 +296,15 @@ static int uvc_queue_waiton(struct uvc_buffer *buf, int nonblocking)
{
if (nonblocking) {
return (buf->state != UVC_BUF_STATE_QUEUED &&
- buf->state != UVC_BUF_STATE_ACTIVE)
+ buf->state != UVC_BUF_STATE_ACTIVE &&
+ buf->state != UVC_BUF_STATE_READY)
? 0 : -EAGAIN;
}
return wait_event_interruptible(buf->wait,
buf->state != UVC_BUF_STATE_QUEUED &&
- buf->state != UVC_BUF_STATE_ACTIVE);
+ buf->state != UVC_BUF_STATE_ACTIVE &&
+ buf->state != UVC_BUF_STATE_READY);
}
/*
@@ -348,6 +351,7 @@ int uvc_dequeue_buffer(struct uvc_video_queue *queue,
case UVC_BUF_STATE_IDLE:
case UVC_BUF_STATE_QUEUED:
case UVC_BUF_STATE_ACTIVE:
+ case UVC_BUF_STATE_READY:
default:
uvc_trace(UVC_TRACE_CAPTURE, "[E] Invalid buffer state %u "
"(driver bug?).\n", buf->state);
@@ -489,6 +493,7 @@ struct uvc_buffer *uvc_queue_next_buffer(struct uvc_video_queue *queue,
spin_lock_irqsave(&queue->irqlock, flags);
list_del(&buf->queue);
+ buf->state = UVC_BUF_STATE_DONE;
if (!list_empty(&queue->irqqueue))
nextbuf = list_first_entry(&queue->irqqueue, struct uvc_buffer,
queue);
@@ -497,7 +502,6 @@ struct uvc_buffer *uvc_queue_next_buffer(struct uvc_video_queue *queue,
spin_unlock_irqrestore(&queue->irqlock, flags);
buf->buf.sequence = queue->sequence++;
- do_gettimeofday(&buf->buf.timestamp);
wake_up(&buf->wait);
return nextbuf;
diff --git a/drivers/media/video/uvc/uvc_video.c b/drivers/media/video/uvc/uvc_video.c
index 9a9802830d41..6b0666be370f 100644
--- a/drivers/media/video/uvc/uvc_video.c
+++ b/drivers/media/video/uvc/uvc_video.c
@@ -410,6 +410,8 @@ static int uvc_video_decode_start(struct uvc_streaming *stream,
* when the EOF bit is set to force synchronisation on the next packet.
*/
if (buf->state != UVC_BUF_STATE_ACTIVE) {
+ struct timespec ts;
+
if (fid == stream->last_fid) {
uvc_trace(UVC_TRACE_FRAME, "Dropping payload (out of "
"sync).\n");
@@ -419,6 +421,14 @@ static int uvc_video_decode_start(struct uvc_streaming *stream,
return -ENODATA;
}
+ if (uvc_clock_param == CLOCK_MONOTONIC)
+ ktime_get_ts(&ts);
+ else
+ ktime_get_real_ts(&ts);
+
+ buf->buf.timestamp.tv_sec = ts.tv_sec;
+ buf->buf.timestamp.tv_usec = ts.tv_nsec / NSEC_PER_USEC;
+
/* TODO: Handle PTS and SCR. */
buf->state = UVC_BUF_STATE_ACTIVE;
}
@@ -441,7 +451,7 @@ static int uvc_video_decode_start(struct uvc_streaming *stream,
if (fid != stream->last_fid && buf->buf.bytesused != 0) {
uvc_trace(UVC_TRACE_FRAME, "Frame complete (FID bit "
"toggled).\n");
- buf->state = UVC_BUF_STATE_DONE;
+ buf->state = UVC_BUF_STATE_READY;
return -EAGAIN;
}
@@ -470,7 +480,7 @@ static void uvc_video_decode_data(struct uvc_streaming *stream,
/* Complete the current frame if the buffer size was exceeded. */
if (len > maxlen) {
uvc_trace(UVC_TRACE_FRAME, "Frame complete (overflow).\n");
- buf->state = UVC_BUF_STATE_DONE;
+ buf->state = UVC_BUF_STATE_READY;
}
}
@@ -482,7 +492,7 @@ static void uvc_video_decode_end(struct uvc_streaming *stream,
uvc_trace(UVC_TRACE_FRAME, "Frame complete (EOF found).\n");
if (data[0] == len)
uvc_trace(UVC_TRACE_FRAME, "EOF in empty payload.\n");
- buf->state = UVC_BUF_STATE_DONE;
+ buf->state = UVC_BUF_STATE_READY;
if (stream->dev->quirks & UVC_QUIRK_STREAM_NO_FID)
stream->last_fid ^= UVC_STREAM_FID;
}
@@ -568,8 +578,7 @@ static void uvc_video_decode_isoc(struct urb *urb, struct uvc_streaming *stream,
uvc_video_decode_end(stream, buf, mem,
urb->iso_frame_desc[i].actual_length);
- if (buf->state == UVC_BUF_STATE_DONE ||
- buf->state == UVC_BUF_STATE_ERROR)
+ if (buf->state == UVC_BUF_STATE_READY)
buf = uvc_queue_next_buffer(&stream->queue, buf);
}
}
@@ -627,8 +636,7 @@ static void uvc_video_decode_bulk(struct urb *urb, struct uvc_streaming *stream,
if (!stream->bulk.skip_payload && buf != NULL) {
uvc_video_decode_end(stream, buf, stream->bulk.header,
stream->bulk.payload_size);
- if (buf->state == UVC_BUF_STATE_DONE ||
- buf->state == UVC_BUF_STATE_ERROR)
+ if (buf->state == UVC_BUF_STATE_READY)
buf = uvc_queue_next_buffer(&stream->queue,
buf);
}
@@ -669,7 +677,7 @@ static void uvc_video_encode_bulk(struct urb *urb, struct uvc_streaming *stream,
stream->bulk.payload_size == stream->bulk.max_payload_size) {
if (buf->buf.bytesused == stream->queue.buf_used) {
stream->queue.buf_used = 0;
- buf->state = UVC_BUF_STATE_DONE;
+ buf->state = UVC_BUF_STATE_READY;
uvc_queue_next_buffer(&stream->queue, buf);
stream->last_fid ^= UVC_STREAM_FID;
}
@@ -924,10 +932,8 @@ static int uvc_init_video_bulk(struct uvc_streaming *stream,
static int uvc_init_video(struct uvc_streaming *stream, gfp_t gfp_flags)
{
struct usb_interface *intf = stream->intf;
- struct usb_host_interface *alts;
- struct usb_host_endpoint *ep = NULL;
- int intfnum = stream->intfnum;
- unsigned int bandwidth, psize, i;
+ struct usb_host_endpoint *ep;
+ unsigned int i;
int ret;
stream->last_fid = -1;
@@ -936,6 +942,12 @@ static int uvc_init_video(struct uvc_streaming *stream, gfp_t gfp_flags)
stream->bulk.payload_size = 0;
if (intf->num_altsetting > 1) {
+ struct usb_host_endpoint *best_ep = NULL;
+ unsigned int best_psize = 3 * 1024;
+ unsigned int bandwidth;
+ unsigned int uninitialized_var(altsetting);
+ int intfnum = stream->intfnum;
+
/* Isochronous endpoint, select the alternate setting. */
bandwidth = stream->ctrl.dwMaxPayloadTransferSize;
@@ -949,6 +961,9 @@ static int uvc_init_video(struct uvc_streaming *stream, gfp_t gfp_flags)
}
for (i = 0; i < intf->num_altsetting; ++i) {
+ struct usb_host_interface *alts;
+ unsigned int psize;
+
alts = &intf->altsetting[i];
ep = uvc_find_endpoint(alts,
stream->header.bEndpointAddress);
@@ -958,21 +973,27 @@ static int uvc_init_video(struct uvc_streaming *stream, gfp_t gfp_flags)
/* Check if the bandwidth is high enough. */
psize = le16_to_cpu(ep->desc.wMaxPacketSize);
psize = (psize & 0x07ff) * (1 + ((psize >> 11) & 3));
- if (psize >= bandwidth)
- break;
+ if (psize >= bandwidth && psize <= best_psize) {
+ altsetting = i;
+ best_psize = psize;
+ best_ep = ep;
+ }
}
- if (i >= intf->num_altsetting) {
+ if (best_ep == NULL) {
uvc_trace(UVC_TRACE_VIDEO, "No fast enough alt setting "
"for requested bandwidth.\n");
return -EIO;
}
- ret = usb_set_interface(stream->dev->udev, intfnum, i);
+ uvc_trace(UVC_TRACE_VIDEO, "Selecting alternate setting %u "
+ "(%u B/frame bandwidth).\n", altsetting, best_psize);
+
+ ret = usb_set_interface(stream->dev->udev, intfnum, altsetting);
if (ret < 0)
return ret;
- ret = uvc_init_video_isoc(stream, ep, gfp_flags);
+ ret = uvc_init_video_isoc(stream, best_ep, gfp_flags);
} else {
/* Bulk endpoint, proceed to URB initialization. */
ep = uvc_find_endpoint(&intf->altsetting[0],
diff --git a/drivers/media/video/uvc/uvcvideo.h b/drivers/media/video/uvc/uvcvideo.h
index 7ec9a04ced50..6aa9b2c2b685 100644
--- a/drivers/media/video/uvc/uvcvideo.h
+++ b/drivers/media/video/uvc/uvcvideo.h
@@ -113,6 +113,9 @@ struct uvc_xu_control {
#define UVC_GUID_FORMAT_YUY2 \
{ 'Y', 'U', 'Y', '2', 0x00, 0x00, 0x10, 0x00, \
0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}
+#define UVC_GUID_FORMAT_YUY2_ISIGHT \
+ { 'Y', 'U', 'Y', '2', 0x00, 0x00, 0x10, 0x00, \
+ 0x80, 0x00, 0x00, 0x00, 0x00, 0x38, 0x9b, 0x71}
#define UVC_GUID_FORMAT_NV12 \
{ 'N', 'V', '1', '2', 0x00, 0x00, 0x10, 0x00, \
0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}
@@ -365,8 +368,9 @@ enum uvc_buffer_state {
UVC_BUF_STATE_IDLE = 0,
UVC_BUF_STATE_QUEUED = 1,
UVC_BUF_STATE_ACTIVE = 2,
- UVC_BUF_STATE_DONE = 3,
- UVC_BUF_STATE_ERROR = 4,
+ UVC_BUF_STATE_READY = 3,
+ UVC_BUF_STATE_DONE = 4,
+ UVC_BUF_STATE_ERROR = 5,
};
struct uvc_buffer {
@@ -532,6 +536,7 @@ struct uvc_driver {
#define UVC_WARN_MINMAX 0
#define UVC_WARN_PROBE_DEF 1
+extern unsigned int uvc_clock_param;
extern unsigned int uvc_no_drop_param;
extern unsigned int uvc_trace_param;
extern unsigned int uvc_timeout_param;