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
 				  &reg1,.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
 				  &reg1,.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@linuxtv.org
http://www.linuxtv.org/cgi-bin/mailman/listinfo/linux-dvb

Reply via email to