Commit 2faae422 authored by Linus Torvalds's avatar Linus Torvalds

Merge branch 'mantis' of git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-2.6

* 'mantis' of git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-2.6: (117 commits)
  V4L/DVB (13851): Fix Input dependency for Mantis
  V4L/DVB(13824a): mantis: Fix __devexit bad annotations
  V4L/DVB (13808b): mantis: replace DMA_nnBIT_MASK to DMA_BIT_MASK(32)
  V4L/DVB (13808): [Mantis/Hopper] Build update for Mantis/Hopper based cards
  V4L/DVB(13808a): mantis: convert it to the new ir-core register/unregister functions
  V4L/DVB (13812): [Mantis/Hopper] Update Copyright header
  V4L/DVB (13811): [MB86A16] Update Copyright header
  V4L/DVB (13810): [MB86A16] Use DVB_* macros
  V4L/DVB (13809): Fix Checkpatch violations
  V4L/DVB (13807): Fix: Free device in the device registration failure case
  V4L/DVB (13806): Register and Initialize Remote control
  V4L/DVB (13805): Fix: Unregister the frontend before detaching
  V4L/DVB (13804): Remove unused I2C Adapter ID
  V4L/DVB (13803): Remove unused dependency on CU1216
  V4L/DVB (13802): [Mantis/Hopper] Fix all build related warnings
  V4L/DVB (13801): [MB86A16] Use the search callback
  V4L/DVB (13800): [Mantis] I2C optimization. Required delay is much lesser than 1mS.
  V4L/DVB (13799): [Mantis] Unregister frontend
  V4L/DVB (13798): [Mantis] Enable power for all cards, use byte mode only on relevant devices
  V4L/DVB (13797): [Mantis/Hopper/TDA665x] Large overhaul,
  ...
parents 630ca048 fcd89de3
...@@ -72,6 +72,10 @@ comment "Supported Earthsoft PT1 Adapters" ...@@ -72,6 +72,10 @@ comment "Supported Earthsoft PT1 Adapters"
depends on DVB_CORE && PCI && I2C depends on DVB_CORE && PCI && I2C
source "drivers/media/dvb/pt1/Kconfig" 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" comment "Supported DVB Frontends"
depends on DVB_CORE depends on DVB_CORE
source "drivers/media/dvb/frontends/Kconfig" source "drivers/media/dvb/frontends/Kconfig"
......
...@@ -2,6 +2,18 @@ ...@@ -2,6 +2,18 @@
# Makefile for the kernel multimedia device drivers. # 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/ obj-$(CONFIG_DVB_FIREDTV) += firewire/
...@@ -208,6 +208,14 @@ config DVB_DS3000 ...@@ -208,6 +208,14 @@ config DVB_DS3000
help help
A DVB-S/S2 tuner module. Say Y when you want to support this frontend. 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" comment "DVB-T (terrestrial) frontends"
depends on DVB_CORE depends on DVB_CORE
...@@ -587,6 +595,17 @@ config DVB_ATBM8830 ...@@ -587,6 +595,17 @@ config DVB_ATBM8830
help help
A DMB-TH tuner module. Say Y when you want to support this frontend. 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" comment "Tools to develop new frontends"
config DVB_DUMMY_FE config DVB_DUMMY_FE
......
...@@ -64,6 +64,7 @@ obj-$(CONFIG_DVB_TDA10048) += tda10048.o ...@@ -64,6 +64,7 @@ obj-$(CONFIG_DVB_TDA10048) += tda10048.o
obj-$(CONFIG_DVB_TUNER_CX24113) += cx24113.o obj-$(CONFIG_DVB_TUNER_CX24113) += cx24113.o
obj-$(CONFIG_DVB_S5H1411) += s5h1411.o obj-$(CONFIG_DVB_S5H1411) += s5h1411.o
obj-$(CONFIG_DVB_LGS8GL5) += lgs8gl5.o obj-$(CONFIG_DVB_LGS8GL5) += lgs8gl5.o
obj-$(CONFIG_DVB_TDA665x) += tda665x.o
obj-$(CONFIG_DVB_LGS8GXX) += lgs8gxx.o obj-$(CONFIG_DVB_LGS8GXX) += lgs8gxx.o
obj-$(CONFIG_DVB_ATBM8830) += atbm8830.o obj-$(CONFIG_DVB_ATBM8830) += atbm8830.o
obj-$(CONFIG_DVB_DUMMY_FE) += dvb_dummy_fe.o obj-$(CONFIG_DVB_DUMMY_FE) += dvb_dummy_fe.o
...@@ -80,3 +81,4 @@ obj-$(CONFIG_DVB_STV6110x) += stv6110x.o ...@@ -80,3 +81,4 @@ obj-$(CONFIG_DVB_STV6110x) += stv6110x.o
obj-$(CONFIG_DVB_ISL6423) += isl6423.o obj-$(CONFIG_DVB_ISL6423) += isl6423.o
obj-$(CONFIG_DVB_EC100) += ec100.o obj-$(CONFIG_DVB_EC100) += ec100.o
obj-$(CONFIG_DVB_DS3000) += ds3000.o obj-$(CONFIG_DVB_DS3000) += ds3000.o
obj-$(CONFIG_DVB_MB86A16) += mb86a16.o
This diff is collapsed.
/*
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 */
/*
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 */
...@@ -426,6 +426,10 @@ struct dvb_frontend* tda10021_attach(const struct tda1002x_config* config, ...@@ -426,6 +426,10 @@ struct dvb_frontend* tda10021_attach(const struct tda1002x_config* config,
id = tda10021_readreg(state, 0x1a); id = tda10021_readreg(state, 0x1a);
if ((id & 0xf0) != 0x70) goto error; 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", printk("TDA10021: i2c-addr = 0x%02x, id = 0x%02x\n",
state->config->demod_address, id); state->config->demod_address, id);
......
/*
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");
/*
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 */
config MANTIS_CORE
tristate "Mantis/Hopper PCI bridge based devices"
depends on PCI && I2C && INPUT
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
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/
/*
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");
/*
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,
};
/*
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 */
/*
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);
/*
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 */
/*
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");
/*
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 */
/*
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);
}
}
/*
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 */
/*
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;
}
}
/*
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 */
/*
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);
/*
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 */
/*
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);
}
/*
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);
}
/*
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 */
This diff is collapsed.
/*
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 */
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
/*
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 */
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment