Pierre Willenbrock schrieb: > Michael Krufky schrieb: >> Pierre Willenbrock wrote: >>> Hi list, >>> >>> I am owner of a "MSI DIGIVOX mini-II". I got it to work using the >>> attached patch and firmware. The patch and firmware are the result of >>> analyzing some usb logs from windows. >>> >>> The patch breaks all users of tda10046, as i don't understand how that >>> chip is supposed to work. The same goes for my driver implementation of >>> the Philips 8275a. >>> >>> So this mess needs to be fixed before it can go into the repository. >>> >>> The patch is against a fresh hg checkout from >>> http://linuxtv.org/hg/v4l-dvb at 2007-02-22 21:00 UTC. >>> >>> Regards, >>> Pierre >> Pierre- >> >> I am very happy to hear that you got this device working... Interestingly >> enough, we have already created a new tda827x dvb fe module, which might be >> better for your device... This new tda827x module has not yet been merged into >> the master v4l-dvb repository, but it will be soon. Could you try to use the >> code located in: >> >> http://linuxtv.org/hg/~hhackmann/v4l-dvb >> >> The tda827x module will be able to detect the difference between the tda8275 and >> the tda8275a ... You do not have to fill the callback functions in the config >> struct -- that is really meant as a hack for some required GPIO handling in the >> saa7134-dvb driver for input switching. >> >> If you can generate a new patch against the repository above, it would make it >> _much_ easier to integrate your patch into the sources. After you get that >> done, we can work out the tda1004x differences. >> >> You might also want to speak to aett and friedrich, regulars of the #linuxtv irc >> chat room on irc.freenode.net ... aet is the author of the m920x driver, and >> friedrich has the same device that you have. They have been working on it, but >> haven't yet gotten successful results. >> >> Good work! Hopefully we can clean this up after you generate a new patch using >> the tda827x module from hhackmann's repository. >> >> Regards, >> >> Mike Krufky >> > > Thanks for the pointer. > I am going to try to get my device to work with hhackmanns repository > over the weekend and talk back when i have something working. This will > probably need a few additions to the tda1004x driver, though(Mostly > caused by lazyness and misunderstanding). > hi again, here is the patch against http://linuxtv.org/hg/v4l-dvb at 2007-02-25 00:16 UTC. I could not get my device to work with the original bandwidth settings, so you will find the "if" hard coded to 4.75MHz in tda827x.c (Usable for uhf. There is a small bug fix and probable improvement in there, too). Consequently, "set_bandwidth" in tda1004x.c is completely replaced. The rest of the changes probably accumulates to another set of gpio settings. Again, this patch breaks all other users of tda827x.c and tda1004x.c. Regards, Pierre
diff -r 3556fab363b5 linux/drivers/media/dvb/dvb-usb/dvb-usb-ids.h --- a/linux/drivers/media/dvb/dvb-usb/dvb-usb-ids.h Sat Feb 24 09:05:23 2007 -0200 +++ b/linux/drivers/media/dvb/dvb-usb/dvb-usb-ids.h Tue Feb 13 18:32:45 2007 +0100 @@ -37,6 +37,7 @@ #define USB_VID_ULTIMA_ELECTRONIC 0x05d8 #define USB_VID_UNIWILL 0x1584 #define USB_VID_WIDEVIEW 0x14aa +#define USB_VID_ANUBIS_ELECTRONIC 0x10fd /* Product IDs */ #define USB_PID_ADSTECH_USB2_COLD 0xa333 @@ -139,6 +140,7 @@ #define USB_PID_GENPIX_8PSK_COLD 0x0200 #define USB_PID_GENPIX_8PSK_WARM 0x0201 #define USB_PID_SIGMATEK_DVB_110 0x6610 +#define USB_PID_ANUBIS_ELECTRONIC_MSI_DIGI_VOX_MINI_II 0x1513 #endif diff -r 3556fab363b5 linux/drivers/media/dvb/dvb-usb/m920x.c --- a/linux/drivers/media/dvb/dvb-usb/m920x.c Sat Feb 24 09:05:23 2007 -0200 +++ b/linux/drivers/media/dvb/dvb-usb/m920x.c Sat Feb 24 22:47:49 2007 +0100 @@ -14,6 +14,8 @@ #include "mt352.h" #include "mt352_priv.h" #include "qt1010.h" +#include "tda1004x.h" +#include "tda827x.h" /* debug */ static int dvb_usb_m920x_debug; @@ -44,14 +46,25 @@ static inline int m9206_read(struct usb_ { int ret; + deb_rc("m9206_read(..., %x, %x, %x, %p, %x)\n", + request, value, index, data, size); + ret = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), request, USB_TYPE_VENDOR | USB_DIR_IN, value, index, data, size, 2000); - if (ret < 0) - return ret; - - if (ret != size) + if (ret < 0) { + printk(KERN_INFO "m9206_read = error: %d\n", ret); + return ret; + } + + if (ret != size) { + deb_rc("m9206_read = no data\n"); return -EIO; + } + + + deb_rc("m9206_read = %x\n", + ((unsigned char*)data)[0]); return 0; } @@ -60,10 +73,17 @@ static inline int m9206_write(struct usb u16 value, u16 index) { int ret; + + deb_rc("m9206_write(..., %x, %x, %x)=...\n", + request, value, index); ret = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), request, USB_TYPE_VENDOR | USB_DIR_OUT, value, index, NULL, 0, 2000); + + deb_rc("m9206_write...=%d\n", + ret); + return ret; } @@ -145,51 +165,72 @@ static int m9206_i2c_xfer(struct i2c_ada { struct dvb_usb_device *d = i2c_get_adapdata(adap); struct m9206_state *m = d->priv; - int i; + int i, j; int ret = 0; if (mutex_lock_interruptible(&d->i2c_mutex) < 0) return -EAGAIN; - if (num > 2) - return -EINVAL; +/* +sequences found in logs: +[index value] +0x80 write addr +(0x00 out byte)* +0x40 out byte + +0x80 write addr +(0x00 out byte)* +0x80 read addr +(0x21 in byte)* +0x60 in byte + +this sequence works: +0x80 read addr +(0x21 in byte)* +0x60 in byte + +_my guess_: +0x80: begin i2c transfer using address. value=address<<1|(reading?1:0) +0x00: write byte +0x21: read byte, more to follow +0x40: write last byte of message sequence +0x60: read last byte of message sequence + */ + for (i = 0; i < num; i++) { - if ((ret = m9206_write(d->udev, M9206_I2C, msg[i].addr, 0x80)) != 0) - goto unlock; - - if ((ret = m9206_write(d->udev, M9206_I2C, msg[i].buf[0], 0x0)) != 0) - goto unlock; - - if (i + 1 < num && msg[i + 1].flags & I2C_M_RD) { - int i2c_i; - - for (i2c_i = 0; i2c_i < M9206_I2C_MAX; i2c_i++) - if (msg[i].addr == m->i2c_r[i2c_i].addr) - break; - - if (i2c_i >= M9206_I2C_MAX) { - deb_rc("No magic for i2c addr!\n"); - ret = -EINVAL; + if (msg[i].flags & I2C_M_RD) { + + if ((ret = m9206_write(d->udev, M9206_I2C, msg[i].addr | 0x01, 0x80)) != 0) goto unlock; + + for(j = 0; j < msg[i].len; j++) { + if (j + 1 == msg[i].len && i + 1== num) { + if ((ret = m9206_read(d->udev, M9206_I2C, 0x0, 0x60, &msg[i].buf[j], msg[i].len)) != 0) + goto unlock; + } else { + if ((ret = m9206_read(d->udev, M9206_I2C, 0x0, 0x21, &msg[i].buf[j], msg[i].len)) != 0) + goto unlock; + } } - if ((ret = m9206_write(d->udev, M9206_I2C, m->i2c_r[i2c_i].magic, 0x80)) != 0) + } else { + if ((ret = m9206_write(d->udev, M9206_I2C, msg[i].addr, 0x80)) != 0) goto unlock; - - if ((ret = m9206_read(d->udev, M9206_I2C, 0x0, 0x60, msg[i + 1].buf, msg[i + 1].len)) != 0) - goto unlock; - - i++; - } else { - if (msg[i].len != 2) - return -EINVAL; - - if ((ret = m9206_write(d->udev, M9206_I2C, msg[i].buf[1], 0x40)) != 0) - goto unlock; - } - } - ret = i; + + for(j = 0; j < msg[i].len; j++) { + if (j + 1 == msg[i].len && i + 1== num) { + if ((ret = m9206_write(d->udev, M9206_I2C, msg[i].buf[j], 0x40)) != 0) + goto unlock; + + } else { + if ((ret = m9206_write(d->udev, M9206_I2C, msg[i].buf[j], 0x0)) != 0) + goto unlock; + } + } + } + } + ret = num; unlock: mutex_unlock(&d->i2c_mutex); @@ -331,6 +372,7 @@ static int m9206_firmware_download(struc i += size; } if (i != fw->size) { + deb_rc("bad firmware file!\n"); ret = -EINVAL; goto done; } @@ -426,8 +468,75 @@ static int megasky_qt1010_tuner_attach(s return 0; } +static struct tda1004x_config digivox_tda10046_config = { + /* the demodulator's i2c address */ + .demod_address = 0x10, + + /* does the "inversion" need inverted? */ + .invert = 0, + + /* Does the OCLK signal need inverted? */ + .invert_oclk = 0, + + /* Xtal frequency, 4 or 16MHz*/ + .xtal_freq = TDA10046_XTAL_16M, + + /* IF frequency */ + .if_freq = TDA10046_FREQ_045,/*currently doing our own*/ + + /* AGC configuration */ +/* .agc_config = TDA10046_AGC_DIGIVOX,*/ + + /* setting of GPIO1 and 3 */ +/* .gpio_config;*/ + + /* slave address and configuration of the tuner */ +/* .tuner_address;*/ +/* .tuner_config;*/ +/* .antenna_switch;*/ + + /* if the board uses another I2c Bridge (tda8290), its address */ +/* .i2c_gate;*/ + + /* request firmware for device */ + /* set this to NULL if the card has a firmware EEPROM */ + .request_firmware = NULL,/*uses firmware EEPROM - TODO: invalid revision*/ +}; + +static int digivox_tda10046_frontend_attach(struct dvb_usb_adapter *adap) +{ + struct m9206_state *m = adap->dev->priv; + + deb_rc("digivox_tda10046_frontend_attach!\n"); + + m->i2c_r[M9206_I2C_DEMOD].addr = digivox_tda10046_config.demod_address; + m->i2c_r[M9206_I2C_DEMOD].magic = 0x11; + + if ((adap->fe = dvb_attach(tda10046_attach, &digivox_tda10046_config, &adap->dev->i2c_adap)) == NULL) + return -EIO; + + return 0; +} + +static struct tda827x_config digivox_tda8275_config = { +}; + +static int digivox_tda8275_tuner_attach(struct dvb_usb_adapter *adap) +{ + struct m9206_state *m = adap->dev->priv; + + m->i2c_r[M9206_I2C_TUNER].addr = 0xc0; + m->i2c_r[M9206_I2C_TUNER].magic = 0xc1; + + if (dvb_attach(tda827x_attach, adap->fe, 0xc0, &adap->dev->i2c_adap, + &digivox_tda8275_config) == NULL) + return -ENODEV; + return 0; +} + /* DVB USB Driver stuff */ static struct dvb_usb_device_properties megasky_properties; +static struct dvb_usb_device_properties digivox_properties; static int m920x_probe(struct usb_interface *intf, const struct usb_device_id *id) @@ -454,12 +563,30 @@ static int m920x_probe(struct usb_interf if ((ret = m9206_rc_init(d->udev)) != 0) return ret; + } else if ((ret = dvb_usb_device_init(intf, &digivox_properties, THIS_MODULE, &d)) == 0) { + deb_rc("probed!\n"); + + alt = usb_altnum_to_altsetting(intf, 1); + if (alt == NULL) { + deb_rc("not alt found!\n"); + return -ENODEV; + } + + ret = usb_set_interface(d->udev, alt->desc.bInterfaceNumber, + alt->desc.bAlternateSetting); + if (ret < 0) + return ret; + + if ((ret = m9206_rc_init(d->udev)) != 0) + return ret; } return ret; } static struct usb_device_id m920x_table [] = { { USB_DEVICE(USB_VID_MSI, USB_PID_MSI_MEGASKY580) }, + { USB_DEVICE(USB_VID_ANUBIS_ELECTRONIC, + USB_PID_ANUBIS_ELECTRONIC_MSI_DIGI_VOX_MINI_II) }, { } /* Terminating entry */ }; MODULE_DEVICE_TABLE (usb, m920x_table); @@ -509,6 +636,55 @@ static struct dvb_usb_device_properties { "MSI Mega Sky 580 DVB-T USB2.0", { &m920x_table[0], NULL }, { NULL }, + } + } +}; + +static struct dvb_usb_device_properties digivox_properties = { + .caps = DVB_USB_IS_AN_I2C_ADAPTER, + + .usb_ctrl = DEVICE_SPECIFIC, + .firmware = "dvb-usb-digivox-02.fw", + .download_firmware = m9206_firmware_download, + +/* .rc_interval = 100, + .rc_key_map = digivox_rc_keys, + .rc_key_map_size = ARRAY_SIZE(digivox_rc_keys), + .rc_query = m9206_rc_query,*/ + + .size_of_priv = sizeof(struct m9206_state), + + .identify_state = megasky_identify_state, + .num_adapters = 1, + .adapter = {{ +/* .caps = DVB_USB_ADAP_HAS_PID_FILTER | + DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF,*/ + + .pid_filter_count = 8, + .pid_filter = m9206_pid_filter, + .pid_filter_ctrl = m9206_pid_filter_ctrl, + + .frontend_attach = digivox_tda10046_frontend_attach, + .tuner_attach = digivox_tda8275_tuner_attach, + + .stream = { + .type = USB_BULK, + .count = 8, + .endpoint = 0x81, + .u = { + .bulk = { + .buffersize = 0x4000, + } + } + }, + }}, + .i2c_algo = &m9206_i2c_algo, + + .num_device_descs = 1, + .devices = { + { "MSI DIGI VOX mini II DVB-T USB2.0", + { &m920x_table[1], NULL }, + { NULL }, }, } }; diff -r 3556fab363b5 linux/drivers/media/dvb/frontends/tda1004x.c --- a/linux/drivers/media/dvb/frontends/tda1004x.c Sat Feb 24 09:05:23 2007 -0200 +++ b/linux/drivers/media/dvb/frontends/tda1004x.c Sun Feb 25 00:25:56 2007 +0100 @@ -256,6 +256,16 @@ static int tda10046h_set_bandwidth(struc static int tda10046h_set_bandwidth(struct tda1004x_state *state, fe_bandwidth_t bandwidth) { +#if 1 + static u8 digivox_vhf[] = { 0x79, 0x16, 0x1c, 0x21, 0xc2 }; + static u8 digivox_uhf[] = { 0x5b, 0x02, 0xd0, 0x2d, 0x03 }; + + tda1004x_write_buf(state, TDA10046H_TIME_WREF1, digivox_uhf, + sizeof(digivox_uhf)); +/*for vhf: 0x09, 0xd9*/ + tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_MSB, 0x0b); + tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_LSB, 0xb2); +#else static u8 bandwidth_6mhz_53M[] = { 0x7b, 0x2e, 0x11, 0xf0, 0xd2 }; static u8 bandwidth_7mhz_53M[] = { 0x6a, 0x02, 0x6a, 0x43, 0x9f }; static u8 bandwidth_8mhz_53M[] = { 0x5c, 0x32, 0xc2, 0x96, 0x6d }; @@ -313,6 +323,7 @@ static int tda10046h_set_bandwidth(struc default: return -EINVAL; } +#endif return 0; } @@ -359,8 +370,10 @@ static int tda1004x_check_upload_ok(stru u8 data1, data2; unsigned long timeout; + dprintk("%s\n", __FUNCTION__); + if (state->demod_type == TDA1004X_DEMOD_TDA10046) { - timeout = jiffies + 2 * HZ; + timeout = jiffies + 4 * HZ; while(!(tda1004x_read_byte(state, TDA1004X_STATUS_CD) & 0x20)) { if (time_after(jiffies, timeout)) { printk(KERN_ERR "tda1004x: timeout waiting for DSP ready\n"); @@ -436,7 +449,12 @@ static void tda10046_init_plls(struct dv else tda10046_clk53m = 1; +#if 1 tda1004x_write_byteI(state, TDA10046H_CONFPLL1, 0xf0); + printk(KERN_INFO "tda1004x: setting up plls for 52MHz sampling clock\n"); + tda1004x_write_byteI(state, TDA10046H_CONFPLL2, 0x07); // PLL M = 7 +#endif +#if 0 if(tda10046_clk53m) { printk(KERN_INFO "tda1004x: setting up plls for 53MHz sampling clock\n"); tda1004x_write_byteI(state, TDA10046H_CONFPLL2, 0x08); // PLL M = 8 @@ -444,6 +462,7 @@ static void tda10046_init_plls(struct dv printk(KERN_INFO "tda1004x: setting up plls for 48MHz sampling clock\n"); tda1004x_write_byteI(state, TDA10046H_CONFPLL2, 0x03); // PLL M = 3 } +#endif if (state->config->xtal_freq == TDA10046_XTAL_4M ) { dprintk("%s: setting up PLLs for a 4 MHz Xtal\n", __FUNCTION__); tda1004x_write_byteI(state, TDA10046H_CONFPLL3, 0); // PLL P = N = 0 @@ -632,6 +651,12 @@ static int tda10046_init(struct dvb_fron return -EIO; } +/*from windows driver*/ + tda1004x_write_byteI(state, TDA1004X_CONFC4, 0x00); + tda1004x_write_byteI(state, TDA10046H_CONF_TRISTATE2, 0x2f); + tda1004x_write_byteI(state, TDA10046H_GPIO_OUT_SEL, 0xcf); +/*from windows driver*/ + // tda setup tda1004x_write_mask(state, TDA1004X_CONFC4, 0x20, 0); // disable DSP watchdog timer tda1004x_write_byteI(state, TDA1004X_AUTO, 0x87); // 100 ppm crystal, select HP stream @@ -656,9 +681,19 @@ static int tda10046_init(struct dvb_fron tda1004x_write_byteI(state, TDA10046H_AGC_RENORM, 0x08); // Gain Renormalize tda1004x_write_mask(state, TDA10046H_CONF_POLARITY, 0xf0, 0x60); // set AGC polarities break; - } + case TDA10046_AGC_DIGIVOX: + tda1004x_write_byteI(state, TDA10046H_AGC_CONF, 0x0a); // AGC setup + tda1004x_write_byteI(state, TDA10046H_AGC_THR, 0x70); // set AGC threshold + tda1004x_write_byteI(state, TDA10046H_CONF_POLARITY, 0x24); // set AGC polarities + break; + } +#if 1 + tda1004x_write_byteI(state, TDA1004X_CONFADC2, 0x34); + tda1004x_write_byteI(state, TDA10046H_CONF_TRISTATE1, 0xa1); +#else tda1004x_write_byteI(state, TDA1004X_CONFADC2, 0x38); tda1004x_write_byteI(state, TDA10046H_CONF_TRISTATE1, 0x79); // Turn IF AGC output on +#endif tda1004x_write_byteI(state, TDA10046H_AGC_TUN_MIN, 0); // } tda1004x_write_byteI(state, TDA10046H_AGC_TUN_MAX, 0xff); // } AGC min/max values tda1004x_write_byteI(state, TDA10046H_AGC_IF_MIN, 0); // } diff -r 3556fab363b5 linux/drivers/media/dvb/frontends/tda1004x.h --- a/linux/drivers/media/dvb/frontends/tda1004x.h Sat Feb 24 09:05:23 2007 -0200 +++ b/linux/drivers/media/dvb/frontends/tda1004x.h Sat Feb 24 17:35:15 2007 +0100 @@ -36,6 +36,7 @@ enum tda10046_agc { TDA10046_AGC_IFO_AUTO_NEG, /* IF AGC only, automatic, negtive */ TDA10046_AGC_IFO_AUTO_POS, /* IF AGC only, automatic, positive */ TDA10046_AGC_TDA827X, /* IF AGC only, special setup for tda827x */ + TDA10046_AGC_DIGIVOX, /* setup for msi digivox mini ii*/ }; /* Many (hybrid) boards use GPIO 1 and 3 diff -r 3556fab363b5 linux/drivers/media/dvb/frontends/tda827x.c --- a/linux/drivers/media/dvb/frontends/tda827x.c Sat Feb 24 09:05:23 2007 -0200 +++ b/linux/drivers/media/dvb/frontends/tda827x.c Sun Feb 25 00:22:41 2007 +0100 @@ -214,7 +214,7 @@ static int tda827xa_set_params(struct dv struct dvb_frontend_parameters *params) { struct tda827x_priv *priv = fe->tuner_priv; - u8 buf[10]; + u8 buf[14]; struct i2c_msg msg = { .addr = priv->i2c_addr, .flags = 0, .buf = buf, .len = sizeof(buf) }; @@ -237,7 +237,12 @@ static int tda827xa_set_params(struct dv if_freq = 5000000; break; } +#if 1 + if_freq = 4750000;//uhf -- 4500000 for vhf +#endif tuner_freq = params->frequency + if_freq; + + dprintk(KERN_INFO "tda827xa: request to tune to %d\n", params->frequency); i = 0; while (tda827xa_dvbt[i].lomax < tuner_freq) { @@ -257,9 +262,12 @@ static int tda827xa_set_params(struct dv buf[6] = 0x4b + (tda827xa_dvbt[i].gc3 << 4); buf[7] = 0x1c; buf[8] = 0x06; - buf[9] = 0x24; - buf[10] = 0x00; - msg.len = 11; + buf[9] = 0x26; + buf[10] = 0xff; + buf[11] = 0x60; + buf[12] = 0x00; + buf[13] = 0x59; // lpsel, for 6MHz + 2 + msg.len = 14; if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 1); if (i2c_transfer(priv->i2c_adap, &msg, 1) != 1) { @@ -267,15 +275,6 @@ static int tda827xa_set_params(struct dv __FUNCTION__, priv->i2c_addr << 1); return -EIO; } - buf[0] = 0x90; - buf[1] = 0xff; - buf[2] = 0x60; - buf[3] = 0x00; - buf[4] = 0x59; // lpsel, for 6MHz + 2 - msg.len = 5; - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 1); - i2c_transfer(priv->i2c_adap, &msg, 1); buf[0] = 0xa0; buf[1] = 0x40;
_______________________________________________ linux-dvb mailing list linux-dvb@xxxxxxxxxxx http://www.linuxtv.org/cgi-bin/mailman/listinfo/linux-dvb