Note:
* Only tested with qam256.
* I changed the EM2880_DVB_MAX_PACKETSIZE value to 752. Don't
know how you want to deal with that.
* To compile you have to create a top level tda18271/ directory and
copy tda18271.h into it. It's not in the kernel headers so you need
to get it from the kernel sources.
* The following is getting set for cards that don't even have the
chip, so I boxed that stuff in.
/* zl10353 powersaving */
dvb_dev->init_override = dvb_dev->frontend->ops.init;
dvb_dev->frontend->ops.sleep = em28xx_zl10353_sleep;
dvb_dev->frontend->ops.init = em28xx_zl10353_init;
* dvb_dmx_swfilter() is getting called twice in em2880-dvb.c and
corrupting data.
diff -r 677bbac6845b em2880-dvb.c
--- a/em2880-dvb.c Sun Jul 20 17:52:57 2008 +0200
+++ b/em2880-dvb.c Mon Jul 21 20:36:10 2008 -0400
@@ -42,10 +42,11 @@
#include "lgdt3304/lgdt3304.h"
#include "qt1010/qt1010.h"
#include "mt2060/mt2060.h"
+#include "tda18271/tda18271.h"
#include "lgdt330x.h"
-#define EM2880_DVB_MAX_PACKETSIZE 564
+#define EM2880_DVB_MAX_PACKETSIZE 752 //564
#define EM2880_DVB_NUM_PACKETS 64
#define EM2880_URB_COUNT 32
@@ -244,20 +245,21 @@
if (urb->status == -ENOENT)
return;
- if (urb->actual_length > 0)
+ if (urb->actual_length > 0) {
dvb_dmx_swfilter(&dvb_dev->demux, urb->transfer_buffer,
urb->actual_length);
-
- for (i = 0; i < urb->number_of_packets; i++) {
- if (urb->iso_frame_desc[i].status != 0) {
- dprintk(1, "em2880-dvb.c: status != 0\n");
- continue;
- } else if (urb->iso_frame_desc[i].actual_length > 0)
- dvb_dmx_swfilter(&dvb_dev->demux,
+ } else {
+ for (i = 0; i < urb->number_of_packets; i++) {
+ if (urb->iso_frame_desc[i].status != 0) {
+ dprintk(1, "em2880-dvb.c: status != 0\n");
+ continue;
+ } else if (urb->iso_frame_desc[i].actual_length > 0)
+ dvb_dmx_swfilter(&dvb_dev->demux,
urb->transfer_buffer +
urb->iso_frame_desc[i].offset,
urb->iso_frame_desc[i]
.actual_length);
+ }
}
status = usb_submit_urb(urb, GFP_ATOMIC);
if (status)
@@ -430,6 +432,10 @@
.i2c_address = 0x62
};
+static struct tda18271_config em2870_tda18271_config = {
+ //.i2c_address = 0xc0;
+};
+
static int kworld355u_i2c_gate_ctrl(struct dvb_frontend *fe, int enable)
{
struct zl10353_state {
@@ -805,6 +811,7 @@
&em2880_kworld_355u_dev,
&dev->i2c_adap);
break;
+ case EM2870_BOARD_KWORLD_A340:
case EM2883_BOARD_TERRATEC_HYBRID_XS_ATSC:
dvb_dev->frontend = dvb_attach(lgdt3304_attach,
&lgdt3304_atsc_config, &dev->i2c_adap);
@@ -844,16 +851,38 @@
dvb_attach(qt1010_attach, dvb_dev->frontend,
&dev->i2c_adap, &em2870_qt1010_config);
break;
+ case TUNER_PHILIPS_TDA18271:
+ dvb_attach(tda18271_attach, dvb_dev->frontend, 0x60, &dev->i2c_adap, &em2870_tda18271_config);
+ break;
default:
printk(KERN_INFO"unsupported tuner (%d)\n",
dev->tuner_type);
}
- /* zl10353 powersaving */
- dvb_dev->init_override = dvb_dev->frontend->ops.init;
+ switch (dev->model) {
+ case EM2883_BOARD_TERRATEC_HYBRID_XS_FM:
+ case EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900:
+ case EM2880_BOARD_TERRATEC_HYBRID_XS:
+ case EM2880_BOARD_TERRATEC_HYBRID_XS_FR:
+ case EM2882_BOARD_TERRATEC_HYBRID_XS:
+ case EM2870_BOARD_TERRATEC_XS:
+ case EM2881_BOARD_PINNACLE_HYBRID_PRO:
+ case EM2881_BOARD_DNT_DA2_HYBRID:
+ case EM2880_BOARD_MSI_DIGIVOX_AD:
+ case EM2880_BOARD_MSI_DIGIVOX_AD_II:
+ case EM2870_BOARD_KWORLD_350U:
+ case EM2883_BOARD_KWORLD_HYBRID_E323:
+ case EM2888_BOARD_KWORLD_HYBRID_E329:
+ case EM2888_BOARD_EMPIA_HYBRID:
+ /* zl10353 powersaving */
+ dvb_dev->init_override = dvb_dev->frontend->ops.init;
- dvb_dev->frontend->ops.sleep = em28xx_zl10353_sleep;
- dvb_dev->frontend->ops.init = em28xx_zl10353_init;
+ dvb_dev->frontend->ops.sleep = em28xx_zl10353_sleep;
+ dvb_dev->frontend->ops.init = em28xx_zl10353_init;
+ break;
+ default:
+ break;
+ }
}
if (NULL == dvb_dev->frontend) {
diff -r 677bbac6845b em28xx-cards.c
--- a/em28xx-cards.c Sun Jul 20 17:52:57 2008 +0200
+++ b/em28xx-cards.c Mon Jul 21 20:36:10 2008 -0400
@@ -2352,7 +2352,7 @@
.dvbnorms = EETI_XC3028_DEFAULT_DVBT,
#endif
},
- [EM2883_BOARD_KWORLD_A340] = {
+ [EM2870_BOARD_KWORLD_A340] = {
.name = "KWorld ATSC 340",
.tuner_type = TUNER_PHILIPS_TDA18271,
.dev_modes = EM28XX_ATSC,
@@ -2507,6 +2507,7 @@
{ USB_DEVICE(0x1b80, 0xe329), .driver_info = EM2888_BOARD_KWORLD_HYBRID_E329 },
{ USB_DEVICE(0xeb1a, 0x2889), .driver_info = EM2888_BOARD_EMPIA_HYBRID },
{ USB_DEVICE(0xeb1a, 0xe323), .driver_info = EM2883_BOARD_KWORLD_HYBRID_E323 },
+ { USB_DEVICE(0x1b80, 0xa340), .driver_info = EM2870_BOARD_KWORLD_A340 },
{ USB_DEVICE(0xeb1a, 0xa139), .driver_info = EM2888_BOARD_LINCOLN_TV_FM },
#if 0
{ USB_DEVICE(0x2304, 0x0242), .driver_info = EM2888_BOARD_DVB_TC_HYBRID },
@@ -3037,6 +3038,40 @@
#endif
break;
}
+ case EM2870_BOARD_KWORLD_A340:
+ {
+ ret = em28xx_write_regs(dev, R0F_XCLK_REG, "\x07", 1); // protocol?
+ if (ret < 0)
+ return ret;
+ ret = em28xx_write_regs(dev, R06_I2C_CLK_REG, "\x4c", 1);
+ if (ret < 0)
+ return ret;
+ ret = em28xx_write_regs(dev, 0x08, "\xfe", 1);
+ if (ret < 0)
+ return ret;
+ ret = em28xx_write_regs(dev, 0x04, "\xde", 1);
+ if (ret < 0)
+ return ret;
+ ret = em28xx_write_regs(dev, 0x04, "\xfe", 1);
+ if (ret < 0)
+ return ret;
+ ret = em28xx_write_regs(dev, 0x08, "\xfd", 1);
+ if (ret < 0)
+ return ret;
+ ret = em28xx_write_regs(dev, 0x04, "\xff", 1);
+ if (ret < 0)
+ return ret;
+ ret = em28xx_write_regs(dev, 0x08, "\xfd", 1);
+ if (ret < 0)
+ return ret;
+ ret = em28xx_write_regs(dev, 0x04, "\xff", 1);
+ if (ret < 0)
+ return ret;
+ ret = em28xx_write_regs(dev, 0x08, "\xfd", 1);
+ if (ret < 0)
+ return ret;
+ break;
+ }
default:
ret = dev->em28xx_write_regs(dev, R0F_XCLK_REG, "\x27", 1);
if (ret < 0)
diff -r 677bbac6845b em28xx.h
--- a/em28xx.h Sun Jul 20 17:52:57 2008 +0200
+++ b/em28xx.h Mon Jul 21 20:36:10 2008 -0400
@@ -120,7 +120,7 @@
#define EM2883_BOARD_KWORLD_HYBRID_F306 65
#define EM2888_BOARD_KWORLD_HYBRID_E329 66
#define EM2883_BOARD_KWORLD_HYBRID_E323 67
-#define EM2883_BOARD_KWORLD_A340 68
+#define EM2870_BOARD_KWORLD_A340 68
#define EM2888_BOARD_LINCOLN_TV_FM 69
#define EM2888_BOARD_DVB_TC_HYBRID 70
#define EM2888_BOARD_EMPIA_HYBRID 71
diff -r 677bbac6845b lgdt3304/lgdt3304.c
--- a/lgdt3304/lgdt3304.c Sun Jul 20 17:52:57 2008 +0200
+++ b/lgdt3304/lgdt3304.c Mon Jul 21 20:36:10 2008 -0400
@@ -37,6 +37,13 @@
#include "dvb_frontend.h"
#include "lgdt3304.h"
+static unsigned int debug = 0;
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug,"lgdt3304 debugging (default off)");
+
+#define dprintk(fmt, args...) if (debug) do {\
+ printk("lgdt3304 debug: " fmt, ##args); } while (0)
+
struct lgdt3304_state
{
struct dvb_frontend frontend;
@@ -61,6 +68,7 @@
for (i=0; i<len-1; i+=3){
if((err = i2c_transfer(state->i2c, &i2cmsgs, 1))<0) {
+ printk("%s i2c_transfer error %d\n", __FUNCTION__, err);
if (err < 0)
return err;
else
@@ -90,8 +98,10 @@
i2cmsgs[1].len = 1;
i2cmsgs[1].buf = &buf;
- if((ret = i2c_transfer(state->i2c, i2cmsgs, 2))<0)
+ if((ret = i2c_transfer(state->i2c, i2cmsgs, 2))<0) {
+ printk("%s i2c_transfer error %d\n", __FUNCTION__, ret);
return ret;
+ }
return buf;
}
@@ -100,6 +110,7 @@
{
struct lgdt3304_state *state = fe->demodulator_priv;
char buffer[3] = { reg>>8, reg&0xff, val };
+ int ret;
struct i2c_msg i2cmsgs = {
.addr = state->addr,
@@ -107,7 +118,11 @@
.len = 3,
.buf=buffer
};
- i2c_transfer(state->i2c, &i2cmsgs, 1);
+ ret = i2c_transfer(state->i2c, &i2cmsgs, 1);
+ if (ret != 1) {
+ printk("%s i2c_transfer error %d\n", __FUNCTION__, ret);
+ return ret;
+ }
return 0;
}
@@ -122,7 +137,7 @@
}
static int lgdt3304_set_parameters(struct dvb_frontend *fe, struct dvb_frontend_parameters *param) {
- int err;
+ int err = 0;
static __u8 lgdt3304_vsb8_data[] = {
/* 16bit , 8bit */
@@ -168,6 +183,7 @@
0x05, 0x0e, 0x5b,
};
+#if 0
/* not yet tested */
static __u8 lgdt3304_qam256_data[] = {
/* 16bit , 8bit */
@@ -184,6 +200,67 @@
0x03, 0x0a, 0x08,
0x03, 0x0b, 0x9b,
0x03, 0x0d, 0x14,
+ 0x05, 0x0e, 0x5b,
+ };
+#endif
+
+ /* tested with KWorld a340 */
+ static __u8 lgdt3304_qam256_data[] = {
+ /* 16bit , 8bit */
+ /* regs , val */
+ 0x00, 0x00, 0x01, //0x19,
+ 0x00, 0x12, 0x2a,
+ 0x00, 0x13, 0x80,
+ 0x00, 0x0d, 0x02,
+ 0x03, 0x14, 0xe3,
+
+ 0x03, 0x0e, 0x1c,
+ 0x03, 0x08, 0x66,
+ 0x03, 0x09, 0x66,
+ 0x03, 0x0a, 0x08,
+ 0x03, 0x0b, 0x9b,
+
+ 0x03, 0x0d, 0x14,
+ //0x05, 0x0e, 0x5b,
+ 0x01, 0x06, 0x4a,
+ 0x01, 0x07, 0x3d,
+ 0x01, 0x08, 0x70,
+ 0x01, 0x09, 0xa3,
+
+ 0x05, 0x04, 0xfd,
+
+ 0x00, 0x0d, 0x82,
+
+ 0x05, 0x0e, 0x5b,
+
+ 0x05, 0x0e, 0x5b,
+
+ 0x00, 0x02, 0x9a,
+
+ 0x00, 0x02, 0x9b,
+
+ 0x00, 0x00, 0x01,
+ 0x00, 0x12, 0x2a,
+ 0x00, 0x13, 0x80,
+ 0x00, 0x0d, 0x02,
+ 0x03, 0x14, 0xe3,
+
+ 0x03, 0x0e, 0x1c,
+ 0x03, 0x08, 0x66,
+ 0x03, 0x09, 0x66,
+ 0x03, 0x0a, 0x08,
+ 0x03, 0x0b, 0x9b,
+
+ 0x03, 0x0d, 0x14,
+ 0x01, 0x06, 0x4a,
+ 0x01, 0x07, 0x3d,
+ 0x01, 0x08, 0x70,
+ 0x01, 0x09, 0xa3,
+
+ 0x05, 0x04, 0xfd,
+
+ 0x00, 0x0d, 0x82,
+
0x05, 0x0e, 0x5b,
};
@@ -205,7 +282,12 @@
default:
break;
}
- state->current_modulation = param->u.vsb.modulation;
+
+ if (err) {
+ printk("%s error setting modulation\n", __FUNCTION__);
+ } else {
+ state->current_modulation = param->u.vsb.modulation;
+ }
}
state->current_frequency = param->frequency;
@@ -234,16 +316,16 @@
int qam_lck;
*status = 0;
- printk("lgdt read status\n");
+ dprintk("lgdt read status\n");
r011d = lgdt3304_i2c_read_reg(fe, 0x011d);
- printk("%02x\n", r011d);
+ dprintk("%02x\n", r011d);
switch(state->current_modulation) {
case VSB_8:
if (r011d & 0x80) {
- printk("VSB Locked\n");
+ dprintk("VSB Locked\n");
*status |= FE_HAS_CARRIER;
*status |= FE_HAS_LOCK;
*status |= FE_HAS_SYNC;
@@ -254,13 +336,13 @@
case QAM_256:
qam_lck = r011d & 0x7;
switch(qam_lck) {
- case 0x0: printk("Unlock\n");
+ case 0x0: dprintk("Unlock\n");
break;
- case 0x4: printk("1st Lock in acquisition state\n");
+ case 0x4: dprintk("1st Lock in acquisition state\n");
break;
- case 0x6: printk("2nd Lock in acquisition state\n");
+ case 0x6: dprintk("2nd Lock in acquisition state\n");
break;
- case 0x7: printk("Final Lock in good reception state\n");
+ case 0x7: dprintk("Final Lock in good reception state\n");
*status |= FE_HAS_CARRIER;
*status |= FE_HAS_LOCK;
*status |= FE_HAS_SYNC;
@@ -269,7 +351,7 @@
}
break;
default:
- printk("unhandled modulation\n");
+ printk("%s unhandled modulation\n", __FUNCTION__);
}
@@ -278,26 +360,32 @@
static int lgdt3304_read_ber(struct dvb_frontend *fe, __u32 *ber)
{
- printk("read ber\n");
+ dprintk("read ber\n");
return 0;
}
static int lgdt3304_read_snr(struct dvb_frontend *fe, __u16 *snr)
{
- printk("read snr\n");
+ dprintk("read snr\n");
return 0;
}
static int lgdt3304_read_ucblocks(struct dvb_frontend *fe, __u32 *ucblocks)
{
- printk("read ucblocks\n");
+ dprintk("read ucblocks\n");
return 0;
+}
+
+static void lgdt3304_release(struct dvb_frontend *fe)
+{
+ struct lgdt3304_state *state = (struct lgdt3304_state *)fe->demodulator_priv;
+ kfree(state);
}
static struct dvb_frontend_ops demod_lgdt3304={
.info = {
.name = "LG 3304",
- .type = FE_OFDM,
+ .type = FE_ATSC,
.frequency_min = 54000000,
.frequency_max = 858000000,
.frequency_stepsize = 62500,
@@ -311,7 +399,8 @@
.read_snr = lgdt3304_read_snr,
.read_ber = lgdt3304_read_ber,
.read_status = lgdt3304_read_status,
- .read_ucblocks = lgdt3304_read_ucblocks
+ .read_ucblocks = lgdt3304_read_ucblocks,
+ .release = lgdt3304_release,
};
struct dvb_frontend* lgdt3304_attach(const struct lgdt3304_config *config,
@@ -322,6 +411,7 @@
state = kzalloc(sizeof(struct lgdt3304_state), GFP_KERNEL);
memset(state, 0x0, sizeof(struct lgdt3304_state));
state->addr = config->i2c_address;
+ state->i2c = i2c;
memcpy(&state->frontend.ops, &demod_lgdt3304, sizeof(struct dvb_frontend_ops));
state->frontend.demodulator_priv = state;
_______________________________________________
Em28xx mailing list
[email protected]
http://mcentral.de/mailman/listinfo/em28xx