Gitweb:     
http://git.kernel.org/git/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commit;h=7d58d1117ec02f5fe22ddd03ca08fe2a8c777ea2
Commit:     7d58d1117ec02f5fe22ddd03ca08fe2a8c777ea2
Parent:     e155d908f72cc429b538c101ee8ffcd10a44b69b
Author:     Chris Pascoe <[EMAIL PROTECTED]>
AuthorDate: Mon Nov 19 04:31:58 2007 -0300
Committer:  Mauro Carvalho Chehab <[EMAIL PROTECTED]>
CommitDate: Fri Jan 25 19:02:22 2008 -0200

    V4L/DVB (6633): xc2028: make register reads atomic
    
    Issuing register reads as a separate address write and data read 
transactions
    means that other I2C activity could occur in between and state could get out
    of sync.  Issue both the write and read in a single transaction so that the
    i2c layer can prevent other users accessing the bus until we are complete.
    
    Signed-off-by: Chris Pascoe <[EMAIL PROTECTED]>
    Signed-off-by: Mauro Carvalho Chehab <[EMAIL PROTECTED]>
---
 drivers/media/video/tuner-i2c.h    |   13 ++++++++
 drivers/media/video/tuner-xc2028.c |   55 +++++++++++++++++++----------------
 2 files changed, 43 insertions(+), 25 deletions(-)

diff --git a/drivers/media/video/tuner-i2c.h b/drivers/media/video/tuner-i2c.h
index b5ac189..d7cf72c 100644
--- a/drivers/media/video/tuner-i2c.h
+++ b/drivers/media/video/tuner-i2c.h
@@ -46,6 +46,19 @@ static inline int tuner_i2c_xfer_recv(struct tuner_i2c_props 
*props, char *buf,
        return (ret == 1) ? len : ret;
 }
 
+static inline int tuner_i2c_xfer_send_recv(struct tuner_i2c_props *props,
+                                          char *obuf, int olen,
+                                          char *ibuf, int ilen)
+{
+       struct i2c_msg msg[2] = { { .addr = props->addr, .flags = 0,
+                                   .buf = obuf, .len = olen },
+                                 { .addr = props->addr, .flags = I2C_M_RD,
+                                   .buf = ibuf, .len = ilen } };
+       int ret = i2c_transfer(props->adap, msg, 2);
+
+       return (ret == 2) ? ilen : ret;
+}
+
 #ifndef __TUNER_DRIVER_H__
 #define tuner_warn(fmt, arg...) do {                                   \
        printk(KERN_WARNING "%s %d-%04x: " fmt, PREFIX,                 \
diff --git a/drivers/media/video/tuner-xc2028.c 
b/drivers/media/video/tuner-xc2028.c
index 166fede..a49a4e8 100644
--- a/drivers/media/video/tuner-xc2028.c
+++ b/drivers/media/video/tuner-xc2028.c
@@ -101,6 +101,16 @@ struct xc2028_data {
        _rc;                                                            \
 })
 
+#define i2c_send_recv(priv, obuf, osize, ibuf, isize) ({               \
+       int _rc;                                                        \
+       _rc = tuner_i2c_xfer_send_recv(&priv->i2c_props, obuf, osize,   \
+                                      ibuf, isize);                    \
+       if (isize != _rc)                                               \
+               tuner_err("i2c input error: rc = %d (should be %d)\n",  \
+                          _rc, (int)isize);                            \
+       _rc;                                                            \
+})
+
 #define send_seq(priv, data...)        ({                                      
\
        static u8 _val[] = data;                                        \
        int _rc;                                                        \
@@ -113,25 +123,21 @@ struct xc2028_data {
        _rc;                                                            \
 })
 
-static unsigned int xc2028_get_reg(struct xc2028_data *priv, u16 reg)
+static unsigned int xc2028_get_reg(struct xc2028_data *priv, u16 reg, u16 *val)
 {
-       int rc;
        unsigned char buf[2];
+       unsigned char ibuf[2];
 
-       tuner_dbg("%s called\n", __FUNCTION__);
+       tuner_dbg("%s %04x called\n", __FUNCTION__, reg);
 
-       buf[0] = reg>>8;
+       buf[0] = reg >> 8;
        buf[1] = (unsigned char) reg;
 
-       rc = i2c_send(priv, buf, 2);
-       if (rc < 0)
-               return rc;
-
-       rc = i2c_rcv(priv, buf, 2);
-       if (rc < 0)
-               return rc;
+       if (i2c_send_recv(priv, buf, 2, ibuf, 2) != 2)
+               return -EIO;
 
-       return (buf[1]) | (buf[0] << 8);
+       *val = (ibuf[1]) | (ibuf[0] << 8);
+       return 0;
 }
 
 void dump_firm_type(unsigned int type)
@@ -567,7 +573,8 @@ static int check_firmware(struct dvb_frontend *fe, enum 
tuner_mode new_mode,
                          v4l2_std_id std, fe_bandwidth_t bandwidth)
 {
        struct xc2028_data      *priv = fe->tuner_priv;
-       int                     rc, version, hwmodel;
+       int                     rc;
+       u16                     version, hwmodel;
        v4l2_std_id             std0 = 0;
        unsigned int            type0 = 0, type = 0;
        int                     change_digital_bandwidth;
@@ -692,8 +699,8 @@ static int check_firmware(struct dvb_frontend *fe, enum 
tuner_mode new_mode,
 
        rc = load_scode(fe, type, &std, 0);
 
-       version = xc2028_get_reg(priv, 0x0004);
-       hwmodel = xc2028_get_reg(priv, 0x0008);
+       xc2028_get_reg(priv, 0x0004, &version);
+       xc2028_get_reg(priv, 0x0008, &hwmodel);
 
        tuner_info("Device is Xceive %d version %d.%d, "
                   "firmware version %d.%d\n",
@@ -708,33 +715,31 @@ static int check_firmware(struct dvb_frontend *fe, enum 
tuner_mode new_mode,
 static int xc2028_signal(struct dvb_frontend *fe, u16 *strength)
 {
        struct xc2028_data *priv = fe->tuner_priv;
-       int                frq_lock, signal = 0;
+       u16                 frq_lock, signal = 0;
+       int                 rc;
 
        tuner_dbg("%s called\n", __FUNCTION__);
 
        mutex_lock(&priv->lock);
 
-       *strength = 0;
-
        /* Sync Lock Indicator */
-       frq_lock = xc2028_get_reg(priv, 0x0002);
-       if (frq_lock <= 0)
+       rc = xc2028_get_reg(priv, 0x0002, &frq_lock);
+       if (rc < 0 || frq_lock == 0)
                goto ret;
 
        /* Frequency is locked. Return signal quality */
 
        /* Get SNR of the video signal */
-       signal = xc2028_get_reg(priv, 0x0040);
-
-       if (signal <= 0)
-               signal = frq_lock;
+       rc = xc2028_get_reg(priv, 0x0040, &signal);
+       if (rc < 0)
+               signal = -frq_lock;
 
 ret:
        mutex_unlock(&priv->lock);
 
        *strength = signal;
 
-       return 0;
+       return rc;
 }
 
 #define DIV 15625
-
To unsubscribe from this list: send the line "unsubscribe git-commits-head" in
the body of a message to [EMAIL PROTECTED]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to