forked from luck/tmp_suning_uos_patched
i2c-algo-bit: Read block data bugfix
This fixes a bug in the way i2c-algo-bit handles I2C_M_RECV_LEN, used to implement i2c_smbus_read_block_data(). Previously, in the absence of PEC (rarely used!) it would NAK the "length" byte: S addr Rd [A] [length] NA That prevents the subsequent data bytes from being read: S addr Rd [A] [length] { A [data] }* NA The primary fix just reorders two code blocks, so the length used in the "should I NAK now?" check incorporates the data which it just read from the slave device. However, that move also highlighted other fault handling glitches. This fixes those by abstracting the RX path ack/nak logic, so it can be used in more than one location. Also, a few CodingStyle issues were also resolved. Signed-off-by: David Brownell <dbrownell@users.sourceforge.net> Signed-off-by: Jean Delvare <khali@linux-fr.org>
This commit is contained in:
parent
51e5709ad4
commit
939bc4943d
|
@ -357,13 +357,29 @@ static int sendbytes(struct i2c_adapter *i2c_adap, struct i2c_msg *msg)
|
|||
return wrcount;
|
||||
}
|
||||
|
||||
static int acknak(struct i2c_adapter *i2c_adap, int is_ack)
|
||||
{
|
||||
struct i2c_algo_bit_data *adap = i2c_adap->algo_data;
|
||||
|
||||
/* assert: sda is high */
|
||||
if (is_ack) /* send ack */
|
||||
setsda(adap, 0);
|
||||
udelay((adap->udelay + 1) / 2);
|
||||
if (sclhi(adap) < 0) { /* timeout */
|
||||
dev_err(&i2c_adap->dev, "readbytes: ack/nak timeout\n");
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
scllo(adap);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int readbytes(struct i2c_adapter *i2c_adap, struct i2c_msg *msg)
|
||||
{
|
||||
int inval;
|
||||
int rdcount=0; /* counts bytes read */
|
||||
struct i2c_algo_bit_data *adap = i2c_adap->algo_data;
|
||||
unsigned char *temp = msg->buf;
|
||||
int count = msg->len;
|
||||
const unsigned flags = msg->flags;
|
||||
|
||||
while (count > 0) {
|
||||
inval = i2c_inb(i2c_adap);
|
||||
|
@ -377,28 +393,12 @@ static int readbytes(struct i2c_adapter *i2c_adap, struct i2c_msg *msg)
|
|||
temp++;
|
||||
count--;
|
||||
|
||||
if (msg->flags & I2C_M_NO_RD_ACK) {
|
||||
bit_dbg(2, &i2c_adap->dev, "i2c_inb: 0x%02x\n",
|
||||
inval);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* assert: sda is high */
|
||||
if (count) /* send ack */
|
||||
setsda(adap, 0);
|
||||
udelay((adap->udelay + 1) / 2);
|
||||
bit_dbg(2, &i2c_adap->dev, "i2c_inb: 0x%02x %s\n", inval,
|
||||
count ? "A" : "NA");
|
||||
if (sclhi(adap)<0) { /* timeout */
|
||||
dev_err(&i2c_adap->dev, "readbytes: timeout at ack\n");
|
||||
return -ETIMEDOUT;
|
||||
};
|
||||
scllo(adap);
|
||||
|
||||
/* Some SMBus transactions require that we receive the
|
||||
transaction length as the first read byte. */
|
||||
if (rdcount == 1 && (msg->flags & I2C_M_RECV_LEN)) {
|
||||
if (rdcount == 1 && (flags & I2C_M_RECV_LEN)) {
|
||||
if (inval <= 0 || inval > I2C_SMBUS_BLOCK_MAX) {
|
||||
if (!(flags & I2C_M_NO_RD_ACK))
|
||||
acknak(i2c_adap, 0);
|
||||
dev_err(&i2c_adap->dev, "readbytes: invalid "
|
||||
"block length (%d)\n", inval);
|
||||
return -EREMOTEIO;
|
||||
|
@ -409,6 +409,18 @@ static int readbytes(struct i2c_adapter *i2c_adap, struct i2c_msg *msg)
|
|||
count += inval;
|
||||
msg->len += inval;
|
||||
}
|
||||
|
||||
bit_dbg(2, &i2c_adap->dev, "readbytes: 0x%02x %s\n",
|
||||
inval,
|
||||
(flags & I2C_M_NO_RD_ACK)
|
||||
? "(no ack/nak)"
|
||||
: (count ? "A" : "NA"));
|
||||
|
||||
if (!(flags & I2C_M_NO_RD_ACK)) {
|
||||
inval = acknak(i2c_adap, count);
|
||||
if (inval < 0)
|
||||
return inval;
|
||||
}
|
||||
}
|
||||
return rdcount;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue
Block a user