All of lore.kernel.org
 help / color / mirror / Atom feed
* DVB TDA18218 tuner driver BUG in I2C write
@ 2011-01-22  1:09 Andrea Merello
  0 siblings, 0 replies; only message in thread
From: Andrea Merello @ 2011-01-22  1:09 UTC (permalink / raw)
  To: Antti Palosaari; +Cc: linux-kernel

Hello.

I'm looking at tda18218.c file from 2.6.37 kernel.
I think the tda18218_wr_regs function has a bug:

I think it works as long as priv->cfg->i2c_wr_max is > than len parameter,
but let's assume that priv->cfg->i2c_wr_max is set to 2.

If tda18218_wr_regs is called with len = 1 it is easy to see it does
not perform the write. In this case:

msg_len_max is priv->cfg->i2c_wr_max -1, thus it is 1
remainder is len % msg_len_max, thus it is 0

the 'for loop' condition (i <= quotient && remainder) is thus false
and no write is performed at all.

I changed the function so it writes correctly now for me. Maybe you
prefer to fix the original algo rather than heavily changing it as I
did. Anyway I attach the patch I produced to make it working here.

Please note that I tested this only with priv->cfg->i2c_wr_max set to
2 and with the AF9035 driver that is not even in the kernel (any plan
to include ?) and I couldn't try this with any other in-kernel driver
due to lack of HW. So the patch need to be eventually checked and
tested more.

Thank you
Andrea

--- drivers/media/common/tuners/tda18218_orig.c 2011-01-22
22:44:59.323333347 +0100
+++ drivers/media/common/tuners/tda18218.c      2011-01-22
22:46:36.846666668 +0100
@@ -28,8 +28,9 @@ MODULE_PARM_DESC(debug, "Turn on/off deb
 /* write multiple registers */
 static int tda18218_wr_regs(struct tda18218_priv *priv, u8 reg, u8
*val, u8 len)
 {
-       int ret;
-       u8 buf[1+len], quotient, remainder, i, msg_len, msg_len_max;
+       int ret=0;
+       u8 buf[1+len], msg_len, msg_len_max;
+       int remaining;
        struct i2c_msg msg[1] = {
                {
                        .addr = priv->cfg->i2c_address,
@@ -39,18 +40,21 @@ static int tda18218_wr_regs(struct tda18
        };

        msg_len_max = priv->cfg->i2c_wr_max - 1;
-       quotient = len / msg_len_max;
-       remainder = len % msg_len_max;
-       msg_len = msg_len_max;
-       for (i = 0; (i <= quotient && remainder); i++) {
-               if (i == quotient)  /* set len of the last msg */
-                       msg_len = remainder;
-
-               msg[0].len = msg_len + 1;
-               buf[0] = reg + i * msg_len_max;
-               memcpy(&buf[1], &val[i * msg_len_max], msg_len);
+
+       remaining = len;
+       for (; remaining > 0;remaining -= msg_len_max) {
+
+               msg_len = remaining;
+
+               if (msg_len > msg_len_max)  /* set len of the last msg */
+                       msg_len = msg_len_max;
+
+               msg[0].len = msg_len +1;
+               buf[0] = reg + (len - remaining);
+               memcpy(&buf[1], &val[(len - remaining)], msg_len);

                ret = i2c_transfer(priv->i2c, msg, 1);
+
                if (ret != 1)
                        break;
        }

^ permalink raw reply	[flat|nested] only message in thread

only message in thread, other threads:[~2011-01-22  1:09 UTC | newest]

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2011-01-22  1:09 DVB TDA18218 tuner driver BUG in I2C write Andrea Merello

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.