Re: [PATCH] make the registers of the stv0297 visible for other applications (e.g. i2cdump)

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



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

[Index of Archives]     [Linux Media]     [Video 4 Linux]     [Asterisk]     [Samba]     [Xorg]     [Xfree86]     [Linux USB]

  Powered by Linux