Trent Piepho wrote: > This would work for stv0297, wouldn't it? > > -------------------------------------------------------------------- > diff -r 56b4c3e8f350 drivers/i2c/i2c-core.c > --- a/drivers/i2c/i2c-core.c Sat May 19 05:00:32 2007 +0000 > +++ b/drivers/i2c/i2c-core.c Sat May 19 17:35:19 2007 -0700 > @@ -862,6 +862,7 @@ int i2c_transfer(struct i2c_adapter * ad > int ret; > > if (adap->algo->master_xfer) { > + int n, total = 0; > #ifdef DEBUG > for (ret = 0; ret < num; ret++) { > dev_dbg(&adap->dev, "master_xfer[%d] %c, addr=0x%02x, " > @@ -872,10 +873,28 @@ int i2c_transfer(struct i2c_adapter * ad > #endif > > mutex_lock_nested(&adap->bus_lock, adap->level); > - ret = adap->algo->master_xfer(adap,msgs,num); > + for (n=1; n<=num; n++) { > + /* xfer the message(s) if we want a stop or if > + it's the last message. */ > + if (n == num || (msgs[n-1].flags & I2C_M_STOP)) { > + ret = adap->algo->master_xfer(adap,msgs,n); > + > + total += ret; > + if (ret < n) { > + /* Return error code, if any */ > + if (ret < 0) > + total = ret; > + break; > + } > + > + /* Process any remaining messages */ > + msgs += n; > + num -= n; > + n = 0; > + } > + } > mutex_unlock(&adap->bus_lock); > - > - return ret; > + return total; > } else { > dev_dbg(&adap->dev, "I2C level transfers not supported\n"); > return -ENOSYS; > diff -r 56b4c3e8f350 include/linux/i2c.h > --- a/include/linux/i2c.h Sat May 19 05:00:32 2007 +0000 > +++ b/include/linux/i2c.h Sat May 19 17:35:03 2007 -0700 > @@ -448,6 +448,7 @@ struct i2c_msg { > #define I2C_M_IGNORE_NAK 0x1000 > #define I2C_M_NO_RD_ACK 0x0800 > #define I2C_M_RECV_LEN 0x0400 /* length will be first received byte */ > +#define I2C_M_STOP 0x0200 /* send STOP condition after this msg */ > __u16 len; /* msg length */ > __u8 *buf; /* pointer to msg data */ > }; > With the attached patch, it works for the stv0297 functions. It doesn't solve the problem, why I've wrote the initial patch. I need a dump from the registers of the stv0297. I've attach a second patch. stv0297_attach() inserts a wrapper between i2ctransfer() and the transfer function of the saa7146. The add/del functions for the wrapper are a little bit dirty. I didn't find a clean way for the add/del function. - Hartmut
diff -r 6785574f5f6e linux/drivers/media/dvb/frontends/stv0297.c --- a/linux/drivers/media/dvb/frontends/stv0297.c Mon May 14 04:25:57 2007 +0200 +++ b/linux/drivers/media/dvb/frontends/stv0297.c Sun May 20 09:14:50 2007 +0200 @@ -71,7 +71,10 @@ static int stv0297_readreg(struct stv029 struct i2c_msg msg[] = { {.addr = state->config->demod_address,.flags = 0,.buf = b0,.len = 1}, {.addr = state->config->demod_address,.flags = I2C_M_RD,.buf = b1,.len = 1} }; - +#ifdef I2C_M_STOP + msg[0].flags = I2C_M_STOP; + { +#else // this device needs a STOP between the register and data if (state->config->stop_during_read) { if ((ret = i2c_transfer(state->i2c, &msg[0], 1)) != 1) { @@ -83,6 +86,7 @@ static int stv0297_readreg(struct stv029 return -1; } } else { +#endif if ((ret = i2c_transfer(state->i2c, msg, 2)) != 2) { dprintk("%s: readreg error (reg == 0x%02x, ret == %i)\n", __FUNCTION__, reg, ret); return -1; @@ -111,7 +115,10 @@ static int stv0297_readregs(struct stv02 ®1,.len = 1}, {.addr = state->config->demod_address,.flags = I2C_M_RD,.buf = b,.len = len} }; - +#ifdef I2C_M_STOP + msg[0].flags = I2C_M_STOP; + { +#else // this device needs a STOP between the register and data if (state->config->stop_during_read) { if ((ret = i2c_transfer(state->i2c, &msg[0], 1)) != 1) { @@ -123,6 +130,7 @@ static int stv0297_readregs(struct stv02 return -1; } } else { +#endif if ((ret = i2c_transfer(state->i2c, msg, 2)) != 2) { dprintk("%s: readreg error (reg == 0x%02x, ret == %i)\n", __FUNCTION__, reg1, ret); return -1;
diff -r 6785574f5f6e linux/drivers/media/dvb/frontends/stv0297.c --- a/linux/drivers/media/dvb/frontends/stv0297.c Mon May 14 04:25:57 2007 +0200 +++ b/linux/drivers/media/dvb/frontends/stv0297.c Sun May 20 19:05:06 2007 +0200 @@ -31,6 +31,11 @@ #include "stv0297.h" struct stv0297_state { + struct i2c_algorithm algo; + const struct i2c_algorithm *old_algo; + void *old_algo_data; + unsigned char remove:1; + struct i2c_adapter *i2c; const struct stv0297_config *config; struct dvb_frontend frontend; @@ -47,7 +52,61 @@ struct stv0297_state { #define STV0297_CLOCK_KHZ 28900 - +static int stv0297_readreg(struct stv0297_state *state, u8 reg); + +static int stv0297_master_xfer_wrapper(struct i2c_adapter *adapter, struct i2c_msg* msgs, int num) +{ + struct stv0297_state *state = (struct stv0297_state*) adapter->algo_data; + int ret = 0, i; + + adapter->algo_data = state->old_algo_data; + adapter->algo = state->old_algo; + + if (msgs[0].addr == state->config->demod_address) { + for (i = 0; i < num; i++) { + ret = adapter->algo->master_xfer(adapter, &msgs[i], 1); + if (ret != 1) { + if (ret == 0) + ret = i; + break; + } + } + if (i >= num) { + ret = num; + } + + } else { + ret = adapter->algo->master_xfer(adapter, msgs, num); + } + + if (!state->remove) { + state->old_algo = adapter->algo; + state->old_algo_data = adapter->algo_data; + adapter->algo_data = (void*)state; + adapter->algo = &state->algo; + } + + return ret; +} + +static void stv0297_add_wrapper(struct stv0297_state *state) +{ + state->remove = 0; + memcpy(&state->algo, state->i2c->algo, sizeof(struct i2c_algorithm)); + state->old_algo = state->i2c->algo; + state->algo.master_xfer = stv0297_master_xfer_wrapper; + mutex_lock_nested(&state->i2c->bus_lock, i2c->level); + state->i2c->algo_data = state; + state->i2c->algo = &state->algo; + mutex_unlock(&state->i2c->bus_lock); +} + +static void stv0297_del_wrapper(struct stv0297_state *state) +{ + state->remove = 1; + stv0297_readreg(state, 0x80); +} + static int stv0297_writereg(struct stv0297_state *state, u8 reg, u8 data) { int ret; @@ -71,22 +130,9 @@ static int stv0297_readreg(struct stv029 struct i2c_msg msg[] = { {.addr = state->config->demod_address,.flags = 0,.buf = b0,.len = 1}, {.addr = state->config->demod_address,.flags = I2C_M_RD,.buf = b1,.len = 1} }; - - // this device needs a STOP between the register and data - if (state->config->stop_during_read) { - if ((ret = i2c_transfer(state->i2c, &msg[0], 1)) != 1) { - dprintk("%s: readreg error (reg == 0x%02x, ret == %i)\n", __FUNCTION__, reg, ret); - return -1; - } - if ((ret = i2c_transfer(state->i2c, &msg[1], 1)) != 1) { - dprintk("%s: readreg error (reg == 0x%02x, ret == %i)\n", __FUNCTION__, reg, ret); - return -1; - } - } else { - if ((ret = i2c_transfer(state->i2c, msg, 2)) != 2) { - dprintk("%s: readreg error (reg == 0x%02x, ret == %i)\n", __FUNCTION__, reg, ret); - return -1; - } + if ((ret = i2c_transfer(state->i2c, msg, 2)) != 2) { + dprintk("%s: readreg error (reg == 0x%02x, ret == %i)\n", __FUNCTION__, reg, ret); + return -1; } return b1[0]; @@ -111,22 +157,9 @@ static int stv0297_readregs(struct stv02 ®1,.len = 1}, {.addr = state->config->demod_address,.flags = I2C_M_RD,.buf = b,.len = len} }; - - // this device needs a STOP between the register and data - if (state->config->stop_during_read) { - if ((ret = i2c_transfer(state->i2c, &msg[0], 1)) != 1) { - dprintk("%s: readreg error (reg == 0x%02x, ret == %i)\n", __FUNCTION__, reg1, ret); - return -1; - } - if ((ret = i2c_transfer(state->i2c, &msg[1], 1)) != 1) { - dprintk("%s: readreg error (reg == 0x%02x, ret == %i)\n", __FUNCTION__, reg1, ret); - return -1; - } - } else { - if ((ret = i2c_transfer(state->i2c, msg, 2)) != 2) { - dprintk("%s: readreg error (reg == 0x%02x, ret == %i)\n", __FUNCTION__, reg1, ret); - return -1; - } + if ((ret = i2c_transfer(state->i2c, msg, 2)) != 2) { + dprintk("%s: readreg error (reg == 0x%02x, ret == %i)\n", __FUNCTION__, reg1, ret); + return -1; } return 0; @@ -640,6 +673,9 @@ static void stv0297_release(struct dvb_f static void stv0297_release(struct dvb_frontend *fe) { struct stv0297_state *state = fe->demodulator_priv; + + stv0297_del_wrapper(state); + kfree(state); } @@ -660,6 +696,8 @@ struct dvb_frontend *stv0297_attach(cons state->i2c = i2c; state->last_ber = 0; state->base_freq = 0; + + stv0297_add_wrapper(state); /* check if the demod is there */ if ((stv0297_readreg(state, 0x80) & 0x70) != 0x20) @@ -671,6 +709,7 @@ struct dvb_frontend *stv0297_attach(cons return &state->frontend; error: + stv0297_del_wrapper(state); kfree(state); return NULL; }
_______________________________________________ linux-dvb mailing list linux-dvb@xxxxxxxxxxx http://www.linuxtv.org/cgi-bin/mailman/listinfo/linux-dvb