summaryrefslogtreecommitdiffstats
path: root/drivers/media/dvb
diff options
context:
space:
mode:
authorIngo Molnar <mingo@elte.hu>2008-10-03 19:28:46 +0200
committerIngo Molnar <mingo@elte.hu>2008-10-03 19:28:46 +0200
commitf68ec0c24755e5cdb779be6240925f2175311d84 (patch)
treea7b7128e61a8456385d82bd1c7ca5f14eecbf2ca /drivers/media/dvb
parent98920dc3d1113b883cbc73e3293446d3525c6042 (diff)
parent94aca1dac6f6d21f4b07e4864baf7768cabcc6e7 (diff)
Merge commit 'v2.6.27-rc8' into x86/setup
Diffstat (limited to 'drivers/media/dvb')
-rw-r--r--drivers/media/dvb/Kconfig1
-rw-r--r--drivers/media/dvb/Makefile2
-rw-r--r--drivers/media/dvb/b2c2/flexcop-fe-tuner.c3
-rw-r--r--drivers/media/dvb/b2c2/flexcop-i2c.c12
-rw-r--r--drivers/media/dvb/bt8xx/Kconfig2
-rw-r--r--drivers/media/dvb/bt8xx/bt878.h2
-rw-r--r--drivers/media/dvb/bt8xx/dst.c4
-rw-r--r--drivers/media/dvb/dvb-core/demux.h2
-rw-r--r--drivers/media/dvb/dvb-core/dmxdev.c3
-rw-r--r--drivers/media/dvb/dvb-core/dvb_ca_en50221.c12
-rw-r--r--drivers/media/dvb/dvb-core/dvb_demux.c17
-rw-r--r--drivers/media/dvb/dvb-core/dvb_frontend.c8
-rw-r--r--drivers/media/dvb/dvb-core/dvb_net.c6
-rw-r--r--drivers/media/dvb/dvb-core/dvb_ringbuffer.c78
-rw-r--r--drivers/media/dvb/dvb-core/dvb_ringbuffer.h12
-rw-r--r--drivers/media/dvb/dvb-core/dvbdev.c4
-rw-r--r--drivers/media/dvb/dvb-usb/Kconfig25
-rw-r--r--drivers/media/dvb/dvb-usb/Makefile6
-rw-r--r--drivers/media/dvb/dvb-usb/anysee.c553
-rw-r--r--drivers/media/dvb/dvb-usb/anysee.h304
-rw-r--r--drivers/media/dvb/dvb-usb/au6610.c83
-rw-r--r--drivers/media/dvb/dvb-usb/au6610.h22
-rw-r--r--drivers/media/dvb/dvb-usb/cxusb.c153
-rw-r--r--drivers/media/dvb/dvb-usb/cxusb.h3
-rw-r--r--drivers/media/dvb/dvb-usb/dib0700_devices.c12
-rw-r--r--drivers/media/dvb/dvb-usb/dvb-usb-i2c.c4
-rw-r--r--drivers/media/dvb/dvb-usb/dvb-usb-ids.h10
-rw-r--r--drivers/media/dvb/dvb-usb/dw2102.c425
-rw-r--r--drivers/media/dvb/dvb-usb/dw2102.h9
-rw-r--r--drivers/media/dvb/dvb-usb/gl861.c38
-rw-r--r--drivers/media/dvb/dvb-usb/gl861.h2
-rw-r--r--drivers/media/dvb/frontends/Kconfig37
-rw-r--r--drivers/media/dvb/frontends/Makefile1
-rw-r--r--drivers/media/dvb/frontends/au8522.c48
-rw-r--r--drivers/media/dvb/frontends/au8522.h11
-rw-r--r--drivers/media/dvb/frontends/cx22702.c2
-rw-r--r--drivers/media/dvb/frontends/cx22702.h2
-rw-r--r--drivers/media/dvb/frontends/cx24123.c6
-rw-r--r--drivers/media/dvb/frontends/cx24123.h2
-rw-r--r--drivers/media/dvb/frontends/drx397xD.c1504
-rw-r--r--drivers/media/dvb/frontends/drx397xD.h130
-rw-r--r--drivers/media/dvb/frontends/drx397xD_fw.h40
-rw-r--r--drivers/media/dvb/frontends/dvb-pll.c47
-rw-r--r--drivers/media/dvb/frontends/dvb-pll.h1
-rw-r--r--drivers/media/dvb/frontends/lgdt330x.c24
-rw-r--r--drivers/media/dvb/frontends/s5h1409.c4
-rw-r--r--drivers/media/dvb/frontends/s5h1409.h2
-rw-r--r--drivers/media/dvb/frontends/s5h1411.c4
-rw-r--r--drivers/media/dvb/frontends/s5h1411.h2
-rw-r--r--drivers/media/dvb/frontends/s5h1420.c3
-rw-r--r--drivers/media/dvb/frontends/tda10023.c197
-rw-r--r--drivers/media/dvb/frontends/tda1002x.h41
-rw-r--r--drivers/media/dvb/frontends/tda10048.c4
-rw-r--r--drivers/media/dvb/frontends/tda10048.h2
-rw-r--r--drivers/media/dvb/frontends/z0194a.h97
-rw-r--r--drivers/media/dvb/pluto2/pluto2.c4
-rw-r--r--drivers/media/dvb/siano/Kconfig26
-rw-r--r--drivers/media/dvb/siano/Makefile8
-rw-r--r--drivers/media/dvb/siano/sms-cards.c102
-rw-r--r--drivers/media/dvb/siano/sms-cards.h45
-rw-r--r--drivers/media/dvb/siano/smscoreapi.c1251
-rw-r--r--drivers/media/dvb/siano/smscoreapi.h434
-rw-r--r--drivers/media/dvb/siano/smsdvb.c449
-rw-r--r--drivers/media/dvb/siano/smsusb.c459
-rw-r--r--drivers/media/dvb/ttpci/Kconfig6
-rw-r--r--drivers/media/dvb/ttpci/Makefile7
-rw-r--r--drivers/media/dvb/ttpci/av7110.c47
-rw-r--r--drivers/media/dvb/ttpci/av7110.h1
-rw-r--r--drivers/media/dvb/ttpci/av7110_av.c2
-rw-r--r--drivers/media/dvb/ttpci/av7110_ca.c2
-rw-r--r--drivers/media/dvb/ttpci/av7110_hw.h3
-rw-r--r--drivers/media/dvb/ttpci/budget-av.c12
-rw-r--r--drivers/media/dvb/ttpci/budget-ci.c24
-rw-r--r--drivers/media/dvb/ttpci/budget-core.c4
-rw-r--r--drivers/media/dvb/ttpci/budget-patch.c47
-rw-r--r--drivers/media/dvb/ttpci/budget.c3
-rw-r--r--drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c22
-rw-r--r--drivers/media/dvb/ttusb-dec/Kconfig2
78 files changed, 6623 insertions, 365 deletions
diff --git a/drivers/media/dvb/Kconfig b/drivers/media/dvb/Kconfig
index 7b21b49f194..8bc1445bd33 100644
--- a/drivers/media/dvb/Kconfig
+++ b/drivers/media/dvb/Kconfig
@@ -21,6 +21,7 @@ source "drivers/media/dvb/dvb-usb/Kconfig"
source "drivers/media/dvb/ttusb-budget/Kconfig"
source "drivers/media/dvb/ttusb-dec/Kconfig"
source "drivers/media/dvb/cinergyT2/Kconfig"
+source "drivers/media/dvb/siano/Kconfig"
comment "Supported FlexCopII (B2C2) Adapters"
depends on DVB_CORE && (PCI || USB) && I2C
diff --git a/drivers/media/dvb/Makefile b/drivers/media/dvb/Makefile
index a7ad0841e6f..d6ba4d19520 100644
--- a/drivers/media/dvb/Makefile
+++ b/drivers/media/dvb/Makefile
@@ -2,4 +2,4 @@
# Makefile for the kernel multimedia device drivers.
#
-obj-y := dvb-core/ frontends/ ttpci/ ttusb-dec/ ttusb-budget/ b2c2/ bt8xx/ cinergyT2/ dvb-usb/ pluto2/
+obj-y := dvb-core/ frontends/ ttpci/ ttusb-dec/ ttusb-budget/ b2c2/ bt8xx/ cinergyT2/ dvb-usb/ pluto2/ siano/
diff --git a/drivers/media/dvb/b2c2/flexcop-fe-tuner.c b/drivers/media/dvb/b2c2/flexcop-fe-tuner.c
index f9d087669d5..4eed783f4bc 100644
--- a/drivers/media/dvb/b2c2/flexcop-fe-tuner.c
+++ b/drivers/media/dvb/b2c2/flexcop-fe-tuner.c
@@ -137,7 +137,8 @@ static int flexcop_send_diseqc_msg(struct dvb_frontend* fe, int len, u8 *msg, un
flexcop_diseqc_send_byte(fe, 0xff);
else {
flexcop_set_tone(fe, SEC_TONE_ON);
- udelay(12500);
+ mdelay(12);
+ udelay(500);
flexcop_set_tone(fe, SEC_TONE_OFF);
}
msleep(20);
diff --git a/drivers/media/dvb/b2c2/flexcop-i2c.c b/drivers/media/dvb/b2c2/flexcop-i2c.c
index 55973eaf371..43a112ec6d4 100644
--- a/drivers/media/dvb/b2c2/flexcop-i2c.c
+++ b/drivers/media/dvb/b2c2/flexcop-i2c.c
@@ -221,12 +221,12 @@ int flexcop_i2c_init(struct flexcop_device *fc)
fc->fc_i2c_adap[1].port = FC_I2C_PORT_EEPROM;
fc->fc_i2c_adap[2].port = FC_I2C_PORT_TUNER;
- strncpy(fc->fc_i2c_adap[0].i2c_adap.name,
- "B2C2 FlexCop I2C to demod", I2C_NAME_SIZE);
- strncpy(fc->fc_i2c_adap[1].i2c_adap.name,
- "B2C2 FlexCop I2C to eeprom", I2C_NAME_SIZE);
- strncpy(fc->fc_i2c_adap[2].i2c_adap.name,
- "B2C2 FlexCop I2C to tuner", I2C_NAME_SIZE);
+ strlcpy(fc->fc_i2c_adap[0].i2c_adap.name, "B2C2 FlexCop I2C to demod",
+ sizeof(fc->fc_i2c_adap[0].i2c_adap.name));
+ strlcpy(fc->fc_i2c_adap[1].i2c_adap.name, "B2C2 FlexCop I2C to eeprom",
+ sizeof(fc->fc_i2c_adap[1].i2c_adap.name));
+ strlcpy(fc->fc_i2c_adap[2].i2c_adap.name, "B2C2 FlexCop I2C to tuner",
+ sizeof(fc->fc_i2c_adap[2].i2c_adap.name));
i2c_set_adapdata(&fc->fc_i2c_adap[0].i2c_adap, &fc->fc_i2c_adap[0]);
i2c_set_adapdata(&fc->fc_i2c_adap[1].i2c_adap, &fc->fc_i2c_adap[1]);
diff --git a/drivers/media/dvb/bt8xx/Kconfig b/drivers/media/dvb/bt8xx/Kconfig
index 7588db1319d..7e9c090fc04 100644
--- a/drivers/media/dvb/bt8xx/Kconfig
+++ b/drivers/media/dvb/bt8xx/Kconfig
@@ -1,7 +1,6 @@
config DVB_BT8XX
tristate "BT8xx based PCI cards"
depends on DVB_CORE && PCI && I2C && VIDEO_BT848
- depends on HOTPLUG # due to FW_LOADER
select DVB_MT352 if !DVB_FE_CUSTOMISE
select DVB_SP887X if !DVB_FE_CUSTOMISE
select DVB_NXT6000 if !DVB_FE_CUSTOMISE
@@ -10,7 +9,6 @@ config DVB_BT8XX
select DVB_LGDT330X if !DVB_FE_CUSTOMISE
select DVB_ZL10353 if !DVB_FE_CUSTOMISE
select MEDIA_TUNER_SIMPLE if !DVB_FE_CUSTOMISE
- select FW_LOADER
help
Support for PCI cards based on the Bt8xx PCI bridge. Examples are
the Nebula cards, the Pinnacle PCTV cards, the Twinhan DST cards,
diff --git a/drivers/media/dvb/bt8xx/bt878.h b/drivers/media/dvb/bt8xx/bt878.h
index 375fd2892a1..d19b59299d7 100644
--- a/drivers/media/dvb/bt8xx/bt878.h
+++ b/drivers/media/dvb/bt8xx/bt878.h
@@ -128,7 +128,7 @@ struct bt878 {
dma_addr_t buf_dma;
u32 risc_size;
- u32 *risc_cpu;
+ __le32 *risc_cpu;
dma_addr_t risc_dma;
u32 risc_pos;
diff --git a/drivers/media/dvb/bt8xx/dst.c b/drivers/media/dvb/bt8xx/dst.c
index a7637562e74..aa3db57d32d 100644
--- a/drivers/media/dvb/bt8xx/dst.c
+++ b/drivers/media/dvb/bt8xx/dst.c
@@ -1244,7 +1244,7 @@ static int dst_command(struct dst_state *state, u8 *data, u8 len)
goto error;
}
if (state->type_flags & DST_TYPE_HAS_FW_1)
- udelay(3000);
+ mdelay(3);
if (read_dst(state, &reply, GET_ACK)) {
dprintk(verbose, DST_DEBUG, 1, "Trying to recover.. ");
if ((dst_error_recovery(state)) < 0) {
@@ -1260,7 +1260,7 @@ static int dst_command(struct dst_state *state, u8 *data, u8 len)
if (len >= 2 && data[0] == 0 && (data[1] == 1 || data[1] == 3))
goto error;
if (state->type_flags & DST_TYPE_HAS_FW_1)
- udelay(3000);
+ mdelay(3);
else
udelay(2000);
if (!dst_wait_dst_ready(state, NO_DELAY))
diff --git a/drivers/media/dvb/dvb-core/demux.h b/drivers/media/dvb/dvb-core/demux.h
index b0d347daae4..eb91fd808c1 100644
--- a/drivers/media/dvb/dvb-core/demux.h
+++ b/drivers/media/dvb/dvb-core/demux.h
@@ -247,7 +247,7 @@ struct dmx_demux {
void* priv; /* Pointer to private data of the API client */
int (*open) (struct dmx_demux* demux);
int (*close) (struct dmx_demux* demux);
- int (*write) (struct dmx_demux* demux, const char* buf, size_t count);
+ int (*write) (struct dmx_demux* demux, const char __user *buf, size_t count);
int (*allocate_ts_feed) (struct dmx_demux* demux,
struct dmx_ts_feed** feed,
dmx_ts_cb callback);
diff --git a/drivers/media/dvb/dvb-core/dmxdev.c b/drivers/media/dvb/dvb-core/dmxdev.c
index df5bef6a251..069d847ba88 100644
--- a/drivers/media/dvb/dvb-core/dmxdev.c
+++ b/drivers/media/dvb/dvb-core/dmxdev.c
@@ -96,7 +96,7 @@ static ssize_t dvb_dmxdev_buffer_read(struct dvb_ringbuffer *src,
if (avail > todo)
avail = todo;
- ret = dvb_ringbuffer_read(src, (u8 *)buf, avail, 1);
+ ret = dvb_ringbuffer_read_user(src, buf, avail);
if (ret < 0)
break;
@@ -641,7 +641,6 @@ static int dvb_dmxdev_filter_start(struct dmxdev_filter *filter)
struct timespec timeout = { 0 };
struct dmx_pes_filter_params *para = &filter->params.pes;
dmx_output_t otype;
- int ret;
int ts_type;
enum dmx_ts_pes ts_pes;
struct dmx_ts_feed **tsfeed = &filter->feed.ts;
diff --git a/drivers/media/dvb/dvb-core/dvb_ca_en50221.c b/drivers/media/dvb/dvb-core/dvb_ca_en50221.c
index 588fbe105c2..98ee16773ff 100644
--- a/drivers/media/dvb/dvb-core/dvb_ca_en50221.c
+++ b/drivers/media/dvb/dvb-core/dvb_ca_en50221.c
@@ -1032,7 +1032,7 @@ static int dvb_ca_en50221_thread(void *data)
/* we need this extra check for annoying interfaces like the budget-av */
if ((!(ca->flags & DVB_CA_EN50221_FLAG_IRQ_CAMCHANGE)) &&
(ca->pub->poll_slot_status)) {
- int status = ca->pub->poll_slot_status(ca->pub, slot, 0);
+ status = ca->pub->poll_slot_status(ca->pub, slot, 0);
if (!(status & DVB_CA_EN50221_POLL_CAM_PRESENT)) {
ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_NONE;
dvb_ca_en50221_thread_update_delay(ca);
@@ -1089,7 +1089,7 @@ static int dvb_ca_en50221_thread(void *data)
/* we need this extra check for annoying interfaces like the budget-av */
if ((!(ca->flags & DVB_CA_EN50221_FLAG_IRQ_CAMCHANGE)) &&
(ca->pub->poll_slot_status)) {
- int status = ca->pub->poll_slot_status(ca->pub, slot, 0);
+ status = ca->pub->poll_slot_status(ca->pub, slot, 0);
if (!(status & DVB_CA_EN50221_POLL_CAM_PRESENT)) {
ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_NONE;
dvb_ca_en50221_thread_update_delay(ca);
@@ -1357,7 +1357,7 @@ static int dvb_ca_en50221_io_read_condition(struct dvb_ca_private *ca,
idx = dvb_ringbuffer_pkt_next(&ca->slot_info[slot].rx_buffer, -1, &fraglen);
while (idx != -1) {
- dvb_ringbuffer_pkt_read(&ca->slot_info[slot].rx_buffer, idx, 0, hdr, 2, 0);
+ dvb_ringbuffer_pkt_read(&ca->slot_info[slot].rx_buffer, idx, 0, hdr, 2);
if (connection_id == -1)
connection_id = hdr[0];
if ((hdr[0] == connection_id) && ((hdr[1] & 0x80) == 0)) {
@@ -1438,7 +1438,7 @@ static ssize_t dvb_ca_en50221_io_read(struct file *file, char __user * buf,
goto exit;
}
- dvb_ringbuffer_pkt_read(&ca->slot_info[slot].rx_buffer, idx, 0, hdr, 2, 0);
+ dvb_ringbuffer_pkt_read(&ca->slot_info[slot].rx_buffer, idx, 0, hdr, 2);
if (connection_id == -1)
connection_id = hdr[0];
if (hdr[0] == connection_id) {
@@ -1449,8 +1449,8 @@ static ssize_t dvb_ca_en50221_io_read(struct file *file, char __user * buf,
fraglen -= 2;
}
- if ((status = dvb_ringbuffer_pkt_read(&ca->slot_info[slot].rx_buffer, idx, 2,
- (u8 *)buf + pktlen, fraglen, 1)) < 0) {
+ if ((status = dvb_ringbuffer_pkt_read_user(&ca->slot_info[slot].rx_buffer, idx, 2,
+ buf + pktlen, fraglen)) < 0) {
goto exit;
}
pktlen += fraglen;
diff --git a/drivers/media/dvb/dvb-core/dvb_demux.c b/drivers/media/dvb/dvb-core/dvb_demux.c
index 934e15fffc5..e2eca0b1fe7 100644
--- a/drivers/media/dvb/dvb-core/dvb_demux.c
+++ b/drivers/media/dvb/dvb-core/dvb_demux.c
@@ -1056,16 +1056,27 @@ static int dvbdmx_close(struct dmx_demux *demux)
return 0;
}
-static int dvbdmx_write(struct dmx_demux *demux, const char *buf, size_t count)
+static int dvbdmx_write(struct dmx_demux *demux, const char __user *buf, size_t count)
{
struct dvb_demux *dvbdemux = (struct dvb_demux *)demux;
+ void *p;
if ((!demux->frontend) || (demux->frontend->source != DMX_MEMORY_FE))
return -EINVAL;
- if (mutex_lock_interruptible(&dvbdemux->mutex))
+ p = kmalloc(count, GFP_USER);
+ if (!p)
+ return -ENOMEM;
+ if (copy_from_user(p, buf, count)) {
+ kfree(p);
+ return -EFAULT;
+ }
+ if (mutex_lock_interruptible(&dvbdemux->mutex)) {
+ kfree(p);
return -ERESTARTSYS;
- dvb_dmx_swfilter(dvbdemux, (u8 *)buf, count);
+ }
+ dvb_dmx_swfilter(dvbdemux, p, count);
+ kfree(p);
mutex_unlock(&dvbdemux->mutex);
if (signal_pending(current))
diff --git a/drivers/media/dvb/dvb-core/dvb_frontend.c b/drivers/media/dvb/dvb-core/dvb_frontend.c
index 8cbdb218952..3526e3ee948 100644
--- a/drivers/media/dvb/dvb-core/dvb_frontend.c
+++ b/drivers/media/dvb/dvb-core/dvb_frontend.c
@@ -889,13 +889,13 @@ static int dvb_frontend_ioctl(struct inode *inode, struct file *file,
* initialization, so parg is 8 bits and does not
* include the initialization or start bit
*/
- unsigned long cmd = ((unsigned long) parg) << 1;
+ unsigned long swcmd = ((unsigned long) parg) << 1;
struct timeval nexttime;
struct timeval tv[10];
int i;
u8 last = 1;
if (dvb_frontend_debug)
- printk("%s switch command: 0x%04lx\n", __func__, cmd);
+ printk("%s switch command: 0x%04lx\n", __func__, swcmd);
do_gettimeofday(&nexttime);
if (dvb_frontend_debug)
memcpy(&tv[0], &nexttime, sizeof(struct timeval));
@@ -908,12 +908,12 @@ static int dvb_frontend_ioctl(struct inode *inode, struct file *file,
for (i = 0; i < 9; i++) {
if (dvb_frontend_debug)
do_gettimeofday(&tv[i + 1]);
- if ((cmd & 0x01) != last) {
+ if ((swcmd & 0x01) != last) {
/* set voltage to (last ? 13V : 18V) */
fe->ops.set_voltage(fe, (last) ? SEC_VOLTAGE_13 : SEC_VOLTAGE_18);
last = (last) ? 0 : 1;
}
- cmd = cmd >> 1;
+ swcmd = swcmd >> 1;
if (i != 8)
dvb_frontend_sleep_until(&nexttime, 8000);
}
diff --git a/drivers/media/dvb/dvb-core/dvb_net.c b/drivers/media/dvb/dvb-core/dvb_net.c
index c2334aef414..c93019ca519 100644
--- a/drivers/media/dvb/dvb-core/dvb_net.c
+++ b/drivers/media/dvb/dvb-core/dvb_net.c
@@ -606,7 +606,7 @@ static void dvb_net_ule( struct net_device *dev, const u8 *buf, size_t buf_len )
if (priv->ule_dbit) {
/* Set D-bit for CRC32 verification,
* if it was set originally. */
- ulen |= 0x0080;
+ ulen |= htons(0x8000);
}
ule_crc = iov_crc32(ule_crc, iov, 3);
@@ -1133,7 +1133,7 @@ static void wq_set_multicast_list (struct work_struct *work)
dvb_net_feed_stop(dev);
priv->rx_mode = RX_MODE_UNI;
- netif_tx_lock_bh(dev);
+ netif_addr_lock_bh(dev);
if (dev->flags & IFF_PROMISC) {
dprintk("%s: promiscuous mode\n", dev->name);
@@ -1158,7 +1158,7 @@ static void wq_set_multicast_list (struct work_struct *work)
}
}
- netif_tx_unlock_bh(dev);
+ netif_addr_unlock_bh(dev);
dvb_net_feed_start(dev);
}
diff --git a/drivers/media/dvb/dvb-core/dvb_ringbuffer.c b/drivers/media/dvb/dvb-core/dvb_ringbuffer.c
index 872985b7912..584bbd194dc 100644
--- a/drivers/media/dvb/dvb-core/dvb_ringbuffer.c
+++ b/drivers/media/dvb/dvb-core/dvb_ringbuffer.c
@@ -107,35 +107,43 @@ void dvb_ringbuffer_flush_spinlock_wakeup(struct dvb_ringbuffer *rbuf)
wake_up(&rbuf->queue);
}
-
-
-ssize_t dvb_ringbuffer_read(struct dvb_ringbuffer *rbuf, u8 *buf, size_t len, int usermem)
+ssize_t dvb_ringbuffer_read_user(struct dvb_ringbuffer *rbuf, u8 __user *buf, size_t len)
{
size_t todo = len;
size_t split;
split = (rbuf->pread + len > rbuf->size) ? rbuf->size - rbuf->pread : 0;
if (split > 0) {
- if (!usermem)
- memcpy(buf, rbuf->data+rbuf->pread, split);
- else
- if (copy_to_user(buf, rbuf->data+rbuf->pread, split))
- return -EFAULT;
+ if (copy_to_user(buf, rbuf->data+rbuf->pread, split))
+ return -EFAULT;
buf += split;
todo -= split;
rbuf->pread = 0;
}
- if (!usermem)
- memcpy(buf, rbuf->data+rbuf->pread, todo);
- else
- if (copy_to_user(buf, rbuf->data+rbuf->pread, todo))
- return -EFAULT;
+ if (copy_to_user(buf, rbuf->data+rbuf->pread, todo))
+ return -EFAULT;
rbuf->pread = (rbuf->pread + todo) % rbuf->size;
return len;
}
+void dvb_ringbuffer_read(struct dvb_ringbuffer *rbuf, u8 *buf, size_t len)
+{
+ size_t todo = len;
+ size_t split;
+
+ split = (rbuf->pread + len > rbuf->size) ? rbuf->size - rbuf->pread : 0;
+ if (split > 0) {
+ memcpy(buf, rbuf->data+rbuf->pread, split);
+ buf += split;
+ todo -= split;
+ rbuf->pread = 0;
+ }
+ memcpy(buf, rbuf->data+rbuf->pread, todo);
+
+ rbuf->pread = (rbuf->pread + todo) % rbuf->size;
+}
ssize_t dvb_ringbuffer_write(struct dvb_ringbuffer *rbuf, const u8 *buf, size_t len)
@@ -171,8 +179,8 @@ ssize_t dvb_ringbuffer_pkt_write(struct dvb_ringbuffer *rbuf, u8* buf, size_t le
return status;
}
-ssize_t dvb_ringbuffer_pkt_read(struct dvb_ringbuffer *rbuf, size_t idx,
- int offset, u8* buf, size_t len, int usermem)
+ssize_t dvb_ringbuffer_pkt_read_user(struct dvb_ringbuffer *rbuf, size_t idx,
+ int offset, u8 __user *buf, size_t len)
{
size_t todo;
size_t split;
@@ -187,21 +195,40 @@ ssize_t dvb_ringbuffer_pkt_read(struct dvb_ringbuffer *rbuf, size_t idx,
todo = len;
split = ((idx + len) > rbuf->size) ? rbuf->size - idx : 0;
if (split > 0) {
- if (!usermem)
- memcpy(buf, rbuf->data+idx, split);
- else
- if (copy_to_user(buf, rbuf->data+idx, split))
- return -EFAULT;
+ if (copy_to_user(buf, rbuf->data+idx, split))
+ return -EFAULT;
buf += split;
todo -= split;
idx = 0;
}
- if (!usermem)
- memcpy(buf, rbuf->data+idx, todo);
- else
- if (copy_to_user(buf, rbuf->data+idx, todo))
- return -EFAULT;
+ if (copy_to_user(buf, rbuf->data+idx, todo))
+ return -EFAULT;
+
+ return len;
+}
+ssize_t dvb_ringbuffer_pkt_read(struct dvb_ringbuffer *rbuf, size_t idx,
+ int offset, u8* buf, size_t len)
+{
+ size_t todo;
+ size_t split;
+ size_t pktlen;
+
+ pktlen = rbuf->data[idx] << 8;
+ pktlen |= rbuf->data[(idx + 1) % rbuf->size];
+ if (offset > pktlen) return -EINVAL;
+ if ((offset + len) > pktlen) len = pktlen - offset;
+
+ idx = (idx + DVB_RINGBUFFER_PKTHDRSIZE + offset) % rbuf->size;
+ todo = len;
+ split = ((idx + len) > rbuf->size) ? rbuf->size - idx : 0;
+ if (split > 0) {
+ memcpy(buf, rbuf->data+idx, split);
+ buf += split;
+ todo -= split;
+ idx = 0;
+ }
+ memcpy(buf, rbuf->data+idx, todo);
return len;
}
@@ -266,5 +293,6 @@ EXPORT_SYMBOL(dvb_ringbuffer_empty);
EXPORT_SYMBOL(dvb_ringbuffer_free);
EXPORT_SYMBOL(dvb_ringbuffer_avail);
EXPORT_SYMBOL(dvb_ringbuffer_flush_spinlock_wakeup);
+EXPORT_SYMBOL(dvb_ringbuffer_read_user);
EXPORT_SYMBOL(dvb_ringbuffer_read);
EXPORT_SYMBOL(dvb_ringbuffer_write);
diff --git a/drivers/media/dvb/dvb-core/dvb_ringbuffer.h b/drivers/media/dvb/dvb-core/dvb_ringbuffer.h
index 89082626296..41f04dae69b 100644
--- a/drivers/media/dvb/dvb-core/dvb_ringbuffer.h
+++ b/drivers/media/dvb/dvb-core/dvb_ringbuffer.h
@@ -61,7 +61,7 @@ struct dvb_ringbuffer {
** *** read min. 1000, max. <bufsize> bytes ***
** avail = dvb_ringbuffer_avail(rbuf);
** if (avail >= 1000)
-** count = dvb_ringbuffer_read(rbuf, buffer, min(avail, bufsize), 0);
+** count = dvb_ringbuffer_read(rbuf, buffer, min(avail, bufsize));
** else
** ...
**
@@ -114,8 +114,10 @@ extern void dvb_ringbuffer_flush_spinlock_wakeup(struct dvb_ringbuffer *rbuf);
** <usermem> specifies whether <buf> resides in user space
** returns number of bytes transferred or -EFAULT
*/
-extern ssize_t dvb_ringbuffer_read(struct dvb_ringbuffer *rbuf, u8 *buf,
- size_t len, int usermem);
+extern ssize_t dvb_ringbuffer_read_user(struct dvb_ringbuffer *rbuf,
+ u8 __user *buf, size_t len);
+extern void dvb_ringbuffer_read(struct dvb_ringbuffer *rbuf,
+ u8 *buf, size_t len);
/* write routines & macros */
@@ -157,8 +159,10 @@ extern ssize_t dvb_ringbuffer_pkt_write(struct dvb_ringbuffer *rbuf, u8* buf,
* <usermem> Set to 1 if <buf> is in userspace.
* returns Number of bytes read, or -EFAULT.
*/
+extern ssize_t dvb_ringbuffer_pkt_read_user(struct dvb_ringbuffer *rbuf, size_t idx,
+ int offset, u8 __user *buf, size_t len);
extern ssize_t dvb_ringbuffer_pkt_read(struct dvb_ringbuffer *rbuf, size_t idx,
- int offset, u8* buf, size_t len, int usermem);
+ int offset, u8 *buf, size_t len);
/**
* Dispose of a packet in the ring buffer.
diff --git a/drivers/media/dvb/dvb-core/dvbdev.c b/drivers/media/dvb/dvb-core/dvbdev.c
index e208a60c048..e7132770a3b 100644
--- a/drivers/media/dvb/dvb-core/dvbdev.c
+++ b/drivers/media/dvb/dvb-core/dvbdev.c
@@ -233,9 +233,9 @@ int dvb_register_device(struct dvb_adapter *adap, struct dvb_device **pdvbdev,
mutex_unlock(&dvbdev_register_lock);
- clsdev = device_create(dvb_class, adap->device,
+ clsdev = device_create_drvdata(dvb_class, adap->device,
MKDEV(DVB_MAJOR, nums2minor(adap->num, type, id)),
- "dvb%d.%s%d", adap->num, dnames[type], id);
+ NULL, "dvb%d.%s%d", adap->num, dnames[type], id);
if (IS_ERR(clsdev)) {
printk(KERN_ERR "%s: failed to create device dvb%d.%s%d (%ld)\n",
__func__, adap->num, dnames[type], id, PTR_ERR(clsdev));
diff --git a/drivers/media/dvb/dvb-usb/Kconfig b/drivers/media/dvb/dvb-usb/Kconfig
index f00a0eb4042..e84152b7576 100644
--- a/drivers/media/dvb/dvb-usb/Kconfig
+++ b/drivers/media/dvb/dvb-usb/Kconfig
@@ -1,8 +1,6 @@
config DVB_USB
tristate "Support for various USB DVB devices"
depends on DVB_CORE && USB && I2C && INPUT
- depends on HOTPLUG # due to FW_LOADER
- select FW_LOADER
help
By enabling this you will be able to choose the various supported
USB1.1 and USB2.0 DVB devices.
@@ -76,6 +74,7 @@ config DVB_USB_DIB0700
select DVB_DIB3000MC
select MEDIA_TUNER_MT2060 if !DVB_FE_CUSTOMISE
select MEDIA_TUNER_MT2266 if !DVB_FE_CUSTOMISE
+ select MEDIA_TUNER_XC2028 if !DVB_FE_CUSTOMISE
select DVB_TUNER_DIB0070
help
Support for USB2.0/1.1 DVB receivers based on the DiB0700 USB bridge. The
@@ -107,6 +106,8 @@ config DVB_USB_CXUSB
select DVB_MT352 if !DVB_FE_CUSTOMISE
select DVB_ZL10353 if !DVB_FE_CUSTOMISE
select MEDIA_TUNER_SIMPLE if !DVB_FE_CUSTOMISE
+ select MEDIA_TUNER_XC2028 if !DVB_FE_CUSTOMISE
+ select MEDIA_TUNER_MXL5005S if !DVB_FE_CUSTOMISE
help
Say Y here to support the Conexant USB2.0 hybrid reference design.
Currently, only DVB and ATSC modes are supported, analog mode
@@ -120,6 +121,8 @@ config DVB_USB_M920X
depends on DVB_USB
select DVB_MT352 if !DVB_FE_CUSTOMISE
select MEDIA_TUNER_QT1010 if !DVB_FE_CUSTOMISE
+ select MEDIA_TUNER_TDA827X if !DVB_FE_CUSTOMISE
+ select DVB_TDA1004X if !DVB_FE_CUSTOMISE
help
Say Y here to support the MSI Mega Sky 580 USB2.0 DVB-T receiver.
Currently, only devices with a product id of
@@ -241,3 +244,21 @@ config DVB_USB_AF9005_REMOTE
Say Y here to support the default remote control decoding for the
Afatech AF9005 based receiver.
+config DVB_USB_DW2102
+ tristate "DvbWorld 2102 DVB-S USB2.0 receiver"
+ depends on DVB_USB
+ select DVB_STV0299 if !DVB_FE_CUSTOMISE
+ select DVB_PLL if !DVB_FE_CUSTOMISE
+ help
+ Say Y here to support the DvbWorld 2102 DVB-S USB2.0 receiver.
+
+config DVB_USB_ANYSEE
+ tristate "Anysee DVB-T/C USB2.0 support"
+ depends on DVB_USB
+ select DVB_PLL if !DVB_FE_CUSTOMISE
+ select DVB_MT352 if !DVB_FE_CUSTOMISE
+ select DVB_ZL10353 if !DVB_FE_CUSTOMISE
+ select DVB_TDA10023 if !DVB_FE_CUSTOMISE
+ help
+ Say Y here to support the Anysee E30, Anysee E30 Plus or
+ Anysee E30 C Plus DVB USB2.0 receiver.
diff --git a/drivers/media/dvb/dvb-usb/Makefile b/drivers/media/dvb/dvb-usb/Makefile
index c6511a6c0ab..e206f1ea002 100644
--- a/drivers/media/dvb/dvb-usb/Makefile
+++ b/drivers/media/dvb/dvb-usb/Makefile
@@ -61,6 +61,12 @@ obj-$(CONFIG_DVB_USB_AF9005) += dvb-usb-af9005.o
dvb-usb-af9005-remote-objs = af9005-remote.o
obj-$(CONFIG_DVB_USB_AF9005_REMOTE) += dvb-usb-af9005-remote.o
+dvb-usb-anysee-objs = anysee.o
+obj-$(CONFIG_DVB_USB_ANYSEE) += dvb-usb-anysee.o
+
+dvb-usb-dw2102-objs = dw2102.o
+obj-$(CONFIG_DVB_USB_DW2102) += dvb-usb-dw2102.o
+
EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core/ -Idrivers/media/dvb/frontends/
# due to tuner-xc3028
EXTRA_CFLAGS += -Idrivers/media/common/tuners
diff --git a/drivers/media/dvb/dvb-usb/anysee.c b/drivers/media/dvb/dvb-usb/anysee.c
new file mode 100644
index 00000000000..2f408d2e1ef
--- /dev/null
+++ b/drivers/media/dvb/dvb-usb/anysee.c
@@ -0,0 +1,553 @@
+/*
+ * DVB USB Linux driver for Anysee E30 DVB-C & DVB-T USB2.0 receiver
+ *
+ * Copyright (C) 2007 Antti Palosaari <crope@iki.fi>
+ *
+ * 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.
+ *
+ * TODO:
+ * - add smart card reader support for Conditional Access (CA)
+ *
+ * Card reader in Anysee is nothing more than ISO 7816 card reader.
+ * There is no hardware CAM in any Anysee device sold.
+ * In my understanding it should be implemented by making own module
+ * for ISO 7816 card reader, like dvb_ca_en50221 is implemented. This
+ * module registers serial interface that can be used to communicate
+ * with any ISO 7816 smart card.
+ *
+ * Any help according to implement serial smart card reader support
+ * is highly welcome!
+ */
+
+#include "anysee.h"
+#include "tda1002x.h"
+#include "mt352.h"
+#include "mt352_priv.h"
+#include "zl10353.h"
+
+/* debug */
+static int dvb_usb_anysee_debug;
+module_param_named(debug, dvb_usb_anysee_debug, int, 0644);
+MODULE_PARM_DESC(debug, "set debugging level" DVB_USB_DEBUG_STATUS);
+DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
+
+static struct mutex anysee_usb_mutex;
+
+static int anysee_ctrl_msg(struct dvb_usb_device *d, u8 *sbuf, u8 slen,
+ u8 *rbuf, u8 rlen)
+{
+ struct anysee_state *state = d->priv;
+ int act_len, ret;
+ u8 buf[64];
+
+ if (slen > sizeof(buf))
+ slen = sizeof(buf);
+ memcpy(&buf[0], sbuf, slen);
+ buf[60] = state->seq++;
+
+ if (mutex_lock_interruptible(&anysee_usb_mutex) < 0)
+ return -EAGAIN;
+
+ /* We need receive one message more after dvb_usb_generic_rw due
+ to weird transaction flow, which is 1 x send + 2 x receive. */
+ ret = dvb_usb_generic_rw(d, buf, sizeof(buf), buf, sizeof(buf), 0);
+
+ if (!ret) {
+ /* receive 2nd answer */
+ ret = usb_bulk_msg(d->udev, usb_rcvbulkpipe(d->udev,
+ d->props.generic_bulk_ctrl_endpoint), buf, sizeof(buf),
+ &act_len, 2000);
+ if (ret)
+ err("%s: recv bulk message failed: %d", __func__, ret);
+ else {
+ deb_xfer("<<< ");
+ debug_dump(buf, act_len, deb_xfer);
+ }
+ }
+
+ /* read request, copy returned data to return buf */
+ if (!ret && rbuf && rlen)
+ memcpy(rbuf, buf, rlen);
+
+ mutex_unlock(&anysee_usb_mutex);
+
+ return ret;
+}
+
+static int anysee_read_reg(struct dvb_usb_device *d, u16 reg, u8 *val)
+{
+ u8 buf[] = {CMD_REG_READ, reg >> 8, reg & 0xff, 0x01};
+ int ret;
+ ret = anysee_ctrl_msg(d, buf, sizeof(buf), val, 1);
+ deb_info("%s: reg:%04x val:%02x\n", __func__, reg, *val);
+ return ret;
+}
+
+static int anysee_write_reg(struct dvb_usb_device *d, u16 reg, u8 val)
+{
+ u8 buf[] = {CMD_REG_WRITE, reg >> 8, reg & 0xff, 0x01, val};
+ deb_info("%s: reg:%04x val:%02x\n", __func__, reg, val);
+ return anysee_ctrl_msg(d, buf, sizeof(buf), NULL, 0);
+}
+
+static int anysee_get_hw_info(struct dvb_usb_device *d, u8 *id)
+{
+ u8 buf[] = {CMD_GET_HW_INFO};
+ return anysee_ctrl_msg(d, buf, sizeof(buf), id, 3);
+}
+
+static int anysee_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff)
+{
+ u8 buf[] = {CMD_STREAMING_CTRL, (u8)onoff, 0x00};
+ deb_info("%s: onoff:%02x\n", __func__, onoff);
+ return anysee_ctrl_msg(adap->dev, buf, sizeof(buf), NULL, 0);
+}
+
+static int anysee_led_ctrl(struct dvb_usb_device *d, u8 mode, u8 interval)
+{
+ u8 buf[] = {CMD_LED_AND_IR_CTRL, 0x01, mode, interval};
+ deb_info("%s: state:%02x interval:%02x\n", __func__, mode, interval);
+ return anysee_ctrl_msg(d, buf, sizeof(buf), NULL, 0);
+}
+
+static int anysee_ir_ctrl(struct dvb_usb_device *d, u8 onoff)
+{
+ u8 buf[] = {CMD_LED_AND_IR_CTRL, 0x02, onoff};
+ deb_info("%s: onoff:%02x\n", __func__, onoff);
+ return anysee_ctrl_msg(d, buf, sizeof(buf), NULL, 0);
+}
+
+static int anysee_init(struct dvb_usb_device *d)
+{
+ int ret;
+ /* LED light */
+ ret = anysee_led_ctrl(d, 0x01, 0x03);
+ if (ret)
+ return ret;
+
+ /* enable IR */
+ ret = anysee_ir_ctrl(d, 1);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+/* I2C */
+static int anysee_master_xfer(struct i2c_adapter *adap, struct i2c_msg *msg,
+ int num)
+{
+ struct dvb_usb_device *d = i2c_get_adapdata(adap);
+ int ret, inc, i = 0;
+
+ if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
+ return -EAGAIN;
+
+ while (i < num) {
+ if (num > i + 1 && (msg[i+1].flags & I2C_M_RD)) {
+ u8 buf[6];
+ buf[0] = CMD_I2C_READ;
+ buf[1] = msg[i].addr + 1;
+ buf[2] = msg[i].buf[0];
+ buf[3] = 0x00;
+ buf[4] = 0x00;
+ buf[5] = 0x01;
+ ret = anysee_ctrl_msg(d, buf, sizeof(buf), msg[i+1].buf,
+ msg[i+1].len);
+ inc = 2;
+ } else {
+ u8 buf[4+msg[i].len];
+ buf[0] = CMD_I2C_WRITE;
+ buf[1] = msg[i].addr;
+ buf[2] = msg[i].len;
+ buf[3] = 0x01;
+ memcpy(&buf[4], msg[i].buf, msg[i].len);
+ ret = anysee_ctrl_msg(d, buf, sizeof(buf), NULL, 0);
+ inc = 1;
+ }
+ if (ret)
+ return ret;
+
+ i += inc;
+ }
+
+ mutex_unlock(&d->i2c_mutex);
+
+ return i;
+}
+
+static u32 anysee_i2c_func(struct i2c_adapter *adapter)
+{
+ return I2C_FUNC_I2C;
+}
+
+static struct i2c_algorithm anysee_i2c_algo = {
+ .master_xfer = anysee_master_xfer,
+ .functionality = anysee_i2c_func,
+};
+
+static int anysee_mt352_demod_init(struct dvb_frontend *fe)
+{
+ static u8 clock_config [] = { CLOCK_CTL, 0x38, 0x28 };
+ static u8 reset [] = { RESET, 0x80 };
+ static u8 adc_ctl_1_cfg [] = { ADC_CTL_1, 0x40 };
+ static u8 agc_cfg [] = { AGC_TARGET, 0x28, 0x20 };
+ static u8 gpp_ctl_cfg [] = { GPP_CTL, 0x33 };
+ static u8 capt_range_cfg[] = { CAPT_RANGE, 0x32 };
+
+ mt352_write(fe, clock_config, sizeof(clock_config));
+ udelay(200);
+ mt352_write(fe, reset, sizeof(reset));
+ mt352_write(fe, adc_ctl_1_cfg, sizeof(adc_ctl_1_cfg));
+
+ mt352_write(fe, agc_cfg, sizeof(agc_cfg));
+ mt352_write(fe, gpp_ctl_cfg, sizeof(gpp_ctl_cfg));
+ mt352_write(fe, capt_range_cfg, sizeof(capt_range_cfg));
+
+ return 0;
+}
+
+/* Callbacks for DVB USB */
+static struct tda10023_config anysee_tda10023_config = {
+ .demod_address = 0x1a,
+ .invert = 0,
+ .xtal = 16000000,
+ .pll_m = 11,
+ .pll_p = 3,
+ .pll_n = 1,
+ .output_mode = TDA10023_OUTPUT_MODE_PARALLEL_C,
+ .deltaf = 0xfeeb,
+};
+
+static struct mt352_config anysee_mt352_config = {
+ .demod_address = 0x1e,
+ .demod_init = anysee_mt352_demod_init,
+};
+
+static struct zl10353_config anysee_zl10353_config = {
+ .demod_address = 0x1e,
+ .parallel_ts = 1,
+};
+
+static int anysee_frontend_attach(struct dvb_usb_adapter *adap)
+{
+ int ret;
+ struct anysee_state *state = adap->dev->priv;
+ u8 hw_info[3];
+ u8 io_d; /* IO port D */
+
+ /* check which hardware we have
+ We must do this call two times to get reliable values (hw bug). */
+ ret = anysee_get_hw_info(adap->dev, hw_info);
+ if (ret)
+ return ret;
+ ret = anysee_get_hw_info(adap->dev, hw_info);
+ if (ret)
+ return ret;
+
+ /* Meaning of these info bytes are guessed. */
+ info("firmware version:%d.%d.%d hardware id:%d",
+ 0, hw_info[1], hw_info[2], hw_info[0]);
+
+ ret = anysee_read_reg(adap->dev, 0xb0, &io_d); /* IO port D */
+ if (ret)
+ return ret;
+ deb_info("%s: IO port D:%02x\n", __func__, io_d);
+
+ /* Select demod using trial and error method. */
+
+ /* Try to attach demodulator in following order:
+ model demod hw firmware
+ 1. E30 MT352 02 0.2.1
+ 2. E30 ZL10353 02 0.2.1
+ 3. E30 Plus ZL10353 06 0.1.0
+ 4. E30C Plus TDA10023 0a 0.1.0 rev 0.2
+ 4. E30C Plus TDA10023 0f 0.1.2 rev 0.4
+ */
+
+ /* Zarlink MT352 DVB-T demod inside of Samsung DNOS404ZH102A NIM */
+ adap->fe = dvb_attach(mt352_attach, &anysee_mt352_config,
+ &adap->dev->i2c_adap);
+ if (adap->fe != NULL) {
+ state->tuner = DVB_PLL_THOMSON_DTT7579;
+ return 0;
+ }
+
+ /* Zarlink ZL10353 DVB-T demod inside of Samsung DNOS404ZH103A NIM */
+ adap->fe = dvb_attach(zl10353_attach, &anysee_zl10353_config,
+ &adap->dev->i2c_adap);
+ if (adap->fe != NULL) {
+ state->tuner = DVB_PLL_THOMSON_DTT7579;
+ return 0;
+ }
+
+ /* connect demod on IO port D for TDA10023 & ZL10353 */
+ ret = anysee_write_reg(adap->dev, 0xb0, 0x25);
+ if (ret)
+ return ret;
+
+ /* Zarlink ZL10353 DVB-T demod inside of Samsung DNOS404ZH103A NIM */
+ adap->fe = dvb_attach(zl10353_attach, &anysee_zl10353_config,
+ &adap->dev->i2c_adap);
+ if (adap->fe != NULL) {
+ state->tuner = DVB_PLL_THOMSON_DTT7579;
+ return 0;
+ }
+
+ /* IO port E - E30C rev 0.4 board requires this */
+ ret = anysee_write_reg(adap->dev, 0xb1, 0xa7);
+ if (ret)
+ return ret;
+
+ /* Philips TDA10023 DVB-C demod */
+ adap->fe = dvb_attach(tda10023_attach, &anysee_tda10023_config,
+ &adap->dev->i2c_adap, 0x48);
+ if (adap->fe != NULL) {
+ state->tuner = DVB_PLL_SAMSUNG_DTOS403IH102A;
+ return 0;
+ }
+
+ /* return IO port D to init value for safe */
+ ret = anysee_write_reg(adap->dev, 0xb0, io_d);
+ if (ret)
+ return ret;
+
+ err("Unkown Anysee version: %02x %02x %02x. "\
+ "Please report the <linux-dvb@linuxtv.org>.",
+ hw_info[0], hw_info[1], hw_info[2]);
+
+ return -ENODEV;
+}
+
+static int anysee_tuner_attach(struct dvb_usb_adapter *adap)
+{
+ struct anysee_state *state = adap->dev->priv;
+ deb_info("%s: \n", __func__);
+
+ switch (state->tuner) {
+ case DVB_PLL_THOMSON_DTT7579:
+ /* Thomson dtt7579 (not sure) PLL inside of:
+ Samsung DNOS404ZH102A NIM
+ Samsung DNOS404ZH103A NIM */
+ dvb_attach(dvb_pll_attach, adap->fe, 0x61,
+ NULL, DVB_PLL_THOMSON_DTT7579);
+ break;
+ case DVB_PLL_SAMSUNG_DTOS403IH102A:
+ /* Unknown PLL inside of Samsung DTOS403IH102A tuner module */
+ dvb_attach(dvb_pll_attach, adap->fe, 0xc0,
+ &adap->dev->i2c_adap, DVB_PLL_SAMSUNG_DTOS403IH102A);
+ break;
+ }
+
+ return 0;
+}
+
+static int anysee_rc_query(struct dvb_usb_device *d, u32 *event, int *state)
+{
+ u8 buf[] = {CMD_GET_IR_CODE};
+ struct dvb_usb_rc_key *keymap = d->props.rc_key_map;
+ u8 ircode[2];
+ int i, ret;
+
+ ret = anysee_ctrl_msg(d, buf, sizeof(buf), &ircode[0], 2);
+ if (ret)
+ return ret;
+
+ *event = 0;
+ *state = REMOTE_NO_KEY_PRESSED;
+
+ for (i = 0; i < d->props.rc_key_map_size; i++) {
+ if (keymap[i].custom == ircode[0] &&
+ keymap[i].data == ircode[1]) {
+ *event = keymap[i].event;
+ *state = REMOTE_KEY_PRESSED;
+ return 0;
+ }
+ }
+ return 0;
+}
+
+static struct dvb_usb_rc_key anysee_rc_keys[] = {
+ { 0x01, 0x00, KEY_0 },
+ { 0x01, 0x01, KEY_1 },
+ { 0x01, 0x02, KEY_2 },
+ { 0x01, 0x03, KEY_3 },
+ { 0x01, 0x04, KEY_4 },
+ { 0x01, 0x05, KEY_5 },
+ { 0x01, 0x06, KEY_6 },
+ { 0x01, 0x07, KEY_7 },
+ { 0x01, 0x08, KEY_8 },
+ { 0x01, 0x09, KEY_9 },
+ { 0x01, 0x0a, KEY_POWER },
+ { 0x01, 0x0b, KEY_DOCUMENTS }, /* * */
+ { 0x01, 0x19, KEY_FAVORITES },
+ { 0x01, 0x20, KEY_SLEEP },
+ { 0x01, 0x21, KEY_MODE }, /* 4:3 / 16:9 select */
+ { 0x01, 0x22, KEY_ZOOM },
+ { 0x01, 0x47, KEY_TEXT },
+ { 0x01, 0x16, KEY_TV }, /* TV / radio select */
+ { 0x01, 0x1e, KEY_LANGUAGE }, /* Second Audio Program */
+ { 0x01, 0x1a, KEY_SUBTITLE },
+ { 0x01, 0x1b, KEY_CAMERA }, /* screenshot */
+ { 0x01, 0x42, KEY_MUTE },
+ { 0x01, 0x0e, KEY_MENU },
+ { 0x01, 0x0f, KEY_EPG },
+ { 0x01, 0x17, KEY_INFO },
+ { 0x01, 0x10, KEY_EXIT },
+ { 0x01, 0x13, KEY_VOLUMEUP },
+ { 0x01, 0x12, KEY_VOLUMEDOWN },
+ { 0x01, 0x11, KEY_CHANNELUP },
+ { 0x01, 0x14, KEY_CHANNELDOWN },
+ { 0x01, 0x15, KEY_OK },
+ { 0x01, 0x1d, KEY_RED },
+ { 0x01, 0x1f, KEY_GREEN },
+ { 0x01, 0x1c, KEY_YELLOW },
+ { 0x01, 0x44, KEY_BLUE },
+ { 0x01, 0x0c, KEY_SHUFFLE }, /* snapshot */
+ { 0x01, 0x48, KEY_STOP },
+ { 0x01, 0x50, KEY_PLAY },
+ { 0x01, 0x51, KEY_PAUSE },
+ { 0x01, 0x49, KEY_RECORD },
+ { 0x01, 0x18, KEY_PREVIOUS }, /* |<< */
+ { 0x01, 0x0d, KEY_NEXT }, /* >>| */
+ { 0x01, 0x24, KEY_PROG1 }, /* F1 */
+ { 0x01, 0x25, KEY_PROG2 }, /* F2 */
+};
+
+/* DVB USB Driver stuff */
+static struct dvb_usb_device_properties anysee_properties;
+
+static int anysee_probe(struct usb_interface *intf,
+ const struct usb_device_id *id)
+{
+ struct dvb_usb_device *d;
+ struct usb_host_interface *alt;
+ int ret;
+
+ mutex_init(&anysee_usb_mutex);
+
+ /* There is one interface with two alternate settings.
+ Alternate setting 0 is for bulk transfer.
+ Alternate setting 1 is for isochronous transfer.
+ We use bulk transfer (alternate setting 0). */
+ if (intf->num_altsetting < 1)
+ return -ENODEV;
+
+ ret = dvb_usb_device_init(intf, &anysee_properties, THIS_MODULE, &d,
+ adapter_nr);
+ if (ret)
+ return ret;
+
+ alt = usb_altnum_to_altsetting(intf, 0);
+ if (alt == NULL) {
+ deb_info("%s: no alt found!\n", __func__);
+ return -ENODEV;
+ }
+
+ ret = usb_set_interface(d->udev, alt->desc.bInterfaceNumber,
+ alt->desc.bAlternateSetting);
+ if (ret)
+ return ret;
+
+ if (d)
+ ret = anysee_init(d);
+
+ return ret;
+}
+
+static struct usb_device_id anysee_table [] = {
+ { USB_DEVICE(USB_VID_CYPRESS, USB_PID_ANYSEE) },
+ { USB_DEVICE(USB_VID_AMT, USB_PID_ANYSEE) },
+ { } /* Terminating entry */
+};
+MODULE_DEVICE_TABLE(usb, anysee_table);
+
+static struct dvb_usb_device_properties anysee_properties = {
+ .caps = DVB_USB_IS_AN_I2C_ADAPTER,
+
+ .usb_ctrl = DEVICE_SPECIFIC,
+
+ .size_of_priv = sizeof(struct anysee_state),
+
+ .num_adapters = 1,
+ .adapter = {
+ {
+ .streaming_ctrl = anysee_streaming_ctrl,
+ .frontend_attach = anysee_frontend_attach,
+ .tuner_attach = anysee_tuner_attach,
+ .stream = {
+ .type = USB_BULK,
+ .count = 8,
+ .endpoint = 0x82,
+ .u = {
+ .bulk = {
+ .buffersize = 512,
+ }
+ }
+ },
+ }
+ },
+
+ .rc_key_map = anysee_rc_keys,
+ .rc_key_map_size = ARRAY_SIZE(anysee_rc_keys),
+ .rc_query = anysee_rc_query,
+ .rc_interval = 200, /* windows driver uses 500ms */
+
+ .i2c_algo = &anysee_i2c_algo,
+
+ .generic_bulk_ctrl_endpoint = 1,
+
+ .num_device_descs = 1,
+ .devices = {
+ {
+ .name = "Anysee DVB USB2.0",
+ .cold_ids = {NULL},
+ .warm_ids = {&anysee_table[0],
+ &anysee_table[1], NULL},
+ },
+ }
+};
+
+static struct usb_driver anysee_driver = {
+ .name = "dvb_usb_anysee",
+ .probe = anysee_probe,
+ .disconnect = dvb_usb_device_exit,
+ .id_table = anysee_table,
+};
+
+/* module stuff */
+static int __init anysee_module_init(void)
+{
+ int ret;
+
+ ret = usb_register(&anysee_driver);
+ if (ret)
+ err("%s: usb_register failed. Error number %d", __func__, ret);
+
+ return ret;
+}
+
+static void __exit anysee_module_exit(void)
+{
+ /* deregister this driver from the USB subsystem */
+ usb_deregister(&anysee_driver);
+}
+
+module_init(anysee_module_init);
+module_exit(anysee_module_exit);
+
+MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>");
+MODULE_DESCRIPTION("Driver Anysee E30 DVB-C & DVB-T USB2.0");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/dvb-usb/anysee.h b/drivers/media/dvb/dvb-usb/anysee.h
new file mode 100644
index 00000000000..7ca01ff6e13
--- /dev/null
+++ b/drivers/media/dvb/dvb-usb/anysee.h
@@ -0,0 +1,304 @@
+/*
+ * DVB USB Linux driver for Anysee E30 DVB-C & DVB-T USB2.0 receiver
+ *
+ * Copyright (C) 2007 Antti Palosaari <crope@iki.fi>
+ *
+ * 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.
+ *
+ * TODO:
+ * - add smart card reader support for Conditional Access (CA)
+ *
+ * Card reader in Anysee is nothing more than ISO 7816 card reader.
+ * There is no hardware CAM in any Anysee device sold.
+ * In my understanding it should be implemented by making own module
+ * for ISO 7816 card reader, like dvb_ca_en50221 is implemented. This
+ * module registers serial interface that can be used to communicate
+ * with any ISO 7816 smart card.
+ *
+ * Any help according to implement serial smart card reader support
+ * is highly welcome!
+ */
+
+#ifndef _DVB_USB_ANYSEE_H_
+#define _DVB_USB_ANYSEE_H_
+
+#define DVB_USB_LOG_PREFIX "anysee"
+#include "dvb-usb.h"
+
+#define deb_info(args...) dprintk(dvb_usb_anysee_debug, 0x01, args)
+#define deb_xfer(args...) dprintk(dvb_usb_anysee_debug, 0x02, args)
+#define deb_rc(args...) dprintk(dvb_usb_anysee_debug, 0x04, args)
+#define deb_reg(args...) dprintk(dvb_usb_anysee_debug, 0x08, args)
+#define deb_i2c(args...) dprintk(dvb_usb_anysee_debug, 0x10, args)
+#define deb_fw(args...) dprintk(dvb_usb_anysee_debug, 0x20, args)
+
+enum cmd {
+ CMD_I2C_READ = 0x33,
+ CMD_I2C_WRITE = 0x31,
+ CMD_REG_READ = 0xb0,
+ CMD_REG_WRITE = 0xb1,
+ CMD_STREAMING_CTRL = 0x12,
+ CMD_LED_AND_IR_CTRL = 0x16,
+ CMD_GET_IR_CODE = 0x41,
+ CMD_GET_HW_INFO = 0x19,
+ CMD_SMARTCARD = 0x34,
+};
+
+struct anysee_state {
+ u8 tuner;
+ u8 seq;
+};
+
+#endif
+
+/***************************************************************************
+ * USB API description (reverse engineered)
+ ***************************************************************************
+
+Transaction flow:
+=================
+BULK[00001] >>> REQUEST PACKET 64 bytes
+BULK[00081] <<< REPLY PACKET #1 64 bytes (PREVIOUS TRANSACTION REPLY)
+BULK[00081] <<< REPLY PACKET #2 64 bytes (CURRENT TRANSACTION REPLY)
+
+General reply packet(s) are always used if not own reply defined.
+
+============================================================================
+| 00-63 | GENERAL REPLY PACKET #1 (PREVIOUS REPLY)
+============================================================================
+| 00 | reply data (if any) from previous transaction
+| | Just same reply packet as returned during previous transaction.
+| | Needed only if reply is missed in previous transaction.
+| | Just skip normally.
+----------------------------------------------------------------------------
+| 01-59 | don't care
+----------------------------------------------------------------------------
+| 60 | packet sequence number
+----------------------------------------------------------------------------
+| 61-63 | don't care
+----------------------------------------------------------------------------
+
+============================================================================
+| 00-63 | GENERAL REPLY PACKET #2 (CURRENT REPLY)
+============================================================================
+| 00 | reply data (if any)
+----------------------------------------------------------------------------
+| 01-59 | don't care
+----------------------------------------------------------------------------
+| 60 | packet sequence number
+----------------------------------------------------------------------------
+| 61-63 | don't care
+----------------------------------------------------------------------------
+
+============================================================================
+| 00-63 | I2C WRITE REQUEST PACKET
+============================================================================
+| 00 | 0x31 I2C write command
+----------------------------------------------------------------------------
+| 01 | i2c address
+----------------------------------------------------------------------------
+| 02 | data length
+| | 0x02 (for typical I2C reg / val pair)
+----------------------------------------------------------------------------
+| 03 | 0x01
+----------------------------------------------------------------------------
+| 04- | data
+----------------------------------------------------------------------------
+| -59 | don't care
+----------------------------------------------------------------------------
+| 60 | packet sequence number
+----------------------------------------------------------------------------
+| 61-63 | don't care
+----------------------------------------------------------------------------
+
+============================================================================
+| 00-63 | I2C READ REQUEST PACKET
+============================================================================
+| 00 | 0x33 I2C read command
+----------------------------------------------------------------------------
+| 01 | i2c address + 1
+----------------------------------------------------------------------------
+| 02 | register
+----------------------------------------------------------------------------
+| 03 | 0x00
+----------------------------------------------------------------------------
+| 04 | 0x00
+----------------------------------------------------------------------------
+| 05 | 0x01
+----------------------------------------------------------------------------
+| 06-59 | don't care
+----------------------------------------------------------------------------
+| 60 | packet sequence number
+----------------------------------------------------------------------------
+| 61-63 | don't care
+----------------------------------------------------------------------------
+
+============================================================================
+| 00-63 | USB CONTROLLER REGISTER WRITE REQUEST PACKET
+============================================================================
+| 00 | 0xb1 register write command
+----------------------------------------------------------------------------
+| 01-02 | register
+----------------------------------------------------------------------------
+| 03 | 0x01
+----------------------------------------------------------------------------
+| 04 | value
+----------------------------------------------------------------------------
+| 05-59 | don't care
+----------------------------------------------------------------------------
+| 60 | packet sequence number
+----------------------------------------------------------------------------
+| 61-63 | don't care
+----------------------------------------------------------------------------
+
+============================================================================
+| 00-63 | USB CONTROLLER REGISTER READ REQUEST PACKET
+============================================================================
+| 00 | 0xb0 register read command
+----------------------------------------------------------------------------
+| 01-02 | register
+----------------------------------------------------------------------------
+| 03 | 0x01
+----------------------------------------------------------------------------
+| 04-59 | don't care
+----------------------------------------------------------------------------
+| 60 | packet sequence number
+----------------------------------------------------------------------------
+| 61-63 | don't care
+----------------------------------------------------------------------------
+
+============================================================================
+| 00-63 | LED CONTROL REQUEST PACKET
+============================================================================
+| 00 | 0x16 LED and IR control command
+----------------------------------------------------------------------------
+| 01 | 0x01 (LED)
+----------------------------------------------------------------------------
+| 03 | 0x00 blink
+| | 0x01 lights continuously
+----------------------------------------------------------------------------
+| 04 | blink interval
+| | 0x00 fastest (looks like LED lights continuously)
+| | 0xff slowest
+----------------------------------------------------------------------------
+| 05-59 | don't care
+----------------------------------------------------------------------------
+| 60 | packet sequence number
+----------------------------------------------------------------------------
+| 61-63 | don't care
+----------------------------------------------------------------------------
+
+============================================================================
+| 00-63 | IR CONTROL REQUEST PACKET
+============================================================================
+| 00 | 0x16 LED and IR control command
+----------------------------------------------------------------------------
+| 01 | 0x02 (IR)
+----------------------------------------------------------------------------
+| 03 | 0x00 IR disabled
+| | 0x01 IR enabled
+----------------------------------------------------------------------------
+| 04-59 | don't care
+----------------------------------------------------------------------------
+| 60 | packet sequence number
+----------------------------------------------------------------------------
+| 61-63 | don't care
+----------------------------------------------------------------------------
+
+============================================================================
+| 00-63 | STREAMING CONTROL REQUEST PACKET
+============================================================================
+| 00 | 0x12 streaming control command
+----------------------------------------------------------------------------
+| 01 | 0x00 streaming disabled
+| | 0x01 streaming enabled
+----------------------------------------------------------------------------
+| 02 | 0x00
+----------------------------------------------------------------------------
+| 03-59 | don't care
+----------------------------------------------------------------------------
+| 60 | packet sequence number
+----------------------------------------------------------------------------
+| 61-63 | don't care
+----------------------------------------------------------------------------
+
+============================================================================
+| 00-63 | REMOTE CONTROL REQUEST PACKET
+============================================================================
+| 00 | 0x41 remote control command
+----------------------------------------------------------------------------
+| 01-59 | don't care
+----------------------------------------------------------------------------
+| 60 | packet sequence number
+----------------------------------------------------------------------------
+| 61-63 | don't care
+----------------------------------------------------------------------------
+
+============================================================================
+| 00-63 | REMOTE CONTROL REPLY PACKET
+============================================================================
+| 00 | 0x00 code not received
+| | 0x01 code received
+----------------------------------------------------------------------------
+| 01 | remote control code
+----------------------------------------------------------------------------
+| 02-59 | don't care
+----------------------------------------------------------------------------
+| 60 | packet sequence number
+----------------------------------------------------------------------------
+| 61-63 | don't care
+----------------------------------------------------------------------------
+
+============================================================================
+| 00-63 | GET HARDWARE INFO REQUEST PACKET
+============================================================================
+| 00 | 0x19 get hardware info command
+----------------------------------------------------------------------------
+| 01-59 | don't care
+----------------------------------------------------------------------------
+| 60 | packet sequence number
+----------------------------------------------------------------------------
+| 61-63 | don't care
+----------------------------------------------------------------------------
+
+============================================================================
+| 00-63 | GET HARDWARE INFO REPLY PACKET
+============================================================================
+| 00 | hardware id
+----------------------------------------------------------------------------
+| 01-02 | firmware version
+----------------------------------------------------------------------------
+| 03-59 | don't care
+----------------------------------------------------------------------------
+| 60 | packet sequence number
+----------------------------------------------------------------------------
+| 61-63 | don't care
+----------------------------------------------------------------------------
+
+============================================================================
+| 00-63 | SMART CARD READER PACKET
+============================================================================
+| 00 | 0x34 smart card reader command
+----------------------------------------------------------------------------
+| xx |
+----------------------------------------------------------------------------
+| xx-59 | don't care
+----------------------------------------------------------------------------
+| 60 | packet sequence number
+----------------------------------------------------------------------------
+| 61-63 | don't care
+----------------------------------------------------------------------------
+
+*/
diff --git a/drivers/media/dvb/dvb-usb/au6610.c b/drivers/media/dvb/dvb-usb/au6610.c
index 2ccb90fa60c..eb34cc3894e 100644
--- a/drivers/media/dvb/dvb-usb/au6610.c
+++ b/drivers/media/dvb/dvb-usb/au6610.c
@@ -1,24 +1,31 @@
-/* DVB USB compliant linux driver for Sigmatek DVB-110 DVB-T USB2.0 receiver
+/*
+ * DVB USB Linux driver for Alcor Micro AU6610 DVB-T USB2.0.
*
* Copyright (C) 2006 Antti Palosaari <crope@iki.fi>
*
- * 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.
+ * 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.
*
- * see Documentation/dvb/README.dvb-usb for more information
+ * 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 "au6610.h"
-
#include "zl10353.h"
#include "qt1010.h"
/* debug */
static int dvb_usb_au6610_debug;
module_param_named(debug, dvb_usb_au6610_debug, int, 0644);
-MODULE_PARM_DESC(debug, "set debugging level (1=rc (or-able))." DVB_USB_DEBUG_STATUS);
-
+MODULE_PARM_DESC(debug, "set debugging level" DVB_USB_DEBUG_STATUS);
DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
static int au6610_usb_msg(struct dvb_usb_device *d, u8 operation, u8 addr,
@@ -42,9 +49,8 @@ static int au6610_usb_msg(struct dvb_usb_device *d, u8 operation, u8 addr,
}
ret = usb_control_msg(d->udev, usb_rcvctrlpipe(d->udev, 0), operation,
- USB_TYPE_VENDOR|USB_DIR_IN, addr << 1, index, usb_buf,
- sizeof(usb_buf), AU6610_USB_TIMEOUT);
-
+ USB_TYPE_VENDOR|USB_DIR_IN, addr << 1, index,
+ usb_buf, sizeof(usb_buf), AU6610_USB_TIMEOUT);
if (ret < 0)
return ret;
@@ -116,15 +122,6 @@ static struct i2c_algorithm au6610_i2c_algo = {
};
/* Callbacks for DVB USB */
-static int au6610_identify_state(struct usb_device *udev,
- struct dvb_usb_device_properties *props,
- struct dvb_usb_device_description **desc,
- int *cold)
-{
- *cold = 0;
- return 0;
-}
-
static struct zl10353_config au6610_zl10353_config = {
.demod_address = 0x0f,
.no_tuner = 1,
@@ -133,12 +130,12 @@ static struct zl10353_config au6610_zl10353_config = {
static int au6610_zl10353_frontend_attach(struct dvb_usb_adapter *adap)
{
- if ((adap->fe = dvb_attach(zl10353_attach, &au6610_zl10353_config,
- &adap->dev->i2c_adap)) != NULL) {
- return 0;
- }
+ adap->fe = dvb_attach(zl10353_attach, &au6610_zl10353_config,
+ &adap->dev->i2c_adap);
+ if (adap->fe == NULL)
+ return -ENODEV;
- return -EIO;
+ return 0;
}
static struct qt1010_config au6610_qt1010_config = {
@@ -171,7 +168,7 @@ static int au6610_probe(struct usb_interface *intf,
alt = usb_altnum_to_altsetting(intf, AU6610_ALTSETTING);
if (alt == NULL) {
- deb_rc("no alt found!\n");
+ deb_info("%s: no alt found!\n", __func__);
return -ENODEV;
}
ret = usb_set_interface(d->udev, alt->desc.bInterfaceNumber,
@@ -181,18 +178,19 @@ static int au6610_probe(struct usb_interface *intf,
return ret;
}
-
static struct usb_device_id au6610_table [] = {
{ USB_DEVICE(USB_VID_ALCOR_MICRO, USB_PID_SIGMATEK_DVB_110) },
{ } /* Terminating entry */
};
-MODULE_DEVICE_TABLE (usb, au6610_table);
+MODULE_DEVICE_TABLE(usb, au6610_table);
static struct dvb_usb_device_properties au6610_properties = {
.caps = DVB_USB_IS_AN_I2C_ADAPTER,
+
.usb_ctrl = DEVICE_SPECIFIC,
- .size_of_priv = 0,
- .identify_state = au6610_identify_state,
+
+ .size_of_priv = 0,
+
.num_adapters = 1,
.adapter = {
{
@@ -206,20 +204,22 @@ static struct dvb_usb_device_properties au6610_properties = {
.u = {
.isoc = {
.framesperurb = 40,
- .framesize = 942, /* maximum packet size */
- .interval = 1.25, /* 125 us */
+ .framesize = 942,
+ .interval = 1,
}
}
},
}
},
+
.i2c_algo = &au6610_i2c_algo,
+
.num_device_descs = 1,
.devices = {
{
- "Sigmatek DVB-110 DVB-T USB2.0",
- { &au6610_table[0], NULL },
- { NULL },
+ .name = "Sigmatek DVB-110 DVB-T USB2.0",
+ .cold_ids = {NULL},
+ .warm_ids = {&au6610_table[0], NULL},
},
}
};
@@ -236,12 +236,11 @@ static int __init au6610_module_init(void)
{
int ret;
- if ((ret = usb_register(&au6610_driver))) {
+ ret = usb_register(&au6610_driver);
+ if (ret)
err("usb_register failed. Error number %d", ret);
- return ret;
- }
- return 0;
+ return ret;
}
static void __exit au6610_module_exit(void)
@@ -250,10 +249,10 @@ static void __exit au6610_module_exit(void)
usb_deregister(&au6610_driver);
}
-module_init (au6610_module_init);
-module_exit (au6610_module_exit);
+module_init(au6610_module_init);
+module_exit(au6610_module_exit);
MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>");
-MODULE_DESCRIPTION("Driver Sigmatek DVB-110 DVB-T USB2.0 / AU6610");
+MODULE_DESCRIPTION("Driver for Alcor Micro AU6610 DVB-T USB2.0");
MODULE_VERSION("0.1");
MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/dvb-usb/au6610.h b/drivers/media/dvb/dvb-usb/au6610.h
index 4161b054c71..7849abe2c61 100644
--- a/drivers/media/dvb/dvb-usb/au6610.h
+++ b/drivers/media/dvb/dvb-usb/au6610.h
@@ -1,10 +1,30 @@
+/*
+ * DVB USB Linux driver for Alcor Micro AU6610 DVB-T USB2.0.
+ *
+ * Copyright (C) 2006 Antti Palosaari <crope@iki.fi>
+ *
+ * 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 _DVB_USB_AU6610_H_
#define _DVB_USB_AU6610_H_
#define DVB_USB_LOG_PREFIX "au6610"
#include "dvb-usb.h"
-#define deb_rc(args...) dprintk(dvb_usb_au6610_debug,0x01,args)
+#define deb_info(args...) dprintk(dvb_usb_au6610_debug, 0x01, args)
#define AU6610_REQ_I2C_WRITE 0x14
#define AU6610_REQ_I2C_READ 0x13
diff --git a/drivers/media/dvb/dvb-usb/cxusb.c b/drivers/media/dvb/dvb-usb/cxusb.c
index 0286156704f..563400277a4 100644
--- a/drivers/media/dvb/dvb-usb/cxusb.c
+++ b/drivers/media/dvb/dvb-usb/cxusb.c
@@ -35,6 +35,7 @@
#include "zl10353.h"
#include "tuner-xc2028.h"
#include "tuner-simple.h"
+#include "mxl5005s.h"
/* debug */
static int dvb_usb_cxusb_debug;
@@ -43,9 +44,8 @@ MODULE_PARM_DESC(debug, "set debugging level (1=rc (or-able))." DVB_USB_DEBUG_ST
DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
-#define deb_info(args...) dprintk(dvb_usb_cxusb_debug,0x01,args)
-#define deb_i2c(args...) if (d->udev->descriptor.idVendor == USB_VID_MEDION) \
- dprintk(dvb_usb_cxusb_debug,0x01,args)
+#define deb_info(args...) dprintk(dvb_usb_cxusb_debug, 0x03, args)
+#define deb_i2c(args...) dprintk(dvb_usb_cxusb_debug, 0x02, args)
static int cxusb_ctrl_msg(struct dvb_usb_device *d,
u8 cmd, u8 *wbuf, int wlen, u8 *rbuf, int rlen)
@@ -202,6 +202,46 @@ static int cxusb_power_ctrl(struct dvb_usb_device *d, int onoff)
return cxusb_ctrl_msg(d, CMD_POWER_OFF, &b, 1, NULL, 0);
}
+static int cxusb_aver_power_ctrl(struct dvb_usb_device *d, int onoff)
+{
+ int ret;
+ if (!onoff)
+ return cxusb_ctrl_msg(d, CMD_POWER_OFF, NULL, 0, NULL, 0);
+ if (d->state == DVB_USB_STATE_INIT &&
+ usb_set_interface(d->udev, 0, 0) < 0)
+ err("set interface failed");
+ do {} while (!(ret = cxusb_ctrl_msg(d, CMD_POWER_ON, NULL, 0, NULL, 0)) &&
+ !(ret = cxusb_ctrl_msg(d, 0x15, NULL, 0, NULL, 0)) &&
+ !(ret = cxusb_ctrl_msg(d, 0x17, NULL, 0, NULL, 0)) && 0);
+ if (!ret) {
+ /* FIXME: We don't know why, but we need to configure the
+ * lgdt3303 with the register settings below on resume */
+ int i;
+ u8 buf, bufs[] = {
+ 0x0e, 0x2, 0x00, 0x7f,
+ 0x0e, 0x2, 0x02, 0xfe,
+ 0x0e, 0x2, 0x02, 0x01,
+ 0x0e, 0x2, 0x00, 0x03,
+ 0x0e, 0x2, 0x0d, 0x40,
+ 0x0e, 0x2, 0x0e, 0x87,
+ 0x0e, 0x2, 0x0f, 0x8e,
+ 0x0e, 0x2, 0x10, 0x01,
+ 0x0e, 0x2, 0x14, 0xd7,
+ 0x0e, 0x2, 0x47, 0x88,
+ };
+ msleep(20);
+ for (i = 0; i < sizeof(bufs)/sizeof(u8); i += 4/sizeof(u8)) {
+ ret = cxusb_ctrl_msg(d, CMD_I2C_WRITE,
+ bufs+i, 4, &buf, 1);
+ if (ret)
+ break;
+ if (buf != 0x8)
+ return -EREMOTEIO;
+ }
+ }
+ return ret;
+}
+
static int cxusb_bluebird_power_ctrl(struct dvb_usb_device *d, int onoff)
{
u8 b = 0;
@@ -233,6 +273,16 @@ static int cxusb_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff)
return 0;
}
+static int cxusb_aver_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff)
+{
+ if (onoff)
+ cxusb_ctrl_msg(adap->dev, CMD_AVER_STREAM_ON, NULL, 0, NULL, 0);
+ else
+ cxusb_ctrl_msg(adap->dev, CMD_AVER_STREAM_OFF,
+ NULL, 0, NULL, 0);
+ return 0;
+}
+
static int cxusb_rc_query(struct dvb_usb_device *d, u32 *event, int *state)
{
struct dvb_usb_rc_key *keymap = d->props.rc_key_map;
@@ -423,6 +473,12 @@ static struct lgdt330x_config cxusb_lgdt3303_config = {
.demod_chip = LGDT3303,
};
+static struct lgdt330x_config cxusb_aver_lgdt3303_config = {
+ .demod_address = 0x0e,
+ .demod_chip = LGDT3303,
+ .clock_polarity_flip = 2,
+};
+
static struct mt352_config cxusb_dee1601_config = {
.demod_address = 0x0f,
.demod_init = cxusb_dee1601_demod_init,
@@ -453,6 +509,24 @@ static struct mt352_config cxusb_mt352_xc3028_config = {
.demod_init = cxusb_mt352_demod_init,
};
+/* FIXME: needs tweaking */
+static struct mxl5005s_config aver_a868r_tuner = {
+ .i2c_address = 0x63,
+ .if_freq = 6000000UL,
+ .xtal_freq = CRYSTAL_FREQ_16000000HZ,
+ .agc_mode = MXL_SINGLE_AGC,
+ .tracking_filter = MXL_TF_C,
+ .rssi_enable = MXL_RSSI_ENABLE,
+ .cap_select = MXL_CAP_SEL_ENABLE,
+ .div_out = MXL_DIV_OUT_4,
+ .clock_out = MXL_CLOCK_OUT_DISABLE,
+ .output_load = MXL5005S_IF_OUTPUT_LOAD_200_OHM,
+ .top = MXL5005S_TOP_25P2,
+ .mod_mode = MXL_DIGITAL_MODE,
+ .if_mode = MXL_ZERO_IF,
+ .AgcMasterByte = 0x00,
+};
+
/* Callbacks for DVB USB */
static int cxusb_fmd1216me_tuner_attach(struct dvb_usb_adapter *adap)
{
@@ -491,7 +565,8 @@ static int cxusb_lgh064f_tuner_attach(struct dvb_usb_adapter *adap)
static int dvico_bluebird_xc2028_callback(void *ptr, int command, int arg)
{
- struct dvb_usb_device *d = ptr;
+ struct dvb_usb_adapter *adap = ptr;
+ struct dvb_usb_device *d = adap->dev;
switch (command) {
case XC2028_TUNER_RESET:
@@ -519,9 +594,9 @@ static int cxusb_dvico_xc3028_tuner_attach(struct dvb_usb_adapter *adap)
.callback = dvico_bluebird_xc2028_callback,
};
static struct xc2028_ctrl ctl = {
- .fname = "xc3028-dvico-au-01.fw",
+ .fname = "xc3028-v27.fw",
.max_len = 64,
- .scode_table = XC3028_FE_ZARLINK456,
+ .demod = XC3028_FE_ZARLINK456,
};
fe = dvb_attach(xc2028_attach, adap->fe, &cfg);
@@ -533,6 +608,13 @@ static int cxusb_dvico_xc3028_tuner_attach(struct dvb_usb_adapter *adap)
return 0;
}
+static int cxusb_mxl5003s_tuner_attach(struct dvb_usb_adapter *adap)
+{
+ dvb_attach(mxl5005s_attach, adap->fe,
+ &adap->dev->i2c_adap, &aver_a868r_tuner);
+ return 0;
+}
+
static int cxusb_cx22702_frontend_attach(struct dvb_usb_adapter *adap)
{
u8 b;
@@ -562,6 +644,16 @@ static int cxusb_lgdt3303_frontend_attach(struct dvb_usb_adapter *adap)
return -EIO;
}
+static int cxusb_aver_lgdt3303_frontend_attach(struct dvb_usb_adapter *adap)
+{
+ adap->fe = dvb_attach(lgdt330x_attach, &cxusb_aver_lgdt3303_config,
+ &adap->dev->i2c_adap);
+ if (adap->fe != NULL)
+ return 0;
+
+ return -EIO;
+}
+
static int cxusb_mt352_frontend_attach(struct dvb_usb_adapter *adap)
{
/* used in both lgz201 and th7579 */
@@ -736,6 +828,7 @@ static struct dvb_usb_device_properties cxusb_bluebird_dtt7579_properties;
static struct dvb_usb_device_properties cxusb_bluebird_dualdig4_properties;
static struct dvb_usb_device_properties cxusb_bluebird_nano2_properties;
static struct dvb_usb_device_properties cxusb_bluebird_nano2_needsfirmware_properties;
+static struct dvb_usb_device_properties cxusb_aver_a868r_properties;
static int cxusb_probe(struct usb_interface *intf,
const struct usb_device_id *id)
@@ -756,7 +849,10 @@ static int cxusb_probe(struct usb_interface *intf,
THIS_MODULE, NULL, adapter_nr) ||
0 == dvb_usb_device_init(intf,
&cxusb_bluebird_nano2_needsfirmware_properties,
- THIS_MODULE, NULL, adapter_nr))
+ THIS_MODULE, NULL, adapter_nr) ||
+ 0 == dvb_usb_device_init(intf, &cxusb_aver_a868r_properties,
+ THIS_MODULE, NULL, adapter_nr) ||
+ 0)
return 0;
return -EINVAL;
@@ -779,6 +875,7 @@ static struct usb_device_id cxusb_table [] = {
{ USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_DUAL_4) },
{ USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_DVB_T_NANO_2) },
{ USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_DVB_T_NANO_2_NFW_WARM) },
+ { USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_VOLAR_A868R) },
{} /* Terminating entry */
};
MODULE_DEVICE_TABLE (usb, cxusb_table);
@@ -1182,6 +1279,48 @@ static struct dvb_usb_device_properties cxusb_bluebird_nano2_needsfirmware_prope
}
};
+static struct dvb_usb_device_properties cxusb_aver_a868r_properties = {
+ .caps = DVB_USB_IS_AN_I2C_ADAPTER,
+
+ .usb_ctrl = CYPRESS_FX2,
+
+ .size_of_priv = sizeof(struct cxusb_state),
+
+ .num_adapters = 1,
+ .adapter = {
+ {
+ .streaming_ctrl = cxusb_aver_streaming_ctrl,
+ .frontend_attach = cxusb_aver_lgdt3303_frontend_attach,
+ .tuner_attach = cxusb_mxl5003s_tuner_attach,
+ /* parameter for the MPEG2-data transfer */
+ .stream = {
+ .type = USB_BULK,
+ .count = 5,
+ .endpoint = 0x04,
+ .u = {
+ .bulk = {
+ .buffersize = 8192,
+ }
+ }
+ },
+
+ },
+ },
+ .power_ctrl = cxusb_aver_power_ctrl,
+
+ .i2c_algo = &cxusb_i2c_algo,
+
+ .generic_bulk_ctrl_endpoint = 0x01,
+
+ .num_device_descs = 1,
+ .devices = {
+ { "AVerMedia AVerTVHD Volar (A868R)",
+ { NULL },
+ { &cxusb_table[16], NULL },
+ },
+ }
+};
+
static struct usb_driver cxusb_driver = {
.name = "dvb_usb_cxusb",
.probe = cxusb_probe,
diff --git a/drivers/media/dvb/dvb-usb/cxusb.h b/drivers/media/dvb/dvb-usb/cxusb.h
index 4768a2c3551..1a51eafd31b 100644
--- a/drivers/media/dvb/dvb-usb/cxusb.h
+++ b/drivers/media/dvb/dvb-usb/cxusb.h
@@ -20,6 +20,9 @@
#define CMD_STREAMING_ON 0x36
#define CMD_STREAMING_OFF 0x37
+#define CMD_AVER_STREAM_ON 0x18
+#define CMD_AVER_STREAM_OFF 0x19
+
#define CMD_GET_IR_CODE 0x47
#define CMD_ANALOG 0x50
diff --git a/drivers/media/dvb/dvb-usb/dib0700_devices.c b/drivers/media/dvb/dvb-usb/dib0700_devices.c
index c4d40fe01d5..6c0e5c5f436 100644
--- a/drivers/media/dvb/dvb-usb/dib0700_devices.c
+++ b/drivers/media/dvb/dvb-usb/dib0700_devices.c
@@ -1117,6 +1117,8 @@ struct usb_device_id dib0700_usb_id_table[] = {
{ USB_DEVICE(USB_VID_TERRATEC, USB_PID_TERRATEC_CINERGY_HT_EXPRESS) },
{ USB_DEVICE(USB_VID_TERRATEC, USB_PID_TERRATEC_CINERGY_T_XXS) },
{ USB_DEVICE(USB_VID_LEADTEK, USB_PID_WINFAST_DTV_DONGLE_STK7700P_2) },
+/* 35 */{ USB_DEVICE(USB_VID_HAUPPAUGE, USB_PID_HAUPPAUGE_NOVA_TD_STICK_52009) },
+ { USB_DEVICE(USB_VID_HAUPPAUGE, USB_PID_HAUPPAUGE_NOVA_T_500_3) },
{ 0 } /* Terminating entry */
};
MODULE_DEVICE_TABLE(usb, dib0700_usb_id_table);
@@ -1372,7 +1374,7 @@ struct dvb_usb_device_properties dib0700_devices[] = {
}
},
- .num_device_descs = 2,
+ .num_device_descs = 4,
.devices = {
{ "DiBcom STK7070PD reference design",
{ &dib0700_usb_id_table[17], NULL },
@@ -1381,6 +1383,14 @@ struct dvb_usb_device_properties dib0700_devices[] = {
{ "Pinnacle PCTV Dual DVB-T Diversity Stick",
{ &dib0700_usb_id_table[18], NULL },
{ NULL },
+ },
+ { "Hauppauge Nova-TD Stick (52009)",
+ { &dib0700_usb_id_table[35], NULL },
+ { NULL },
+ },
+ { "Hauppauge Nova-TD-500 (84xxx)",
+ { &dib0700_usb_id_table[36], NULL },
+ { NULL },
}
}
}, { DIB0700_DEFAULT_DEVICE_PROPERTIES,
diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-i2c.c b/drivers/media/dvb/dvb-usb/dvb-usb-i2c.c
index 23428cd3075..326f7608954 100644
--- a/drivers/media/dvb/dvb-usb/dvb-usb-i2c.c
+++ b/drivers/media/dvb/dvb-usb/dvb-usb-i2c.c
@@ -20,11 +20,7 @@ int dvb_usb_i2c_init(struct dvb_usb_device *d)
}
strncpy(d->i2c_adap.name, d->desc->name, sizeof(d->i2c_adap.name));
-#ifdef I2C_ADAP_CLASS_TV_DIGITAL
- d->i2c_adap.class = I2C_ADAP_CLASS_TV_DIGITAL,
-#else
d->i2c_adap.class = I2C_CLASS_TV_DIGITAL,
-#endif
d->i2c_adap.algo = d->props.i2c_algo;
d->i2c_adap.algo_data = NULL;
d->i2c_adap.dev.parent = &d->udev->dev;
diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-ids.h b/drivers/media/dvb/dvb-usb/dvb-usb-ids.h
index 34245d1b7dd..03dfb9f2fe3 100644
--- a/drivers/media/dvb/dvb-usb/dvb-usb-ids.h
+++ b/drivers/media/dvb/dvb-usb/dvb-usb-ids.h
@@ -14,6 +14,7 @@
#define USB_VID_AFATECH 0x15a4
#define USB_VID_ALCOR_MICRO 0x058f
#define USB_VID_ALINK 0x05e3
+#define USB_VID_AMT 0x1c73
#define USB_VID_ANCHOR 0x0547
#define USB_VID_ANSONIC 0x10b9
#define USB_VID_ANUBIS_ELECTRONIC 0x10fd
@@ -57,6 +58,7 @@
#define USB_PID_AFATECH_AF9005 0x9020
#define USB_VID_ALINK_DTU 0xf170
#define USB_PID_ANSONIC_DVBT_USB 0x6000
+#define USB_PID_ANYSEE 0x861f
#define USB_PID_AVERMEDIA_DVBT_USB_COLD 0x0001
#define USB_PID_AVERMEDIA_DVBT_USB_WARM 0x0002
#define USB_PID_AVERMEDIA_DVBT_USB2_COLD 0xa800
@@ -127,14 +129,21 @@
#define USB_PID_WINTV_NOVA_T_USB2_WARM 0x9301
#define USB_PID_HAUPPAUGE_NOVA_T_500 0x9941
#define USB_PID_HAUPPAUGE_NOVA_T_500_2 0x9950
+#define USB_PID_HAUPPAUGE_NOVA_T_500_3 0x8400
#define USB_PID_HAUPPAUGE_NOVA_T_STICK 0x7050
#define USB_PID_HAUPPAUGE_NOVA_T_STICK_2 0x7060
#define USB_PID_HAUPPAUGE_NOVA_T_STICK_3 0x7070
#define USB_PID_HAUPPAUGE_MYTV_T 0x7080
#define USB_PID_HAUPPAUGE_NOVA_TD_STICK 0x9580
+#define USB_PID_HAUPPAUGE_NOVA_TD_STICK_52009 0x5200
#define USB_PID_AVERMEDIA_EXPRESS 0xb568
#define USB_PID_AVERMEDIA_VOLAR 0xa807
#define USB_PID_AVERMEDIA_VOLAR_2 0xb808
+#define USB_PID_AVERMEDIA_VOLAR_A868R 0xa868
+#define USB_PID_AVERMEDIA_MCE_USB_M038 0x1228
+#define USB_PID_AVERMEDIA_HYBRID_ULTRA_USB_M039R 0x0039
+#define USB_PID_AVERMEDIA_HYBRID_ULTRA_USB_M039R_ATSC 0x1039
+#define USB_PID_AVERMEDIA_HYBRID_ULTRA_USB_M039R_DVBT 0x2039
#define USB_PID_TECHNOTREND_CONNECT_S2400 0x3006
#define USB_PID_TERRATEC_CINERGY_DT_XS_DIVERSITY 0x005a
#define USB_PID_TERRATEC_CINERGY_HT_USB_XE 0x0058
@@ -196,5 +205,6 @@
#define USB_PID_ASUS_U3000 0x171f
#define USB_PID_ASUS_U3100 0x173f
#define USB_PID_YUAN_EC372S 0x1edc
+#define USB_PID_DW2102 0x2102
#endif
diff --git a/drivers/media/dvb/dvb-usb/dw2102.c b/drivers/media/dvb/dvb-usb/dw2102.c
new file mode 100644
index 00000000000..a4d898b44e5
--- /dev/null
+++ b/drivers/media/dvb/dvb-usb/dw2102.c
@@ -0,0 +1,425 @@
+/* DVB USB framework compliant Linux driver for the DVBWorld DVB-S 2102 Card
+*
+* Copyright (C) 2008 Igor M. Liplianin (liplianin@me.by)
+*
+* 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.
+*
+* see Documentation/dvb/README.dvb-usb for more information
+*/
+#include <linux/version.h>
+#include "dw2102.h"
+#include "stv0299.h"
+#include "z0194a.h"
+
+#ifndef USB_PID_DW2102
+#define USB_PID_DW2102 0x2102
+#endif
+
+#define DW2102_READ_MSG 0
+#define DW2102_WRITE_MSG 1
+
+#define REG_1F_SYMBOLRATE_BYTE0 0x1f
+#define REG_20_SYMBOLRATE_BYTE1 0x20
+#define REG_21_SYMBOLRATE_BYTE2 0x21
+
+#define DW2102_VOLTAGE_CTRL (0x1800)
+#define DW2102_RC_QUERY (0x1a00)
+
+struct dw2102_state {
+ u32 last_key_pressed;
+};
+struct dw2102_rc_keys {
+ u32 keycode;
+ u32 event;
+};
+
+DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
+
+static int dw2102_op_rw(struct usb_device *dev, u8 request, u16 value,
+ u8 *data, u16 len, int flags)
+{
+ int ret;
+ u8 u8buf[len];
+
+ unsigned int pipe = (flags == DW2102_READ_MSG) ?
+ usb_rcvctrlpipe(dev, 0) : usb_sndctrlpipe(dev, 0);
+ u8 request_type = (flags == DW2102_READ_MSG) ? USB_DIR_IN : USB_DIR_OUT;
+
+ if (flags == DW2102_WRITE_MSG)
+ memcpy(u8buf, data, len);
+ ret = usb_control_msg(dev, pipe, request,
+ request_type | USB_TYPE_VENDOR, value, 0 , u8buf, len, 2000);
+
+ if (flags == DW2102_READ_MSG)
+ memcpy(data, u8buf, len);
+ return ret;
+}
+
+/* I2C */
+
+static int dw2102_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[],
+ int num)
+{
+struct dvb_usb_device *d = i2c_get_adapdata(adap);
+ int i = 0, ret = 0;
+ u8 buf6[] = {0x2c, 0x05, 0xc0, 0, 0, 0, 0};
+ u8 request;
+ u16 value;
+
+ if (!d)
+ return -ENODEV;
+ if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
+ return -EAGAIN;
+
+ switch (num) {
+ case 2:
+ /* read stv0299 register */
+ request = 0xb5;
+ value = msg[0].buf[0];/* register */
+ for (i = 0; i < msg[1].len; i++) {
+ value = value + i;
+ ret = dw2102_op_rw(d->udev, 0xb5,
+ value, buf6, 2, DW2102_READ_MSG);
+ msg[1].buf[i] = buf6[0];
+
+ }
+ break;
+ case 1:
+ switch (msg[0].addr) {
+ case 0x68:
+ /* write to stv0299 register */
+ buf6[0] = 0x2a;
+ buf6[1] = msg[0].buf[0];
+ buf6[2] = msg[0].buf[1];
+ ret = dw2102_op_rw(d->udev, 0xb2,
+ 0, buf6, 3, DW2102_WRITE_MSG);
+ break;
+ case 0x60:
+ if (msg[0].flags == 0) {
+ /* write to tuner pll */
+ buf6[0] = 0x2c;
+ buf6[1] = 5;
+ buf6[2] = 0xc0;
+ buf6[3] = msg[0].buf[0];
+ buf6[4] = msg[0].buf[1];
+ buf6[5] = msg[0].buf[2];
+ buf6[6] = msg[0].buf[3];
+ ret = dw2102_op_rw(d->udev, 0xb2,
+ 0, buf6, 7, DW2102_WRITE_MSG);
+ } else {
+ /* write to tuner pll */
+ ret = dw2102_op_rw(d->udev, 0xb5,
+ 0, buf6, 1, DW2102_READ_MSG);
+ msg[0].buf[0] = buf6[0];
+ }
+ break;
+ case (DW2102_RC_QUERY):
+ ret = dw2102_op_rw(d->udev, 0xb8,
+ 0, buf6, 2, DW2102_READ_MSG);
+ msg[0].buf[0] = buf6[0];
+ msg[0].buf[1] = buf6[1];
+ break;
+ case (DW2102_VOLTAGE_CTRL):
+ buf6[0] = 0x30;
+ buf6[1] = msg[0].buf[0];
+ ret = dw2102_op_rw(d->udev, 0xb2,
+ 0, buf6, 2, DW2102_WRITE_MSG);
+ break;
+ }
+
+ break;
+ }
+
+ mutex_unlock(&d->i2c_mutex);
+ return num;
+}
+
+static u32 dw2102_i2c_func(struct i2c_adapter *adapter)
+{
+ return I2C_FUNC_I2C;
+}
+
+static struct i2c_algorithm dw2102_i2c_algo = {
+ .master_xfer = dw2102_i2c_transfer,
+ .functionality = dw2102_i2c_func,
+};
+
+static int dw2102_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},
+ };
+
+ 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);
+ return 0;
+}
+
+static int dw2102_frontend_attach(struct dvb_usb_adapter *d)
+{
+ d->fe = dvb_attach(stv0299_attach, &sharp_z0194a_config,
+ &d->dev->i2c_adap);
+ if (d->fe != NULL) {
+ d->fe->ops.set_voltage = dw2102_set_voltage;
+ info("Attached stv0299!\n");
+ return 0;
+ }
+ return -EIO;
+}
+
+static int dw2102_tuner_attach(struct dvb_usb_adapter *adap)
+{
+ dvb_attach(dvb_pll_attach, adap->fe, 0x60,
+ &adap->dev->i2c_adap, DVB_PLL_OPERA1);
+ return 0;
+}
+
+static struct dvb_usb_rc_key dw2102_rc_keys[] = {
+ { 0xf8, 0x0a, KEY_Q }, /*power*/
+ { 0xf8, 0x0c, KEY_M }, /*mute*/
+ { 0xf8, 0x11, KEY_1 },
+ { 0xf8, 0x12, KEY_2 },
+ { 0xf8, 0x13, KEY_3 },
+ { 0xf8, 0x14, KEY_4 },
+ { 0xf8, 0x15, KEY_5 },
+ { 0xf8, 0x16, KEY_6 },
+ { 0xf8, 0x17, KEY_7 },
+ { 0xf8, 0x18, KEY_8 },
+ { 0xf8, 0x19, KEY_9 },
+ { 0xf8, 0x10, KEY_0 },
+ { 0xf8, 0x1c, KEY_PAGEUP }, /*ch+*/
+ { 0xf8, 0x0f, KEY_PAGEDOWN }, /*ch-*/
+ { 0xf8, 0x1a, KEY_O }, /*vol+*/
+ { 0xf8, 0x0e, KEY_Z }, /*vol-*/
+ { 0xf8, 0x04, KEY_R }, /*rec*/
+ { 0xf8, 0x09, KEY_D }, /*fav*/
+ { 0xf8, 0x08, KEY_BACKSPACE }, /*rewind*/
+ { 0xf8, 0x07, KEY_A }, /*fast*/
+ { 0xf8, 0x0b, KEY_P }, /*pause*/
+ { 0xf8, 0x02, KEY_ESC }, /*cancel*/
+ { 0xf8, 0x03, KEY_G }, /*tab*/
+ { 0xf8, 0x00, KEY_UP }, /*up*/
+ { 0xf8, 0x1f, KEY_ENTER }, /*ok*/
+ { 0xf8, 0x01, KEY_DOWN }, /*down*/
+ { 0xf8, 0x05, KEY_C }, /*cap*/
+ { 0xf8, 0x06, KEY_S }, /*stop*/
+ { 0xf8, 0x40, KEY_F }, /*full*/
+ { 0xf8, 0x1e, KEY_W }, /*tvmode*/
+ { 0xf8, 0x1b, KEY_B }, /*recall*/
+
+};
+
+
+
+static int dw2102_rc_query(struct dvb_usb_device *d, u32 *event, int *state)
+{
+ struct dw2102_state *st = d->priv;
+ u8 key[2];
+ struct i2c_msg msg[] = {
+ {.addr = DW2102_RC_QUERY, .flags = I2C_M_RD, .buf = key,
+ .len = 2},
+ };
+ int i;
+
+ *state = REMOTE_NO_KEY_PRESSED;
+ if (dw2102_i2c_transfer(&d->i2c_adap, msg, 1) == 1) {
+ for (i = 0; i < ARRAY_SIZE(dw2102_rc_keys); i++) {
+ if (dw2102_rc_keys[i].data == msg[0].buf[0]) {
+ *state = REMOTE_KEY_PRESSED;
+ *event = dw2102_rc_keys[i].event;
+ st->last_key_pressed =
+ dw2102_rc_keys[i].event;
+ break;
+ }
+ st->last_key_pressed = 0;
+ }
+ }
+ /* info("key: %x %x\n",key[0],key[1]); */
+ return 0;
+}
+
+static struct usb_device_id dw2102_table[] = {
+ {USB_DEVICE(USB_VID_CYPRESS, USB_PID_DW2102)},
+ {USB_DEVICE(USB_VID_CYPRESS, 0x2101)},
+ { }
+};
+
+MODULE_DEVICE_TABLE(usb, dw2102_table);
+
+static int dw2102_load_firmware(struct usb_device *dev,
+ const struct firmware *frmwr)
+{
+ u8 *b, *p;
+ int ret = 0, i;
+ u8 reset;
+ u8 reset16 [] = {0, 0, 0, 0, 0, 0, 0};
+ const struct firmware *fw;
+ const char *filename = "dvb-usb-dw2101.fw";
+ switch (dev->descriptor.idProduct) {
+ case 0x2101:
+ ret = request_firmware(&fw, filename, &dev->dev);
+ if (ret != 0) {
+ err("did not find the firmware file. (%s) "
+ "Please see linux/Documentation/dvb/ for more details "
+ "on firmware-problems.", filename);
+ return ret;
+ }
+ break;
+ case USB_PID_DW2102:
+ fw = frmwr;
+ break;
+ }
+ info("start downloading DW2102 firmware");
+ p = kmalloc(fw->size, GFP_KERNEL);
+ reset = 1;
+ /*stop the CPU*/
+ dw2102_op_rw(dev, 0xa0, 0x7f92, &reset, 1, DW2102_WRITE_MSG);
+ dw2102_op_rw(dev, 0xa0, 0xe600, &reset, 1, DW2102_WRITE_MSG);
+
+ if (p != NULL) {
+ memcpy(p, fw->data, fw->size);
+ for (i = 0; i < fw->size; i += 0x40) {
+ b = (u8 *) p + i;
+ if (dw2102_op_rw
+ (dev, 0xa0, i, b , 0x40,
+ DW2102_WRITE_MSG) != 0x40
+ ) {
+ err("error while transferring firmware");
+ ret = -EINVAL;
+ break;
+ }
+ }
+ /* restart the CPU */
+ reset = 0;
+ if (ret || dw2102_op_rw
+ (dev, 0xa0, 0x7f92, &reset, 1,
+ DW2102_WRITE_MSG) != 1) {
+ err("could not restart the USB controller CPU.");
+ ret = -EINVAL;
+ }
+ if (ret || dw2102_op_rw
+ (dev, 0xa0, 0xe600, &reset, 1,
+ DW2102_WRITE_MSG) != 1) {
+ err("could not restart the USB controller CPU.");
+ ret = -EINVAL;
+ }
+ /* init registers */
+ switch (dev->descriptor.idProduct) {
+ case USB_PID_DW2102:
+ dw2102_op_rw
+ (dev, 0xbf, 0x0040, &reset, 0,
+ DW2102_WRITE_MSG);
+ dw2102_op_rw
+ (dev, 0xb9, 0x0000, &reset16[0], 2,
+ DW2102_READ_MSG);
+ break;
+ case 0x2101:
+ dw2102_op_rw
+ (dev, 0xbc, 0x0030, &reset16[0], 2,
+ DW2102_READ_MSG);
+ dw2102_op_rw
+ (dev, 0xba, 0x0000, &reset16[0], 7,
+ DW2102_READ_MSG);
+ dw2102_op_rw
+ (dev, 0xba, 0x0000, &reset16[0], 7,
+ DW2102_READ_MSG);
+ dw2102_op_rw
+ (dev, 0xb9, 0x0000, &reset16[0], 2,
+ DW2102_READ_MSG);
+ break;
+ }
+ kfree(p);
+ }
+ return ret;
+}
+
+static struct dvb_usb_device_properties dw2102_properties = {
+ .caps = DVB_USB_IS_AN_I2C_ADAPTER,
+ .usb_ctrl = DEVICE_SPECIFIC,
+ .firmware = "dvb-usb-dw2102.fw",
+ .size_of_priv = sizeof(struct dw2102_state),
+ .no_reconnect = 1,
+
+ .i2c_algo = &dw2102_i2c_algo,
+ .rc_key_map = dw2102_rc_keys,
+ .rc_key_map_size = ARRAY_SIZE(dw2102_rc_keys),
+ .rc_interval = 150,
+ .rc_query = dw2102_rc_query,
+
+ .generic_bulk_ctrl_endpoint = 0x81,
+ /* parameter for the MPEG2-data transfer */
+ .num_adapters = 1,
+ .download_firmware = dw2102_load_firmware,
+ .adapter = {
+ {
+ .frontend_attach = dw2102_frontend_attach,
+ .streaming_ctrl = NULL,
+ .tuner_attach = dw2102_tuner_attach,
+ .stream = {
+ .type = USB_BULK,
+ .count = 8,
+ .endpoint = 0x82,
+ .u = {
+ .bulk = {
+ .buffersize = 4096,
+ }
+ }
+ },
+ }
+ },
+ .num_device_descs = 2,
+ .devices = {
+ {"DVBWorld DVB-S 2102 USB2.0",
+ {&dw2102_table[0], NULL},
+ {NULL},
+ },
+ {"DVBWorld DVB-S 2101 USB2.0",
+ {&dw2102_table[1], NULL},
+ {NULL},
+ },
+ }
+};
+
+static int dw2102_probe(struct usb_interface *intf,
+ const struct usb_device_id *id)
+{
+ return dvb_usb_device_init(intf, &dw2102_properties,
+ THIS_MODULE, NULL, adapter_nr);
+}
+
+static struct usb_driver dw2102_driver = {
+ .name = "dw2102",
+ .probe = dw2102_probe,
+ .disconnect = dvb_usb_device_exit,
+ .id_table = dw2102_table,
+};
+
+static int __init dw2102_module_init(void)
+{
+ int ret = usb_register(&dw2102_driver);
+ if (ret)
+ err("usb_register failed. Error number %d", ret);
+
+ return ret;
+}
+
+static void __exit dw2102_module_exit(void)
+{
+ usb_deregister(&dw2102_driver);
+}
+
+module_init(dw2102_module_init);
+module_exit(dw2102_module_exit);
+
+MODULE_AUTHOR("Igor M. Liplianin (c) liplianin@me.by");
+MODULE_DESCRIPTION("Driver for DVBWorld DVB-S 2101 2102 USB2.0 device");
+MODULE_VERSION("0.1");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/dvb-usb/dw2102.h b/drivers/media/dvb/dvb-usb/dw2102.h
new file mode 100644
index 00000000000..7a310f90683
--- /dev/null
+++ b/drivers/media/dvb/dvb-usb/dw2102.h
@@ -0,0 +1,9 @@
+#ifndef _DW2102_H_
+#define _DW2102_H_
+
+#define DVB_USB_LOG_PREFIX "dw2102"
+#include "dvb-usb.h"
+
+extern int dvb_usb_dw2102_debug;
+#define deb_xfer(args...) dprintk(dvb_usb_dw2102_debug, 0x02, args)
+#endif
diff --git a/drivers/media/dvb/dvb-usb/gl861.c b/drivers/media/dvb/dvb-usb/gl861.c
index 037f7ffb47b..6f596ed4176 100644
--- a/drivers/media/dvb/dvb-usb/gl861.c
+++ b/drivers/media/dvb/dvb-usb/gl861.c
@@ -1,8 +1,8 @@
/* DVB USB compliant linux driver for GL861 USB2.0 devices.
*
* 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.
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation, version 2.
*
* see Documentation/dvb/README.dvb-usb for more information
*/
@@ -13,9 +13,9 @@
/* debug */
static int dvb_usb_gl861_debug;
-module_param_named(debug,dvb_usb_gl861_debug, int, 0644);
-MODULE_PARM_DESC(debug, "set debugging level (1=rc (or-able))." DVB_USB_DEBUG_STATUS);
-
+module_param_named(debug, dvb_usb_gl861_debug, int, 0644);
+MODULE_PARM_DESC(debug, "set debugging level (1=rc (or-able))."
+ DVB_USB_DEBUG_STATUS);
DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
static int gl861_i2c_msg(struct dvb_usb_device *d, u8 addr,
@@ -70,7 +70,7 @@ static int gl861_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[],
/* write/read request */
if (i+1 < num && (msg[i+1].flags & I2C_M_RD)) {
if (gl861_i2c_msg(d, msg[i].addr, msg[i].buf,
- msg[i].len, msg[i+1].buf, msg[i+1].len) < 0)
+ msg[i].len, msg[i+1].buf, msg[i+1].len) < 0)
break;
i++;
} else
@@ -102,12 +102,13 @@ static struct zl10353_config gl861_zl10353_config = {
static int gl861_frontend_attach(struct dvb_usb_adapter *adap)
{
- if ((adap->fe = dvb_attach(zl10353_attach, &gl861_zl10353_config,
- &adap->dev->i2c_adap)) != NULL) {
- return 0;
- }
- return -EIO;
+ adap->fe = dvb_attach(zl10353_attach, &gl861_zl10353_config,
+ &adap->dev->i2c_adap);
+ if (adap->fe == NULL)
+ return -EIO;
+
+ return 0;
}
static struct qt1010_config gl861_qt1010_config = {
@@ -156,7 +157,7 @@ static struct usb_device_id gl861_table [] = {
{ USB_DEVICE(USB_VID_ALINK, USB_VID_ALINK_DTU) },
{ } /* Terminating entry */
};
-MODULE_DEVICE_TABLE (usb, gl861_table);
+MODULE_DEVICE_TABLE(usb, gl861_table);
static struct dvb_usb_device_properties gl861_properties = {
.caps = DVB_USB_IS_AN_I2C_ADAPTER,
@@ -180,7 +181,7 @@ static struct dvb_usb_device_properties gl861_properties = {
}
}
},
- }},
+ } },
.i2c_algo = &gl861_i2c_algo,
.num_device_descs = 2,
@@ -210,12 +211,11 @@ static int __init gl861_module_init(void)
{
int ret;
- if ((ret = usb_register(&gl861_driver))) {
+ ret = usb_register(&gl861_driver);
+ if (ret)
err("usb_register failed. Error number %d", ret);
- return ret;
- }
- return 0;
+ return ret;
}
static void __exit gl861_module_exit(void)
@@ -224,8 +224,8 @@ static void __exit gl861_module_exit(void)
usb_deregister(&gl861_driver);
}
-module_init (gl861_module_init);
-module_exit (gl861_module_exit);
+module_init(gl861_module_init);
+module_exit(gl861_module_exit);
MODULE_AUTHOR("Carl Lundqvist <comabug@gmail.com>");
MODULE_DESCRIPTION("Driver MSI Mega Sky 580 DVB-T USB2.0 / GL861");
diff --git a/drivers/media/dvb/dvb-usb/gl861.h b/drivers/media/dvb/dvb-usb/gl861.h
index 72a51afd5ee..c54855e2c23 100644
--- a/drivers/media/dvb/dvb-usb/gl861.h
+++ b/drivers/media/dvb/dvb-usb/gl861.h
@@ -4,7 +4,7 @@
#define DVB_USB_LOG_PREFIX "gl861"
#include "dvb-usb.h"
-#define deb_rc(args...) dprintk(dvb_usb_gl861_debug,0x01,args)
+#define deb_rc(args...) dprintk(dvb_usb_gl861_debug, 0x01, args)
#define GL861_WRITE 0x40
#define GL861_READ 0xc0
diff --git a/drivers/media/dvb/frontends/Kconfig b/drivers/media/dvb/frontends/Kconfig
index c20553c4da1..7dbb4a223c9 100644
--- a/drivers/media/dvb/frontends/Kconfig
+++ b/drivers/media/dvb/frontends/Kconfig
@@ -97,9 +97,8 @@ comment "DVB-T (terrestrial) frontends"
config DVB_SP8870
tristate "Spase sp8870 based"
- depends on DVB_CORE && I2C && HOTPLUG
+ depends on DVB_CORE && I2C
default m if DVB_FE_CUSTOMISE
- select FW_LOADER
help
A DVB-T tuner module. Say Y when you want to support this frontend.
@@ -110,9 +109,8 @@ config DVB_SP8870
config DVB_SP887X
tristate "Spase sp887x based"
- depends on DVB_CORE && I2C && HOTPLUG
+ depends on DVB_CORE && I2C
default m if DVB_FE_CUSTOMISE
- select FW_LOADER
help
A DVB-T tuner module. Say Y when you want to support this frontend.
@@ -135,6 +133,19 @@ config DVB_CX22702
help
A DVB-T tuner module. Say Y when you want to support this frontend.
+config DVB_DRX397XD
+ tristate "Micronas DRX3975D/DRX3977D based"
+ depends on DVB_CORE && I2C
+ default m if DVB_FE_CUSTOMISE
+ help
+ A DVB-T tuner module. Say Y when you want to support this frontend.
+
+ TODO:
+ This driver needs external firmware. Please use the command
+ "<kerneldir>/Documentation/dvb/get_dvb_firmware drx397xD" to
+ download/extract them, and then copy them to /usr/lib/hotplug/firmware
+ or /lib/firmware (depending on configuration of firmware hotplug).
+
config DVB_L64781
tristate "LSI L64781"
depends on DVB_CORE && I2C
@@ -144,9 +155,8 @@ config DVB_L64781
config DVB_TDA1004X
tristate "Philips TDA10045H/TDA10046H based"
- depends on DVB_CORE && I2C && HOTPLUG
+ depends on DVB_CORE && I2C
default m if DVB_FE_CUSTOMISE
- select FW_LOADER
help
A DVB-T tuner module. Say Y when you want to support this frontend.
@@ -211,9 +221,8 @@ config DVB_DIB7000P
config DVB_TDA10048
tristate "Philips TDA10048HN based"
- depends on DVB_CORE && I2C && HOTPLUG
+ depends on DVB_CORE && I2C
default m if DVB_FE_CUSTOMISE
- select FW_LOADER
help
A DVB-T tuner module. Say Y when you want to support this frontend.
@@ -253,9 +262,8 @@ comment "ATSC (North American/Korean Terrestrial/Cable DTV) frontends"
config DVB_NXT200X
tristate "NxtWave Communications NXT2002/NXT2004 based"
- depends on DVB_CORE && I2C && HOTPLUG
+ depends on DVB_CORE && I2C
default m if DVB_FE_CUSTOMISE
- select FW_LOADER
help
An ATSC 8VSB and QAM64/256 tuner module. Say Y when you want
to support this frontend.
@@ -268,9 +276,8 @@ config DVB_NXT200X
config DVB_OR51211
tristate "Oren OR51211 based"
- depends on DVB_CORE && I2C && HOTPLUG
+ depends on DVB_CORE && I2C
default m if DVB_FE_CUSTOMISE
- select FW_LOADER
help
An ATSC 8VSB tuner module. Say Y when you want to support this frontend.
@@ -281,9 +288,8 @@ config DVB_OR51211
config DVB_OR51132
tristate "Oren OR51132 based"
- depends on DVB_CORE && I2C && HOTPLUG
+ depends on DVB_CORE && I2C
default m if DVB_FE_CUSTOMISE
- select FW_LOADER
help
An ATSC 8VSB and QAM64/256 tuner module. Say Y when you want
to support this frontend.
@@ -297,9 +303,8 @@ config DVB_OR51132
config DVB_BCM3510
tristate "Broadcom BCM3510"
- depends on DVB_CORE && I2C && HOTPLUG
+ depends on DVB_CORE && I2C
default m if DVB_FE_CUSTOMISE
- select FW_LOADER
help
An ATSC 8VSB/16VSB and QAM64/256 tuner module. Say Y when you want to
support this frontend.
diff --git a/drivers/media/dvb/frontends/Makefile b/drivers/media/dvb/frontends/Makefile
index a89dc0fc4c6..028da55611c 100644
--- a/drivers/media/dvb/frontends/Makefile
+++ b/drivers/media/dvb/frontends/Makefile
@@ -25,6 +25,7 @@ obj-$(CONFIG_DVB_NXT6000) += nxt6000.o
obj-$(CONFIG_DVB_MT352) += mt352.o
obj-$(CONFIG_DVB_ZL10353) += zl10353.o
obj-$(CONFIG_DVB_CX22702) += cx22702.o
+obj-$(CONFIG_DVB_DRX397XD) += drx397xD.o
obj-$(CONFIG_DVB_TDA10021) += tda10021.o
obj-$(CONFIG_DVB_TDA10023) += tda10023.o
obj-$(CONFIG_DVB_STV0297) += stv0297.o
diff --git a/drivers/media/dvb/frontends/au8522.c b/drivers/media/dvb/frontends/au8522.c
index 03900d241a7..0b82cc2a1e1 100644
--- a/drivers/media/dvb/frontends/au8522.c
+++ b/drivers/media/dvb/frontends/au8522.c
@@ -1,7 +1,7 @@
/*
Auvitek AU8522 QAM/8VSB demodulator driver
- Copyright (C) 2008 Steven Toth <stoth@hauppauge.com>
+ Copyright (C) 2008 Steven Toth <stoth@linuxtv.org>
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
@@ -26,7 +26,6 @@
#include <linux/slab.h>
#include <linux/delay.h>
#include "dvb_frontend.h"
-#include "dvb-pll.h"
#include "au8522.h"
struct au8522_state {
@@ -305,6 +304,43 @@ static int au8522_mse2snr_lookup(struct mse2snr_tab *tab, int sz, int mse,
return ret;
}
+static int au8522_set_if(struct dvb_frontend *fe, enum au8522_if_freq if_freq)
+{
+ struct au8522_state *state = fe->demodulator_priv;
+ u8 r0b5, r0b6, r0b7;
+ char *ifmhz;
+
+ switch (if_freq) {
+ case AU8522_IF_3_25MHZ:
+ ifmhz = "3.25";
+ r0b5 = 0x00;
+ r0b6 = 0x3d;
+ r0b7 = 0xa0;
+ break;
+ case AU8522_IF_4MHZ:
+ ifmhz = "4.00";
+ r0b5 = 0x00;
+ r0b6 = 0x4b;
+ r0b7 = 0xd9;
+ break;
+ case AU8522_IF_6MHZ:
+ ifmhz = "6.00";
+ r0b5 = 0xfb;
+ r0b6 = 0x8e;
+ r0b7 = 0x39;
+ break;
+ default:
+ dprintk("%s() IF Frequency not supported\n", __func__);
+ return -EINVAL;
+ }
+ dprintk("%s() %s MHz\n", __func__, ifmhz);
+ au8522_writereg(state, 0x80b5, r0b5);
+ au8522_writereg(state, 0x80b6, r0b6);
+ au8522_writereg(state, 0x80b7, r0b7);
+
+ return 0;
+}
+
/* VSB Modulation table */
static struct {
u16 reg;
@@ -335,9 +371,6 @@ static struct {
{ 0x80af, 0x66 },
{ 0x821b, 0xcc },
{ 0x821d, 0x80 },
- { 0x80b5, 0xfb },
- { 0x80b6, 0x8e },
- { 0x80b7, 0x39 },
{ 0x80a4, 0xe8 },
{ 0x8231, 0x13 },
};
@@ -351,9 +384,6 @@ static struct {
{ 0x80a4, 0x00 },
{ 0x8081, 0xc4 },
{ 0x80a5, 0x40 },
- { 0x80b5, 0xfb },
- { 0x80b6, 0x8e },
- { 0x80b7, 0x39 },
{ 0x80aa, 0x77 },
{ 0x80ad, 0x77 },
{ 0x80a6, 0x67 },
@@ -439,6 +469,7 @@ static int au8522_enable_modulation(struct dvb_frontend *fe,
au8522_writereg(state,
VSB_mod_tab[i].reg,
VSB_mod_tab[i].data);
+ au8522_set_if(fe, state->config->vsb_if);
break;
case QAM_64:
case QAM_256:
@@ -447,6 +478,7 @@ static int au8522_enable_modulation(struct dvb_frontend *fe,
au8522_writereg(state,
QAM_mod_tab[i].reg,
QAM_mod_tab[i].data);
+ au8522_set_if(fe, state->config->qam_if);
break;
default:
dprintk("%s() Invalid modulation\n", __func__);
diff --git a/drivers/media/dvb/frontends/au8522.h b/drivers/media/dvb/frontends/au8522.h
index d7affa3cdb2..595915ade8c 100644
--- a/drivers/media/dvb/frontends/au8522.h
+++ b/drivers/media/dvb/frontends/au8522.h
@@ -1,7 +1,7 @@
/*
Auvitek AU8522 QAM/8VSB demodulator driver
- Copyright (C) 2008 Steven Toth <stoth@hauppauge.com>
+ Copyright (C) 2008 Steven Toth <stoth@linuxtv.org>
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
@@ -24,6 +24,12 @@
#include <linux/dvb/frontend.h>
+enum au8522_if_freq {
+ AU8522_IF_6MHZ = 0,
+ AU8522_IF_4MHZ,
+ AU8522_IF_3_25MHZ,
+};
+
struct au8522_config {
/* the demodulator's i2c address */
u8 demod_address;
@@ -32,6 +38,9 @@ struct au8522_config {
#define AU8522_TUNERLOCKING 0
#define AU8522_DEMODLOCKING 1
u8 status_mode;
+
+ enum au8522_if_freq vsb_if;
+ enum au8522_if_freq qam_if;
};
#if defined(CONFIG_DVB_AU8522) || \
diff --git a/drivers/media/dvb/frontends/cx22702.c b/drivers/media/dvb/frontends/cx22702.c
index cc1db4e371c..9430e03dba6 100644
--- a/drivers/media/dvb/frontends/cx22702.c
+++ b/drivers/media/dvb/frontends/cx22702.c
@@ -7,7 +7,7 @@
Copyright (C) 2001-2002 Convergence Integrated Media GmbH
Holger Waechtler <holger@convergence.de>
- Copyright (C) 2004 Steven Toth <stoth@hauppauge.com>
+ Copyright (C) 2004 Steven Toth <stoth@linuxtv.org>
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
diff --git a/drivers/media/dvb/frontends/cx22702.h b/drivers/media/dvb/frontends/cx22702.h
index 8af766a3155..b1e465c6c2c 100644
--- a/drivers/media/dvb/frontends/cx22702.h
+++ b/drivers/media/dvb/frontends/cx22702.h
@@ -7,7 +7,7 @@
Copyright (C) 2001-2002 Convergence Integrated Media GmbH
Holger Waechtler <holger@convergence.de>
- Copyright (C) 2004 Steven Toth <stoth@hauppauge.com>
+ Copyright (C) 2004 Steven Toth <stoth@linuxtv.org>
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
diff --git a/drivers/media/dvb/frontends/cx24123.c b/drivers/media/dvb/frontends/cx24123.c
index 7f68d78c655..7156157cb34 100644
--- a/drivers/media/dvb/frontends/cx24123.c
+++ b/drivers/media/dvb/frontends/cx24123.c
@@ -1,7 +1,7 @@
/*
* Conexant cx24123/cx24109 - DVB QPSK Satellite demod/tuner driver
*
- * Copyright (C) 2005 Steven Toth <stoth@hauppauge.com>
+ * Copyright (C) 2005 Steven Toth <stoth@linuxtv.org>
*
* Support for KWorld DVB-S 100 by Vadim Catana <skystar@moldova.cc>
*
@@ -1072,8 +1072,8 @@ struct dvb_frontend* cx24123_attach(const struct cx24123_config* config,
if (config->dont_use_pll)
cx24123_repeater_mode(state, 1, 0);
- strncpy(state->tuner_i2c_adapter.name,
- "CX24123 tuner I2C bus", I2C_NAME_SIZE);
+ strlcpy(state->tuner_i2c_adapter.name, "CX24123 tuner I2C bus",
+ sizeof(state->tuner_i2c_adapter.name));
state->tuner_i2c_adapter.class = I2C_CLASS_TV_DIGITAL,
state->tuner_i2c_adapter.algo = &cx24123_tuner_i2c_algo;
state->tuner_i2c_adapter.algo_data = NULL;
diff --git a/drivers/media/dvb/frontends/cx24123.h b/drivers/media/dvb/frontends/cx24123.h
index 81ebc3d2f19..cc6b411d6d2 100644
--- a/drivers/media/dvb/frontends/cx24123.h
+++ b/drivers/media/dvb/frontends/cx24123.h
@@ -1,7 +1,7 @@
/*
Conexant cx24123/cx24109 - DVB QPSK Satellite demod/tuner driver
- Copyright (C) 2005 Steven Toth <stoth@hauppauge.com>
+ Copyright (C) 2005 Steven Toth <stoth@linuxtv.org>
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
diff --git a/drivers/media/dvb/frontends/drx397xD.c b/drivers/media/dvb/frontends/drx397xD.c
new file mode 100644
index 00000000000..3cbed874a6f
--- /dev/null
+++ b/drivers/media/dvb/frontends/drx397xD.c
@@ -0,0 +1,1504 @@
+/*
+ * Driver for Micronas drx397xD demodulator
+ *
+ * Copyright (C) 2007 Henk Vergonet <Henk.Vergonet@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, see <http://www.gnu.org/licenses/>.
+ */
+
+#define DEBUG /* uncomment if you want debugging output */
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/device.h>
+#include <linux/delay.h>
+#include <linux/string.h>
+#include <linux/firmware.h>
+#include <asm/div64.h>
+
+#include "dvb_frontend.h"
+#include "drx397xD.h"
+
+static const char mod_name[] = "drx397xD";
+
+#define MAX_CLOCK_DRIFT 200 /* maximal 200 PPM allowed */
+
+#define F_SET_0D0h 1
+#define F_SET_0D4h 2
+
+typedef enum fw_ix {
+#define _FW_ENTRY(a, b) b
+#include "drx397xD_fw.h"
+} fw_ix_t;
+
+/* chip specifics */
+struct drx397xD_state {
+ struct i2c_adapter *i2c;
+ struct dvb_frontend frontend;
+ struct drx397xD_config config;
+ fw_ix_t chip_rev;
+ int flags;
+ u32 bandwidth_parm; /* internal bandwidth conversions */
+ u32 f_osc; /* w90: actual osc frequency [Hz] */
+};
+
+/*******************************************************************************
+ * Firmware
+ ******************************************************************************/
+
+static const char *blob_name[] = {
+#define _BLOB_ENTRY(a, b) a
+#include "drx397xD_fw.h"
+};
+
+typedef enum blob_ix {
+#define _BLOB_ENTRY(a, b) b
+#include "drx397xD_fw.h"
+} blob_ix_t;
+
+static struct {
+ const char *name;
+ const struct firmware *file;
+ rwlock_t lock;
+ int refcnt;
+ const u8 *data[ARRAY_SIZE(blob_name)];
+} fw[] = {
+#define _FW_ENTRY(a, b) { \
+ .name = a, \
+ .file = 0, \
+ .lock = RW_LOCK_UNLOCKED, \
+ .refcnt = 0, \
+ .data = { } }
+#include "drx397xD_fw.h"
+};
+
+/* use only with writer lock aquired */
+static void _drx_release_fw(struct drx397xD_state *s, fw_ix_t ix)
+{
+ memset(&fw[ix].data[0], 0, sizeof(fw[0].data));
+ if (fw[ix].file)
+ release_firmware(fw[ix].file);
+}
+
+static void drx_release_fw(struct drx397xD_state *s)
+{
+ fw_ix_t ix = s->chip_rev;
+
+ pr_debug("%s\n", __FUNCTION__);
+
+ write_lock(&fw[ix].lock);
+ if (fw[ix].refcnt) {
+ fw[ix].refcnt--;
+ if (fw[ix].refcnt == 0)
+ _drx_release_fw(s, ix);
+ }
+ write_unlock(&fw[ix].lock);
+}
+
+static int drx_load_fw(struct drx397xD_state *s, fw_ix_t ix)
+{
+ const u8 *data;
+ size_t size, len;
+ int i = 0, j, rc = -EINVAL;
+
+ pr_debug("%s\n", __FUNCTION__);
+
+ if (ix < 0 || ix >= ARRAY_SIZE(fw))
+ return -EINVAL;
+ s->chip_rev = ix;
+
+ write_lock(&fw[ix].lock);
+ if (fw[ix].file) {
+ rc = 0;
+ goto exit_ok;
+ }
+ memset(&fw[ix].data[0], 0, sizeof(fw[0].data));
+
+ if (request_firmware(&fw[ix].file, fw[ix].name, &s->i2c->dev) != 0) {
+ printk(KERN_ERR "%s: Firmware \"%s\" not available\n",
+ mod_name, fw[ix].name);
+ rc = -ENOENT;
+ goto exit_err;
+ }
+
+ if (!fw[ix].file->data || fw[ix].file->size < 10)
+ goto exit_corrupt;
+
+ data = fw[ix].file->data;
+ size = fw[ix].file->size;
+
+ if (data[i++] != 2) /* check firmware version */
+ goto exit_corrupt;
+
+ do {
+ switch (data[i++]) {
+ case 0x00: /* bytecode */
+ if (i >= size)
+ break;
+ i += data[i];
+ case 0x01: /* reset */
+ case 0x02: /* sleep */
+ i++;
+ break;
+ case 0xfe: /* name */
+ len = strnlen(&data[i], size - i);
+ if (i + len + 1 >= size)
+ goto exit_corrupt;
+ if (data[i + len + 1] != 0)
+ goto exit_corrupt;
+ for (j = 0; j < ARRAY_SIZE(blob_name); j++) {
+ if (strcmp(blob_name[j], &data[i]) == 0) {
+ fw[ix].data[j] = &data[i + len + 1];
+ pr_debug("Loading %s\n", blob_name[j]);
+ }
+ }
+ i += len + 1;
+ break;
+ case 0xff: /* file terminator */
+ if (i == size) {
+ rc = 0;
+ goto exit_ok;
+ }
+ default:
+ goto exit_corrupt;
+ }
+ } while (i < size);
+ exit_corrupt:
+ printk(KERN_ERR "%s: Firmware is corrupt\n", mod_name);
+ exit_err:
+ _drx_release_fw(s, ix);
+ fw[ix].refcnt--;
+ exit_ok:
+ fw[ix].refcnt++;
+ write_unlock(&fw[ix].lock);
+ return rc;
+}
+
+/*******************************************************************************
+ * i2c bus IO
+ ******************************************************************************/
+
+static int write_fw(struct drx397xD_state *s, blob_ix_t ix)
+{
+ struct i2c_msg msg = {.addr = s->config.demod_address,.flags = 0 };
+ const u8 *data;
+ int len, rc = 0, i = 0;
+
+ if (ix < 0 || ix >= ARRAY_SIZE(blob_name)) {
+ pr_debug("%s drx_fw_ix_t out of range\n", __FUNCTION__);
+ return -EINVAL;
+ }
+ pr_debug("%s %s\n", __FUNCTION__, blob_name[ix]);
+
+ read_lock(&fw[s->chip_rev].lock);
+ data = fw[s->chip_rev].data[ix];
+ if (!data) {
+ rc = -EINVAL;
+ goto exit_rc;
+ }
+
+ for (;;) {
+ switch (data[i++]) {
+ case 0: /* bytecode */
+ len = data[i++];
+ msg.len = len;
+ msg.buf = (__u8 *) &data[i];
+ if (i2c_transfer(s->i2c, &msg, 1) != 1) {
+ rc = -EIO;
+ goto exit_rc;
+ }
+ i += len;
+ break;
+ case 1: /* reset */
+ case 2: /* sleep */
+ i++;
+ break;
+ default:
+ goto exit_rc;
+ }
+ }
+ exit_rc:
+ read_unlock(&fw[s->chip_rev].lock);
+ return 0;
+}
+
+/* Function is not endian safe, use the RD16 wrapper below */
+static int _read16(struct drx397xD_state *s, u32 i2c_adr)
+{
+ int rc;
+ u8 a[4];
+ u16 v;
+ struct i2c_msg msg[2] = {
+ {
+ .addr = s->config.demod_address,
+ .flags = 0,
+ .buf = a,
+ .len = sizeof(a)
+ }
+ , {
+ .addr = s->config.demod_address,
+ .flags = I2C_M_RD,
+ .buf = (u8 *) & v,
+ .len = sizeof(v)
+ }
+ };
+
+ *(u32 *) a = i2c_adr;
+
+ rc = i2c_transfer(s->i2c, msg, 2);
+ if (rc != 2)
+ return -EIO;
+
+ return le16_to_cpu(v);
+}
+
+/* Function is not endian safe, use the WR16.. wrappers below */
+static int _write16(struct drx397xD_state *s, u32 i2c_adr, u16 val)
+{
+ u8 a[6];
+ int rc;
+ struct i2c_msg msg = {
+ .addr = s->config.demod_address,
+ .flags = 0,
+ .buf = a,
+ .len = sizeof(a)
+ };
+
+ *(u32 *) a = i2c_adr;
+ *(u16 *) & a[4] = val;
+
+ rc = i2c_transfer(s->i2c, &msg, 1);
+ if (rc != 1)
+ return -EIO;
+ return 0;
+}
+
+#define WR16(ss,adr, val) \
+ _write16(ss, I2C_ADR_C0(adr), cpu_to_le16(val))
+#define WR16_E0(ss,adr, val) \
+ _write16(ss, I2C_ADR_E0(adr), cpu_to_le16(val))
+#define RD16(ss,adr) \
+ _read16(ss, I2C_ADR_C0(adr))
+
+#define EXIT_RC( cmd ) if ( (rc = (cmd)) < 0) goto exit_rc
+
+/*******************************************************************************
+ * Tuner callback
+ ******************************************************************************/
+
+static int PLL_Set(struct drx397xD_state *s,
+ struct dvb_frontend_parameters *fep, int *df_tuner)
+{
+ struct dvb_frontend *fe = &s->frontend;
+ u32 f_tuner, f = fep->frequency;
+ int rc;
+
+ pr_debug("%s\n", __FUNCTION__);
+
+ if ((f > s->frontend.ops.tuner_ops.info.frequency_max) ||
+ (f < s->frontend.ops.tuner_ops.info.frequency_min))
+ return -EINVAL;
+
+ *df_tuner = 0;
+ if (!s->frontend.ops.tuner_ops.set_params ||
+ !s->frontend.ops.tuner_ops.get_frequency)
+ return -ENOSYS;
+
+ rc = s->frontend.ops.tuner_ops.set_params(fe, fep);
+ if (rc < 0)
+ return rc;
+
+ rc = s->frontend.ops.tuner_ops.get_frequency(fe, &f_tuner);
+ if (rc < 0)
+ return rc;
+
+ *df_tuner = f_tuner - f;
+ pr_debug("%s requested %d [Hz] tuner %d [Hz]\n", __FUNCTION__, f,
+ f_tuner);
+
+ return 0;
+}
+
+/*******************************************************************************
+ * Demodulator helper functions
+ ******************************************************************************/
+
+static int SC_WaitForReady(struct drx397xD_state *s)
+{
+ int cnt = 1000;
+ int rc;
+
+ pr_debug("%s\n", __FUNCTION__);
+
+ while (cnt--) {
+ rc = RD16(s, 0x820043);
+ if (rc == 0)
+ return 0;
+ }
+ return -1;
+}
+
+static int SC_SendCommand(struct drx397xD_state *s, int cmd)
+{
+ int rc;
+
+ pr_debug("%s\n", __FUNCTION__);
+
+ WR16(s, 0x820043, cmd);
+ SC_WaitForReady(s);
+ rc = RD16(s, 0x820042);
+ if ((rc & 0xffff) == 0xffff)
+ return -1;
+ return 0;
+}
+
+static int HI_Command(struct drx397xD_state *s, u16 cmd)
+{
+ int rc, cnt = 1000;
+
+ pr_debug("%s\n", __FUNCTION__);
+
+ rc = WR16(s, 0x420032, cmd);
+ if (rc < 0)
+ return rc;
+
+ do {
+ rc = RD16(s, 0x420032);
+ if (rc == 0) {
+ rc = RD16(s, 0x420031);
+ return rc;
+ }
+ if (rc < 0)
+ return rc;
+ } while (--cnt);
+ return rc;
+}
+
+static int HI_CfgCommand(struct drx397xD_state *s)
+{
+
+ pr_debug("%s\n", __FUNCTION__);
+
+ WR16(s, 0x420033, 0x3973);
+ WR16(s, 0x420034, s->config.w50); // code 4, log 4
+ WR16(s, 0x420035, s->config.w52); // code 15, log 9
+ WR16(s, 0x420036, s->config.demod_address << 1);
+ WR16(s, 0x420037, s->config.w56); // code (set_i2c ?? initX 1 ), log 1
+// WR16(s, 0x420033, 0x3973);
+ if ((s->config.w56 & 8) == 0)
+ return HI_Command(s, 3);
+ return WR16(s, 0x420032, 0x3);
+}
+
+static const u8 fastIncrDecLUT_15273[] = {
+ 0x0e, 0x0f, 0x0f, 0x10, 0x11, 0x12, 0x12, 0x13, 0x14,
+ 0x15, 0x16, 0x17, 0x18, 0x1a, 0x1b, 0x1c, 0x1d, 0x1f
+};
+
+static const u8 slowIncrDecLUT_15272[] = {
+ 3, 4, 4, 5, 6
+};
+
+static int SetCfgIfAgc(struct drx397xD_state *s, struct drx397xD_CfgIfAgc *agc)
+{
+ u16 w06 = agc->w06;
+ u16 w08 = agc->w08;
+ u16 w0A = agc->w0A;
+ u16 w0C = agc->w0C;
+ int quot, rem, i, rc = -EINVAL;
+
+ pr_debug("%s\n", __FUNCTION__);
+
+ if (agc->w04 > 0x3ff)
+ goto exit_rc;
+
+ if (agc->d00 == 1) {
+ EXIT_RC(RD16(s, 0x0c20010));
+ rc &= ~0x10;
+ EXIT_RC(WR16(s, 0x0c20010, rc));
+ return WR16(s, 0x0c20030, agc->w04 & 0x7ff);
+ }
+
+ if (agc->d00 != 0)
+ goto exit_rc;
+ if (w0A < w08)
+ goto exit_rc;
+ if (w0A > 0x3ff)
+ goto exit_rc;
+ if (w0C > 0x3ff)
+ goto exit_rc;
+ if (w06 > 0x3ff)
+ goto exit_rc;
+
+ EXIT_RC(RD16(s, 0x0c20010));
+ rc |= 0x10;
+ EXIT_RC(WR16(s, 0x0c20010, rc));
+
+ EXIT_RC(WR16(s, 0x0c20025, (w06 >> 1) & 0x1ff));
+ EXIT_RC(WR16(s, 0x0c20031, (w0A - w08) >> 1));
+ EXIT_RC(WR16(s, 0x0c20032, ((w0A + w08) >> 1) - 0x1ff));
+
+ quot = w0C / 113;
+ rem = w0C % 113;
+ if (quot <= 8) {
+ quot = 8 - quot;
+ } else {
+ quot = 0;
+ rem += 113;
+ }
+
+ EXIT_RC(WR16(s, 0x0c20024, quot));
+
+ i = fastIncrDecLUT_15273[rem / 8];
+ EXIT_RC(WR16(s, 0x0c2002d, i));
+ EXIT_RC(WR16(s, 0x0c2002e, i));
+
+ i = slowIncrDecLUT_15272[rem / 28];
+ EXIT_RC(WR16(s, 0x0c2002b, i));
+ rc = WR16(s, 0x0c2002c, i);
+ exit_rc:
+ return rc;
+}
+
+static int SetCfgRfAgc(struct drx397xD_state *s, struct drx397xD_CfgRfAgc *agc)
+{
+ u16 w04 = agc->w04;
+ u16 w06 = agc->w06;
+ int rc = -1;
+
+ pr_debug("%s %d 0x%x 0x%x\n", __FUNCTION__, agc->d00, w04, w06);
+
+ if (w04 > 0x3ff)
+ goto exit_rc;
+
+ switch (agc->d00) {
+ case 1:
+ if (w04 == 0x3ff)
+ w04 = 0x400;
+
+ EXIT_RC(WR16(s, 0x0c20036, w04));
+ s->config.w9C &= ~2;
+ EXIT_RC(WR16(s, 0x0c20015, s->config.w9C));
+ EXIT_RC(RD16(s, 0x0c20010));
+ rc &= 0xbfdf;
+ EXIT_RC(WR16(s, 0x0c20010, rc));
+ EXIT_RC(RD16(s, 0x0c20013));
+ rc &= ~2;
+ break;
+ case 0:
+ // loc_8000659
+ s->config.w9C &= ~2;
+ EXIT_RC(WR16(s, 0x0c20015, s->config.w9C));
+ EXIT_RC(RD16(s, 0x0c20010));
+ rc &= 0xbfdf;
+ rc |= 0x4000;
+ EXIT_RC(WR16(s, 0x0c20010, rc));
+ EXIT_RC(WR16(s, 0x0c20051, (w06 >> 4) & 0x3f));
+ EXIT_RC(RD16(s, 0x0c20013));
+ rc &= ~2;
+ break;
+ default:
+ s->config.w9C |= 2;
+ EXIT_RC(WR16(s, 0x0c20015, s->config.w9C));
+ EXIT_RC(RD16(s, 0x0c20010));
+ rc &= 0xbfdf;
+ EXIT_RC(WR16(s, 0x0c20010, rc));
+
+ EXIT_RC(WR16(s, 0x0c20036, 0));
+
+ EXIT_RC(RD16(s, 0x0c20013));
+ rc |= 2;
+ }
+ rc = WR16(s, 0x0c20013, rc);
+ exit_rc:
+ return rc;
+}
+
+static int GetLockStatus(struct drx397xD_state *s, int *lockstat)
+{
+ int rc;
+
+ *lockstat = 0;
+
+ rc = RD16(s, 0x082004b);
+ if (rc < 0)
+ return rc;
+
+ if (s->config.d60 != 2)
+ return 0;
+
+ if ((rc & 7) == 7)
+ *lockstat |= 1;
+ if ((rc & 3) == 3)
+ *lockstat |= 2;
+ if (rc & 1)
+ *lockstat |= 4;
+ return 0;
+}
+
+static int CorrectSysClockDeviation(struct drx397xD_state *s)
+{
+ int rc = -EINVAL;
+ int lockstat;
+ u32 clk, clk_limit;
+
+ pr_debug("%s\n", __FUNCTION__);
+
+ if (s->config.d5C == 0) {
+ EXIT_RC(WR16(s, 0x08200e8, 0x010));
+ EXIT_RC(WR16(s, 0x08200e9, 0x113));
+ s->config.d5C = 1;
+ return rc;
+ }
+ if (s->config.d5C != 1)
+ goto exit_rc;
+
+ rc = RD16(s, 0x0820048);
+
+ rc = GetLockStatus(s, &lockstat);
+ if (rc < 0)
+ goto exit_rc;
+ if ((lockstat & 1) == 0)
+ goto exit_rc;
+
+ EXIT_RC(WR16(s, 0x0420033, 0x200));
+ EXIT_RC(WR16(s, 0x0420034, 0xc5));
+ EXIT_RC(WR16(s, 0x0420035, 0x10));
+ EXIT_RC(WR16(s, 0x0420036, 0x1));
+ EXIT_RC(WR16(s, 0x0420037, 0xa));
+ EXIT_RC(HI_Command(s, 6));
+ EXIT_RC(RD16(s, 0x0420040));
+ clk = rc;
+ EXIT_RC(RD16(s, 0x0420041));
+ clk |= rc << 16;
+
+ if (clk <= 0x26ffff)
+ goto exit_rc;
+ if (clk > 0x610000)
+ goto exit_rc;
+
+ if (!s->bandwidth_parm)
+ return -EINVAL;
+
+ /* round & convert to Hz */
+ clk = ((u64) (clk + 0x800000) * s->bandwidth_parm + (1 << 20)) >> 21;
+ clk_limit = s->config.f_osc * MAX_CLOCK_DRIFT / 1000;
+
+ if (clk - s->config.f_osc * 1000 + clk_limit <= 2 * clk_limit) {
+ s->f_osc = clk;
+ pr_debug("%s: osc %d %d [Hz]\n", __FUNCTION__,
+ s->config.f_osc * 1000, clk - s->config.f_osc * 1000);
+ }
+ rc = WR16(s, 0x08200e8, 0);
+ exit_rc:
+ return rc;
+}
+
+static int ConfigureMPEGOutput(struct drx397xD_state *s, int type)
+{
+ int rc, si, bp;
+
+ pr_debug("%s\n", __FUNCTION__);
+
+ si = s->config.wA0;
+ if (s->config.w98 == 0) {
+ si |= 1;
+ bp = 0;
+ } else {
+ si &= ~1;
+ bp = 0x200;
+ }
+ if (s->config.w9A == 0) {
+ si |= 0x80;
+ } else {
+ si &= ~0x80;
+ }
+
+ EXIT_RC(WR16(s, 0x2150045, 0));
+ EXIT_RC(WR16(s, 0x2150010, si));
+ EXIT_RC(WR16(s, 0x2150011, bp));
+ rc = WR16(s, 0x2150012, (type == 0 ? 0xfff : 0));
+ exit_rc:
+ return rc;
+}
+
+static int drx_tune(struct drx397xD_state *s,
+ struct dvb_frontend_parameters *fep)
+{
+ u16 v22 = 0;
+ u16 v1C = 0;
+ u16 v1A = 0;
+ u16 v18 = 0;
+ u32 edi = 0, ebx = 0, ebp = 0, edx = 0;
+ u16 v20 = 0, v1E = 0, v16 = 0, v14 = 0, v12 = 0, v10 = 0, v0E = 0;
+
+ int rc, df_tuner;
+ int a, b, c, d;
+ pr_debug("%s %d\n", __FUNCTION__, s->config.d60);
+
+ if (s->config.d60 != 2)
+ goto set_tuner;
+ rc = CorrectSysClockDeviation(s);
+ if (rc < 0)
+ goto set_tuner;
+
+ s->config.d60 = 1;
+ rc = ConfigureMPEGOutput(s, 0);
+ if (rc < 0)
+ goto set_tuner;
+ set_tuner:
+
+ rc = PLL_Set(s, fep, &df_tuner);
+ if (rc < 0) {
+ printk(KERN_ERR "Error in pll_set\n");
+ goto exit_rc;
+ }
+ msleep(200);
+
+ a = rc = RD16(s, 0x2150016);
+ if (rc < 0)
+ goto exit_rc;
+ b = rc = RD16(s, 0x2150010);
+ if (rc < 0)
+ goto exit_rc;
+ c = rc = RD16(s, 0x2150034);
+ if (rc < 0)
+ goto exit_rc;
+ d = rc = RD16(s, 0x2150035);
+ if (rc < 0)
+ goto exit_rc;
+ rc = WR16(s, 0x2150014, c);
+ rc = WR16(s, 0x2150015, d);
+ rc = WR16(s, 0x2150010, 0);
+ rc = WR16(s, 0x2150000, 2);
+ rc = WR16(s, 0x2150036, 0x0fff);
+ rc = WR16(s, 0x2150016, a);
+
+ rc = WR16(s, 0x2150010, 2);
+ rc = WR16(s, 0x2150007, 0);
+ rc = WR16(s, 0x2150000, 1);
+ rc = WR16(s, 0x2110000, 0);
+ rc = WR16(s, 0x0800000, 0);
+ rc = WR16(s, 0x2800000, 0);
+ rc = WR16(s, 0x2110010, 0x664);
+
+ rc = write_fw(s, DRXD_ResetECRAM);
+ rc = WR16(s, 0x2110000, 1);
+
+ rc = write_fw(s, DRXD_InitSC);
+ if (rc < 0)
+ goto exit_rc;
+
+ rc = SetCfgIfAgc(s, &s->config.ifagc);
+ if (rc < 0)
+ goto exit_rc;
+
+ rc = SetCfgRfAgc(s, &s->config.rfagc);
+ if (rc < 0)
+ goto exit_rc;
+
+ if (fep->u.ofdm.transmission_mode != TRANSMISSION_MODE_2K)
+ v22 = 1;
+ switch (fep->u.ofdm.transmission_mode) {
+ case TRANSMISSION_MODE_8K:
+ edi = 1;
+ if (s->chip_rev == DRXD_FW_B1)
+ break;
+
+ rc = WR16(s, 0x2010010, 0);
+ if (rc < 0)
+ break;
+ v1C = 0x63;
+ v1A = 0x53;
+ v18 = 0x43;
+ break;
+ default:
+ edi = 0;
+ if (s->chip_rev == DRXD_FW_B1)
+ break;
+
+ rc = WR16(s, 0x2010010, 1);
+ if (rc < 0)
+ break;
+
+ v1C = 0x61;
+ v1A = 0x47;
+ v18 = 0x41;
+ }
+
+ switch (fep->u.ofdm.guard_interval) {
+ case GUARD_INTERVAL_1_4:
+ edi |= 0x0c;
+ break;
+ case GUARD_INTERVAL_1_8:
+ edi |= 0x08;
+ break;
+ case GUARD_INTERVAL_1_16:
+ edi |= 0x04;
+ break;
+ case GUARD_INTERVAL_1_32:
+ break;
+ default:
+ v22 |= 2;
+ }
+
+ ebx = 0;
+ ebp = 0;
+ v20 = 0;
+ v1E = 0;
+ v16 = 0;
+ v14 = 0;
+ v12 = 0;
+ v10 = 0;
+ v0E = 0;
+
+ switch (fep->u.ofdm.hierarchy_information) {
+ case HIERARCHY_1:
+ edi |= 0x40;
+ if (s->chip_rev == DRXD_FW_B1)
+ break;
+ rc = WR16(s, 0x1c10047, 1);
+ if (rc < 0)
+ goto exit_rc;
+ rc = WR16(s, 0x2010012, 1);
+ if (rc < 0)
+ goto exit_rc;
+ ebx = 0x19f;
+ ebp = 0x1fb;
+ v20 = 0x0c0;
+ v1E = 0x195;
+ v16 = 0x1d6;
+ v14 = 0x1ef;
+ v12 = 4;
+ v10 = 5;
+ v0E = 5;
+ break;
+ case HIERARCHY_2:
+ edi |= 0x80;
+ if (s->chip_rev == DRXD_FW_B1)
+ break;
+ rc = WR16(s, 0x1c10047, 2);
+ if (rc < 0)
+ goto exit_rc;
+ rc = WR16(s, 0x2010012, 2);
+ if (rc < 0)
+ goto exit_rc;
+ ebx = 0x08f;
+ ebp = 0x12f;
+ v20 = 0x0c0;
+ v1E = 0x11e;
+ v16 = 0x1d6;
+ v14 = 0x15e;
+ v12 = 4;
+ v10 = 5;
+ v0E = 5;
+ break;
+ case HIERARCHY_4:
+ edi |= 0xc0;
+ if (s->chip_rev == DRXD_FW_B1)
+ break;
+ rc = WR16(s, 0x1c10047, 3);
+ if (rc < 0)
+ goto exit_rc;
+ rc = WR16(s, 0x2010012, 3);
+ if (rc < 0)
+ goto exit_rc;
+ ebx = 0x14d;
+ ebp = 0x197;
+ v20 = 0x0c0;
+ v1E = 0x1ce;
+ v16 = 0x1d6;
+ v14 = 0x11a;
+ v12 = 4;
+ v10 = 6;
+ v0E = 5;
+ break;
+ default:
+ v22 |= 8;
+ if (s->chip_rev == DRXD_FW_B1)
+ break;
+ rc = WR16(s, 0x1c10047, 0);
+ if (rc < 0)
+ goto exit_rc;
+ rc = WR16(s, 0x2010012, 0);
+ if (rc < 0)
+ goto exit_rc;
+ // QPSK QAM16 QAM64
+ ebx = 0x19f; // 62
+ ebp = 0x1fb; // 15
+ v20 = 0x16a; // 62
+ v1E = 0x195; // 62
+ v16 = 0x1bb; // 15
+ v14 = 0x1ef; // 15
+ v12 = 5; // 16
+ v10 = 5; // 16
+ v0E = 5; // 16
+ }
+
+ switch (fep->u.ofdm.constellation) {
+ default:
+ v22 |= 4;
+ case QPSK:
+ if (s->chip_rev == DRXD_FW_B1)
+ break;
+
+ rc = WR16(s, 0x1c10046, 0);
+ if (rc < 0)
+ goto exit_rc;
+ rc = WR16(s, 0x2010011, 0);
+ if (rc < 0)
+ goto exit_rc;
+ rc = WR16(s, 0x201001a, 0x10);
+ if (rc < 0)
+ goto exit_rc;
+ rc = WR16(s, 0x201001b, 0);
+ if (rc < 0)
+ goto exit_rc;
+ rc = WR16(s, 0x201001c, 0);
+ if (rc < 0)
+ goto exit_rc;
+ rc = WR16(s, 0x1c10062, v20);
+ if (rc < 0)
+ goto exit_rc;
+ rc = WR16(s, 0x1c1002a, v1C);
+ if (rc < 0)
+ goto exit_rc;
+ rc = WR16(s, 0x1c10015, v16);
+ if (rc < 0)
+ goto exit_rc;
+ rc = WR16(s, 0x1c10016, v12);
+ if (rc < 0)
+ goto exit_rc;
+ break;
+ case QAM_16:
+ edi |= 0x10;
+ if (s->chip_rev == DRXD_FW_B1)
+ break;
+
+ rc = WR16(s, 0x1c10046, 1);
+ if (rc < 0)
+ goto exit_rc;
+ rc = WR16(s, 0x2010011, 1);
+ if (rc < 0)
+ goto exit_rc;
+ rc = WR16(s, 0x201001a, 0x10);
+ if (rc < 0)
+ goto exit_rc;
+ rc = WR16(s, 0x201001b, 4);
+ if (rc < 0)
+ goto exit_rc;
+ rc = WR16(s, 0x201001c, 0);
+ if (rc < 0)
+ goto exit_rc;
+ rc = WR16(s, 0x1c10062, v1E);
+ if (rc < 0)
+ goto exit_rc;
+ rc = WR16(s, 0x1c1002a, v1A);
+ if (rc < 0)
+ goto exit_rc;
+ rc = WR16(s, 0x1c10015, v14);
+ if (rc < 0)
+ goto exit_rc;
+ rc = WR16(s, 0x1c10016, v10);
+ if (rc < 0)
+ goto exit_rc;
+ break;
+ case QAM_64:
+ edi |= 0x20;
+ rc = WR16(s, 0x1c10046, 2);
+ if (rc < 0)
+ goto exit_rc;
+ rc = WR16(s, 0x2010011, 2);
+ if (rc < 0)
+ goto exit_rc;
+ rc = WR16(s, 0x201001a, 0x20);
+ if (rc < 0)
+ goto exit_rc;
+ rc = WR16(s, 0x201001b, 8);
+ if (rc < 0)
+ goto exit_rc;
+ rc = WR16(s, 0x201001c, 2);
+ if (rc < 0)
+ goto exit_rc;
+ rc = WR16(s, 0x1c10062, ebx);
+ if (rc < 0)
+ goto exit_rc;
+ rc = WR16(s, 0x1c1002a, v18);
+ if (rc < 0)
+ goto exit_rc;
+ rc = WR16(s, 0x1c10015, ebp);
+ if (rc < 0)
+ goto exit_rc;
+ rc = WR16(s, 0x1c10016, v0E);
+ if (rc < 0)
+ goto exit_rc;
+ break;
+ }
+
+ if (s->config.s20d24 == 1) {
+ rc = WR16(s, 0x2010013, 0);
+ } else {
+ rc = WR16(s, 0x2010013, 1);
+ edi |= 0x1000;
+ }
+
+ switch (fep->u.ofdm.code_rate_HP) {
+ default:
+ v22 |= 0x10;
+ case FEC_1_2:
+ if (s->chip_rev == DRXD_FW_B1)
+ break;
+ rc = WR16(s, 0x2090011, 0);
+ break;
+ case FEC_2_3:
+ edi |= 0x200;
+ if (s->chip_rev == DRXD_FW_B1)
+ break;
+ rc = WR16(s, 0x2090011, 1);
+ break;
+ case FEC_3_4:
+ edi |= 0x400;
+ if (s->chip_rev == DRXD_FW_B1)
+ break;
+ rc = WR16(s, 0x2090011, 2);
+ break;
+ case FEC_5_6: /* 5 */
+ edi |= 0x600;
+ if (s->chip_rev == DRXD_FW_B1)
+ break;
+ rc = WR16(s, 0x2090011, 3);
+ break;
+ case FEC_7_8: /* 7 */
+ edi |= 0x800;
+ if (s->chip_rev == DRXD_FW_B1)
+ break;
+ rc = WR16(s, 0x2090011, 4);
+ break;
+ };
+ if (rc < 0)
+ goto exit_rc;
+
+ switch (fep->u.ofdm.bandwidth) {
+ default:
+ rc = -EINVAL;
+ goto exit_rc;
+ case BANDWIDTH_8_MHZ: /* 0 */
+ case BANDWIDTH_AUTO:
+ rc = WR16(s, 0x0c2003f, 0x32);
+ s->bandwidth_parm = ebx = 0x8b8249; // 9142857
+ edx = 0;
+ break;
+ case BANDWIDTH_7_MHZ:
+ rc = WR16(s, 0x0c2003f, 0x3b);
+ s->bandwidth_parm = ebx = 0x7a1200; // 8000000
+ edx = 0x4807;
+ break;
+ case BANDWIDTH_6_MHZ:
+ rc = WR16(s, 0x0c2003f, 0x47);
+ s->bandwidth_parm = ebx = 0x68a1b6; // 6857142
+ edx = 0x0f07;
+ break;
+ };
+
+ if (rc < 0)
+ goto exit_rc;
+
+ rc = WR16(s, 0x08200ec, edx);
+ if (rc < 0)
+ goto exit_rc;
+
+ rc = RD16(s, 0x0820050);
+ if (rc < 0)
+ goto exit_rc;
+ rc = WR16(s, 0x0820050, rc);
+
+ {
+ /* Configure bandwidth specific factor */
+ ebx = div64_u64(((u64) (s->f_osc) << 21) + (ebx >> 1),
+ (u64)ebx) - 0x800000;
+ EXIT_RC(WR16(s, 0x0c50010, ebx & 0xffff));
+ EXIT_RC(WR16(s, 0x0c50011, ebx >> 16));
+
+ /* drx397xD oscillator calibration */
+ ebx = div64_u64(((u64) (s->config.f_if + df_tuner) << 28) +
+ (s->f_osc >> 1), (u64)s->f_osc);
+ }
+ ebx &= 0xfffffff;
+ if (fep->inversion == INVERSION_ON)
+ ebx = 0x10000000 - ebx;
+
+ EXIT_RC(WR16(s, 0x0c30010, ebx & 0xffff));
+ EXIT_RC(WR16(s, 0x0c30011, ebx >> 16));
+
+ EXIT_RC(WR16(s, 0x0800000, 1));
+ EXIT_RC(RD16(s, 0x0800000));
+
+
+ EXIT_RC(SC_WaitForReady(s));
+ EXIT_RC(WR16(s, 0x0820042, 0));
+ EXIT_RC(WR16(s, 0x0820041, v22));
+ EXIT_RC(WR16(s, 0x0820040, edi));
+ EXIT_RC(SC_SendCommand(s, 3));
+
+ rc = RD16(s, 0x0800000);
+
+ SC_WaitForReady(s);
+ WR16(s, 0x0820042, 0);
+ WR16(s, 0x0820041, 1);
+ WR16(s, 0x0820040, 1);
+ SC_SendCommand(s, 1);
+
+// rc = WR16(s, 0x2150000, 1);
+// if (rc < 0) goto exit_rc;
+
+ rc = WR16(s, 0x2150000, 2);
+ rc = WR16(s, 0x2150016, a);
+ rc = WR16(s, 0x2150010, 4);
+ rc = WR16(s, 0x2150036, 0);
+ rc = WR16(s, 0x2150000, 1);
+ s->config.d60 = 2;
+ exit_rc:
+ return rc;
+}
+
+/*******************************************************************************
+ * DVB interface
+ ******************************************************************************/
+
+static int drx397x_init(struct dvb_frontend *fe)
+{
+ struct drx397xD_state *s = fe->demodulator_priv;
+ int rc;
+
+ pr_debug("%s\n", __FUNCTION__);
+
+ s->config.rfagc.d00 = 2; /* 0x7c */
+ s->config.rfagc.w04 = 0;
+ s->config.rfagc.w06 = 0x3ff;
+
+ s->config.ifagc.d00 = 0; /* 0x68 */
+ s->config.ifagc.w04 = 0;
+ s->config.ifagc.w06 = 140;
+ s->config.ifagc.w08 = 0;
+ s->config.ifagc.w0A = 0x3ff;
+ s->config.ifagc.w0C = 0x388;
+
+ /* for signal strenght calculations */
+ s->config.ss76 = 820;
+ s->config.ss78 = 2200;
+ s->config.ss7A = 150;
+
+ /* HI_CfgCommand */
+ s->config.w50 = 4;
+ s->config.w52 = 9; // 0xf;
+
+ s->config.f_if = 42800000; /* d14: intermediate frequency [Hz] */
+ s->config.f_osc = 48000; /* s66 : oscillator frequency [kHz] */
+ s->config.w92 = 12000; // 20000;
+
+ s->config.w9C = 0x000e;
+ s->config.w9E = 0x0000;
+
+ /* ConfigureMPEGOutput params */
+ s->config.wA0 = 4;
+ s->config.w98 = 1; // 0;
+ s->config.w9A = 1;
+
+ /* get chip revision */
+ rc = RD16(s, 0x2410019);
+ if (rc < 0)
+ return -ENODEV;
+
+ if (rc == 0) {
+ printk(KERN_INFO "%s: chip revision A2\n", mod_name);
+ rc = drx_load_fw(s, DRXD_FW_A2);
+ } else {
+
+ rc = (rc >> 12) - 3;
+ switch (rc) {
+ case 1:
+ s->flags |= F_SET_0D4h;
+ case 0:
+ case 4:
+ s->flags |= F_SET_0D0h;
+ break;
+ case 2:
+ case 5:
+ break;
+ case 3:
+ s->flags |= F_SET_0D4h;
+ break;
+ default:
+ return -ENODEV;
+ };
+ printk(KERN_INFO "%s: chip revision B1.%d\n", mod_name, rc);
+ rc = drx_load_fw(s, DRXD_FW_B1);
+ }
+ if (rc < 0)
+ goto error;
+
+ rc = WR16(s, 0x0420033, 0x3973);
+ if (rc < 0)
+ goto error;
+
+ rc = HI_Command(s, 2);
+
+ msleep(1);
+
+ if (s->chip_rev == DRXD_FW_A2) {
+ rc = WR16(s, 0x043012d, 0x47F);
+ if (rc < 0)
+ goto error;
+ }
+ rc = WR16_E0(s, 0x0400000, 0);
+ if (rc < 0)
+ goto error;
+
+ if (s->config.w92 > 20000 || s->config.w92 % 4000) {
+ printk(KERN_ERR "%s: invalid osc frequency\n", mod_name);
+ rc = -1;
+ goto error;
+ }
+
+ rc = WR16(s, 0x2410010, 1);
+ if (rc < 0)
+ goto error;
+ rc = WR16(s, 0x2410011, 0x15);
+ if (rc < 0)
+ goto error;
+ rc = WR16(s, 0x2410012, s->config.w92 / 4000);
+ if (rc < 0)
+ goto error;
+#ifdef ORIG_FW
+ rc = WR16(s, 0x2410015, 2);
+ if (rc < 0)
+ goto error;
+#endif
+ rc = WR16(s, 0x2410017, 0x3973);
+ if (rc < 0)
+ goto error;
+
+ s->f_osc = s->config.f_osc * 1000; /* initial estimator */
+
+ s->config.w56 = 1;
+
+ rc = HI_CfgCommand(s);
+ if (rc < 0)
+ goto error;
+
+ rc = write_fw(s, DRXD_InitAtomicRead);
+ if (rc < 0)
+ goto error;
+
+ if (s->chip_rev == DRXD_FW_A2) {
+ rc = WR16(s, 0x2150013, 0);
+ if (rc < 0)
+ goto error;
+ }
+
+ rc = WR16_E0(s, 0x0400002, 0);
+ if (rc < 0)
+ goto error;
+ rc = WR16(s, 0x0400002, 0);
+ if (rc < 0)
+ goto error;
+
+ if (s->chip_rev == DRXD_FW_A2) {
+ rc = write_fw(s, DRXD_ResetCEFR);
+ if (rc < 0)
+ goto error;
+ }
+ rc = write_fw(s, DRXD_microcode);
+ if (rc < 0)
+ goto error;
+
+ s->config.w9C = 0x0e;
+ if (s->flags & F_SET_0D0h) {
+ s->config.w9C = 0;
+ rc = RD16(s, 0x0c20010);
+ if (rc < 0)
+ goto write_DRXD_InitFE_1;
+
+ rc &= ~0x1000;
+ rc = WR16(s, 0x0c20010, rc);
+ if (rc < 0)
+ goto write_DRXD_InitFE_1;
+
+ rc = RD16(s, 0x0c20011);
+ if (rc < 0)
+ goto write_DRXD_InitFE_1;
+
+ rc &= ~0x8;
+ rc = WR16(s, 0x0c20011, rc);
+ if (rc < 0)
+ goto write_DRXD_InitFE_1;
+
+ rc = WR16(s, 0x0c20012, 1);
+ }
+
+ write_DRXD_InitFE_1:
+
+ rc = write_fw(s, DRXD_InitFE_1);
+ if (rc < 0)
+ goto error;
+
+ rc = 1;
+ if (s->chip_rev == DRXD_FW_B1) {
+ if (s->flags & F_SET_0D0h)
+ rc = 0;
+ } else {
+ if (s->flags & F_SET_0D0h)
+ rc = 4;
+ }
+
+ rc = WR16(s, 0x0C20012, rc);
+ if (rc < 0)
+ goto error;
+
+ rc = WR16(s, 0x0C20013, s->config.w9E);
+ if (rc < 0)
+ goto error;
+ rc = WR16(s, 0x0C20015, s->config.w9C);
+ if (rc < 0)
+ goto error;
+
+ rc = write_fw(s, DRXD_InitFE_2);
+ if (rc < 0)
+ goto error;
+ rc = write_fw(s, DRXD_InitFT);
+ if (rc < 0)
+ goto error;
+ rc = write_fw(s, DRXD_InitCP);
+ if (rc < 0)
+ goto error;
+ rc = write_fw(s, DRXD_InitCE);
+ if (rc < 0)
+ goto error;
+ rc = write_fw(s, DRXD_InitEQ);
+ if (rc < 0)
+ goto error;
+ rc = write_fw(s, DRXD_InitEC);
+ if (rc < 0)
+ goto error;
+ rc = write_fw(s, DRXD_InitSC);
+ if (rc < 0)
+ goto error;
+
+ rc = SetCfgIfAgc(s, &s->config.ifagc);
+ if (rc < 0)
+ goto error;
+
+ rc = SetCfgRfAgc(s, &s->config.rfagc);
+ if (rc < 0)
+ goto error;
+
+ rc = ConfigureMPEGOutput(s, 1);
+ rc = WR16(s, 0x08201fe, 0x0017);
+ rc = WR16(s, 0x08201ff, 0x0101);
+
+ s->config.d5C = 0;
+ s->config.d60 = 1;
+ s->config.d48 = 1;
+ error:
+ return rc;
+}
+
+static int drx397x_get_frontend(struct dvb_frontend *fe,
+ struct dvb_frontend_parameters *params)
+{
+ return 0;
+}
+
+static int drx397x_set_frontend(struct dvb_frontend *fe,
+ struct dvb_frontend_parameters *params)
+{
+ struct drx397xD_state *s = fe->demodulator_priv;
+
+ s->config.s20d24 = 1; // 0;
+ return drx_tune(s, params);
+}
+
+static int drx397x_get_tune_settings(struct dvb_frontend *fe,
+ struct dvb_frontend_tune_settings
+ *fe_tune_settings)
+{
+ fe_tune_settings->min_delay_ms = 10000;
+ fe_tune_settings->step_size = 0;
+ fe_tune_settings->max_drift = 0;
+ return 0;
+}
+
+static int drx397x_read_status(struct dvb_frontend *fe, fe_status_t * status)
+{
+ struct drx397xD_state *s = fe->demodulator_priv;
+ int lockstat;
+
+ GetLockStatus(s, &lockstat);
+ /* TODO */
+// if (lockstat & 1)
+// CorrectSysClockDeviation(s);
+
+ *status = 0;
+ if (lockstat & 2) {
+ CorrectSysClockDeviation(s);
+ ConfigureMPEGOutput(s, 1);
+ *status = FE_HAS_LOCK | FE_HAS_SYNC | FE_HAS_VITERBI;
+ }
+ if (lockstat & 4) {
+ *status |= FE_HAS_CARRIER | FE_HAS_SIGNAL;
+ }
+
+ return 0;
+}
+
+static int drx397x_read_ber(struct dvb_frontend *fe, unsigned int *ber)
+{
+ *ber = 0;
+ return 0;
+}
+
+static int drx397x_read_snr(struct dvb_frontend *fe, u16 * snr)
+{
+ *snr = 0;
+ return 0;
+}
+
+static int drx397x_read_signal_strength(struct dvb_frontend *fe, u16 * strength)
+{
+ struct drx397xD_state *s = fe->demodulator_priv;
+ int rc;
+
+ if (s->config.ifagc.d00 == 2) {
+ *strength = 0xffff;
+ return 0;
+ }
+ rc = RD16(s, 0x0c20035);
+ if (rc < 0) {
+ *strength = 0;
+ return 0;
+ }
+ rc &= 0x3ff;
+ /* Signal strength is calculated using the following formula:
+ *
+ * a = 2200 * 150 / (2200 + 150);
+ * a = a * 3300 / (a + 820);
+ * b = 2200 * 3300 / (2200 + 820);
+ * c = (((b-a) * rc) >> 10 + a) << 4;
+ * strength = ~c & 0xffff;
+ *
+ * The following does the same but with less rounding errors:
+ */
+ *strength = ~(7720 + (rc * 30744 >> 10));
+ return 0;
+}
+
+static int drx397x_read_ucblocks(struct dvb_frontend *fe,
+ unsigned int *ucblocks)
+{
+ *ucblocks = 0;
+ return 0;
+}
+
+static int drx397x_sleep(struct dvb_frontend *fe)
+{
+ return 0;
+}
+
+static void drx397x_release(struct dvb_frontend *fe)
+{
+ struct drx397xD_state *s = fe->demodulator_priv;
+ printk(KERN_INFO "%s: release demodulator\n", mod_name);
+ if (s) {
+ drx_release_fw(s);
+ kfree(s);
+ }
+
+}
+
+static struct dvb_frontend_ops drx397x_ops = {
+
+ .info = {
+ .name = "Micronas DRX397xD DVB-T Frontend",
+ .type = FE_OFDM,
+ .frequency_min = 47125000,
+ .frequency_max = 855250000,
+ .frequency_stepsize = 166667,
+ .frequency_tolerance = 0,
+ .caps = /* 0x0C01B2EAE */
+ FE_CAN_FEC_1_2 | // = 0x2,
+ FE_CAN_FEC_2_3 | // = 0x4,
+ FE_CAN_FEC_3_4 | // = 0x8,
+ FE_CAN_FEC_5_6 | // = 0x20,
+ FE_CAN_FEC_7_8 | // = 0x80,
+ FE_CAN_FEC_AUTO | // = 0x200,
+ FE_CAN_QPSK | // = 0x400,
+ FE_CAN_QAM_16 | // = 0x800,
+ FE_CAN_QAM_64 | // = 0x2000,
+ FE_CAN_QAM_AUTO | // = 0x10000,
+ FE_CAN_TRANSMISSION_MODE_AUTO | // = 0x20000,
+ FE_CAN_GUARD_INTERVAL_AUTO | // = 0x80000,
+ FE_CAN_HIERARCHY_AUTO | // = 0x100000,
+ FE_CAN_RECOVER | // = 0x40000000,
+ FE_CAN_MUTE_TS // = 0x80000000
+ },
+
+ .release = drx397x_release,
+ .init = drx397x_init,
+ .sleep = drx397x_sleep,
+
+ .set_frontend = drx397x_set_frontend,
+ .get_tune_settings = drx397x_get_tune_settings,
+ .get_frontend = drx397x_get_frontend,
+
+ .read_status = drx397x_read_status,
+ .read_snr = drx397x_read_snr,
+ .read_signal_strength = drx397x_read_signal_strength,
+ .read_ber = drx397x_read_ber,
+ .read_ucblocks = drx397x_read_ucblocks,
+};
+
+struct dvb_frontend *drx397xD_attach(const struct drx397xD_config *config,
+ struct i2c_adapter *i2c)
+{
+ struct drx397xD_state *s = NULL;
+
+ /* allocate memory for the internal state */
+ s = kzalloc(sizeof(struct drx397xD_state), GFP_KERNEL);
+ if (s == NULL)
+ goto error;
+
+ /* setup the state */
+ s->i2c = i2c;
+ memcpy(&s->config, config, sizeof(struct drx397xD_config));
+
+ /* check if the demod is there */
+ if (RD16(s, 0x2410019) < 0)
+ goto error;
+
+ /* create dvb_frontend */
+ memcpy(&s->frontend.ops, &drx397x_ops, sizeof(struct dvb_frontend_ops));
+ s->frontend.demodulator_priv = s;
+
+ return &s->frontend;
+ error:
+ kfree(s);
+ return NULL;
+}
+
+MODULE_DESCRIPTION("Micronas DRX397xD DVB-T Frontend");
+MODULE_AUTHOR("Henk Vergonet");
+MODULE_LICENSE("GPL");
+
+EXPORT_SYMBOL(drx397xD_attach);
diff --git a/drivers/media/dvb/frontends/drx397xD.h b/drivers/media/dvb/frontends/drx397xD.h
new file mode 100644
index 00000000000..ddc7a07971b
--- /dev/null
+++ b/drivers/media/dvb/frontends/drx397xD.h
@@ -0,0 +1,130 @@
+/*
+ * Driver for Micronas DVB-T drx397xD demodulator
+ *
+ * Copyright (C) 2007 Henk vergonet <Henk.Vergonet@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 _DRX397XD_H_INCLUDED
+#define _DRX397XD_H_INCLUDED
+
+#include <linux/dvb/frontend.h>
+
+#define DRX_F_STEPSIZE 166667
+#define DRX_F_OFFSET 36000000
+
+#define I2C_ADR_C0(x) \
+( (u32)cpu_to_le32( \
+ (u32)( \
+ (((u32)(x) & (u32)0x000000ffUL) ) | \
+ (((u32)(x) & (u32)0x0000ff00UL) << 16) | \
+ (((u32)(x) & (u32)0x0fff0000UL) >> 8) | \
+ ( (u32)0x00c00000UL) \
+ )) \
+)
+
+#define I2C_ADR_E0(x) \
+( (u32)cpu_to_le32( \
+ (u32)( \
+ (((u32)(x) & (u32)0x000000ffUL) ) | \
+ (((u32)(x) & (u32)0x0000ff00UL) << 16) | \
+ (((u32)(x) & (u32)0x0fff0000UL) >> 8) | \
+ ( (u32)0x00e00000UL) \
+ )) \
+)
+
+struct drx397xD_CfgRfAgc /* 0x7c */
+{
+ int d00; /* 2 */
+ u16 w04;
+ u16 w06;
+};
+
+struct drx397xD_CfgIfAgc /* 0x68 */
+{
+ int d00; /* 0 */
+ u16 w04; /* 0 */
+ u16 w06;
+ u16 w08;
+ u16 w0A;
+ u16 w0C;
+};
+
+struct drx397xD_s20 {
+ int d04;
+ u32 d18;
+ u32 d1C;
+ u32 d20;
+ u32 d14;
+ u32 d24;
+ u32 d0C;
+ u32 d08;
+};
+
+struct drx397xD_config
+{
+ /* demodulator's I2C address */
+ u8 demod_address; /* 0x0f */
+
+ struct drx397xD_CfgIfAgc ifagc; /* 0x68 */
+ struct drx397xD_CfgRfAgc rfagc; /* 0x7c */
+ u32 s20d24;
+
+ /* HI_CfgCommand parameters */
+ u16 w50, w52, /* w54, */ w56;
+
+ int d5C;
+ int d60;
+ int d48;
+ int d28;
+
+ u32 f_if; /* d14: intermediate frequency [Hz] */
+ /* 36000000 on Cinergy 2400i DT */
+ /* 42800000 on Pinnacle Hybrid PRO 330e */
+
+ u16 f_osc; /* s66: 48000 oscillator frequency [kHz] */
+
+ u16 w92; /* 20000 */
+
+ u16 wA0;
+ u16 w98;
+ u16 w9A;
+
+ u16 w9C; /* 0xe0 */
+ u16 w9E; /* 0x00 */
+
+ /* used for signal strength calculations in
+ drx397x_read_signal_strength
+ */
+ u16 ss78; // 2200
+ u16 ss7A; // 150
+ u16 ss76; // 820
+};
+
+#if defined(CONFIG_DVB_DRX397XD) || (defined(CONFIG_DVB_DRX397XD_MODULE) && defined(MODULE))
+extern struct dvb_frontend* drx397xD_attach(const struct drx397xD_config *config,
+ struct i2c_adapter *i2c);
+#else
+static inline struct dvb_frontend* drx397xD_attach(const struct drx397xD_config *config,
+ struct i2c_adapter *i2c)
+{
+ printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __FUNCTION__);
+ return NULL;
+}
+#endif /* CONFIG_DVB_DRX397XD */
+
+#endif /* _DRX397XD_H_INCLUDED */
diff --git a/drivers/media/dvb/frontends/drx397xD_fw.h b/drivers/media/dvb/frontends/drx397xD_fw.h
new file mode 100644
index 00000000000..01de02a81cd
--- /dev/null
+++ b/drivers/media/dvb/frontends/drx397xD_fw.h
@@ -0,0 +1,40 @@
+/*
+ * Firmware definitions for Micronas drx397xD
+ *
+ * Copyright (C) 2007 Henk Vergonet <Henk.Vergonet@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, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifdef _FW_ENTRY
+ _FW_ENTRY("drx397xD.A2.fw", DRXD_FW_A2 = 0 ),
+ _FW_ENTRY("drx397xD.B1.fw", DRXD_FW_B1 ),
+#undef _FW_ENTRY
+#endif /* _FW_ENTRY */
+
+#ifdef _BLOB_ENTRY
+ _BLOB_ENTRY("InitAtomicRead", DRXD_InitAtomicRead = 0 ),
+ _BLOB_ENTRY("InitCE", DRXD_InitCE ),
+ _BLOB_ENTRY("InitCP", DRXD_InitCP ),
+ _BLOB_ENTRY("InitEC", DRXD_InitEC ),
+ _BLOB_ENTRY("InitEQ", DRXD_InitEQ ),
+ _BLOB_ENTRY("InitFE_1", DRXD_InitFE_1 ),
+ _BLOB_ENTRY("InitFE_2", DRXD_InitFE_2 ),
+ _BLOB_ENTRY("InitFT", DRXD_InitFT ),
+ _BLOB_ENTRY("InitSC", DRXD_InitSC ),
+ _BLOB_ENTRY("ResetCEFR", DRXD_ResetCEFR ),
+ _BLOB_ENTRY("ResetECRAM", DRXD_ResetECRAM ),
+ _BLOB_ENTRY("microcode", DRXD_microcode ),
+#undef _BLOB_ENTRY
+#endif /* _BLOB_ENTRY */
diff --git a/drivers/media/dvb/frontends/dvb-pll.c b/drivers/media/dvb/frontends/dvb-pll.c
index a054894ff48..ea058153ebf 100644
--- a/drivers/media/dvb/frontends/dvb-pll.c
+++ b/drivers/media/dvb/frontends/dvb-pll.c
@@ -343,6 +343,52 @@ static struct dvb_pll_desc dvb_pll_opera1 = {
}
};
+static void samsung_dtos403ih102a_set(struct dvb_frontend *fe, u8 *buf,
+ const struct dvb_frontend_parameters *params)
+{
+ struct dvb_pll_priv *priv = fe->tuner_priv;
+ struct i2c_msg msg = {
+ .addr = priv->pll_i2c_address,
+ .flags = 0,
+ .buf = buf,
+ .len = 4
+ };
+ int result;
+
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
+
+ result = i2c_transfer(priv->i2c, &msg, 1);
+ if (result != 1)
+ printk(KERN_ERR "%s: i2c_transfer failed:%d",
+ __func__, result);
+
+ buf[2] = 0x9e;
+ buf[3] = 0x90;
+
+ return;
+}
+
+/* unknown pll used in Samsung DTOS403IH102A DVB-C tuner */
+static struct dvb_pll_desc dvb_pll_samsung_dtos403ih102a = {
+ .name = "Samsung DTOS403IH102A",
+ .min = 44250000,
+ .max = 858000000,
+ .iffreq = 36125000,
+ .count = 8,
+ .set = samsung_dtos403ih102a_set,
+ .entries = {
+ { 135000000, 62500, 0xbe, 0x01 },
+ { 177000000, 62500, 0xf6, 0x01 },
+ { 370000000, 62500, 0xbe, 0x02 },
+ { 450000000, 62500, 0xf6, 0x02 },
+ { 466000000, 62500, 0xfe, 0x02 },
+ { 538000000, 62500, 0xbe, 0x08 },
+ { 826000000, 62500, 0xf6, 0x08 },
+ { 999999999, 62500, 0xfe, 0x08 },
+ }
+};
+
/* ----------------------------------------------------------- */
static struct dvb_pll_desc *pll_list[] = {
@@ -360,6 +406,7 @@ static struct dvb_pll_desc *pll_list[] = {
[DVB_PLL_SAMSUNG_TBMV] = &dvb_pll_samsung_tbmv,
[DVB_PLL_PHILIPS_SD1878_TDA8261] = &dvb_pll_philips_sd1878_tda8261,
[DVB_PLL_OPERA1] = &dvb_pll_opera1,
+ [DVB_PLL_SAMSUNG_DTOS403IH102A] = &dvb_pll_samsung_dtos403ih102a,
};
/* ----------------------------------------------------------- */
diff --git a/drivers/media/dvb/frontends/dvb-pll.h b/drivers/media/dvb/frontends/dvb-pll.h
index 872ca29e7cf..05239f579cc 100644
--- a/drivers/media/dvb/frontends/dvb-pll.h
+++ b/drivers/media/dvb/frontends/dvb-pll.h
@@ -22,6 +22,7 @@
#define DVB_PLL_SAMSUNG_TBMV 11
#define DVB_PLL_PHILIPS_SD1878_TDA8261 12
#define DVB_PLL_OPERA1 13
+#define DVB_PLL_SAMSUNG_DTOS403IH102A 14
/**
* Attach a dvb-pll to the supplied frontend structure.
diff --git a/drivers/media/dvb/frontends/lgdt330x.c b/drivers/media/dvb/frontends/lgdt330x.c
index f0195c8272f..056387b41a8 100644
--- a/drivers/media/dvb/frontends/lgdt330x.c
+++ b/drivers/media/dvb/frontends/lgdt330x.c
@@ -226,11 +226,16 @@ static int lgdt330x_init(struct dvb_frontend* fe)
0x4c, 0x14
};
- static u8 flip_lgdt3303_init_data[] = {
+ static u8 flip_1_lgdt3303_init_data[] = {
0x4c, 0x14,
0x87, 0xf3
};
+ static u8 flip_2_lgdt3303_init_data[] = {
+ 0x4c, 0x14,
+ 0x87, 0xda
+ };
+
struct lgdt330x_state* state = fe->demodulator_priv;
char *chip_name;
int err;
@@ -243,10 +248,19 @@ static int lgdt330x_init(struct dvb_frontend* fe)
break;
case LGDT3303:
chip_name = "LGDT3303";
- if (state->config->clock_polarity_flip) {
- err = i2c_write_demod_bytes(state, flip_lgdt3303_init_data,
- sizeof(flip_lgdt3303_init_data));
- } else {
+ switch (state->config->clock_polarity_flip) {
+ case 2:
+ err = i2c_write_demod_bytes(state,
+ flip_2_lgdt3303_init_data,
+ sizeof(flip_2_lgdt3303_init_data));
+ break;
+ case 1:
+ err = i2c_write_demod_bytes(state,
+ flip_1_lgdt3303_init_data,
+ sizeof(flip_1_lgdt3303_init_data));
+ break;
+ case 0:
+ default:
err = i2c_write_demod_bytes(state, lgdt3303_init_data,
sizeof(lgdt3303_init_data));
}
diff --git a/drivers/media/dvb/frontends/s5h1409.c b/drivers/media/dvb/frontends/s5h1409.c
index b999ec424ff..7500a1c53e6 100644
--- a/drivers/media/dvb/frontends/s5h1409.c
+++ b/drivers/media/dvb/frontends/s5h1409.c
@@ -1,7 +1,7 @@
/*
Samsung S5H1409 VSB/QAM demodulator driver
- Copyright (C) 2006 Steven Toth <stoth@hauppauge.com>
+ Copyright (C) 2006 Steven Toth <stoth@linuxtv.org>
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
@@ -26,7 +26,6 @@
#include <linux/slab.h>
#include <linux/delay.h>
#include "dvb_frontend.h"
-#include "dvb-pll.h"
#include "s5h1409.h"
struct s5h1409_state {
@@ -405,6 +404,7 @@ static int s5h1409_enable_modulation(struct dvb_frontend* fe,
break;
case QAM_64:
case QAM_256:
+ case QAM_AUTO:
dprintk("%s() QAM_AUTO (64/256)\n", __func__);
if (state->if_freq != S5H1409_QAM_IF_FREQ)
s5h1409_set_if_freq(fe, S5H1409_QAM_IF_FREQ);
diff --git a/drivers/media/dvb/frontends/s5h1409.h b/drivers/media/dvb/frontends/s5h1409.h
index 59f4335964c..d1a1d2eb8e1 100644
--- a/drivers/media/dvb/frontends/s5h1409.h
+++ b/drivers/media/dvb/frontends/s5h1409.h
@@ -1,7 +1,7 @@
/*
Samsung S5H1409 VSB/QAM demodulator driver
- Copyright (C) 2006 Steven Toth <stoth@hauppauge.com>
+ Copyright (C) 2006 Steven Toth <stoth@linuxtv.org>
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
diff --git a/drivers/media/dvb/frontends/s5h1411.c b/drivers/media/dvb/frontends/s5h1411.c
index eb5bfc99d4e..2da1a3763de 100644
--- a/drivers/media/dvb/frontends/s5h1411.c
+++ b/drivers/media/dvb/frontends/s5h1411.c
@@ -1,7 +1,7 @@
/*
Samsung S5H1411 VSB/QAM demodulator driver
- Copyright (C) 2008 Steven Toth <stoth@hauppauge.com>
+ Copyright (C) 2008 Steven Toth <stoth@linuxtv.org>
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
@@ -26,7 +26,6 @@
#include <linux/slab.h>
#include <linux/delay.h>
#include "dvb_frontend.h"
-#include "dvb-pll.h"
#include "s5h1411.h"
struct s5h1411_state {
@@ -489,6 +488,7 @@ static int s5h1411_enable_modulation(struct dvb_frontend *fe,
break;
case QAM_64:
case QAM_256:
+ case QAM_AUTO:
dprintk("%s() QAM_AUTO (64/256)\n", __func__);
s5h1411_set_if_freq(fe, state->config->qam_if);
s5h1411_writereg(state, S5H1411_I2C_TOP_ADDR, 0x00, 0x0171);
diff --git a/drivers/media/dvb/frontends/s5h1411.h b/drivers/media/dvb/frontends/s5h1411.h
index 1855f64ed4d..7d542bc00c4 100644
--- a/drivers/media/dvb/frontends/s5h1411.h
+++ b/drivers/media/dvb/frontends/s5h1411.h
@@ -1,7 +1,7 @@
/*
Samsung S5H1411 VSB/QAM demodulator driver
- Copyright (C) 2008 Steven Toth <stoth@hauppauge.com>
+ Copyright (C) 2008 Steven Toth <stoth@linuxtv.org>
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
diff --git a/drivers/media/dvb/frontends/s5h1420.c b/drivers/media/dvb/frontends/s5h1420.c
index 720ed9ff7c5..747d3fa2e5e 100644
--- a/drivers/media/dvb/frontends/s5h1420.c
+++ b/drivers/media/dvb/frontends/s5h1420.c
@@ -915,7 +915,8 @@ struct dvb_frontend *s5h1420_attach(const struct s5h1420_config *config,
state->frontend.demodulator_priv = state;
/* create tuner i2c adapter */
- strncpy(state->tuner_i2c_adapter.name, "S5H1420-PN1010 tuner I2C bus", I2C_NAME_SIZE);
+ strlcpy(state->tuner_i2c_adapter.name, "S5H1420-PN1010 tuner I2C bus",
+ sizeof(state->tuner_i2c_adapter.name));
state->tuner_i2c_adapter.class = I2C_CLASS_TV_DIGITAL,
state->tuner_i2c_adapter.algo = &s5h1420_tuner_i2c_algo;
state->tuner_i2c_adapter.algo_data = NULL;
diff --git a/drivers/media/dvb/frontends/tda10023.c b/drivers/media/dvb/frontends/tda10023.c
index c6ff5b82ff8..a3c34eecdee 100644
--- a/drivers/media/dvb/frontends/tda10023.c
+++ b/drivers/media/dvb/frontends/tda10023.c
@@ -38,75 +38,29 @@
#include "dvb_frontend.h"
#include "tda1002x.h"
+#define REG0_INIT_VAL 0x23
struct tda10023_state {
struct i2c_adapter* i2c;
/* configuration settings */
- const struct tda1002x_config* config;
+ const struct tda10023_config *config;
struct dvb_frontend frontend;
u8 pwm;
u8 reg0;
-};
+ /* clock settings */
+ u32 xtal;
+ u8 pll_m;
+ u8 pll_p;
+ u8 pll_n;
+ u32 sysclk;
+};
#define dprintk(x...)
static int verbose;
-#define XTAL 28920000UL
-#define PLL_M 8UL
-#define PLL_P 4UL
-#define PLL_N 1UL
-#define SYSCLK (XTAL*PLL_M/(PLL_N*PLL_P)) // -> 57840000
-
-static u8 tda10023_inittab[]={
- // reg mask val
- 0x2a,0xff,0x02, // PLL3, Bypass, Power Down
- 0xff,0x64,0x00, // Sleep 100ms
- 0x2a,0xff,0x03, // PLL3, Bypass, Power Down
- 0xff,0x64,0x00, // Sleep 100ms
- 0x28,0xff,PLL_M-1, // PLL1 M=8
- 0x29,0xff,((PLL_P-1)<<6)|(PLL_N-1), // PLL2
- 0x00,0xff,0x23, // GPR FSAMPLING=1
- 0x2a,0xff,0x08, // PLL3 PSACLK=1
- 0xff,0x64,0x00, // Sleep 100ms
- 0x1f,0xff,0x00, // RESET
- 0xff,0x64,0x00, // Sleep 100ms
- 0xe6,0x0c,0x04, // RSCFG_IND
- 0x10,0xc0,0x80, // DECDVBCFG1 PBER=1
-
- 0x0e,0xff,0x82, // GAIN1
- 0x03,0x08,0x08, // CLKCONF DYN=1
- 0x2e,0xbf,0x30, // AGCCONF2 TRIAGC=0,POSAGC=ENAGCIF=1 PPWMTUN=0 PPWMIF=0
- 0x01,0xff,0x30, // AGCREF
- 0x1e,0x84,0x84, // CONTROL SACLK_ON=1
- 0x1b,0xff,0xc8, // ADC TWOS=1
- 0x3b,0xff,0xff, // IFMAX
- 0x3c,0xff,0x00, // IFMIN
- 0x34,0xff,0x00, // PWMREF
- 0x35,0xff,0xff, // TUNMAX
- 0x36,0xff,0x00, // TUNMIN
- 0x06,0xff,0x7f, // EQCONF1 POSI=7 ENADAPT=ENEQUAL=DFE=1 // 0x77
- 0x1c,0x30,0x30, // EQCONF2 STEPALGO=SGNALGO=1
- 0x37,0xff,0xf6, // DELTAF_LSB
- 0x38,0xff,0xff, // DELTAF_MSB
- 0x02,0xff,0x93, // AGCCONF1 IFS=1 KAGCIF=2 KAGCTUN=3
- 0x2d,0xff,0xf6, // SWEEP SWPOS=1 SWDYN=7 SWSTEP=1 SWLEN=2
- 0x04,0x10,0x00, // SWRAMP=1
- 0x12,0xff,0xa1, // INTP1 POCLKP=1 FEL=1 MFS=0
- 0x2b,0x01,0xa1, // INTS1
- 0x20,0xff,0x04, // INTP2 SWAPP=? MSBFIRSTP=? INTPSEL=?
- 0x2c,0xff,0x0d, // INTP/S TRIP=0 TRIS=0
- 0xc4,0xff,0x00,
- 0xc3,0x30,0x00,
- 0xb5,0xff,0x19, // ERAGC_THD
- 0x00,0x03,0x01, // GPR, CLBS soft reset
- 0x00,0x03,0x03, // GPR, CLBS soft reset
- 0xff,0x64,0x00, // Sleep 100ms
- 0xff,0xff,0xff
-};
-
static u8 tda10023_readreg (struct tda10023_state* state, u8 reg)
{
u8 b0 [] = { reg };
@@ -219,30 +173,34 @@ static int tda10023_set_symbolrate (struct tda10023_state* state, u32 sr)
s16 SFIL=0;
u16 NDEC = 0;
- if (sr < (u32)(SYSCLK/98.40)) {
+ /* avoid floating point operations multiplying syscloc and divider
+ by 10 */
+ u32 sysclk_x_10 = state->sysclk * 10;
+
+ if (sr < (u32)(sysclk_x_10/984)) {
NDEC=3;
SFIL=1;
- } else if (sr<(u32)(SYSCLK/64.0)) {
+ } else if (sr < (u32)(sysclk_x_10/640)) {
NDEC=3;
SFIL=0;
- } else if (sr<(u32)(SYSCLK/49.2)) {
+ } else if (sr < (u32)(sysclk_x_10/492)) {
NDEC=2;
SFIL=1;
- } else if (sr<(u32)(SYSCLK/32.0)) {
+ } else if (sr < (u32)(sysclk_x_10/320)) {
NDEC=2;
SFIL=0;
- } else if (sr<(u32)(SYSCLK/24.6)) {
+ } else if (sr < (u32)(sysclk_x_10/246)) {
NDEC=1;
SFIL=1;
- } else if (sr<(u32)(SYSCLK/16.0)) {
+ } else if (sr < (u32)(sysclk_x_10/160)) {
NDEC=1;
SFIL=0;
- } else if (sr<(u32)(SYSCLK/12.3)) {
+ } else if (sr < (u32)(sysclk_x_10/123)) {
NDEC=0;
SFIL=1;
}
- BDRI=SYSCLK*16;
+ BDRI = (state->sysclk)*16;
BDRI>>=NDEC;
BDRI +=sr/2;
BDRI /=sr;
@@ -255,11 +213,12 @@ static int tda10023_set_symbolrate (struct tda10023_state* state, u32 sr)
BDRX=1<<(24+NDEC);
BDRX*=sr;
- do_div(BDRX,SYSCLK); // BDRX/=SYSCLK;
+ do_div(BDRX, state->sysclk); /* BDRX/=SYSCLK; */
BDR=(s32)BDRX;
}
-// printk("Symbolrate %i, BDR %i BDRI %i, NDEC %i\n",sr,BDR,BDRI,NDEC);
+ dprintk("Symbolrate %i, BDR %i BDRI %i, NDEC %i\n",
+ sr, BDR, BDRI, NDEC);
tda10023_writebit (state, 0x03, 0xc0, NDEC<<6);
tda10023_writereg (state, 0x0a, BDR&255);
tda10023_writereg (state, 0x0b, (BDR>>8)&255);
@@ -272,8 +231,67 @@ static int tda10023_set_symbolrate (struct tda10023_state* state, u32 sr)
static int tda10023_init (struct dvb_frontend *fe)
{
struct tda10023_state* state = fe->demodulator_priv;
+ u8 tda10023_inittab[] = {
+/* reg mask val */
+/* 000 */ 0x2a, 0xff, 0x02, /* PLL3, Bypass, Power Down */
+/* 003 */ 0xff, 0x64, 0x00, /* Sleep 100ms */
+/* 006 */ 0x2a, 0xff, 0x03, /* PLL3, Bypass, Power Down */
+/* 009 */ 0xff, 0x64, 0x00, /* Sleep 100ms */
+ /* PLL1 */
+/* 012 */ 0x28, 0xff, (state->pll_m-1),
+ /* PLL2 */
+/* 015 */ 0x29, 0xff, ((state->pll_p-1)<<6)|(state->pll_n-1),
+ /* GPR FSAMPLING=1 */
+/* 018 */ 0x00, 0xff, REG0_INIT_VAL,
+/* 021 */ 0x2a, 0xff, 0x08, /* PLL3 PSACLK=1 */
+/* 024 */ 0xff, 0x64, 0x00, /* Sleep 100ms */
+/* 027 */ 0x1f, 0xff, 0x00, /* RESET */
+/* 030 */ 0xff, 0x64, 0x00, /* Sleep 100ms */
+/* 033 */ 0xe6, 0x0c, 0x04, /* RSCFG_IND */
+/* 036 */ 0x10, 0xc0, 0x80, /* DECDVBCFG1 PBER=1 */
+
+/* 039 */ 0x0e, 0xff, 0x82, /* GAIN1 */
+/* 042 */ 0x03, 0x08, 0x08, /* CLKCONF DYN=1 */
+/* 045 */ 0x2e, 0xbf, 0x30, /* AGCCONF2 TRIAGC=0,POSAGC=ENAGCIF=1
+ PPWMTUN=0 PPWMIF=0 */
+/* 048 */ 0x01, 0xff, 0x30, /* AGCREF */
+/* 051 */ 0x1e, 0x84, 0x84, /* CONTROL SACLK_ON=1 */
+/* 054 */ 0x1b, 0xff, 0xc8, /* ADC TWOS=1 */
+/* 057 */ 0x3b, 0xff, 0xff, /* IFMAX */
+/* 060 */ 0x3c, 0xff, 0x00, /* IFMIN */
+/* 063 */ 0x34, 0xff, 0x00, /* PWMREF */
+/* 066 */ 0x35, 0xff, 0xff, /* TUNMAX */
+/* 069 */ 0x36, 0xff, 0x00, /* TUNMIN */
+/* 072 */ 0x06, 0xff, 0x7f, /* EQCONF1 POSI=7 ENADAPT=ENEQUAL=DFE=1 */
+/* 075 */ 0x1c, 0x30, 0x30, /* EQCONF2 STEPALGO=SGNALGO=1 */
+/* 078 */ 0x37, 0xff, 0xf6, /* DELTAF_LSB */
+/* 081 */ 0x38, 0xff, 0xff, /* DELTAF_MSB */
+/* 084 */ 0x02, 0xff, 0x93, /* AGCCONF1 IFS=1 KAGCIF=2 KAGCTUN=3 */
+/* 087 */ 0x2d, 0xff, 0xf6, /* SWEEP SWPOS=1 SWDYN=7 SWSTEP=1 SWLEN=2 */
+/* 090 */ 0x04, 0x10, 0x00, /* SWRAMP=1 */
+/* 093 */ 0x12, 0xff, TDA10023_OUTPUT_MODE_PARALLEL_B, /*
+ INTP1 POCLKP=1 FEL=1 MFS=0 */
+/* 096 */ 0x2b, 0x01, 0xa1, /* INTS1 */
+/* 099 */ 0x20, 0xff, 0x04, /* INTP2 SWAPP=? MSBFIRSTP=? INTPSEL=? */
+/* 102 */ 0x2c, 0xff, 0x0d, /* INTP/S TRIP=0 TRIS=0 */
+/* 105 */ 0xc4, 0xff, 0x00,
+/* 108 */ 0xc3, 0x30, 0x00,
+/* 111 */ 0xb5, 0xff, 0x19, /* ERAGC_THD */
+/* 114 */ 0x00, 0x03, 0x01, /* GPR, CLBS soft reset */
+/* 117 */ 0x00, 0x03, 0x03, /* GPR, CLBS soft reset */
+/* 120 */ 0xff, 0x64, 0x00, /* Sleep 100ms */
+/* 123 */ 0xff, 0xff, 0xff
+};
+ dprintk("DVB: TDA10023(%d): init chip\n", fe->dvb->num);
+
+ /* override default values if set in config */
+ if (state->config->deltaf) {
+ tda10023_inittab[80] = (state->config->deltaf & 0xff);
+ tda10023_inittab[83] = (state->config->deltaf >> 8);
+ }
- dprintk("DVB: TDA10023(%d): init chip\n", fe->adapter->num);
+ if (state->config->output_mode)
+ tda10023_inittab[95] = state->config->output_mode;
tda10023_writetab(state, tda10023_inittab);
@@ -460,12 +478,11 @@ static void tda10023_release(struct dvb_frontend* fe)
static struct dvb_frontend_ops tda10023_ops;
-struct dvb_frontend* tda10023_attach(const struct tda1002x_config* config,
- struct i2c_adapter* i2c,
+struct dvb_frontend *tda10023_attach(const struct tda10023_config *config,
+ struct i2c_adapter *i2c,
u8 pwm)
{
struct tda10023_state* state = NULL;
- int i;
/* allocate memory for the internal state */
state = kzalloc(sizeof(struct tda10023_state), GFP_KERNEL);
@@ -474,22 +491,40 @@ struct dvb_frontend* tda10023_attach(const struct tda1002x_config* config,
/* setup the state */
state->config = config;
state->i2c = i2c;
- memcpy(&state->frontend.ops, &tda10023_ops, sizeof(struct dvb_frontend_ops));
- state->pwm = pwm;
- for (i=0; i < ARRAY_SIZE(tda10023_inittab);i+=3) {
- if (tda10023_inittab[i] == 0x00) {
- state->reg0 = tda10023_inittab[i+2];
- break;
- }
- }
- // Wakeup if in standby
+ /* wakeup if in standby */
tda10023_writereg (state, 0x00, 0x33);
/* check if the demod is there */
if ((tda10023_readreg(state, 0x1a) & 0xf0) != 0x70) goto error;
/* create dvb_frontend */
memcpy(&state->frontend.ops, &tda10023_ops, sizeof(struct dvb_frontend_ops));
+ state->pwm = pwm;
+ state->reg0 = REG0_INIT_VAL;
+ if (state->config->xtal) {
+ state->xtal = state->config->xtal;
+ state->pll_m = state->config->pll_m;
+ state->pll_p = state->config->pll_p;
+ state->pll_n = state->config->pll_n;
+ } else {
+ /* set default values if not defined in config */
+ state->xtal = 28920000;
+ state->pll_m = 8;
+ state->pll_p = 4;
+ state->pll_n = 1;
+ }
+
+ /* calc sysclk */
+ state->sysclk = (state->xtal * state->pll_m / \
+ (state->pll_n * state->pll_p));
+
+ state->frontend.ops.info.symbol_rate_min = (state->sysclk/2)/64;
+ state->frontend.ops.info.symbol_rate_max = (state->sysclk/2)/4;
+
+ dprintk("DVB: TDA10023 %s: xtal:%d pll_m:%d pll_p:%d pll_n:%d\n",
+ __func__, state->xtal, state->pll_m, state->pll_p,
+ state->pll_n);
+
state->frontend.demodulator_priv = state;
return &state->frontend;
@@ -504,10 +539,10 @@ static struct dvb_frontend_ops tda10023_ops = {
.name = "Philips TDA10023 DVB-C",
.type = FE_QAM,
.frequency_stepsize = 62500,
- .frequency_min = 47000000,
+ .frequency_min = 47000000,
.frequency_max = 862000000,
- .symbol_rate_min = (SYSCLK/2)/64, /* SACLK/64 == (SYSCLK/2)/64 */
- .symbol_rate_max = (SYSCLK/2)/4, /* SACLK/4 */
+ .symbol_rate_min = 0, /* set in tda10023_attach */
+ .symbol_rate_max = 0, /* set in tda10023_attach */
.caps = 0x400 | //FE_CAN_QAM_4
FE_CAN_QAM_16 | FE_CAN_QAM_32 | FE_CAN_QAM_64 |
FE_CAN_QAM_128 | FE_CAN_QAM_256 |
diff --git a/drivers/media/dvb/frontends/tda1002x.h b/drivers/media/dvb/frontends/tda1002x.h
index 1bcc0d44b90..04d19418bf2 100644
--- a/drivers/media/dvb/frontends/tda1002x.h
+++ b/drivers/media/dvb/frontends/tda1002x.h
@@ -26,13 +26,37 @@
#include <linux/dvb/frontend.h>
-struct tda1002x_config
-{
+struct tda1002x_config {
/* the demodulator's i2c address */
u8 demod_address;
u8 invert;
};
+enum tda10023_output_mode {
+ TDA10023_OUTPUT_MODE_PARALLEL_A = 0xe0,
+ TDA10023_OUTPUT_MODE_PARALLEL_B = 0xa1,
+ TDA10023_OUTPUT_MODE_PARALLEL_C = 0xa0,
+ TDA10023_OUTPUT_MODE_SERIAL, /* TODO: not implemented */
+};
+
+struct tda10023_config {
+ /* the demodulator's i2c address */
+ u8 demod_address;
+ u8 invert;
+
+ /* clock settings */
+ u32 xtal; /* defaults: 28920000 */
+ u8 pll_m; /* defaults: 8 */
+ u8 pll_p; /* defaults: 4 */
+ u8 pll_n; /* defaults: 1 */
+
+ /* MPEG2 TS output mode */
+ u8 output_mode;
+
+ /* input freq offset + baseband conversion type */
+ u16 deltaf;
+};
+
#if defined(CONFIG_DVB_TDA10021) || (defined(CONFIG_DVB_TDA10021_MODULE) && defined(MODULE))
extern struct dvb_frontend* tda10021_attach(const struct tda1002x_config* config,
struct i2c_adapter* i2c, u8 pwm);
@@ -45,12 +69,15 @@ static inline struct dvb_frontend* tda10021_attach(const struct tda1002x_config*
}
#endif // CONFIG_DVB_TDA10021
-#if defined(CONFIG_DVB_TDA10023) || (defined(CONFIG_DVB_TDA10023_MODULE) && defined(MODULE))
-extern struct dvb_frontend* tda10023_attach(const struct tda1002x_config* config,
- struct i2c_adapter* i2c, u8 pwm);
+#if defined(CONFIG_DVB_TDA10023) || \
+ (defined(CONFIG_DVB_TDA10023_MODULE) && defined(MODULE))
+extern struct dvb_frontend *tda10023_attach(
+ const struct tda10023_config *config,
+ struct i2c_adapter *i2c, u8 pwm);
#else
-static inline struct dvb_frontend* tda10023_attach(const struct tda1002x_config* config,
- struct i2c_adapter* i2c, u8 pwm)
+static inline struct dvb_frontend *tda10023_attach(
+ const struct tda10023_config *config,
+ struct i2c_adapter *i2c, u8 pwm)
{
printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
return NULL;
diff --git a/drivers/media/dvb/frontends/tda10048.c b/drivers/media/dvb/frontends/tda10048.c
index 0ab8d86b3ae..04e7f1cc140 100644
--- a/drivers/media/dvb/frontends/tda10048.c
+++ b/drivers/media/dvb/frontends/tda10048.c
@@ -1,7 +1,7 @@
/*
NXP TDA10048HN DVB OFDM demodulator driver
- Copyright (C) 2008 Steven Toth <stoth@hauppauge.com>
+ Copyright (C) 2008 Steven Toth <stoth@linuxtv.org>
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
@@ -303,7 +303,7 @@ static int tda10048_firmware_upload(struct dvb_frontend *fe)
if (fw->size != TDA10048_DEFAULT_FIRMWARE_SIZE) {
printk(KERN_ERR "%s: firmware incorrect size\n", __func__);
- return -EIO;
+ ret = -EIO;
} else {
printk(KERN_INFO "%s: firmware uploading\n", __func__);
diff --git a/drivers/media/dvb/frontends/tda10048.h b/drivers/media/dvb/frontends/tda10048.h
index 2b5c78e62c8..0457b24601f 100644
--- a/drivers/media/dvb/frontends/tda10048.h
+++ b/drivers/media/dvb/frontends/tda10048.h
@@ -1,7 +1,7 @@
/*
NXP TDA10048HN DVB OFDM demodulator driver
- Copyright (C) 2008 Steven Toth <stoth@hauppauge.com>
+ Copyright (C) 2008 Steven Toth <stoth@linuxtv.org>
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
diff --git a/drivers/media/dvb/frontends/z0194a.h b/drivers/media/dvb/frontends/z0194a.h
new file mode 100644
index 00000000000..d2876d2e176
--- /dev/null
+++ b/drivers/media/dvb/frontends/z0194a.h
@@ -0,0 +1,97 @@
+/* z0194a.h Sharp z0194a tuner support
+*
+* Copyright (C) 2008 Igor M. Liplianin (liplianin@me.by)
+*
+* 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.
+*
+* see Documentation/dvb/README.dvb-usb for more information
+*/
+
+#ifndef Z0194A
+#define Z0194A
+
+static int sharp_z0194a__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;
+}
+
+static u8 sharp_z0194a__inittab[] = {
+ 0x01, 0x15,
+ 0x02, 0x00,
+ 0x03, 0x00,
+ 0x04, 0x7d, /* F22FR = 0x7d, F22 = f_VCO / 128 / 0x7d = 22 kHz */
+ 0x05, 0x35, /* I2CT = 0, SCLT = 1, SDAT = 1 */
+ 0x06, 0x40, /* DAC not used, set to high impendance mode */
+ 0x07, 0x00, /* DAC LSB */
+ 0x08, 0x40, /* DiSEqC off, LNB power on OP2/LOCK pin on */
+ 0x09, 0x00, /* FIFO */
+ 0x0c, 0x51, /* OP1 ctl = Normal, OP1 val = 1 (LNB Power ON) */
+ 0x0d, 0x82, /* DC offset compensation = ON, beta_agc1 = 2 */
+ 0x0e, 0x23, /* alpha_tmg = 2, beta_tmg = 3 */
+ 0x10, 0x3f, /* AGC2 0x3d */
+ 0x11, 0x84,
+ 0x12, 0xb9,
+ 0x15, 0xc9, /* lock detector threshold */
+ 0x16, 0x00,
+ 0x17, 0x00,
+ 0x18, 0x00,
+ 0x19, 0x00,
+ 0x1a, 0x00,
+ 0x1f, 0x50,
+ 0x20, 0x00,
+ 0x21, 0x00,
+ 0x22, 0x00,
+ 0x23, 0x00,
+ 0x28, 0x00, /* out imp: normal out type: parallel FEC mode:0 */
+ 0x29, 0x1e, /* 1/2 threshold */
+ 0x2a, 0x14, /* 2/3 threshold */
+ 0x2b, 0x0f, /* 3/4 threshold */
+ 0x2c, 0x09, /* 5/6 threshold */
+ 0x2d, 0x05, /* 7/8 threshold */
+ 0x2e, 0x01,
+ 0x31, 0x1f, /* test all FECs */
+ 0x32, 0x19, /* viterbi and synchro search */
+ 0x33, 0xfc, /* rs control */
+ 0x34, 0x93, /* error control */
+ 0x0f, 0x52,
+ 0xff, 0xff
+};
+
+static struct stv0299_config sharp_z0194a_config = {
+ .demod_address = 0x68,
+ .inittab = sharp_z0194a__inittab,
+ .mclk = 88000000UL,
+ .invert = 1,
+ .skip_reinit = 0,
+ .lock_output = STV0299_LOCKOUTPUT_1,
+ .volt13_op0_op1 = STV0299_VOLT13_OP1,
+ .min_delay_ms = 100,
+ .set_symbol_rate = sharp_z0194a__set_symbol_rate,
+};
+
+#endif
diff --git a/drivers/media/dvb/pluto2/pluto2.c b/drivers/media/dvb/pluto2/pluto2.c
index 960ed5763ae..a9653c63f4d 100644
--- a/drivers/media/dvb/pluto2/pluto2.c
+++ b/drivers/media/dvb/pluto2/pluto2.c
@@ -234,7 +234,7 @@ static void pluto_reset_ts(struct pluto *pluto, int reenable)
static void pluto_set_dma_addr(struct pluto *pluto)
{
- pluto_writereg(pluto, REG_PCAR, cpu_to_le32(pluto->dma_addr));
+ pluto_writereg(pluto, REG_PCAR, pluto->dma_addr);
}
static int __devinit pluto_dma_map(struct pluto *pluto)
@@ -242,7 +242,7 @@ static int __devinit pluto_dma_map(struct pluto *pluto)
pluto->dma_addr = pci_map_single(pluto->pdev, pluto->dma_buf,
TS_DMA_BYTES, PCI_DMA_FROMDEVICE);
- return pci_dma_mapping_error(pluto->dma_addr);
+ return pci_dma_mapping_error(pluto->pdev, pluto->dma_addr);
}
static void pluto_dma_unmap(struct pluto *pluto)
diff --git a/drivers/media/dvb/siano/Kconfig b/drivers/media/dvb/siano/Kconfig
new file mode 100644
index 00000000000..dd863f26167
--- /dev/null
+++ b/drivers/media/dvb/siano/Kconfig
@@ -0,0 +1,26 @@
+#
+# Siano Mobile Silicon Digital TV device configuration
+#
+
+config DVB_SIANO_SMS1XXX
+ tristate "Siano SMS1XXX USB dongle support"
+ depends on DVB_CORE && USB
+ ---help---
+ Choose Y here if you have a USB dongle with a SMS1XXX chipset.
+
+ To compile this driver as a module, choose M here: the
+ module will be called sms1xxx.
+
+config DVB_SIANO_SMS1XXX_SMS_IDS
+ bool "Enable support for Siano Mobile Silicon default USB IDs"
+ depends on DVB_SIANO_SMS1XXX
+ default y
+ ---help---
+ Choose Y here if you have a USB dongle with a SMS1XXX chipset
+ that uses Siano Mobile Silicon's default usb vid:pid.
+
+ Choose N here if you would prefer to use Siano's external driver.
+
+ Further documentation on this driver can be found on the WWW at
+ <http://www.siano-ms.com/>.
+
diff --git a/drivers/media/dvb/siano/Makefile b/drivers/media/dvb/siano/Makefile
new file mode 100644
index 00000000000..ee0737af98c
--- /dev/null
+++ b/drivers/media/dvb/siano/Makefile
@@ -0,0 +1,8 @@
+sms1xxx-objs := smscoreapi.o smsusb.o smsdvb.o sms-cards.o
+
+obj-$(CONFIG_DVB_SIANO_SMS1XXX) += sms1xxx.o
+
+EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core
+
+EXTRA_CFLAGS += $(extra-cflags-y) $(extra-cflags-m)
+
diff --git a/drivers/media/dvb/siano/sms-cards.c b/drivers/media/dvb/siano/sms-cards.c
new file mode 100644
index 00000000000..cc5efb643f3
--- /dev/null
+++ b/drivers/media/dvb/siano/sms-cards.c
@@ -0,0 +1,102 @@
+/*
+ * Card-specific functions for the Siano SMS1xxx USB dongle
+ *
+ * Copyright (c) 2008 Michael Krufky <mkrufky@linuxtv.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation;
+ *
+ * Software distributed under the License is distributed on an "AS IS"
+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied.
+ *
+ * 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 "sms-cards.h"
+
+struct usb_device_id smsusb_id_table[] = {
+#ifdef CONFIG_DVB_SIANO_SMS1XXX_SMS_IDS
+ { USB_DEVICE(0x187f, 0x0010),
+ .driver_info = SMS1XXX_BOARD_SIANO_STELLAR },
+ { USB_DEVICE(0x187f, 0x0100),
+ .driver_info = SMS1XXX_BOARD_SIANO_STELLAR },
+ { USB_DEVICE(0x187f, 0x0200),
+ .driver_info = SMS1XXX_BOARD_SIANO_NOVA_A },
+ { USB_DEVICE(0x187f, 0x0201),
+ .driver_info = SMS1XXX_BOARD_SIANO_NOVA_B },
+ { USB_DEVICE(0x187f, 0x0300),
+ .driver_info = SMS1XXX_BOARD_SIANO_VEGA },
+#endif
+ { USB_DEVICE(0x2040, 0x1700),
+ .driver_info = SMS1XXX_BOARD_HAUPPAUGE_CATAMOUNT },
+ { USB_DEVICE(0x2040, 0x1800),
+ .driver_info = SMS1XXX_BOARD_HAUPPAUGE_OKEMO_A },
+ { USB_DEVICE(0x2040, 0x1801),
+ .driver_info = SMS1XXX_BOARD_HAUPPAUGE_OKEMO_B },
+ { USB_DEVICE(0x2040, 0x5500),
+ .driver_info = SMS1XXX_BOARD_HAUPPAUGE_WINDHAM },
+ { USB_DEVICE(0x2040, 0x5580),
+ .driver_info = SMS1XXX_BOARD_HAUPPAUGE_WINDHAM },
+ { USB_DEVICE(0x2040, 0x5590),
+ .driver_info = SMS1XXX_BOARD_HAUPPAUGE_WINDHAM },
+ { } /* Terminating entry */
+};
+MODULE_DEVICE_TABLE(usb, smsusb_id_table);
+
+static struct sms_board sms_boards[] = {
+ [SMS_BOARD_UNKNOWN] = {
+ .name = "Unknown board",
+ },
+ [SMS1XXX_BOARD_SIANO_STELLAR] = {
+ .name = "Siano Stellar Digital Receiver",
+ .type = SMS_STELLAR,
+ .fw[DEVICE_MODE_DVBT_BDA] = "sms1xxx-stellar-dvbt-01.fw",
+ },
+ [SMS1XXX_BOARD_SIANO_NOVA_A] = {
+ .name = "Siano Nova A Digital Receiver",
+ .type = SMS_NOVA_A0,
+ .fw[DEVICE_MODE_DVBT_BDA] = "sms1xxx-nova-a-dvbt-01.fw",
+ },
+ [SMS1XXX_BOARD_SIANO_NOVA_B] = {
+ .name = "Siano Nova B Digital Receiver",
+ .type = SMS_NOVA_B0,
+ .fw[DEVICE_MODE_DVBT_BDA] = "sms1xxx-nova-b-dvbt-01.fw",
+ },
+ [SMS1XXX_BOARD_SIANO_VEGA] = {
+ .name = "Siano Vega Digital Receiver",
+ .type = SMS_VEGA,
+ },
+ [SMS1XXX_BOARD_HAUPPAUGE_CATAMOUNT] = {
+ .name = "Hauppauge Catamount",
+ .type = SMS_STELLAR,
+ .fw[DEVICE_MODE_DVBT_BDA] = "sms1xxx-stellar-dvbt-01.fw",
+ },
+ [SMS1XXX_BOARD_HAUPPAUGE_OKEMO_A] = {
+ .name = "Hauppauge Okemo-A",
+ .type = SMS_NOVA_A0,
+ .fw[DEVICE_MODE_DVBT_BDA] = "sms1xxx-nova-a-dvbt-01.fw",
+ },
+ [SMS1XXX_BOARD_HAUPPAUGE_OKEMO_B] = {
+ .name = "Hauppauge Okemo-B",
+ .type = SMS_NOVA_B0,
+ .fw[DEVICE_MODE_DVBT_BDA] = "sms1xxx-nova-b-dvbt-01.fw",
+ },
+ [SMS1XXX_BOARD_HAUPPAUGE_WINDHAM] = {
+ .name = "Hauppauge WinTV-Nova-T-MiniStick",
+ .type = SMS_NOVA_B0,
+ .fw[DEVICE_MODE_DVBT_BDA] = "sms1xxx-hcw-55xxx-dvbt-01.fw",
+ },
+};
+
+struct sms_board *sms_get_board(int id)
+{
+ BUG_ON(id >= ARRAY_SIZE(sms_boards));
+
+ return &sms_boards[id];
+}
+
diff --git a/drivers/media/dvb/siano/sms-cards.h b/drivers/media/dvb/siano/sms-cards.h
new file mode 100644
index 00000000000..c8f3da6f9bc
--- /dev/null
+++ b/drivers/media/dvb/siano/sms-cards.h
@@ -0,0 +1,45 @@
+/*
+ * Card-specific functions for the Siano SMS1xxx USB dongle
+ *
+ * Copyright (c) 2008 Michael Krufky <mkrufky@linuxtv.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation;
+ *
+ * Software distributed under the License is distributed on an "AS IS"
+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied.
+ *
+ * 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 __SMS_CARDS_H__
+#define __SMS_CARDS_H__
+
+#include <linux/usb.h>
+#include "smscoreapi.h"
+
+#define SMS_BOARD_UNKNOWN 0
+#define SMS1XXX_BOARD_SIANO_STELLAR 1
+#define SMS1XXX_BOARD_SIANO_NOVA_A 2
+#define SMS1XXX_BOARD_SIANO_NOVA_B 3
+#define SMS1XXX_BOARD_SIANO_VEGA 4
+#define SMS1XXX_BOARD_HAUPPAUGE_CATAMOUNT 5
+#define SMS1XXX_BOARD_HAUPPAUGE_OKEMO_A 6
+#define SMS1XXX_BOARD_HAUPPAUGE_OKEMO_B 7
+#define SMS1XXX_BOARD_HAUPPAUGE_WINDHAM 8
+
+struct sms_board {
+ enum sms_device_type_st type;
+ char *name, *fw[DEVICE_MODE_MAX];
+};
+
+struct sms_board *sms_get_board(int id);
+
+extern struct usb_device_id smsusb_id_table[];
+
+#endif /* __SMS_CARDS_H__ */
diff --git a/drivers/media/dvb/siano/smscoreapi.c b/drivers/media/dvb/siano/smscoreapi.c
new file mode 100644
index 00000000000..6576fbb40fc
--- /dev/null
+++ b/drivers/media/dvb/siano/smscoreapi.c
@@ -0,0 +1,1251 @@
+/*
+ * Siano core API module
+ *
+ * This file contains implementation for the interface to sms core component
+ *
+ * author: Anatoly Greenblat
+ *
+ * Copyright (c), 2005-2008 Siano Mobile Silicon, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation;
+ *
+ * Software distributed under the License is distributed on an "AS IS"
+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied.
+ *
+ * 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/init.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/dma-mapping.h>
+#include <linux/delay.h>
+#include <linux/io.h>
+
+#include <linux/firmware.h>
+
+#include "smscoreapi.h"
+#include "sms-cards.h"
+
+int sms_debug;
+module_param_named(debug, sms_debug, int, 0644);
+MODULE_PARM_DESC(debug, "set debug level (info=1, adv=2 (or-able))");
+
+struct smscore_device_notifyee_t {
+ struct list_head entry;
+ hotplug_t hotplug;
+};
+
+struct smscore_idlist_t {
+ struct list_head entry;
+ int id;
+ int data_type;
+};
+
+struct smscore_client_t {
+ struct list_head entry;
+ struct smscore_device_t *coredev;
+ void *context;
+ struct list_head idlist;
+ onresponse_t onresponse_handler;
+ onremove_t onremove_handler;
+};
+
+struct smscore_device_t {
+ struct list_head entry;
+
+ struct list_head clients;
+ struct list_head subclients;
+ spinlock_t clientslock;
+
+ struct list_head buffers;
+ spinlock_t bufferslock;
+ int num_buffers;
+
+ void *common_buffer;
+ int common_buffer_size;
+ dma_addr_t common_buffer_phys;
+
+ void *context;
+ struct device *device;
+
+ char devpath[32];
+ unsigned long device_flags;
+
+ setmode_t setmode_handler;
+ detectmode_t detectmode_handler;
+ sendrequest_t sendrequest_handler;
+ preload_t preload_handler;
+ postload_t postload_handler;
+
+ int mode, modes_supported;
+
+ struct completion version_ex_done, data_download_done, trigger_done;
+ struct completion init_device_done, reload_start_done, resume_done;
+
+ int board_id;
+};
+
+void smscore_set_board_id(struct smscore_device_t *core, int id)
+{
+ core->board_id = id;
+}
+
+int smscore_get_board_id(struct smscore_device_t *core)
+{
+ return core->board_id;
+}
+
+struct smscore_registry_entry_t {
+ struct list_head entry;
+ char devpath[32];
+ int mode;
+ enum sms_device_type_st type;
+};
+
+static struct list_head g_smscore_notifyees;
+static struct list_head g_smscore_devices;
+static struct mutex g_smscore_deviceslock;
+
+static struct list_head g_smscore_registry;
+static struct mutex g_smscore_registrylock;
+
+static int default_mode = 4;
+
+module_param(default_mode, int, 0644);
+MODULE_PARM_DESC(default_mode, "default firmware id (device mode)");
+
+static struct smscore_registry_entry_t *smscore_find_registry(char *devpath)
+{
+ struct smscore_registry_entry_t *entry;
+ struct list_head *next;
+
+ kmutex_lock(&g_smscore_registrylock);
+ for (next = g_smscore_registry.next;
+ next != &g_smscore_registry;
+ next = next->next) {
+ entry = (struct smscore_registry_entry_t *) next;
+ if (!strcmp(entry->devpath, devpath)) {
+ kmutex_unlock(&g_smscore_registrylock);
+ return entry;
+ }
+ }
+ entry = (struct smscore_registry_entry_t *)
+ kmalloc(sizeof(struct smscore_registry_entry_t),
+ GFP_KERNEL);
+ if (entry) {
+ entry->mode = default_mode;
+ strcpy(entry->devpath, devpath);
+ list_add(&entry->entry, &g_smscore_registry);
+ } else
+ sms_err("failed to create smscore_registry.");
+ kmutex_unlock(&g_smscore_registrylock);
+ return entry;
+}
+
+int smscore_registry_getmode(char *devpath)
+{
+ struct smscore_registry_entry_t *entry;
+
+ entry = smscore_find_registry(devpath);
+ if (entry)
+ return entry->mode;
+ else
+ sms_err("No registry found.");
+
+ return default_mode;
+}
+
+static enum sms_device_type_st smscore_registry_gettype(char *devpath)
+{
+ struct smscore_registry_entry_t *entry;
+
+ entry = smscore_find_registry(devpath);
+ if (entry)
+ return entry->type;
+ else
+ sms_err("No registry found.");
+
+ return -1;
+}
+
+void smscore_registry_setmode(char *devpath, int mode)
+{
+ struct smscore_registry_entry_t *entry;
+
+ entry = smscore_find_registry(devpath);
+ if (entry)
+ entry->mode = mode;
+ else
+ sms_err("No registry found.");
+}
+
+static void smscore_registry_settype(char *devpath,
+ enum sms_device_type_st type)
+{
+ struct smscore_registry_entry_t *entry;
+
+ entry = smscore_find_registry(devpath);
+ if (entry)
+ entry->type = type;
+ else
+ sms_err("No registry found.");
+}
+
+
+static void list_add_locked(struct list_head *new, struct list_head *head,
+ spinlock_t *lock)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(lock, flags);
+
+ list_add(new, head);
+
+ spin_unlock_irqrestore(lock, flags);
+}
+
+/**
+ * register a client callback that called when device plugged in/unplugged
+ * NOTE: if devices exist callback is called immediately for each device
+ *
+ * @param hotplug callback
+ *
+ * @return 0 on success, <0 on error.
+ */
+int smscore_register_hotplug(hotplug_t hotplug)
+{
+ struct smscore_device_notifyee_t *notifyee;
+ struct list_head *next, *first;
+ int rc = 0;
+
+ kmutex_lock(&g_smscore_deviceslock);
+
+ notifyee = kmalloc(sizeof(struct smscore_device_notifyee_t),
+ GFP_KERNEL);
+ if (notifyee) {
+ /* now notify callback about existing devices */
+ first = &g_smscore_devices;
+ for (next = first->next;
+ next != first && !rc;
+ next = next->next) {
+ struct smscore_device_t *coredev =
+ (struct smscore_device_t *) next;
+ rc = hotplug(coredev, coredev->device, 1);
+ }
+
+ if (rc >= 0) {
+ notifyee->hotplug = hotplug;
+ list_add(&notifyee->entry, &g_smscore_notifyees);
+ } else
+ kfree(notifyee);
+ } else
+ rc = -ENOMEM;
+
+ kmutex_unlock(&g_smscore_deviceslock);
+
+ return rc;
+}
+
+/**
+ * unregister a client callback that called when device plugged in/unplugged
+ *
+ * @param hotplug callback
+ *
+ */
+void smscore_unregister_hotplug(hotplug_t hotplug)
+{
+ struct list_head *next, *first;
+
+ kmutex_lock(&g_smscore_deviceslock);
+
+ first = &g_smscore_notifyees;
+
+ for (next = first->next; next != first;) {
+ struct smscore_device_notifyee_t *notifyee =
+ (struct smscore_device_notifyee_t *) next;
+ next = next->next;
+
+ if (notifyee->hotplug == hotplug) {
+ list_del(&notifyee->entry);
+ kfree(notifyee);
+ }
+ }
+
+ kmutex_unlock(&g_smscore_deviceslock);
+}
+
+static void smscore_notify_clients(struct smscore_device_t *coredev)
+{
+ struct smscore_client_t *client;
+
+ /* the client must call smscore_unregister_client from remove handler */
+ while (!list_empty(&coredev->clients)) {
+ client = (struct smscore_client_t *) coredev->clients.next;
+ client->onremove_handler(client->context);
+ }
+}
+
+static int smscore_notify_callbacks(struct smscore_device_t *coredev,
+ struct device *device, int arrival)
+{
+ struct list_head *next, *first;
+ int rc = 0;
+
+ /* note: must be called under g_deviceslock */
+
+ first = &g_smscore_notifyees;
+
+ for (next = first->next; next != first; next = next->next) {
+ rc = ((struct smscore_device_notifyee_t *) next)->
+ hotplug(coredev, device, arrival);
+ if (rc < 0)
+ break;
+ }
+
+ return rc;
+}
+
+static struct
+smscore_buffer_t *smscore_createbuffer(u8 *buffer, void *common_buffer,
+ dma_addr_t common_buffer_phys)
+{
+ struct smscore_buffer_t *cb =
+ kmalloc(sizeof(struct smscore_buffer_t), GFP_KERNEL);
+ if (!cb) {
+ sms_info("kmalloc(...) failed");
+ return NULL;
+ }
+
+ cb->p = buffer;
+ cb->offset_in_common = buffer - (u8 *) common_buffer;
+ cb->phys = common_buffer_phys + cb->offset_in_common;
+
+ return cb;
+}
+
+/**
+ * creates coredev object for a device, prepares buffers,
+ * creates buffer mappings, notifies registered hotplugs about new device.
+ *
+ * @param params device pointer to struct with device specific parameters
+ * and handlers
+ * @param coredev pointer to a value that receives created coredev object
+ *
+ * @return 0 on success, <0 on error.
+ */
+int smscore_register_device(struct smsdevice_params_t *params,
+ struct smscore_device_t **coredev)
+{
+ struct smscore_device_t *dev;
+ u8 *buffer;
+
+ dev = kzalloc(sizeof(struct smscore_device_t), GFP_KERNEL);
+ if (!dev) {
+ sms_info("kzalloc(...) failed");
+ return -ENOMEM;
+ }
+
+ /* init list entry so it could be safe in smscore_unregister_device */
+ INIT_LIST_HEAD(&dev->entry);
+
+ /* init queues */
+ INIT_LIST_HEAD(&dev->clients);
+ INIT_LIST_HEAD(&dev->buffers);
+
+ /* init locks */
+ spin_lock_init(&dev->clientslock);
+ spin_lock_init(&dev->bufferslock);
+
+ /* init completion events */
+ init_completion(&dev->version_ex_done);
+ init_completion(&dev->data_download_done);
+ init_completion(&dev->trigger_done);
+ init_completion(&dev->init_device_done);
+ init_completion(&dev->reload_start_done);
+ init_completion(&dev->resume_done);
+
+ /* alloc common buffer */
+ dev->common_buffer_size = params->buffer_size * params->num_buffers;
+ dev->common_buffer = dma_alloc_coherent(NULL, dev->common_buffer_size,
+ &dev->common_buffer_phys,
+ GFP_KERNEL | GFP_DMA);
+ if (!dev->common_buffer) {
+ smscore_unregister_device(dev);
+ return -ENOMEM;
+ }
+
+ /* prepare dma buffers */
+ for (buffer = dev->common_buffer;
+ dev->num_buffers < params->num_buffers;
+ dev->num_buffers++, buffer += params->buffer_size) {
+ struct smscore_buffer_t *cb =
+ smscore_createbuffer(buffer, dev->common_buffer,
+ dev->common_buffer_phys);
+ if (!cb) {
+ smscore_unregister_device(dev);
+ return -ENOMEM;
+ }
+
+ smscore_putbuffer(dev, cb);
+ }
+
+ sms_info("allocated %d buffers", dev->num_buffers);
+
+ dev->mode = DEVICE_MODE_NONE;
+ dev->context = params->context;
+ dev->device = params->device;
+ dev->setmode_handler = params->setmode_handler;
+ dev->detectmode_handler = params->detectmode_handler;
+ dev->sendrequest_handler = params->sendrequest_handler;
+ dev->preload_handler = params->preload_handler;
+ dev->postload_handler = params->postload_handler;
+
+ dev->device_flags = params->flags;
+ strcpy(dev->devpath, params->devpath);
+
+ smscore_registry_settype(dev->devpath, params->device_type);
+
+ /* add device to devices list */
+ kmutex_lock(&g_smscore_deviceslock);
+ list_add(&dev->entry, &g_smscore_devices);
+ kmutex_unlock(&g_smscore_deviceslock);
+
+ *coredev = dev;
+
+ sms_info("device %p created", dev);
+
+ return 0;
+}
+
+/**
+ * sets initial device mode and notifies client hotplugs that device is ready
+ *
+ * @param coredev pointer to a coredev object returned by
+ * smscore_register_device
+ *
+ * @return 0 on success, <0 on error.
+ */
+int smscore_start_device(struct smscore_device_t *coredev)
+{
+ int rc = smscore_set_device_mode(
+ coredev, smscore_registry_getmode(coredev->devpath));
+ if (rc < 0) {
+ sms_info("set device mode faile , rc %d", rc);
+ return rc;
+ }
+
+ kmutex_lock(&g_smscore_deviceslock);
+
+ rc = smscore_notify_callbacks(coredev, coredev->device, 1);
+
+ sms_info("device %p started, rc %d", coredev, rc);
+
+ kmutex_unlock(&g_smscore_deviceslock);
+
+ return rc;
+}
+
+static int smscore_sendrequest_and_wait(struct smscore_device_t *coredev,
+ void *buffer, size_t size,
+ struct completion *completion)
+{
+ int rc = coredev->sendrequest_handler(coredev->context, buffer, size);
+ if (rc < 0) {
+ sms_info("sendrequest returned error %d", rc);
+ return rc;
+ }
+
+ return wait_for_completion_timeout(completion,
+ msecs_to_jiffies(10000)) ?
+ 0 : -ETIME;
+}
+
+static int smscore_load_firmware_family2(struct smscore_device_t *coredev,
+ void *buffer, size_t size)
+{
+ struct SmsFirmware_ST *firmware = (struct SmsFirmware_ST *) buffer;
+ struct SmsMsgHdr_ST *msg;
+ u32 mem_address = firmware->StartAddress;
+ u8 *payload = firmware->Payload;
+ int rc = 0;
+
+ sms_info("loading FW to addr 0x%x size %d",
+ mem_address, firmware->Length);
+ if (coredev->preload_handler) {
+ rc = coredev->preload_handler(coredev->context);
+ if (rc < 0)
+ return rc;
+ }
+
+ /* PAGE_SIZE buffer shall be enough and dma aligned */
+ msg = kmalloc(PAGE_SIZE, GFP_KERNEL | GFP_DMA);
+ if (!msg)
+ return -ENOMEM;
+
+ if (coredev->mode != DEVICE_MODE_NONE) {
+ sms_debug("sending reload command.");
+ SMS_INIT_MSG(msg, MSG_SW_RELOAD_START_REQ,
+ sizeof(struct SmsMsgHdr_ST));
+ rc = smscore_sendrequest_and_wait(coredev, msg,
+ msg->msgLength,
+ &coredev->reload_start_done);
+ mem_address = *(u32 *) &payload[20];
+ }
+
+ while (size && rc >= 0) {
+ struct SmsDataDownload_ST *DataMsg =
+ (struct SmsDataDownload_ST *) msg;
+ int payload_size = min((int) size, SMS_MAX_PAYLOAD_SIZE);
+
+ SMS_INIT_MSG(msg, MSG_SMS_DATA_DOWNLOAD_REQ,
+ (u16)(sizeof(struct SmsMsgHdr_ST) +
+ sizeof(u32) + payload_size));
+
+ DataMsg->MemAddr = mem_address;
+ memcpy(DataMsg->Payload, payload, payload_size);
+
+ if ((coredev->device_flags & SMS_ROM_NO_RESPONSE) &&
+ (coredev->mode == DEVICE_MODE_NONE))
+ rc = coredev->sendrequest_handler(
+ coredev->context, DataMsg,
+ DataMsg->xMsgHeader.msgLength);
+ else
+ rc = smscore_sendrequest_and_wait(
+ coredev, DataMsg,
+ DataMsg->xMsgHeader.msgLength,
+ &coredev->data_download_done);
+
+ payload += payload_size;
+ size -= payload_size;
+ mem_address += payload_size;
+ }
+
+ if (rc >= 0) {
+ if (coredev->mode == DEVICE_MODE_NONE) {
+ struct SmsMsgData_ST *TriggerMsg =
+ (struct SmsMsgData_ST *) msg;
+
+ SMS_INIT_MSG(msg, MSG_SMS_SWDOWNLOAD_TRIGGER_REQ,
+ sizeof(struct SmsMsgHdr_ST) +
+ sizeof(u32) * 5);
+
+ TriggerMsg->msgData[0] = firmware->StartAddress;
+ /* Entry point */
+ TriggerMsg->msgData[1] = 5; /* Priority */
+ TriggerMsg->msgData[2] = 0x200; /* Stack size */
+ TriggerMsg->msgData[3] = 0; /* Parameter */
+ TriggerMsg->msgData[4] = 4; /* Task ID */
+
+ if (coredev->device_flags & SMS_ROM_NO_RESPONSE) {
+ rc = coredev->sendrequest_handler(
+ coredev->context, TriggerMsg,
+ TriggerMsg->xMsgHeader.msgLength);
+ msleep(100);
+ } else
+ rc = smscore_sendrequest_and_wait(
+ coredev, TriggerMsg,
+ TriggerMsg->xMsgHeader.msgLength,
+ &coredev->trigger_done);
+ } else {
+ SMS_INIT_MSG(msg, MSG_SW_RELOAD_EXEC_REQ,
+ sizeof(struct SmsMsgHdr_ST));
+
+ rc = coredev->sendrequest_handler(coredev->context,
+ msg, msg->msgLength);
+ }
+ msleep(500);
+ }
+
+ sms_debug("rc=%d, postload=%p ", rc,
+ coredev->postload_handler);
+
+ kfree(msg);
+
+ return ((rc >= 0) && coredev->postload_handler) ?
+ coredev->postload_handler(coredev->context) :
+ rc;
+}
+
+/**
+ * loads specified firmware into a buffer and calls device loadfirmware_handler
+ *
+ * @param coredev pointer to a coredev object returned by
+ * smscore_register_device
+ * @param filename null-terminated string specifies firmware file name
+ * @param loadfirmware_handler device handler that loads firmware
+ *
+ * @return 0 on success, <0 on error.
+ */
+static int smscore_load_firmware_from_file(struct smscore_device_t *coredev,
+ char *filename,
+ loadfirmware_t loadfirmware_handler)
+{
+ int rc = -ENOENT;
+ const struct firmware *fw;
+ u8 *fw_buffer;
+
+ if (loadfirmware_handler == NULL && !(coredev->device_flags &
+ SMS_DEVICE_FAMILY2))
+ return -EINVAL;
+
+ rc = request_firmware(&fw, filename, coredev->device);
+ if (rc < 0) {
+ sms_info("failed to open \"%s\"", filename);
+ return rc;
+ }
+ sms_info("read FW %s, size=%zd", filename, fw->size);
+ fw_buffer = kmalloc(ALIGN(fw->size, SMS_ALLOC_ALIGNMENT),
+ GFP_KERNEL | GFP_DMA);
+ if (fw_buffer) {
+ memcpy(fw_buffer, fw->data, fw->size);
+
+ rc = (coredev->device_flags & SMS_DEVICE_FAMILY2) ?
+ smscore_load_firmware_family2(coredev,
+ fw_buffer,
+ fw->size) :
+ loadfirmware_handler(coredev->context,
+ fw_buffer, fw->size);
+
+ kfree(fw_buffer);
+ } else {
+ sms_info("failed to allocate firmware buffer");
+ rc = -ENOMEM;
+ }
+
+ release_firmware(fw);
+
+ return rc;
+}
+
+/**
+ * notifies all clients registered with the device, notifies hotplugs,
+ * frees all buffers and coredev object
+ *
+ * @param coredev pointer to a coredev object returned by
+ * smscore_register_device
+ *
+ * @return 0 on success, <0 on error.
+ */
+void smscore_unregister_device(struct smscore_device_t *coredev)
+{
+ struct smscore_buffer_t *cb;
+ int num_buffers = 0;
+ int retry = 0;
+
+ kmutex_lock(&g_smscore_deviceslock);
+
+ smscore_notify_clients(coredev);
+ smscore_notify_callbacks(coredev, NULL, 0);
+
+ /* at this point all buffers should be back
+ * onresponse must no longer be called */
+
+ while (1) {
+ while ((cb = smscore_getbuffer(coredev))) {
+ kfree(cb);
+ num_buffers++;
+ }
+ if (num_buffers == coredev->num_buffers)
+ break;
+ if (++retry > 10) {
+ sms_info("exiting although "
+ "not all buffers released.");
+ break;
+ }
+
+ sms_info("waiting for %d buffer(s)",
+ coredev->num_buffers - num_buffers);
+ msleep(100);
+ }
+
+ sms_info("freed %d buffers", num_buffers);
+
+ if (coredev->common_buffer)
+ dma_free_coherent(NULL, coredev->common_buffer_size,
+ coredev->common_buffer,
+ coredev->common_buffer_phys);
+
+ list_del(&coredev->entry);
+ kfree(coredev);
+
+ kmutex_unlock(&g_smscore_deviceslock);
+
+ sms_info("device %p destroyed", coredev);
+}
+
+static int smscore_detect_mode(struct smscore_device_t *coredev)
+{
+ void *buffer = kmalloc(sizeof(struct SmsMsgHdr_ST) + SMS_DMA_ALIGNMENT,
+ GFP_KERNEL | GFP_DMA);
+ struct SmsMsgHdr_ST *msg =
+ (struct SmsMsgHdr_ST *) SMS_ALIGN_ADDRESS(buffer);
+ int rc;
+
+ if (!buffer)
+ return -ENOMEM;
+
+ SMS_INIT_MSG(msg, MSG_SMS_GET_VERSION_EX_REQ,
+ sizeof(struct SmsMsgHdr_ST));
+
+ rc = smscore_sendrequest_and_wait(coredev, msg, msg->msgLength,
+ &coredev->version_ex_done);
+ if (rc == -ETIME) {
+ sms_err("MSG_SMS_GET_VERSION_EX_REQ failed first try");
+
+ if (wait_for_completion_timeout(&coredev->resume_done,
+ msecs_to_jiffies(5000))) {
+ rc = smscore_sendrequest_and_wait(
+ coredev, msg, msg->msgLength,
+ &coredev->version_ex_done);
+ if (rc < 0)
+ sms_err("MSG_SMS_GET_VERSION_EX_REQ failed "
+ "second try, rc %d", rc);
+ } else
+ rc = -ETIME;
+ }
+
+ kfree(buffer);
+
+ return rc;
+}
+
+static char *smscore_fw_lkup[][SMS_NUM_OF_DEVICE_TYPES] = {
+ /*Stellar NOVA A0 Nova B0 VEGA*/
+ /*DVBT*/
+ {"none", "dvb_nova_12mhz.inp", "dvb_nova_12mhz_b0.inp", "none"},
+ /*DVBH*/
+ {"none", "dvb_nova_12mhz.inp", "dvb_nova_12mhz_b0.inp", "none"},
+ /*TDMB*/
+ {"none", "tdmb_nova_12mhz.inp", "none", "none"},
+ /*DABIP*/
+ {"none", "none", "none", "none"},
+ /*BDA*/
+ {"none", "dvb_nova_12mhz.inp", "dvb_nova_12mhz_b0.inp", "none"},
+ /*ISDBT*/
+ {"none", "isdbt_nova_12mhz.inp", "dvb_nova_12mhz.inp", "none"},
+ /*ISDBTBDA*/
+ {"none", "isdbt_nova_12mhz.inp", "isdbt_nova_12mhz_b0.inp", "none"},
+ /*CMMB*/
+ {"none", "none", "none", "cmmb_vega_12mhz.inp"}
+};
+
+static inline char *sms_get_fw_name(struct smscore_device_t *coredev,
+ int mode, enum sms_device_type_st type)
+{
+ char **fw = sms_get_board(smscore_get_board_id(coredev))->fw;
+ return (fw && fw[mode]) ? fw[mode] : smscore_fw_lkup[mode][type];
+}
+
+/**
+ * calls device handler to change mode of operation
+ * NOTE: stellar/usb may disconnect when changing mode
+ *
+ * @param coredev pointer to a coredev object returned by
+ * smscore_register_device
+ * @param mode requested mode of operation
+ *
+ * @return 0 on success, <0 on error.
+ */
+int smscore_set_device_mode(struct smscore_device_t *coredev, int mode)
+{
+ void *buffer;
+ int rc = 0;
+ enum sms_device_type_st type;
+
+ sms_debug("set device mode to %d", mode);
+ if (coredev->device_flags & SMS_DEVICE_FAMILY2) {
+ if (mode < DEVICE_MODE_DVBT || mode > DEVICE_MODE_RAW_TUNER) {
+ sms_err("invalid mode specified %d", mode);
+ return -EINVAL;
+ }
+
+ smscore_registry_setmode(coredev->devpath, mode);
+
+ if (!(coredev->device_flags & SMS_DEVICE_NOT_READY)) {
+ rc = smscore_detect_mode(coredev);
+ if (rc < 0) {
+ sms_err("mode detect failed %d", rc);
+ return rc;
+ }
+ }
+
+ if (coredev->mode == mode) {
+ sms_info("device mode %d already set", mode);
+ return 0;
+ }
+
+ if (!(coredev->modes_supported & (1 << mode))) {
+ char *fw_filename;
+
+ type = smscore_registry_gettype(coredev->devpath);
+ fw_filename = sms_get_fw_name(coredev, mode, type);
+
+ rc = smscore_load_firmware_from_file(coredev,
+ fw_filename, NULL);
+ if (rc < 0) {
+ sms_warn("error %d loading firmware: %s, "
+ "trying again with default firmware",
+ rc, fw_filename);
+
+ /* try again with the default firmware */
+ fw_filename = smscore_fw_lkup[mode][type];
+ rc = smscore_load_firmware_from_file(coredev,
+ fw_filename, NULL);
+
+ if (rc < 0) {
+ sms_warn("error %d loading "
+ "firmware: %s", rc,
+ fw_filename);
+ return rc;
+ }
+ }
+ sms_log("firmware download success: %s", fw_filename);
+ } else
+ sms_info("mode %d supported by running "
+ "firmware", mode);
+
+ buffer = kmalloc(sizeof(struct SmsMsgData_ST) +
+ SMS_DMA_ALIGNMENT, GFP_KERNEL | GFP_DMA);
+ if (buffer) {
+ struct SmsMsgData_ST *msg =
+ (struct SmsMsgData_ST *)
+ SMS_ALIGN_ADDRESS(buffer);
+
+ SMS_INIT_MSG(&msg->xMsgHeader, MSG_SMS_INIT_DEVICE_REQ,
+ sizeof(struct SmsMsgData_ST));
+ msg->msgData[0] = mode;
+
+ rc = smscore_sendrequest_and_wait(
+ coredev, msg, msg->xMsgHeader.msgLength,
+ &coredev->init_device_done);
+
+ kfree(buffer);
+ } else {
+ sms_err("Could not allocate buffer for "
+ "init device message.");
+ rc = -ENOMEM;
+ }
+ } else {
+ if (mode < DEVICE_MODE_DVBT || mode > DEVICE_MODE_DVBT_BDA) {
+ sms_err("invalid mode specified %d", mode);
+ return -EINVAL;
+ }
+
+ smscore_registry_setmode(coredev->devpath, mode);
+
+ if (coredev->detectmode_handler)
+ coredev->detectmode_handler(coredev->context,
+ &coredev->mode);
+
+ if (coredev->mode != mode && coredev->setmode_handler)
+ rc = coredev->setmode_handler(coredev->context, mode);
+ }
+
+ if (rc >= 0) {
+ coredev->mode = mode;
+ coredev->device_flags &= ~SMS_DEVICE_NOT_READY;
+ }
+
+ if (rc != 0)
+ sms_err("return error code %d.", rc);
+ return rc;
+}
+
+/**
+ * calls device handler to get current mode of operation
+ *
+ * @param coredev pointer to a coredev object returned by
+ * smscore_register_device
+ *
+ * @return current mode
+ */
+int smscore_get_device_mode(struct smscore_device_t *coredev)
+{
+ return coredev->mode;
+}
+
+/**
+ * find client by response id & type within the clients list.
+ * return client handle or NULL.
+ *
+ * @param coredev pointer to a coredev object returned by
+ * smscore_register_device
+ * @param data_type client data type (SMS_DONT_CARE for all types)
+ * @param id client id (SMS_DONT_CARE for all id)
+ *
+ */
+static struct
+smscore_client_t *smscore_find_client(struct smscore_device_t *coredev,
+ int data_type, int id)
+{
+ struct smscore_client_t *client = NULL;
+ struct list_head *next, *first;
+ unsigned long flags;
+ struct list_head *firstid, *nextid;
+
+
+ spin_lock_irqsave(&coredev->clientslock, flags);
+ first = &coredev->clients;
+ for (next = first->next;
+ (next != first) && !client;
+ next = next->next) {
+ firstid = &((struct smscore_client_t *)next)->idlist;
+ for (nextid = firstid->next;
+ nextid != firstid;
+ nextid = nextid->next) {
+ if ((((struct smscore_idlist_t *)nextid)->id == id) &&
+ (((struct smscore_idlist_t *)nextid)->data_type == data_type ||
+ (((struct smscore_idlist_t *)nextid)->data_type == 0))) {
+ client = (struct smscore_client_t *) next;
+ break;
+ }
+ }
+ }
+ spin_unlock_irqrestore(&coredev->clientslock, flags);
+ return client;
+}
+
+/**
+ * find client by response id/type, call clients onresponse handler
+ * return buffer to pool on error
+ *
+ * @param coredev pointer to a coredev object returned by
+ * smscore_register_device
+ * @param cb pointer to response buffer descriptor
+ *
+ */
+void smscore_onresponse(struct smscore_device_t *coredev,
+ struct smscore_buffer_t *cb)
+{
+ struct SmsMsgHdr_ST *phdr =
+ (struct SmsMsgHdr_ST *)((u8 *) cb->p + cb->offset);
+ struct smscore_client_t *client =
+ smscore_find_client(coredev, phdr->msgType, phdr->msgDstId);
+ int rc = -EBUSY;
+
+ static unsigned long last_sample_time; /* = 0; */
+ static int data_total; /* = 0; */
+ unsigned long time_now = jiffies_to_msecs(jiffies);
+
+ if (!last_sample_time)
+ last_sample_time = time_now;
+
+ if (time_now - last_sample_time > 10000) {
+ sms_debug("\ndata rate %d bytes/secs",
+ (int)((data_total * 1000) /
+ (time_now - last_sample_time)));
+
+ last_sample_time = time_now;
+ data_total = 0;
+ }
+
+ data_total += cb->size;
+ /* If no client registered for type & id,
+ * check for control client where type is not registered */
+ if (client)
+ rc = client->onresponse_handler(client->context, cb);
+
+ if (rc < 0) {
+ switch (phdr->msgType) {
+ case MSG_SMS_GET_VERSION_EX_RES:
+ {
+ struct SmsVersionRes_ST *ver =
+ (struct SmsVersionRes_ST *) phdr;
+ sms_debug("MSG_SMS_GET_VERSION_EX_RES "
+ "id %d prots 0x%x ver %d.%d",
+ ver->FirmwareId, ver->SupportedProtocols,
+ ver->RomVersionMajor, ver->RomVersionMinor);
+
+ coredev->mode = ver->FirmwareId == 255 ?
+ DEVICE_MODE_NONE : ver->FirmwareId;
+ coredev->modes_supported = ver->SupportedProtocols;
+
+ complete(&coredev->version_ex_done);
+ break;
+ }
+ case MSG_SMS_INIT_DEVICE_RES:
+ sms_debug("MSG_SMS_INIT_DEVICE_RES");
+ complete(&coredev->init_device_done);
+ break;
+ case MSG_SW_RELOAD_START_RES:
+ sms_debug("MSG_SW_RELOAD_START_RES");
+ complete(&coredev->reload_start_done);
+ break;
+ case MSG_SMS_DATA_DOWNLOAD_RES:
+ complete(&coredev->data_download_done);
+ break;
+ case MSG_SW_RELOAD_EXEC_RES:
+ sms_debug("MSG_SW_RELOAD_EXEC_RES");
+ break;
+ case MSG_SMS_SWDOWNLOAD_TRIGGER_RES:
+ sms_debug("MSG_SMS_SWDOWNLOAD_TRIGGER_RES");
+ complete(&coredev->trigger_done);
+ break;
+ case MSG_SMS_SLEEP_RESUME_COMP_IND:
+ complete(&coredev->resume_done);
+ break;
+ default:
+ break;
+ }
+ smscore_putbuffer(coredev, cb);
+ }
+}
+
+/**
+ * return pointer to next free buffer descriptor from core pool
+ *
+ * @param coredev pointer to a coredev object returned by
+ * smscore_register_device
+ *
+ * @return pointer to descriptor on success, NULL on error.
+ */
+struct smscore_buffer_t *smscore_getbuffer(struct smscore_device_t *coredev)
+{
+ struct smscore_buffer_t *cb = NULL;
+ unsigned long flags;
+
+ spin_lock_irqsave(&coredev->bufferslock, flags);
+
+ if (!list_empty(&coredev->buffers)) {
+ cb = (struct smscore_buffer_t *) coredev->buffers.next;
+ list_del(&cb->entry);
+ }
+
+ spin_unlock_irqrestore(&coredev->bufferslock, flags);
+
+ return cb;
+}
+
+/**
+ * return buffer descriptor to a pool
+ *
+ * @param coredev pointer to a coredev object returned by
+ * smscore_register_device
+ * @param cb pointer buffer descriptor
+ *
+ */
+void smscore_putbuffer(struct smscore_device_t *coredev,
+ struct smscore_buffer_t *cb)
+{
+ list_add_locked(&cb->entry, &coredev->buffers, &coredev->bufferslock);
+}
+
+static int smscore_validate_client(struct smscore_device_t *coredev,
+ struct smscore_client_t *client,
+ int data_type, int id)
+{
+ struct smscore_idlist_t *listentry;
+ struct smscore_client_t *registered_client;
+
+ if (!client) {
+ sms_err("bad parameter.");
+ return -EFAULT;
+ }
+ registered_client = smscore_find_client(coredev, data_type, id);
+ if (registered_client == client)
+ return 0;
+
+ if (registered_client) {
+ sms_err("The msg ID already registered to another client.");
+ return -EEXIST;
+ }
+ listentry = kzalloc(sizeof(struct smscore_idlist_t), GFP_KERNEL);
+ if (!listentry) {
+ sms_err("Can't allocate memory for client id.");
+ return -ENOMEM;
+ }
+ listentry->id = id;
+ listentry->data_type = data_type;
+ list_add_locked(&listentry->entry, &client->idlist,
+ &coredev->clientslock);
+ return 0;
+}
+
+/**
+ * creates smsclient object, check that id is taken by another client
+ *
+ * @param coredev pointer to a coredev object from clients hotplug
+ * @param initial_id all messages with this id would be sent to this client
+ * @param data_type all messages of this type would be sent to this client
+ * @param onresponse_handler client handler that is called to
+ * process incoming messages
+ * @param onremove_handler client handler that is called when device is removed
+ * @param context client-specific context
+ * @param client pointer to a value that receives created smsclient object
+ *
+ * @return 0 on success, <0 on error.
+ */
+int smscore_register_client(struct smscore_device_t *coredev,
+ struct smsclient_params_t *params,
+ struct smscore_client_t **client)
+{
+ struct smscore_client_t *newclient;
+ /* check that no other channel with same parameters exists */
+ if (smscore_find_client(coredev, params->data_type,
+ params->initial_id)) {
+ sms_err("Client already exist.");
+ return -EEXIST;
+ }
+
+ newclient = kzalloc(sizeof(struct smscore_client_t), GFP_KERNEL);
+ if (!newclient) {
+ sms_err("Failed to allocate memory for client.");
+ return -ENOMEM;
+ }
+
+ INIT_LIST_HEAD(&newclient->idlist);
+ newclient->coredev = coredev;
+ newclient->onresponse_handler = params->onresponse_handler;
+ newclient->onremove_handler = params->onremove_handler;
+ newclient->context = params->context;
+ list_add_locked(&newclient->entry, &coredev->clients,
+ &coredev->clientslock);
+ smscore_validate_client(coredev, newclient, params->data_type,
+ params->initial_id);
+ *client = newclient;
+ sms_debug("%p %d %d", params->context, params->data_type,
+ params->initial_id);
+
+ return 0;
+}
+
+/**
+ * frees smsclient object and all subclients associated with it
+ *
+ * @param client pointer to smsclient object returned by
+ * smscore_register_client
+ *
+ */
+void smscore_unregister_client(struct smscore_client_t *client)
+{
+ struct smscore_device_t *coredev = client->coredev;
+ unsigned long flags;
+
+ spin_lock_irqsave(&coredev->clientslock, flags);
+
+
+ while (!list_empty(&client->idlist)) {
+ struct smscore_idlist_t *identry =
+ (struct smscore_idlist_t *) client->idlist.next;
+ list_del(&identry->entry);
+ kfree(identry);
+ }
+
+ sms_info("%p", client->context);
+
+ list_del(&client->entry);
+ kfree(client);
+
+ spin_unlock_irqrestore(&coredev->clientslock, flags);
+}
+
+/**
+ * verifies that source id is not taken by another client,
+ * calls device handler to send requests to the device
+ *
+ * @param client pointer to smsclient object returned by
+ * smscore_register_client
+ * @param buffer pointer to a request buffer
+ * @param size size (in bytes) of request buffer
+ *
+ * @return 0 on success, <0 on error.
+ */
+int smsclient_sendrequest(struct smscore_client_t *client,
+ void *buffer, size_t size)
+{
+ struct smscore_device_t *coredev;
+ struct SmsMsgHdr_ST *phdr = (struct SmsMsgHdr_ST *) buffer;
+ int rc;
+
+ if (client == NULL) {
+ sms_err("Got NULL client");
+ return -EINVAL;
+ }
+
+ coredev = client->coredev;
+
+ /* check that no other channel with same id exists */
+ if (coredev == NULL) {
+ sms_err("Got NULL coredev");
+ return -EINVAL;
+ }
+
+ rc = smscore_validate_client(client->coredev, client, 0,
+ phdr->msgSrcId);
+ if (rc < 0)
+ return rc;
+
+ return coredev->sendrequest_handler(coredev->context, buffer, size);
+}
+
+
+static int __init smscore_module_init(void)
+{
+ int rc = 0;
+
+ INIT_LIST_HEAD(&g_smscore_notifyees);
+ INIT_LIST_HEAD(&g_smscore_devices);
+ kmutex_init(&g_smscore_deviceslock);
+
+ INIT_LIST_HEAD(&g_smscore_registry);
+ kmutex_init(&g_smscore_registrylock);
+
+ /* USB Register */
+ rc = smsusb_register();
+
+ /* DVB Register */
+ rc = smsdvb_register();
+
+ sms_debug("rc %d", rc);
+
+ return rc;
+}
+
+static void __exit smscore_module_exit(void)
+{
+
+ kmutex_lock(&g_smscore_deviceslock);
+ while (!list_empty(&g_smscore_notifyees)) {
+ struct smscore_device_notifyee_t *notifyee =
+ (struct smscore_device_notifyee_t *)
+ g_smscore_notifyees.next;
+
+ list_del(&notifyee->entry);
+ kfree(notifyee);
+ }
+ kmutex_unlock(&g_smscore_deviceslock);
+
+ kmutex_lock(&g_smscore_registrylock);
+ while (!list_empty(&g_smscore_registry)) {
+ struct smscore_registry_entry_t *entry =
+ (struct smscore_registry_entry_t *)
+ g_smscore_registry.next;
+
+ list_del(&entry->entry);
+ kfree(entry);
+ }
+ kmutex_unlock(&g_smscore_registrylock);
+
+ /* DVB UnRegister */
+ smsdvb_unregister();
+
+ /* Unregister USB */
+ smsusb_unregister();
+
+ sms_debug("");
+}
+
+module_init(smscore_module_init);
+module_exit(smscore_module_exit);
+
+MODULE_DESCRIPTION("Driver for the Siano SMS1XXX USB dongle");
+MODULE_AUTHOR("Siano Mobile Silicon,,, (doronc@siano-ms.com)");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/siano/smscoreapi.h b/drivers/media/dvb/siano/smscoreapi.h
new file mode 100644
index 00000000000..8d973f726fb
--- /dev/null
+++ b/drivers/media/dvb/siano/smscoreapi.h
@@ -0,0 +1,434 @@
+/*
+ * Driver for the Siano SMS1xxx USB dongle
+ *
+ * author: Anatoly Greenblat
+ *
+ * Copyright (c), 2005-2008 Siano Mobile Silicon, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation;
+ *
+ * Software distributed under the License is distributed on an "AS IS"
+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied.
+ *
+ * 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 __smscoreapi_h__
+#define __smscoreapi_h__
+
+#include <linux/version.h>
+#include <linux/device.h>
+#include <linux/list.h>
+#include <linux/mm.h>
+#include <linux/scatterlist.h>
+#include <linux/types.h>
+#include <asm/page.h>
+
+#include "dmxdev.h"
+#include "dvbdev.h"
+#include "dvb_demux.h"
+#include "dvb_frontend.h"
+
+#include <linux/mutex.h>
+
+#define kmutex_init(_p_) mutex_init(_p_)
+#define kmutex_lock(_p_) mutex_lock(_p_)
+#define kmutex_trylock(_p_) mutex_trylock(_p_)
+#define kmutex_unlock(_p_) mutex_unlock(_p_)
+
+#ifndef min
+#define min(a, b) (((a) < (b)) ? (a) : (b))
+#endif
+
+#define SMS_ALLOC_ALIGNMENT 128
+#define SMS_DMA_ALIGNMENT 16
+#define SMS_ALIGN_ADDRESS(addr) \
+ ((((uintptr_t)(addr)) + (SMS_DMA_ALIGNMENT-1)) & ~(SMS_DMA_ALIGNMENT-1))
+
+#define SMS_DEVICE_FAMILY2 1
+#define SMS_ROM_NO_RESPONSE 2
+#define SMS_DEVICE_NOT_READY 0x8000000
+
+enum sms_device_type_st {
+ SMS_STELLAR = 0,
+ SMS_NOVA_A0,
+ SMS_NOVA_B0,
+ SMS_VEGA,
+ SMS_NUM_OF_DEVICE_TYPES
+};
+
+struct smscore_device_t;
+struct smscore_client_t;
+struct smscore_buffer_t;
+
+typedef int (*hotplug_t)(struct smscore_device_t *coredev,
+ struct device *device, int arrival);
+
+typedef int (*setmode_t)(void *context, int mode);
+typedef void (*detectmode_t)(void *context, int *mode);
+typedef int (*sendrequest_t)(void *context, void *buffer, size_t size);
+typedef int (*loadfirmware_t)(void *context, void *buffer, size_t size);
+typedef int (*preload_t)(void *context);
+typedef int (*postload_t)(void *context);
+
+typedef int (*onresponse_t)(void *context, struct smscore_buffer_t *cb);
+typedef void (*onremove_t)(void *context);
+
+struct smscore_buffer_t {
+ /* public members, once passed to clients can be changed freely */
+ struct list_head entry;
+ int size;
+ int offset;
+
+ /* private members, read-only for clients */
+ void *p;
+ dma_addr_t phys;
+ unsigned long offset_in_common;
+};
+
+struct smsdevice_params_t {
+ struct device *device;
+
+ int buffer_size;
+ int num_buffers;
+
+ char devpath[32];
+ unsigned long flags;
+
+ setmode_t setmode_handler;
+ detectmode_t detectmode_handler;
+ sendrequest_t sendrequest_handler;
+ preload_t preload_handler;
+ postload_t postload_handler;
+
+ void *context;
+ enum sms_device_type_st device_type;
+};
+
+struct smsclient_params_t {
+ int initial_id;
+ int data_type;
+ onresponse_t onresponse_handler;
+ onremove_t onremove_handler;
+
+ void *context;
+};
+
+/* GPIO definitions for antenna frequency domain control (SMS8021) */
+#define SMS_ANTENNA_GPIO_0 1
+#define SMS_ANTENNA_GPIO_1 0
+
+#define BW_8_MHZ 0
+#define BW_7_MHZ 1
+#define BW_6_MHZ 2
+#define BW_5_MHZ 3
+#define BW_ISDBT_1SEG 4
+#define BW_ISDBT_3SEG 5
+
+#define MSG_HDR_FLAG_SPLIT_MSG 4
+
+#define MAX_GPIO_PIN_NUMBER 31
+
+#define HIF_TASK 11
+#define SMS_HOST_LIB 150
+#define DVBT_BDA_CONTROL_MSG_ID 201
+
+#define SMS_MAX_PAYLOAD_SIZE 240
+#define SMS_TUNE_TIMEOUT 500
+
+#define MSG_SMS_GPIO_CONFIG_REQ 507
+#define MSG_SMS_GPIO_CONFIG_RES 508
+#define MSG_SMS_GPIO_SET_LEVEL_REQ 509
+#define MSG_SMS_GPIO_SET_LEVEL_RES 510
+#define MSG_SMS_GPIO_GET_LEVEL_REQ 511
+#define MSG_SMS_GPIO_GET_LEVEL_RES 512
+#define MSG_SMS_RF_TUNE_REQ 561
+#define MSG_SMS_RF_TUNE_RES 562
+#define MSG_SMS_INIT_DEVICE_REQ 578
+#define MSG_SMS_INIT_DEVICE_RES 579
+#define MSG_SMS_ADD_PID_FILTER_REQ 601
+#define MSG_SMS_ADD_PID_FILTER_RES 602
+#define MSG_SMS_REMOVE_PID_FILTER_REQ 603
+#define MSG_SMS_REMOVE_PID_FILTER_RES 604
+#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_REQ 615
+#define MSG_SMS_GET_STATISTICS_RES 616
+#define MSG_SMS_SET_ANTENNA_CONFIG_REQ 651
+#define MSG_SMS_SET_ANTENNA_CONFIG_RES 652
+#define MSG_SMS_GET_STATISTICS_EX_REQ 653
+#define MSG_SMS_GET_STATISTICS_EX_RES 654
+#define MSG_SMS_SLEEP_RESUME_COMP_IND 655
+#define MSG_SMS_DATA_DOWNLOAD_REQ 660
+#define MSG_SMS_DATA_DOWNLOAD_RES 661
+#define MSG_SMS_SWDOWNLOAD_TRIGGER_REQ 664
+#define MSG_SMS_SWDOWNLOAD_TRIGGER_RES 665
+#define MSG_SMS_SWDOWNLOAD_BACKDOOR_REQ 666
+#define MSG_SMS_SWDOWNLOAD_BACKDOOR_RES 667
+#define MSG_SMS_GET_VERSION_EX_REQ 668
+#define MSG_SMS_GET_VERSION_EX_RES 669
+#define MSG_SMS_SET_CLOCK_OUTPUT_REQ 670
+#define MSG_SMS_I2C_SET_FREQ_REQ 685
+#define MSG_SMS_GENERIC_I2C_REQ 687
+#define MSG_SMS_GENERIC_I2C_RES 688
+#define MSG_SMS_DVBT_BDA_DATA 693
+#define MSG_SW_RELOAD_REQ 697
+#define MSG_SMS_DATA_MSG 699
+#define MSG_SW_RELOAD_START_REQ 702
+#define MSG_SW_RELOAD_START_RES 703
+#define MSG_SW_RELOAD_EXEC_REQ 704
+#define MSG_SW_RELOAD_EXEC_RES 705
+#define MSG_SMS_SPI_INT_LINE_SET_REQ 710
+#define MSG_SMS_ISDBT_TUNE_REQ 776
+#define MSG_SMS_ISDBT_TUNE_RES 777
+
+#define SMS_INIT_MSG_EX(ptr, type, src, dst, len) do { \
+ (ptr)->msgType = type; (ptr)->msgSrcId = src; (ptr)->msgDstId = dst; \
+ (ptr)->msgLength = len; (ptr)->msgFlags = 0; \
+} while (0)
+#define SMS_INIT_MSG(ptr, type, len) \
+ SMS_INIT_MSG_EX(ptr, type, 0, HIF_TASK, len)
+
+enum SMS_DEVICE_MODE {
+ DEVICE_MODE_NONE = -1,
+ DEVICE_MODE_DVBT = 0,
+ DEVICE_MODE_DVBH,
+ DEVICE_MODE_DAB_TDMB,
+ DEVICE_MODE_DAB_TDMB_DABIP,
+ DEVICE_MODE_DVBT_BDA,
+ DEVICE_MODE_ISDBT,
+ DEVICE_MODE_ISDBT_BDA,
+ DEVICE_MODE_CMMB,
+ DEVICE_MODE_RAW_TUNER,
+ DEVICE_MODE_MAX,
+};
+
+struct SmsMsgHdr_ST {
+ u16 msgType;
+ u8 msgSrcId;
+ u8 msgDstId;
+ u16 msgLength; /* Length of entire message, including header */
+ u16 msgFlags;
+};
+
+struct SmsMsgData_ST {
+ struct SmsMsgHdr_ST xMsgHeader;
+ u32 msgData[1];
+};
+
+struct SmsDataDownload_ST {
+ struct SmsMsgHdr_ST xMsgHeader;
+ u32 MemAddr;
+ u8 Payload[SMS_MAX_PAYLOAD_SIZE];
+};
+
+struct SmsVersionRes_ST {
+ struct SmsMsgHdr_ST xMsgHeader;
+
+ u16 ChipModel; /* e.g. 0x1102 for SMS-1102 "Nova" */
+ u8 Step; /* 0 - Step A */
+ u8 MetalFix; /* 0 - Metal 0 */
+
+ u8 FirmwareId; /* 0xFF � ROM, otherwise the
+ * value indicated by
+ * SMSHOSTLIB_DEVICE_MODES_E */
+ u8 SupportedProtocols; /* Bitwise OR combination of
+ * supported protocols */
+
+ u8 VersionMajor;
+ u8 VersionMinor;
+ u8 VersionPatch;
+ u8 VersionFieldPatch;
+
+ u8 RomVersionMajor;
+ u8 RomVersionMinor;
+ u8 RomVersionPatch;
+ u8 RomVersionFieldPatch;
+
+ u8 TextLabel[34];
+};
+
+struct SmsFirmware_ST {
+ u32 CheckSum;
+ u32 Length;
+ u32 StartAddress;
+ u8 Payload[1];
+};
+
+struct SMSHOSTLIB_STATISTICS_ST {
+ u32 Reserved; /* Reserved */
+
+ /* 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 */
+ u32 BER; /* Post Viterbi BER [1E-5] */
+ u32 FIB_CRC; /* CRC errors percentage, valid only for DAB */
+ u32 TS_PER; /* Transport stream PER, 0xFFFFFFFF indicate N/A,
+ * valid only for DVB-T/H */
+ u32 MFER; /* DVB-H frame error rate in percentage,
+ * 0xFFFFFFFF indicate N/A, valid only for DVB-H */
+ s32 RSSI; /* dBm */
+ s32 InBandPwr; /* In band power in dBM */
+ s32 CarrierOffset; /* Carrier Offset in bin/1024 */
+
+ /* Transmission parameters, valid only for DVB-T/H */
+ u32 Frequency; /* Frequency in Hz */
+ u32 Bandwidth; /* Bandwidth in MHz */
+ u32 TransmissionMode; /* Transmission Mode, for DAB modes 1-4,
+ * for DVB-T/H FFT mode carriers in Kilos */
+ u32 ModemState; /* from SMS_DvbModemState_ET */
+ u32 GuardInterval; /* Guard Interval, 1 divided by value */
+ u32 CodeRate; /* Code Rate from SMS_DvbModemState_ET */
+ u32 LPCodeRate; /* Low Priority Code Rate from SMS_DvbModemState_ET */
+ u32 Hierarchy; /* Hierarchy from SMS_Hierarchy_ET */
+ u32 Constellation; /* Constellation from SMS_Constellation_ET */
+
+ /* Burst parameters, valid only for DVB-H */
+ u32 BurstSize; /* Current burst size in bytes */
+ u32 BurstDuration; /* Current burst duration in mSec */
+ u32 BurstCycleTime; /* Current burst cycle time in mSec */
+ u32 CalculatedBurstCycleTime; /* Current burst cycle time in mSec,
+ * as calculated by demodulator */
+ u32 NumOfRows; /* Number of rows in MPE table */
+ u32 NumOfPaddCols; /* Number of padding columns in MPE table */
+ u32 NumOfPunctCols; /* Number of puncturing columns in MPE table */
+ /* Burst parameters */
+ u32 ErrorTSPackets; /* Number of erroneous transport-stream packets */
+ u32 TotalTSPackets; /* Total number of transport-stream packets */
+ u32 NumOfValidMpeTlbs; /* Number of MPE tables which do not include
+ * errors after MPE RS decoding */
+ u32 NumOfInvalidMpeTlbs; /* Number of MPE tables which include errors
+ * after MPE RS decoding */
+ u32 NumOfCorrectedMpeTlbs; /* Number of MPE tables which were corrected
+ * by MPE RS decoding */
+
+ /* Common params */
+ u32 BERErrorCount; /* Number of errornous SYNC bits. */
+ u32 BERBitCount; /* Total number of SYNC bits. */
+
+ /* Interface information */
+ u32 SmsToHostTxErrors; /* Total number of transmission errors. */
+
+ /* DAB/T-DMB */
+ u32 PreBER; /* DAB/T-DMB only: Pre Viterbi BER [1E-5] */
+
+ /* DVB-H TPS parameters */
+ u32 CellId; /* TPS Cell ID in bits 15..0, bits 31..16 zero;
+ * if set to 0xFFFFFFFF cell_id not yet recovered */
+
+};
+
+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 smsdvb_client_t {
+ struct list_head entry;
+
+ struct smscore_device_t *coredev;
+ struct smscore_client_t *smsclient;
+
+ struct dvb_adapter adapter;
+ struct dvb_demux demux;
+ struct dmxdev dmxdev;
+ struct dvb_frontend frontend;
+
+ fe_status_t fe_status;
+ int fe_ber, fe_snr, fe_signal_strength;
+
+ struct completion tune_done, stat_done;
+
+ /* todo: save freq/band instead whole struct */
+ struct dvb_frontend_parameters fe_params;
+
+};
+
+extern void smscore_registry_setmode(char *devpath, int mode);
+extern int smscore_registry_getmode(char *devpath);
+
+extern int smscore_register_hotplug(hotplug_t hotplug);
+extern void smscore_unregister_hotplug(hotplug_t hotplug);
+
+extern int smscore_register_device(struct smsdevice_params_t *params,
+ struct smscore_device_t **coredev);
+extern void smscore_unregister_device(struct smscore_device_t *coredev);
+
+extern int smscore_start_device(struct smscore_device_t *coredev);
+extern int smscore_load_firmware(struct smscore_device_t *coredev,
+ char *filename,
+ loadfirmware_t loadfirmware_handler);
+
+extern int smscore_set_device_mode(struct smscore_device_t *coredev, int mode);
+extern int smscore_get_device_mode(struct smscore_device_t *coredev);
+
+extern int smscore_register_client(struct smscore_device_t *coredev,
+ struct smsclient_params_t *params,
+ struct smscore_client_t **client);
+extern void smscore_unregister_client(struct smscore_client_t *client);
+
+extern int smsclient_sendrequest(struct smscore_client_t *client,
+ void *buffer, size_t size);
+extern void smscore_onresponse(struct smscore_device_t *coredev,
+ struct smscore_buffer_t *cb);
+
+
+extern
+struct smscore_buffer_t *smscore_getbuffer(struct smscore_device_t *coredev);
+extern void smscore_putbuffer(struct smscore_device_t *coredev,
+ struct smscore_buffer_t *cb);
+
+void smscore_set_board_id(struct smscore_device_t *core, int id);
+int smscore_get_board_id(struct smscore_device_t *core);
+
+/* smsdvb.c */
+int smsdvb_register(void);
+void smsdvb_unregister(void);
+
+/* smsusb.c */
+int smsusb_register(void);
+void smsusb_unregister(void);
+
+/* ------------------------------------------------------------------------ */
+
+extern int sms_debug;
+
+#define DBG_INFO 1
+#define DBG_ADV 2
+
+#define sms_printk(kern, fmt, arg...) \
+ printk(kern "%s: " fmt "\n", __func__, ##arg)
+
+#define dprintk(kern, lvl, fmt, arg...) do {\
+ if (sms_debug & lvl) \
+ sms_printk(kern, fmt, ##arg); } while (0)
+
+#define sms_log(fmt, arg...) sms_printk(KERN_INFO, fmt, ##arg)
+#define sms_err(fmt, arg...) \
+ sms_printk(KERN_ERR, "line: %d: " fmt, __LINE__, ##arg)
+#define sms_warn(fmt, arg...) sms_printk(KERN_WARNING, fmt, ##arg)
+#define sms_info(fmt, arg...) \
+ dprintk(KERN_INFO, DBG_INFO, fmt, ##arg)
+#define sms_debug(fmt, arg...) \
+ dprintk(KERN_DEBUG, DBG_ADV, fmt, ##arg)
+
+
+#endif /* __smscoreapi_h__ */
diff --git a/drivers/media/dvb/siano/smsdvb.c b/drivers/media/dvb/siano/smsdvb.c
new file mode 100644
index 00000000000..8d490e133f3
--- /dev/null
+++ b/drivers/media/dvb/siano/smsdvb.c
@@ -0,0 +1,449 @@
+/*
+ * Driver for the Siano SMS1xxx USB dongle
+ *
+ * author: Anatoly Greenblat
+ *
+ * Copyright (c), 2005-2008 Siano Mobile Silicon, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation;
+ *
+ * Software distributed under the License is distributed on an "AS IS"
+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied.
+ *
+ * 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/init.h>
+
+#include "smscoreapi.h"
+#include "sms-cards.h"
+
+DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
+
+static struct list_head g_smsdvb_clients;
+static struct mutex g_smsdvb_clientslock;
+
+static int smsdvb_onresponse(void *context, struct smscore_buffer_t *cb)
+{
+ struct smsdvb_client_t *client = (struct smsdvb_client_t *) context;
+ struct SmsMsgHdr_ST *phdr =
+ (struct SmsMsgHdr_ST *)(((u8 *) cb->p) + cb->offset);
+
+ switch (phdr->msgType) {
+ case MSG_SMS_DVBT_BDA_DATA:
+ dvb_dmx_swfilter(&client->demux, (u8 *)(phdr + 1),
+ cb->size - sizeof(struct SmsMsgHdr_ST));
+ break;
+
+ case MSG_SMS_RF_TUNE_RES:
+ complete(&client->tune_done);
+ break;
+
+ case MSG_SMS_GET_STATISTICS_RES:
+ {
+ struct SmsMsgStatisticsInfo_ST *p =
+ (struct SmsMsgStatisticsInfo_ST *)(phdr + 1);
+
+ if (p->Stat.IsDemodLocked) {
+ client->fe_status = FE_HAS_SIGNAL |
+ FE_HAS_CARRIER |
+ FE_HAS_VITERBI |
+ FE_HAS_SYNC |
+ FE_HAS_LOCK;
+
+ client->fe_snr = p->Stat.SNR;
+ client->fe_ber = p->Stat.BER;
+
+ if (p->Stat.InBandPwr < -95)
+ client->fe_signal_strength = 0;
+ else if (p->Stat.InBandPwr > -29)
+ client->fe_signal_strength = 100;
+ else
+ client->fe_signal_strength =
+ (p->Stat.InBandPwr + 95) * 3 / 2;
+ } else {
+ client->fe_status = 0;
+ client->fe_snr =
+ client->fe_ber =
+ client->fe_signal_strength = 0;
+ }
+
+ complete(&client->stat_done);
+ break;
+ } }
+
+ smscore_putbuffer(client->coredev, cb);
+
+ return 0;
+}
+
+static void smsdvb_unregister_client(struct smsdvb_client_t *client)
+{
+ /* must be called under clientslock */
+
+ list_del(&client->entry);
+
+ smscore_unregister_client(client->smsclient);
+ dvb_unregister_frontend(&client->frontend);
+ dvb_dmxdev_release(&client->dmxdev);
+ dvb_dmx_release(&client->demux);
+ dvb_unregister_adapter(&client->adapter);
+ kfree(client);
+}
+
+static void smsdvb_onremove(void *context)
+{
+ kmutex_lock(&g_smsdvb_clientslock);
+
+ smsdvb_unregister_client((struct smsdvb_client_t *) context);
+
+ kmutex_unlock(&g_smsdvb_clientslock);
+}
+
+static int smsdvb_start_feed(struct dvb_demux_feed *feed)
+{
+ struct smsdvb_client_t *client =
+ container_of(feed->demux, struct smsdvb_client_t, demux);
+ struct SmsMsgData_ST PidMsg;
+
+ sms_debug("add pid %d(%x)",
+ feed->pid, feed->pid);
+
+ PidMsg.xMsgHeader.msgSrcId = DVBT_BDA_CONTROL_MSG_ID;
+ PidMsg.xMsgHeader.msgDstId = HIF_TASK;
+ PidMsg.xMsgHeader.msgFlags = 0;
+ PidMsg.xMsgHeader.msgType = MSG_SMS_ADD_PID_FILTER_REQ;
+ PidMsg.xMsgHeader.msgLength = sizeof(PidMsg);
+ PidMsg.msgData[0] = feed->pid;
+
+ return smsclient_sendrequest(client->smsclient,
+ &PidMsg, sizeof(PidMsg));
+}
+
+static int smsdvb_stop_feed(struct dvb_demux_feed *feed)
+{
+ struct smsdvb_client_t *client =
+ container_of(feed->demux, struct smsdvb_client_t, demux);
+ struct SmsMsgData_ST PidMsg;
+
+ sms_debug("remove pid %d(%x)",
+ feed->pid, feed->pid);
+
+ PidMsg.xMsgHeader.msgSrcId = DVBT_BDA_CONTROL_MSG_ID;
+ PidMsg.xMsgHeader.msgDstId = HIF_TASK;
+ PidMsg.xMsgHeader.msgFlags = 0;
+ PidMsg.xMsgHeader.msgType = MSG_SMS_REMOVE_PID_FILTER_REQ;
+ PidMsg.xMsgHeader.msgLength = sizeof(PidMsg);
+ PidMsg.msgData[0] = feed->pid;
+
+ return smsclient_sendrequest(client->smsclient,
+ &PidMsg, sizeof(PidMsg));
+}
+
+static int smsdvb_sendrequest_and_wait(struct smsdvb_client_t *client,
+ void *buffer, size_t size,
+ struct completion *completion)
+{
+ int rc = smsclient_sendrequest(client->smsclient, buffer, size);
+ if (rc < 0)
+ return rc;
+
+ return wait_for_completion_timeout(completion,
+ msecs_to_jiffies(2000)) ?
+ 0 : -ETIME;
+}
+
+static int smsdvb_send_statistics_request(struct smsdvb_client_t *client)
+{
+ struct SmsMsgHdr_ST Msg = { MSG_SMS_GET_STATISTICS_REQ,
+ DVBT_BDA_CONTROL_MSG_ID,
+ HIF_TASK, sizeof(struct SmsMsgHdr_ST), 0 };
+ return smsdvb_sendrequest_and_wait(client, &Msg, sizeof(Msg),
+ &client->stat_done);
+}
+
+static int smsdvb_read_status(struct dvb_frontend *fe, fe_status_t *stat)
+{
+ struct smsdvb_client_t *client =
+ container_of(fe, struct smsdvb_client_t, frontend);
+ int rc = smsdvb_send_statistics_request(client);
+
+ if (!rc)
+ *stat = client->fe_status;
+
+ return rc;
+}
+
+static int smsdvb_read_ber(struct dvb_frontend *fe, u32 *ber)
+{
+ struct smsdvb_client_t *client =
+ container_of(fe, struct smsdvb_client_t, frontend);
+ int rc = smsdvb_send_statistics_request(client);
+
+ if (!rc)
+ *ber = client->fe_ber;
+
+ return rc;
+}
+
+static int smsdvb_read_signal_strength(struct dvb_frontend *fe, u16 *strength)
+{
+ struct smsdvb_client_t *client =
+ container_of(fe, struct smsdvb_client_t, frontend);
+ int rc = smsdvb_send_statistics_request(client);
+
+ if (!rc)
+ *strength = client->fe_signal_strength;
+
+ return rc;
+}
+
+static int smsdvb_read_snr(struct dvb_frontend *fe, u16 *snr)
+{
+ struct smsdvb_client_t *client =
+ container_of(fe, struct smsdvb_client_t, frontend);
+ int rc = smsdvb_send_statistics_request(client);
+
+ if (!rc)
+ *snr = client->fe_snr;
+
+ return rc;
+}
+
+static int smsdvb_get_tune_settings(struct dvb_frontend *fe,
+ struct dvb_frontend_tune_settings *tune)
+{
+ sms_debug("");
+
+ tune->min_delay_ms = 400;
+ tune->step_size = 250000;
+ tune->max_drift = 0;
+ return 0;
+}
+
+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 {
+ struct SmsMsgHdr_ST Msg;
+ u32 Data[3];
+ } Msg;
+
+ 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[2] = 12000000;
+
+ sms_debug("freq %d band %d",
+ fep->frequency, fep->u.ofdm.bandwidth);
+
+ 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;
+ }
+
+ return smsdvb_sendrequest_and_wait(client, &Msg, sizeof(Msg),
+ &client->tune_done);
+}
+
+static int smsdvb_get_frontend(struct dvb_frontend *fe,
+ struct dvb_frontend_parameters *fep)
+{
+ struct smsdvb_client_t *client =
+ container_of(fe, struct smsdvb_client_t, frontend);
+
+ sms_debug("");
+
+ /* todo: */
+ memcpy(fep, &client->fe_params,
+ sizeof(struct dvb_frontend_parameters));
+ return 0;
+}
+
+static void smsdvb_release(struct dvb_frontend *fe)
+{
+ /* do nothing */
+}
+
+static struct dvb_frontend_ops smsdvb_fe_ops = {
+ .info = {
+ .name = "Siano Mobile Digital SMS1xxx",
+ .type = FE_OFDM,
+ .frequency_min = 44250000,
+ .frequency_max = 867250000,
+ .frequency_stepsize = 250000,
+ .caps = FE_CAN_INVERSION_AUTO |
+ FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
+ FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
+ FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 |
+ FE_CAN_QAM_AUTO | FE_CAN_TRANSMISSION_MODE_AUTO |
+ FE_CAN_GUARD_INTERVAL_AUTO |
+ FE_CAN_RECOVER |
+ FE_CAN_HIERARCHY_AUTO,
+ },
+
+ .release = smsdvb_release,
+
+ .set_frontend = smsdvb_set_frontend,
+ .get_frontend = smsdvb_get_frontend,
+ .get_tune_settings = smsdvb_get_tune_settings,
+
+ .read_status = smsdvb_read_status,
+ .read_ber = smsdvb_read_ber,
+ .read_signal_strength = smsdvb_read_signal_strength,
+ .read_snr = smsdvb_read_snr,
+};
+
+static int smsdvb_hotplug(struct smscore_device_t *coredev,
+ struct device *device, int arrival)
+{
+ struct smsclient_params_t params;
+ struct smsdvb_client_t *client;
+ int rc;
+
+ /* device removal handled by onremove callback */
+ if (!arrival)
+ return 0;
+
+ if (smscore_get_device_mode(coredev) != 4) {
+ 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");
+ return -ENOMEM;
+ }
+
+ /* register dvb adapter */
+ rc = dvb_register_adapter(&client->adapter,
+ sms_get_board(
+ smscore_get_board_id(coredev))->name,
+ THIS_MODULE, device, adapter_nr);
+ if (rc < 0) {
+ sms_err("dvb_register_adapter() failed %d", rc);
+ goto adapter_error;
+ }
+
+ /* init dvb demux */
+ client->demux.dmx.capabilities = DMX_TS_FILTERING;
+ client->demux.filternum = 32; /* todo: nova ??? */
+ client->demux.feednum = 32;
+ client->demux.start_feed = smsdvb_start_feed;
+ client->demux.stop_feed = smsdvb_stop_feed;
+
+ rc = dvb_dmx_init(&client->demux);
+ if (rc < 0) {
+ sms_err("dvb_dmx_init failed %d", rc);
+ goto dvbdmx_error;
+ }
+
+ /* init dmxdev */
+ client->dmxdev.filternum = 32;
+ client->dmxdev.demux = &client->demux.dmx;
+ client->dmxdev.capabilities = 0;
+
+ rc = dvb_dmxdev_init(&client->dmxdev, &client->adapter);
+ if (rc < 0) {
+ sms_err("dvb_dmxdev_init failed %d", rc);
+ goto dmxdev_error;
+ }
+
+ /* init and register frontend */
+ memcpy(&client->frontend.ops, &smsdvb_fe_ops,
+ sizeof(struct dvb_frontend_ops));
+
+ rc = dvb_register_frontend(&client->adapter, &client->frontend);
+ if (rc < 0) {
+ sms_err("frontend registration failed %d", rc);
+ goto frontend_error;
+ }
+
+ params.initial_id = 1;
+ params.data_type = MSG_SMS_DVBT_BDA_DATA;
+ params.onresponse_handler = smsdvb_onresponse;
+ params.onremove_handler = smsdvb_onremove;
+ params.context = client;
+
+ rc = smscore_register_client(coredev, &params, &client->smsclient);
+ if (rc < 0) {
+ sms_err("smscore_register_client() failed %d", rc);
+ goto client_error;
+ }
+
+ client->coredev = coredev;
+
+ init_completion(&client->tune_done);
+ init_completion(&client->stat_done);
+
+ kmutex_lock(&g_smsdvb_clientslock);
+
+ list_add(&client->entry, &g_smsdvb_clients);
+
+ kmutex_unlock(&g_smsdvb_clientslock);
+
+ sms_info("success");
+
+ return 0;
+
+client_error:
+ dvb_unregister_frontend(&client->frontend);
+
+frontend_error:
+ dvb_dmxdev_release(&client->dmxdev);
+
+dmxdev_error:
+ dvb_dmx_release(&client->demux);
+
+dvbdmx_error:
+ dvb_unregister_adapter(&client->adapter);
+
+adapter_error:
+ kfree(client);
+ return rc;
+}
+
+int smsdvb_register(void)
+{
+ int rc;
+
+ INIT_LIST_HEAD(&g_smsdvb_clients);
+ kmutex_init(&g_smsdvb_clientslock);
+
+ rc = smscore_register_hotplug(smsdvb_hotplug);
+
+ sms_debug("");
+
+ return rc;
+}
+
+void smsdvb_unregister(void)
+{
+ smscore_unregister_hotplug(smsdvb_hotplug);
+
+ kmutex_lock(&g_smsdvb_clientslock);
+
+ while (!list_empty(&g_smsdvb_clients))
+ smsdvb_unregister_client(
+ (struct smsdvb_client_t *) g_smsdvb_clients.next);
+
+ kmutex_unlock(&g_smsdvb_clientslock);
+}
diff --git a/drivers/media/dvb/siano/smsusb.c b/drivers/media/dvb/siano/smsusb.c
new file mode 100644
index 00000000000..87a3c24454b
--- /dev/null
+++ b/drivers/media/dvb/siano/smsusb.c
@@ -0,0 +1,459 @@
+/*
+ * Driver for the Siano SMS1xxx USB dongle
+ *
+ * author: Anatoly Greenblat
+ *
+ * Copyright (c), 2005-2008 Siano Mobile Silicon, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation;
+ *
+ * Software distributed under the License is distributed on an "AS IS"
+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied.
+ *
+ * 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/init.h>
+#include <linux/usb.h>
+#include <linux/firmware.h>
+
+#include "smscoreapi.h"
+#include "sms-cards.h"
+
+#define USB1_BUFFER_SIZE 0x1000
+#define USB2_BUFFER_SIZE 0x4000
+
+#define MAX_BUFFERS 50
+#define MAX_URBS 10
+
+struct smsusb_device_t;
+
+struct smsusb_urb_t {
+ struct smscore_buffer_t *cb;
+ struct smsusb_device_t *dev;
+
+ struct urb urb;
+};
+
+struct smsusb_device_t {
+ struct usb_device *udev;
+ struct smscore_device_t *coredev;
+
+ struct smsusb_urb_t surbs[MAX_URBS];
+
+ int response_alignment;
+ int buffer_size;
+};
+
+static int smsusb_submit_urb(struct smsusb_device_t *dev,
+ struct smsusb_urb_t *surb);
+
+static void smsusb_onresponse(struct urb *urb)
+{
+ struct smsusb_urb_t *surb = (struct smsusb_urb_t *) urb->context;
+ struct smsusb_device_t *dev = surb->dev;
+
+ if (urb->status < 0) {
+ sms_err("error, urb status %d, %d bytes",
+ urb->status, urb->actual_length);
+ return;
+ }
+
+ if (urb->actual_length > 0) {
+ struct SmsMsgHdr_ST *phdr = (struct SmsMsgHdr_ST *) surb->cb->p;
+
+ if (urb->actual_length >= phdr->msgLength) {
+ surb->cb->size = phdr->msgLength;
+
+ if (dev->response_alignment &&
+ (phdr->msgFlags & MSG_HDR_FLAG_SPLIT_MSG)) {
+
+ surb->cb->offset =
+ dev->response_alignment +
+ ((phdr->msgFlags >> 8) & 3);
+
+ /* sanity check */
+ if (((int) phdr->msgLength +
+ surb->cb->offset) > urb->actual_length) {
+ sms_err("invalid response "
+ "msglen %d offset %d "
+ "size %d",
+ phdr->msgLength,
+ surb->cb->offset,
+ urb->actual_length);
+ goto exit_and_resubmit;
+ }
+
+ /* move buffer pointer and
+ * copy header to its new location */
+ memcpy((char *) phdr + surb->cb->offset,
+ phdr, sizeof(struct SmsMsgHdr_ST));
+ } else
+ surb->cb->offset = 0;
+
+ smscore_onresponse(dev->coredev, surb->cb);
+ surb->cb = NULL;
+ } else {
+ sms_err("invalid response "
+ "msglen %d actual %d",
+ phdr->msgLength, urb->actual_length);
+ }
+ }
+
+exit_and_resubmit:
+ smsusb_submit_urb(dev, surb);
+}
+
+static int smsusb_submit_urb(struct smsusb_device_t *dev,
+ struct smsusb_urb_t *surb)
+{
+ if (!surb->cb) {
+ surb->cb = smscore_getbuffer(dev->coredev);
+ if (!surb->cb) {
+ sms_err("smscore_getbuffer(...) returned NULL");
+ return -ENOMEM;
+ }
+ }
+
+ usb_fill_bulk_urb(
+ &surb->urb,
+ dev->udev,
+ usb_rcvbulkpipe(dev->udev, 0x81),
+ surb->cb->p,
+ dev->buffer_size,
+ smsusb_onresponse,
+ surb
+ );
+ surb->urb.transfer_dma = surb->cb->phys;
+ surb->urb.transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
+
+ return usb_submit_urb(&surb->urb, GFP_ATOMIC);
+}
+
+static void smsusb_stop_streaming(struct smsusb_device_t *dev)
+{
+ int i;
+
+ for (i = 0; i < MAX_URBS; i++) {
+ usb_kill_urb(&dev->surbs[i].urb);
+
+ if (dev->surbs[i].cb) {
+ smscore_putbuffer(dev->coredev, dev->surbs[i].cb);
+ dev->surbs[i].cb = NULL;
+ }
+ }
+}
+
+static int smsusb_start_streaming(struct smsusb_device_t *dev)
+{
+ int i, rc;
+
+ for (i = 0; i < MAX_URBS; i++) {
+ rc = smsusb_submit_urb(dev, &dev->surbs[i]);
+ if (rc < 0) {
+ sms_err("smsusb_submit_urb(...) failed");
+ smsusb_stop_streaming(dev);
+ break;
+ }
+ }
+
+ return rc;
+}
+
+static int smsusb_sendrequest(void *context, void *buffer, size_t size)
+{
+ struct smsusb_device_t *dev = (struct smsusb_device_t *) context;
+ int dummy;
+
+ return usb_bulk_msg(dev->udev, usb_sndbulkpipe(dev->udev, 2),
+ buffer, size, &dummy, 1000);
+}
+
+static char *smsusb1_fw_lkup[] = {
+ "dvbt_stellar_usb.inp",
+ "dvbh_stellar_usb.inp",
+ "tdmb_stellar_usb.inp",
+ "none",
+ "dvbt_bda_stellar_usb.inp",
+};
+
+static inline char *sms_get_fw_name(int mode, int board_id)
+{
+ char **fw = sms_get_board(board_id)->fw;
+ return (fw && fw[mode]) ? fw[mode] : smsusb1_fw_lkup[mode];
+}
+
+static int smsusb1_load_firmware(struct usb_device *udev, int id, int board_id)
+{
+ const struct firmware *fw;
+ u8 *fw_buffer;
+ int rc, dummy;
+ char *fw_filename;
+
+ if (id < DEVICE_MODE_DVBT || id > DEVICE_MODE_DVBT_BDA) {
+ sms_err("invalid firmware id specified %d", id);
+ return -EINVAL;
+ }
+
+ fw_filename = sms_get_fw_name(id, board_id);
+
+ rc = request_firmware(&fw, fw_filename, &udev->dev);
+ if (rc < 0) {
+ sms_warn("failed to open \"%s\" mode %d, "
+ "trying again with default firmware", fw_filename, id);
+
+ fw_filename = smsusb1_fw_lkup[id];
+ rc = request_firmware(&fw, fw_filename, &udev->dev);
+ if (rc < 0) {
+ sms_warn("failed to open \"%s\" mode %d",
+ fw_filename, id);
+
+ return rc;
+ }
+ }
+
+ fw_buffer = kmalloc(fw->size, GFP_KERNEL);
+ if (fw_buffer) {
+ memcpy(fw_buffer, fw->data, fw->size);
+
+ rc = usb_bulk_msg(udev, usb_sndbulkpipe(udev, 2),
+ fw_buffer, fw->size, &dummy, 1000);
+
+ sms_info("sent %zd(%d) bytes, rc %d", fw->size, dummy, rc);
+
+ kfree(fw_buffer);
+ } else {
+ sms_err("failed to allocate firmware buffer");
+ rc = -ENOMEM;
+ }
+ sms_info("read FW %s, size=%zd", fw_filename, fw->size);
+
+ release_firmware(fw);
+
+ return rc;
+}
+
+static void smsusb1_detectmode(void *context, int *mode)
+{
+ char *product_string =
+ ((struct smsusb_device_t *) context)->udev->product;
+
+ *mode = DEVICE_MODE_NONE;
+
+ if (!product_string) {
+ product_string = "none";
+ sms_err("product string not found");
+ } else if (strstr(product_string, "DVBH"))
+ *mode = 1;
+ else if (strstr(product_string, "BDA"))
+ *mode = 4;
+ else if (strstr(product_string, "DVBT"))
+ *mode = 0;
+ else if (strstr(product_string, "TDMB"))
+ *mode = 2;
+
+ sms_info("%d \"%s\"", *mode, product_string);
+}
+
+static int smsusb1_setmode(void *context, int mode)
+{
+ struct SmsMsgHdr_ST Msg = { MSG_SW_RELOAD_REQ, 0, HIF_TASK,
+ sizeof(struct SmsMsgHdr_ST), 0 };
+
+ if (mode < DEVICE_MODE_DVBT || mode > DEVICE_MODE_DVBT_BDA) {
+ sms_err("invalid firmware id specified %d", mode);
+ return -EINVAL;
+ }
+
+ return smsusb_sendrequest(context, &Msg, sizeof(Msg));
+}
+
+static void smsusb_term_device(struct usb_interface *intf)
+{
+ struct smsusb_device_t *dev =
+ (struct smsusb_device_t *) usb_get_intfdata(intf);
+
+ if (dev) {
+ smsusb_stop_streaming(dev);
+
+ /* unregister from smscore */
+ if (dev->coredev)
+ smscore_unregister_device(dev->coredev);
+
+ kfree(dev);
+
+ sms_info("device %p destroyed", dev);
+ }
+
+ usb_set_intfdata(intf, NULL);
+}
+
+static int smsusb_init_device(struct usb_interface *intf, int board_id)
+{
+ struct smsdevice_params_t params;
+ struct smsusb_device_t *dev;
+ int i, rc;
+
+ /* create device object */
+ dev = kzalloc(sizeof(struct smsusb_device_t), GFP_KERNEL);
+ if (!dev) {
+ sms_err("kzalloc(sizeof(struct smsusb_device_t) failed");
+ return -ENOMEM;
+ }
+
+ memset(&params, 0, sizeof(params));
+ usb_set_intfdata(intf, dev);
+ dev->udev = interface_to_usbdev(intf);
+
+ params.device_type = sms_get_board(board_id)->type;
+
+ switch (params.device_type) {
+ case SMS_STELLAR:
+ dev->buffer_size = USB1_BUFFER_SIZE;
+
+ params.setmode_handler = smsusb1_setmode;
+ params.detectmode_handler = smsusb1_detectmode;
+ break;
+ default:
+ sms_err("Unspecified sms device type!");
+ /* fall-thru */
+ case SMS_NOVA_A0:
+ case SMS_NOVA_B0:
+ case SMS_VEGA:
+ dev->buffer_size = USB2_BUFFER_SIZE;
+ dev->response_alignment =
+ dev->udev->ep_in[1]->desc.wMaxPacketSize -
+ sizeof(struct SmsMsgHdr_ST);
+
+ params.flags |= SMS_DEVICE_FAMILY2;
+ break;
+ }
+
+ params.device = &dev->udev->dev;
+ params.buffer_size = dev->buffer_size;
+ params.num_buffers = MAX_BUFFERS;
+ params.sendrequest_handler = smsusb_sendrequest;
+ params.context = dev;
+ snprintf(params.devpath, sizeof(params.devpath),
+ "usb\\%d-%s", dev->udev->bus->busnum, dev->udev->devpath);
+
+ /* register in smscore */
+ rc = smscore_register_device(&params, &dev->coredev);
+ if (rc < 0) {
+ sms_err("smscore_register_device(...) failed, rc %d", rc);
+ smsusb_term_device(intf);
+ return rc;
+ }
+
+ smscore_set_board_id(dev->coredev, board_id);
+
+ /* initialize urbs */
+ for (i = 0; i < MAX_URBS; i++) {
+ dev->surbs[i].dev = dev;
+ usb_init_urb(&dev->surbs[i].urb);
+ }
+
+ sms_info("smsusb_start_streaming(...).");
+ rc = smsusb_start_streaming(dev);
+ if (rc < 0) {
+ sms_err("smsusb_start_streaming(...) failed");
+ smsusb_term_device(intf);
+ return rc;
+ }
+
+ rc = smscore_start_device(dev->coredev);
+ if (rc < 0) {
+ sms_err("smscore_start_device(...) failed");
+ smsusb_term_device(intf);
+ return rc;
+ }
+
+ sms_info("device %p created", dev);
+
+ return rc;
+}
+
+static int smsusb_probe(struct usb_interface *intf,
+ const struct usb_device_id *id)
+{
+ struct usb_device *udev = interface_to_usbdev(intf);
+ char devpath[32];
+ int i, rc;
+
+ rc = usb_clear_halt(udev, usb_rcvbulkpipe(udev, 0x81));
+ rc = usb_clear_halt(udev, usb_rcvbulkpipe(udev, 0x02));
+
+ if (intf->num_altsetting > 0) {
+ rc = usb_set_interface(
+ udev, intf->cur_altsetting->desc.bInterfaceNumber, 0);
+ if (rc < 0) {
+ sms_err("usb_set_interface failed, rc %d", rc);
+ return rc;
+ }
+ }
+
+ sms_info("smsusb_probe %d",
+ intf->cur_altsetting->desc.bInterfaceNumber);
+ for (i = 0; i < intf->cur_altsetting->desc.bNumEndpoints; i++)
+ sms_info("endpoint %d %02x %02x %d", i,
+ intf->cur_altsetting->endpoint[i].desc.bEndpointAddress,
+ intf->cur_altsetting->endpoint[i].desc.bmAttributes,
+ intf->cur_altsetting->endpoint[i].desc.wMaxPacketSize);
+
+ if ((udev->actconfig->desc.bNumInterfaces == 2) &&
+ (intf->cur_altsetting->desc.bInterfaceNumber == 0)) {
+ sms_err("rom interface 0 is not used");
+ return -ENODEV;
+ }
+
+ if (intf->cur_altsetting->desc.bInterfaceNumber == 1) {
+ snprintf(devpath, sizeof(devpath), "usb\\%d-%s",
+ udev->bus->busnum, udev->devpath);
+ sms_info("stellar device was found.");
+ return smsusb1_load_firmware(
+ udev, smscore_registry_getmode(devpath),
+ id->driver_info);
+ }
+
+ rc = smsusb_init_device(intf, id->driver_info);
+ sms_info("rc %d", rc);
+ return rc;
+}
+
+static void smsusb_disconnect(struct usb_interface *intf)
+{
+ smsusb_term_device(intf);
+}
+
+static struct usb_driver smsusb_driver = {
+ .name = "sms1xxx",
+ .probe = smsusb_probe,
+ .disconnect = smsusb_disconnect,
+ .id_table = smsusb_id_table,
+};
+
+int smsusb_register(void)
+{
+ int rc = usb_register(&smsusb_driver);
+ if (rc)
+ sms_err("usb_register failed. Error number %d", rc);
+
+ sms_debug("");
+
+ return rc;
+}
+
+void smsusb_unregister(void)
+{
+ sms_debug("");
+ /* Regular USB Cleanup */
+ usb_deregister(&smsusb_driver);
+}
+
diff --git a/drivers/media/dvb/ttpci/Kconfig b/drivers/media/dvb/ttpci/Kconfig
index 07643e01009..41b5a988b61 100644
--- a/drivers/media/dvb/ttpci/Kconfig
+++ b/drivers/media/dvb/ttpci/Kconfig
@@ -5,8 +5,6 @@ config TTPCI_EEPROM
config DVB_AV7110
tristate "AV7110 cards"
depends on DVB_CORE && PCI && I2C
- depends on HOTPLUG
- select FW_LOADER if !DVB_AV7110_FIRMWARE
select TTPCI_EEPROM
select VIDEO_SAA7146_VV
depends on VIDEO_DEV # dependencies of VIDEO_SAA7146_VV
@@ -106,6 +104,8 @@ config DVB_BUDGET_CI
select DVB_STV0299 if !DVB_FE_CUSTOMISE
select DVB_TDA1004X if !DVB_FE_CUSTOMISE
select DVB_LNBP21 if !DVB_FE_CUSTOMISE
+ select DVB_TDA10023 if !DVB_FE_CUSTOMISE
+ select MEDIA_TUNER_TDA827X if !DVB_FE_CUSTOMISE
select VIDEO_IR
help
Support for simple SAA7146 based DVB cards
@@ -125,14 +125,12 @@ config DVB_BUDGET_AV
depends on DVB_BUDGET_CORE && I2C
select VIDEO_SAA7146_VV
depends on VIDEO_DEV # dependencies of VIDEO_SAA7146_VV
- depends on HOTPLUG # dependency of FW_LOADER
select DVB_PLL if !DVB_FE_CUSTOMISE
select DVB_STV0299 if !DVB_FE_CUSTOMISE
select DVB_TDA1004X if !DVB_FE_CUSTOMISE
select DVB_TDA10021 if !DVB_FE_CUSTOMISE
select DVB_TDA10023 if !DVB_FE_CUSTOMISE
select DVB_TUA6100 if !DVB_FE_CUSTOMISE
- select FW_LOADER
help
Support for simple SAA7146 based DVB cards
(so called Budget- or Nova-PCI cards) without onboard
diff --git a/drivers/media/dvb/ttpci/Makefile b/drivers/media/dvb/ttpci/Makefile
index d7483f1a9b3..71451237294 100644
--- a/drivers/media/dvb/ttpci/Makefile
+++ b/drivers/media/dvb/ttpci/Makefile
@@ -3,7 +3,11 @@
# and the AV7110 DVB device driver
#
-dvb-ttpci-objs := av7110_hw.o av7110_v4l.o av7110_av.o av7110_ca.o av7110.o av7110_ipack.o av7110_ir.o
+dvb-ttpci-objs := av7110_hw.o av7110_v4l.o av7110_av.o av7110_ca.o av7110.o av7110_ipack.o
+
+ifdef CONFIG_INPUT_EVDEV
+dvb-ttpci-objs += av7110_ir.o
+endif
obj-$(CONFIG_TTPCI_EEPROM) += ttpci-eeprom.o
obj-$(CONFIG_DVB_BUDGET_CORE) += budget-core.o
@@ -14,6 +18,7 @@ obj-$(CONFIG_DVB_BUDGET_PATCH) += budget-patch.o
obj-$(CONFIG_DVB_AV7110) += dvb-ttpci.o
EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core/ -Idrivers/media/dvb/frontends/
+EXTRA_CFLAGS += -Idrivers/media/common/tuners
hostprogs-y := fdump
diff --git a/drivers/media/dvb/ttpci/av7110.c b/drivers/media/dvb/ttpci/av7110.c
index f05d43d8b5c..0777e8f9544 100644
--- a/drivers/media/dvb/ttpci/av7110.c
+++ b/drivers/media/dvb/ttpci/av7110.c
@@ -587,7 +587,7 @@ static void gpioirq(unsigned long data)
}
DVB_RINGBUFFER_SKIP(cibuf, 2);
- dvb_ringbuffer_read(cibuf, av7110->debi_virt, len, 0);
+ dvb_ringbuffer_read(cibuf, av7110->debi_virt, len);
iwdebi(av7110, DEBINOSWAP, TX_LEN, len, 2);
iwdebi(av7110, DEBINOSWAP, IRQ_STATE_EXT, len, 2);
@@ -1198,7 +1198,6 @@ static int start_ts_capture(struct av7110 *budget)
if (budget->feeding1)
return ++budget->feeding1;
memset(budget->grabbing, 0x00, TS_HEIGHT * TS_WIDTH);
- budget->tsf = 0xff;
budget->ttbp = 0;
SAA7146_IER_ENABLE(budget->dev, MASK_10); /* VPE */
saa7146_write(budget->dev, MC1, (MASK_04 | MASK_20)); /* DMA3 on */
@@ -2403,18 +2402,18 @@ static int __devinit av7110_attach(struct saa7146_dev* dev,
saa7146_write(dev, MC1, MASK_29);
/* RPS1 timeout disable */
saa7146_write(dev, RPS_TOV1, 0);
- WRITE_RPS1(cpu_to_le32(CMD_PAUSE | EVT_VBI_B));
- WRITE_RPS1(cpu_to_le32(CMD_WR_REG_MASK | (GPIO_CTRL>>2)));
- WRITE_RPS1(cpu_to_le32(GPIO3_MSK));
- WRITE_RPS1(cpu_to_le32(SAA7146_GPIO_OUTLO<<24));
+ WRITE_RPS1(CMD_PAUSE | EVT_VBI_B);
+ WRITE_RPS1(CMD_WR_REG_MASK | (GPIO_CTRL>>2));
+ WRITE_RPS1(GPIO3_MSK);
+ WRITE_RPS1(SAA7146_GPIO_OUTLO<<24);
#if RPS_IRQ
/* issue RPS1 interrupt to increment counter */
- WRITE_RPS1(cpu_to_le32(CMD_INTERRUPT));
+ WRITE_RPS1(CMD_INTERRUPT);
#endif
- WRITE_RPS1(cpu_to_le32(CMD_STOP));
+ WRITE_RPS1(CMD_STOP);
/* Jump to begin of RPS program as safety measure (p37) */
- WRITE_RPS1(cpu_to_le32(CMD_JUMP));
- WRITE_RPS1(cpu_to_le32(dev->d_rps1.dma_handle));
+ WRITE_RPS1(CMD_JUMP);
+ WRITE_RPS1(dev->d_rps1.dma_handle);
#if RPS_IRQ
/* set event counter 1 source as RPS1 interrupt (0x03) (rE4 p53)
@@ -2472,11 +2471,7 @@ static int __devinit av7110_attach(struct saa7146_dev* dev,
get recognized before the main driver is fully loaded */
saa7146_write(dev, GPIO_CTRL, 0x500000);
-#ifdef I2C_ADAP_CLASS_TV_DIGITAL
- av7110->i2c_adap.class = I2C_ADAP_CLASS_TV_DIGITAL;
-#else
av7110->i2c_adap.class = I2C_CLASS_TV_DIGITAL;
-#endif
strlcpy(av7110->i2c_adap.name, pci_ext->ext_priv, sizeof(av7110->i2c_adap.name));
saa7146_i2c_adapter_prepare(dev, &av7110->i2c_adap, SAA7146_I2C_BUS_BIT_RATE_120); /* 275 kHz */
@@ -2527,28 +2522,28 @@ static int __devinit av7110_attach(struct saa7146_dev* dev,
count = 0;
/* Wait Source Line Counter Threshold (p36) */
- WRITE_RPS1(cpu_to_le32(CMD_PAUSE | EVT_HS));
+ WRITE_RPS1(CMD_PAUSE | EVT_HS);
/* Set GPIO3=1 (p42) */
- WRITE_RPS1(cpu_to_le32(CMD_WR_REG_MASK | (GPIO_CTRL>>2)));
- WRITE_RPS1(cpu_to_le32(GPIO3_MSK));
- WRITE_RPS1(cpu_to_le32(SAA7146_GPIO_OUTHI<<24));
+ WRITE_RPS1(CMD_WR_REG_MASK | (GPIO_CTRL>>2));
+ WRITE_RPS1(GPIO3_MSK);
+ WRITE_RPS1(SAA7146_GPIO_OUTHI<<24);
#if RPS_IRQ
/* issue RPS1 interrupt */
- WRITE_RPS1(cpu_to_le32(CMD_INTERRUPT));
+ WRITE_RPS1(CMD_INTERRUPT);
#endif
/* Wait reset Source Line Counter Threshold (p36) */
- WRITE_RPS1(cpu_to_le32(CMD_PAUSE | RPS_INV | EVT_HS));
+ WRITE_RPS1(CMD_PAUSE | RPS_INV | EVT_HS);
/* Set GPIO3=0 (p42) */
- WRITE_RPS1(cpu_to_le32(CMD_WR_REG_MASK | (GPIO_CTRL>>2)));
- WRITE_RPS1(cpu_to_le32(GPIO3_MSK));
- WRITE_RPS1(cpu_to_le32(SAA7146_GPIO_OUTLO<<24));
+ WRITE_RPS1(CMD_WR_REG_MASK | (GPIO_CTRL>>2));
+ WRITE_RPS1(GPIO3_MSK);
+ WRITE_RPS1(SAA7146_GPIO_OUTLO<<24);
#if RPS_IRQ
/* issue RPS1 interrupt */
- WRITE_RPS1(cpu_to_le32(CMD_INTERRUPT));
+ WRITE_RPS1(CMD_INTERRUPT);
#endif
/* Jump to begin of RPS program (p37) */
- WRITE_RPS1(cpu_to_le32(CMD_JUMP));
- WRITE_RPS1(cpu_to_le32(dev->d_rps1.dma_handle));
+ WRITE_RPS1(CMD_JUMP);
+ WRITE_RPS1(dev->d_rps1.dma_handle);
/* Fix VSYNC level */
saa7146_setgpio(dev, 3, SAA7146_GPIO_OUTLO);
diff --git a/drivers/media/dvb/ttpci/av7110.h b/drivers/media/dvb/ttpci/av7110.h
index e494e04eeee..55f23ddcb99 100644
--- a/drivers/media/dvb/ttpci/av7110.h
+++ b/drivers/media/dvb/ttpci/av7110.h
@@ -188,7 +188,6 @@ struct av7110 {
struct dvb_net dvb_net1;
spinlock_t feedlock1;
int feeding1;
- u8 tsf;
u32 ttbp;
unsigned char *grabbing;
struct saa7146_pgtable pt;
diff --git a/drivers/media/dvb/ttpci/av7110_av.c b/drivers/media/dvb/ttpci/av7110_av.c
index ec55a968f20..184647ad1c7 100644
--- a/drivers/media/dvb/ttpci/av7110_av.c
+++ b/drivers/media/dvb/ttpci/av7110_av.c
@@ -269,7 +269,7 @@ int av7110_pes_play(void *dest, struct dvb_ringbuffer *buf, int dlen)
return -1;
}
- dvb_ringbuffer_read(buf, dest, (size_t) blen, 0);
+ dvb_ringbuffer_read(buf, dest, (size_t) blen);
dprintk(2, "pread=0x%08lx, pwrite=0x%08lx\n",
(unsigned long) buf->pread, (unsigned long) buf->pwrite);
diff --git a/drivers/media/dvb/ttpci/av7110_ca.c b/drivers/media/dvb/ttpci/av7110_ca.c
index c58e3fc509e..261135ded48 100644
--- a/drivers/media/dvb/ttpci/av7110_ca.c
+++ b/drivers/media/dvb/ttpci/av7110_ca.c
@@ -208,7 +208,7 @@ static ssize_t ci_ll_read(struct dvb_ringbuffer *cibuf, struct file *file,
return -EINVAL;
DVB_RINGBUFFER_SKIP(cibuf, 2);
- return dvb_ringbuffer_read(cibuf, (u8 *)buf, len, 1);
+ return dvb_ringbuffer_read_user(cibuf, buf, len);
}
static int dvb_ca_open(struct inode *inode, struct file *file)
diff --git a/drivers/media/dvb/ttpci/av7110_hw.h b/drivers/media/dvb/ttpci/av7110_hw.h
index 74d940f75da..ca99e5c1fc8 100644
--- a/drivers/media/dvb/ttpci/av7110_hw.h
+++ b/drivers/media/dvb/ttpci/av7110_hw.h
@@ -305,7 +305,6 @@ enum av7110_command_type {
#define IRQ_STATE (DPRAM_BASE + 0x0F4)
#define IRQ_STATE_EXT (DPRAM_BASE + 0x0F6)
#define MSGSTATE (DPRAM_BASE + 0x0F8)
-#define FILT_STATE (DPRAM_BASE + 0x0FA)
#define COMMAND (DPRAM_BASE + 0x0FC)
#define COM_BUFF (DPRAM_BASE + 0x100)
#define COM_BUFF_SIZE 0x20
@@ -332,8 +331,6 @@ enum av7110_command_type {
/* firmware status area */
#define STATUS_BASE (DPRAM_BASE + 0x1FC0)
-#define STATUS_SCR (STATUS_BASE + 0x00)
-#define STATUS_MODES (STATUS_BASE + 0x04)
#define STATUS_LOOPS (STATUS_BASE + 0x08)
#define STATUS_MPEG_WIDTH (STATUS_BASE + 0x0C)
diff --git a/drivers/media/dvb/ttpci/budget-av.c b/drivers/media/dvb/ttpci/budget-av.c
index b30a5288e48..b7d1f2f18d3 100644
--- a/drivers/media/dvb/ttpci/budget-av.c
+++ b/drivers/media/dvb/ttpci/budget-av.c
@@ -667,6 +667,11 @@ static struct tda1002x_config philips_cu1216_config_altaddress = {
.invert = 0,
};
+static struct tda10023_config philips_cu1216_tda10023_config = {
+ .demod_address = 0x0c,
+ .invert = 1,
+};
+
static int philips_tu1216_tuner_init(struct dvb_frontend *fe)
{
struct budget *budget = (struct budget *) fe->dvb->priv;
@@ -1019,9 +1024,10 @@ static void frontend_init(struct budget_av *budget_av)
case SUBID_DVBC_KNC1_PLUS_MK3:
budget_av->reinitialise_demod = 1;
budget_av->budget.dev->i2c_bitrate = SAA7146_I2C_BUS_BIT_RATE_240;
- fe = dvb_attach(tda10023_attach, &philips_cu1216_config,
- &budget_av->budget.i2c_adap,
- read_pwm(budget_av));
+ fe = dvb_attach(tda10023_attach,
+ &philips_cu1216_tda10023_config,
+ &budget_av->budget.i2c_adap,
+ read_pwm(budget_av));
if (fe) {
fe->ops.tuner_ops.set_params = philips_cu1216_tuner_set_params;
}
diff --git a/drivers/media/dvb/ttpci/budget-ci.c b/drivers/media/dvb/ttpci/budget-ci.c
index 6530323d540..060e7c78532 100644
--- a/drivers/media/dvb/ttpci/budget-ci.c
+++ b/drivers/media/dvb/ttpci/budget-ci.c
@@ -46,6 +46,8 @@
#include "lnbp21.h"
#include "bsbe1.h"
#include "bsru6.h"
+#include "tda1002x.h"
+#include "tda827x.h"
/*
* Regarding DEBIADDR_IR:
@@ -225,6 +227,7 @@ static int msp430_ir_init(struct budget_ci *budget_ci)
break;
case 0x1010:
case 0x1017:
+ case 0x101a:
/* for the Technotrend 1500 bundled remote */
ir_input_init(input_dev, &budget_ci->ir.state,
IR_TYPE_RC5, ir_codes_tt_1500);
@@ -1056,6 +1059,15 @@ static struct stv0297_config dvbc_philips_tdm1316l_config = {
.stop_during_read = 1,
};
+static struct tda10023_config tda10023_config = {
+ .demod_address = 0xc,
+ .invert = 0,
+ .xtal = 16000000,
+ .pll_m = 11,
+ .pll_p = 3,
+ .pll_n = 1,
+ .deltaf = 0xa511,
+};
@@ -1126,7 +1138,17 @@ static void frontend_init(struct budget_ci *budget_ci)
budget_ci->budget.dvb_frontend = NULL;
}
}
+ break;
+ case 0x101a: /* TT Budget-C-1501 (philips tda10023/philips tda8274A) */
+ budget_ci->budget.dvb_frontend = dvb_attach(tda10023_attach, &tda10023_config, &budget_ci->budget.i2c_adap, 0x48);
+ if (budget_ci->budget.dvb_frontend) {
+ if (dvb_attach(tda827x_attach, budget_ci->budget.dvb_frontend, 0x61, &budget_ci->budget.i2c_adap, NULL) == NULL) {
+ printk(KERN_ERR "%s: No tda827x found!\n", __func__);
+ dvb_frontend_detach(budget_ci->budget.dvb_frontend);
+ budget_ci->budget.dvb_frontend = NULL;
+ }
+ }
break;
}
@@ -1216,6 +1238,7 @@ MAKE_BUDGET_INFO(ttbci, "TT-Budget/WinTV-NOVA-CI PCI", BUDGET_TT_HW_DISEQC);
MAKE_BUDGET_INFO(ttbt2, "TT-Budget/WinTV-NOVA-T PCI", BUDGET_TT);
MAKE_BUDGET_INFO(ttbtci, "TT-Budget-T-CI PCI", BUDGET_TT);
MAKE_BUDGET_INFO(ttbcci, "TT-Budget-C-CI PCI", BUDGET_TT);
+MAKE_BUDGET_INFO(ttc1501, "TT-Budget C-1501 PCI", BUDGET_TT);
static struct pci_device_id pci_tbl[] = {
MAKE_EXTENSION_PCI(ttbci, 0x13c2, 0x100c),
@@ -1224,6 +1247,7 @@ static struct pci_device_id pci_tbl[] = {
MAKE_EXTENSION_PCI(ttbt2, 0x13c2, 0x1011),
MAKE_EXTENSION_PCI(ttbtci, 0x13c2, 0x1012),
MAKE_EXTENSION_PCI(ttbs2, 0x13c2, 0x1017),
+ MAKE_EXTENSION_PCI(ttc1501, 0x13c2, 0x101a),
{
.vendor = 0,
}
diff --git a/drivers/media/dvb/ttpci/budget-core.c b/drivers/media/dvb/ttpci/budget-core.c
index 18cac4b12ab..6f4ddb643fe 100644
--- a/drivers/media/dvb/ttpci/budget-core.c
+++ b/drivers/media/dvb/ttpci/budget-core.c
@@ -497,11 +497,7 @@ int ttpci_budget_init(struct budget *budget, struct saa7146_dev *dev,
if (bi->type != BUDGET_FS_ACTIVY)
saa7146_write(dev, GPIO_CTRL, 0x500000); /* GPIO 3 = 1 */
-#ifdef I2C_ADAP_CLASS_TV_DIGITAL
- budget->i2c_adap.class = I2C_ADAP_CLASS_TV_DIGITAL;
-#else
budget->i2c_adap.class = I2C_CLASS_TV_DIGITAL;
-#endif
strlcpy(budget->i2c_adap.name, budget->card->name, sizeof(budget->i2c_adap.name));
diff --git a/drivers/media/dvb/ttpci/budget-patch.c b/drivers/media/dvb/ttpci/budget-patch.c
index 9a155396d6a..aa5ed4ef19f 100644
--- a/drivers/media/dvb/ttpci/budget-patch.c
+++ b/drivers/media/dvb/ttpci/budget-patch.c
@@ -116,7 +116,8 @@ static int SendDiSEqCMsg (struct budget *budget, int len, u8 *msg, unsigned long
DiseqcSendByte(budget, 0xff);
else {
saa7146_setgpio(dev, 3, SAA7146_GPIO_OUTHI);
- udelay(12500);
+ mdelay(12);
+ udelay(500);
saa7146_setgpio(dev, 3, SAA7146_GPIO_OUTLO);
}
msleep(20);
@@ -431,22 +432,22 @@ static int budget_patch_attach (struct saa7146_dev* dev, struct saa7146_pci_exte
// in budget patch GPIO3 is connected to VSYNC_B
count = 0;
#if 0
- WRITE_RPS1(cpu_to_le32(CMD_UPLOAD |
- MASK_10 | MASK_09 | MASK_08 | MASK_06 | MASK_05 | MASK_04 | MASK_03 | MASK_02 ));
+ WRITE_RPS1(CMD_UPLOAD |
+ MASK_10 | MASK_09 | MASK_08 | MASK_06 | MASK_05 | MASK_04 | MASK_03 | MASK_02 );
#endif
- WRITE_RPS1(cpu_to_le32(CMD_PAUSE | EVT_VBI_B));
- WRITE_RPS1(cpu_to_le32(CMD_WR_REG_MASK | (GPIO_CTRL>>2)));
- WRITE_RPS1(cpu_to_le32(GPIO3_MSK));
- WRITE_RPS1(cpu_to_le32(SAA7146_GPIO_OUTLO<<24));
+ WRITE_RPS1(CMD_PAUSE | EVT_VBI_B);
+ WRITE_RPS1(CMD_WR_REG_MASK | (GPIO_CTRL>>2));
+ WRITE_RPS1(GPIO3_MSK);
+ WRITE_RPS1(SAA7146_GPIO_OUTLO<<24);
#if RPS_IRQ
// issue RPS1 interrupt to increment counter
- WRITE_RPS1(cpu_to_le32(CMD_INTERRUPT));
+ WRITE_RPS1(CMD_INTERRUPT);
// at least a NOP is neede between two interrupts
- WRITE_RPS1(cpu_to_le32(CMD_NOP));
+ WRITE_RPS1(CMD_NOP);
// interrupt again
- WRITE_RPS1(cpu_to_le32(CMD_INTERRUPT));
+ WRITE_RPS1(CMD_INTERRUPT);
#endif
- WRITE_RPS1(cpu_to_le32(CMD_STOP));
+ WRITE_RPS1(CMD_STOP);
#if RPS_IRQ
// set event counter 1 source as RPS1 interrupt (0x03) (rE4 p53)
@@ -558,28 +559,28 @@ static int budget_patch_attach (struct saa7146_dev* dev, struct saa7146_pci_exte
// Wait Source Line Counter Threshold (p36)
- WRITE_RPS1(cpu_to_le32(CMD_PAUSE | EVT_HS));
+ WRITE_RPS1(CMD_PAUSE | EVT_HS);
// Set GPIO3=1 (p42)
- WRITE_RPS1(cpu_to_le32(CMD_WR_REG_MASK | (GPIO_CTRL>>2)));
- WRITE_RPS1(cpu_to_le32(GPIO3_MSK));
- WRITE_RPS1(cpu_to_le32(SAA7146_GPIO_OUTHI<<24));
+ WRITE_RPS1(CMD_WR_REG_MASK | (GPIO_CTRL>>2));
+ WRITE_RPS1(GPIO3_MSK);
+ WRITE_RPS1(SAA7146_GPIO_OUTHI<<24);
#if RPS_IRQ
// issue RPS1 interrupt
- WRITE_RPS1(cpu_to_le32(CMD_INTERRUPT));
+ WRITE_RPS1(CMD_INTERRUPT);
#endif
// Wait reset Source Line Counter Threshold (p36)
- WRITE_RPS1(cpu_to_le32(CMD_PAUSE | RPS_INV | EVT_HS));
+ WRITE_RPS1(CMD_PAUSE | RPS_INV | EVT_HS);
// Set GPIO3=0 (p42)
- WRITE_RPS1(cpu_to_le32(CMD_WR_REG_MASK | (GPIO_CTRL>>2)));
- WRITE_RPS1(cpu_to_le32(GPIO3_MSK));
- WRITE_RPS1(cpu_to_le32(SAA7146_GPIO_OUTLO<<24));
+ WRITE_RPS1(CMD_WR_REG_MASK | (GPIO_CTRL>>2));
+ WRITE_RPS1(GPIO3_MSK);
+ WRITE_RPS1(SAA7146_GPIO_OUTLO<<24);
#if RPS_IRQ
// issue RPS1 interrupt
- WRITE_RPS1(cpu_to_le32(CMD_INTERRUPT));
+ WRITE_RPS1(CMD_INTERRUPT);
#endif
// Jump to begin of RPS program (p37)
- WRITE_RPS1(cpu_to_le32(CMD_JUMP));
- WRITE_RPS1(cpu_to_le32(dev->d_rps1.dma_handle));
+ WRITE_RPS1(CMD_JUMP);
+ WRITE_RPS1(dev->d_rps1.dma_handle);
// Fix VSYNC level
saa7146_setgpio(dev, 3, SAA7146_GPIO_OUTLO);
diff --git a/drivers/media/dvb/ttpci/budget.c b/drivers/media/dvb/ttpci/budget.c
index 2293d80c6e5..f0068996ac0 100644
--- a/drivers/media/dvb/ttpci/budget.c
+++ b/drivers/media/dvb/ttpci/budget.c
@@ -108,7 +108,8 @@ static int SendDiSEqCMsg (struct budget *budget, int len, u8 *msg, unsigned long
DiseqcSendByte(budget, 0xff);
else {
saa7146_setgpio(dev, 3, SAA7146_GPIO_OUTHI);
- udelay(12500);
+ mdelay(12);
+ udelay(500);
saa7146_setgpio(dev, 3, SAA7146_GPIO_OUTLO);
}
msleep(20);
diff --git a/drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c b/drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c
index bc2043e44eb..e6c9cd2e3b9 100644
--- a/drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c
+++ b/drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c
@@ -12,6 +12,7 @@
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/wait.h>
+#include <linux/fs.h>
#include <linux/module.h>
#include <linux/usb.h>
#include <linux/delay.h>
@@ -990,22 +991,9 @@ static int stc_open(struct inode *inode, struct file *file)
}
static ssize_t stc_read(struct file *file, char *buf, size_t count,
- loff_t * offset)
+ loff_t *offset)
{
- int tc = count;
-
- if ((tc + *offset) > 8192)
- tc = 8192 - *offset;
-
- if (tc < 0)
- return 0;
-
- if (copy_to_user(buf, stc_firmware + *offset, tc))
- return -EFAULT;
-
- *offset += tc;
-
- return tc;
+ return simple_read_from_buffer(buf, count, offset, stc_firmware, 8192);
}
static int stc_release(struct inode *inode, struct file *file)
@@ -1693,11 +1681,7 @@ static int ttusb_probe(struct usb_interface *intf, const struct usb_device_id *i
i2c_set_adapdata(&ttusb->i2c_adap, ttusb);
-#ifdef I2C_ADAP_CLASS_TV_DIGITAL
- ttusb->i2c_adap.class = I2C_ADAP_CLASS_TV_DIGITAL;
-#else
ttusb->i2c_adap.class = I2C_CLASS_TV_DIGITAL;
-#endif
ttusb->i2c_adap.algo = &ttusb_dec_algo;
ttusb->i2c_adap.algo_data = NULL;
ttusb->i2c_adap.dev.parent = &udev->dev;
diff --git a/drivers/media/dvb/ttusb-dec/Kconfig b/drivers/media/dvb/ttusb-dec/Kconfig
index a23cc0aa17d..d5f48a3102b 100644
--- a/drivers/media/dvb/ttusb-dec/Kconfig
+++ b/drivers/media/dvb/ttusb-dec/Kconfig
@@ -1,8 +1,6 @@
config DVB_TTUSB_DEC
tristate "Technotrend/Hauppauge USB DEC devices"
depends on DVB_CORE && USB && INPUT
- depends on HOTPLUG # due to FW_LOADER
- select FW_LOADER
select CRC32
help
Support for external USB adapters designed by Technotrend and