[media] em28xx: fix+improve+unify i2c error handling, debug messages and code comments
- do not pass USB specific error codes to userspace/i2c-subsystem - unify the returned error codes and make them compliant with the i2c subsystem spec - check number of actually transferred bytes (via USB) everywehere - fix/improve debug messages - improve code comments Signed-off-by: Frank Schäfer <fschaefer.oss@googlemail.com> Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
This commit is contained in:
parent
eaf33c404c
commit
45f04e82d0
2 changed files with 89 additions and 32 deletions
|
@ -101,7 +101,7 @@ int em28xx_read_reg_req_len(struct em28xx *dev, u8 req, u16 reg,
|
||||||
if (reg_debug)
|
if (reg_debug)
|
||||||
printk(" failed!\n");
|
printk(" failed!\n");
|
||||||
mutex_unlock(&dev->ctrl_urb_lock);
|
mutex_unlock(&dev->ctrl_urb_lock);
|
||||||
return ret;
|
return usb_translate_errors(ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (len)
|
if (len)
|
||||||
|
@ -182,6 +182,9 @@ int em28xx_write_regs_req(struct em28xx *dev, u8 req, u16 reg, char *buf,
|
||||||
0x0000, reg, dev->urb_buf, len, HZ);
|
0x0000, reg, dev->urb_buf, len, HZ);
|
||||||
mutex_unlock(&dev->ctrl_urb_lock);
|
mutex_unlock(&dev->ctrl_urb_lock);
|
||||||
|
|
||||||
|
if (ret < 0)
|
||||||
|
return usb_translate_errors(ret);
|
||||||
|
|
||||||
if (dev->wait_after_write)
|
if (dev->wait_after_write)
|
||||||
msleep(dev->wait_after_write);
|
msleep(dev->wait_after_write);
|
||||||
|
|
||||||
|
|
|
@ -76,18 +76,26 @@ static int em2800_i2c_send_bytes(struct em28xx *dev, u8 addr, u8 *buf, u16 len)
|
||||||
/* trigger write */
|
/* trigger write */
|
||||||
ret = dev->em28xx_write_regs(dev, 4 - len, &b2[4 - len], 2 + len);
|
ret = dev->em28xx_write_regs(dev, 4 - len, &b2[4 - len], 2 + len);
|
||||||
if (ret != 2 + len) {
|
if (ret != 2 + len) {
|
||||||
em28xx_warn("writing to i2c device failed (error=%i)\n", ret);
|
em28xx_warn("failed to trigger write to i2c address 0x%x "
|
||||||
return -EIO;
|
"(error=%i)\n", addr, ret);
|
||||||
|
return (ret < 0) ? ret : -EIO;
|
||||||
}
|
}
|
||||||
/* wait for completion */
|
/* wait for completion */
|
||||||
for (write_timeout = EM2800_I2C_XFER_TIMEOUT; write_timeout > 0;
|
for (write_timeout = EM2800_I2C_XFER_TIMEOUT; write_timeout > 0;
|
||||||
write_timeout -= 5) {
|
write_timeout -= 5) {
|
||||||
ret = dev->em28xx_read_reg(dev, 0x05);
|
ret = dev->em28xx_read_reg(dev, 0x05);
|
||||||
if (ret == 0x80 + len - 1)
|
if (ret == 0x80 + len - 1) {
|
||||||
return len;
|
return len;
|
||||||
|
} else if (ret == 0x94 + len - 1) {
|
||||||
|
return -ENODEV;
|
||||||
|
} else if (ret < 0) {
|
||||||
|
em28xx_warn("failed to get i2c transfer status from "
|
||||||
|
"bridge register (error=%i)\n", ret);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
msleep(5);
|
msleep(5);
|
||||||
}
|
}
|
||||||
em28xx_warn("i2c write timed out\n");
|
em28xx_warn("write to i2c device at 0x%x timed out\n", addr);
|
||||||
return -EIO;
|
return -EIO;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -168,24 +176,48 @@ static int em2800_i2c_check_for_device(struct em28xx *dev, u8 addr)
|
||||||
static int em28xx_i2c_send_bytes(struct em28xx *dev, u16 addr, u8 *buf,
|
static int em28xx_i2c_send_bytes(struct em28xx *dev, u16 addr, u8 *buf,
|
||||||
u16 len, int stop)
|
u16 len, int stop)
|
||||||
{
|
{
|
||||||
int wrcount = 0;
|
|
||||||
int write_timeout, ret;
|
int write_timeout, ret;
|
||||||
|
|
||||||
if (len < 1 || len > 64)
|
if (len < 1 || len > 64)
|
||||||
return -EOPNOTSUPP;
|
return -EOPNOTSUPP;
|
||||||
|
/* NOTE: limited by the USB ctrl message constraints
|
||||||
|
* Zero length reads always succeed, even if no device is connected */
|
||||||
|
|
||||||
wrcount = dev->em28xx_write_regs_req(dev, stop ? 2 : 3, addr, buf, len);
|
/* Write to i2c device */
|
||||||
|
ret = dev->em28xx_write_regs_req(dev, stop ? 2 : 3, addr, buf, len);
|
||||||
|
if (ret != len) {
|
||||||
|
if (ret < 0) {
|
||||||
|
em28xx_warn("writing to i2c device at 0x%x failed "
|
||||||
|
"(error=%i)\n", addr, ret);
|
||||||
|
return ret;
|
||||||
|
} else {
|
||||||
|
em28xx_warn("%i bytes write to i2c device at 0x%x "
|
||||||
|
"requested, but %i bytes written\n",
|
||||||
|
len, addr, ret);
|
||||||
|
return -EIO;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* Seems to be required after a write */
|
/* Check success of the i2c operation */
|
||||||
for (write_timeout = EM2800_I2C_XFER_TIMEOUT; write_timeout > 0;
|
for (write_timeout = EM2800_I2C_XFER_TIMEOUT; write_timeout > 0;
|
||||||
write_timeout -= 5) {
|
write_timeout -= 5) {
|
||||||
ret = dev->em28xx_read_reg(dev, 0x05);
|
ret = dev->em28xx_read_reg(dev, 0x05);
|
||||||
if (!ret)
|
if (ret == 0) { /* success */
|
||||||
break;
|
return len;
|
||||||
msleep(5);
|
} else if (ret == 0x10) {
|
||||||
|
return -ENODEV;
|
||||||
|
} else if (ret < 0) {
|
||||||
|
em28xx_warn("failed to read i2c transfer status from "
|
||||||
|
"bridge (error=%i)\n", ret);
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
msleep(5);
|
||||||
return wrcount;
|
/* NOTE: do we really have to wait for success ?
|
||||||
|
Never seen anything else than 0x00 or 0x10
|
||||||
|
(even with high payload) ... */
|
||||||
|
}
|
||||||
|
em28xx_warn("write to i2c device at 0x%x timed out\n", addr);
|
||||||
|
return -EIO;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -198,15 +230,40 @@ static int em28xx_i2c_recv_bytes(struct em28xx *dev, u16 addr, u8 *buf, u16 len)
|
||||||
|
|
||||||
if (len < 1 || len > 64)
|
if (len < 1 || len > 64)
|
||||||
return -EOPNOTSUPP;
|
return -EOPNOTSUPP;
|
||||||
|
/* NOTE: limited by the USB ctrl message constraints
|
||||||
|
* Zero length reads always succeed, even if no device is connected */
|
||||||
|
|
||||||
|
/* Read data from i2c device */
|
||||||
ret = dev->em28xx_read_reg_req_len(dev, 2, addr, buf, len);
|
ret = dev->em28xx_read_reg_req_len(dev, 2, addr, buf, len);
|
||||||
|
if (ret != len) {
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
em28xx_warn("reading i2c device failed (error=%i)\n", ret);
|
em28xx_warn("reading from i2c device at 0x%x failed "
|
||||||
|
"(error=%i)\n", addr, ret);
|
||||||
|
return ret;
|
||||||
|
} else {
|
||||||
|
em28xx_warn("%i bytes requested from i2c device at "
|
||||||
|
"0x%x, but %i bytes received\n",
|
||||||
|
len, addr, ret);
|
||||||
|
return -EIO;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Check success of the i2c operation */
|
||||||
|
ret = dev->em28xx_read_reg(dev, 0x05);
|
||||||
|
if (ret < 0) {
|
||||||
|
em28xx_warn("failed to read i2c transfer status from "
|
||||||
|
"bridge (error=%i)\n", ret);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
if (dev->em28xx_read_reg(dev, 0x5) != 0)
|
if (ret > 0) {
|
||||||
|
if (ret == 0x10) {
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
return ret;
|
} else {
|
||||||
|
em28xx_warn("unknown i2c error (status=%i)\n", ret);
|
||||||
|
return -EIO;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return len;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -216,15 +273,12 @@ static int em28xx_i2c_recv_bytes(struct em28xx *dev, u16 addr, u8 *buf, u16 len)
|
||||||
static int em28xx_i2c_check_for_device(struct em28xx *dev, u16 addr)
|
static int em28xx_i2c_check_for_device(struct em28xx *dev, u16 addr)
|
||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
|
u8 buf;
|
||||||
|
|
||||||
ret = dev->em28xx_read_reg_req(dev, 2, addr);
|
ret = em28xx_i2c_recv_bytes(dev, addr, &buf, 1);
|
||||||
if (ret < 0) {
|
if (ret == 1)
|
||||||
em28xx_warn("reading from i2c device failed (error=%i)\n", ret);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
if (dev->em28xx_read_reg(dev, 0x5) != 0)
|
|
||||||
return -ENODEV;
|
|
||||||
return 0;
|
return 0;
|
||||||
|
return (ret < 0) ? ret : -EIO;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -249,11 +303,11 @@ static int em28xx_i2c_xfer(struct i2c_adapter *i2c_adap,
|
||||||
rc = em2800_i2c_check_for_device(dev, addr);
|
rc = em2800_i2c_check_for_device(dev, addr);
|
||||||
else
|
else
|
||||||
rc = em28xx_i2c_check_for_device(dev, addr);
|
rc = em28xx_i2c_check_for_device(dev, addr);
|
||||||
if (rc < 0) {
|
if (rc == -ENODEV) {
|
||||||
dprintk2(2, " no device\n");
|
if (i2c_debug >= 2)
|
||||||
|
printk(" no device\n");
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
} else if (msgs[i].flags & I2C_M_RD) {
|
} else if (msgs[i].flags & I2C_M_RD) {
|
||||||
/* read bytes */
|
/* read bytes */
|
||||||
if (dev->board.is_em2800)
|
if (dev->board.is_em2800)
|
||||||
|
@ -284,16 +338,16 @@ static int em28xx_i2c_xfer(struct i2c_adapter *i2c_adap,
|
||||||
msgs[i].len,
|
msgs[i].len,
|
||||||
i == num - 1);
|
i == num - 1);
|
||||||
}
|
}
|
||||||
if (rc < 0)
|
if (rc < 0) {
|
||||||
goto err;
|
if (i2c_debug >= 2)
|
||||||
|
printk(" ERROR: %i\n", rc);
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
if (i2c_debug >= 2)
|
if (i2c_debug >= 2)
|
||||||
printk("\n");
|
printk("\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
return num;
|
return num;
|
||||||
err:
|
|
||||||
dprintk2(2, " ERROR: %i\n", rc);
|
|
||||||
return rc;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* based on linux/sunrpc/svcauth.h and linux/hash.h
|
/* based on linux/sunrpc/svcauth.h and linux/hash.h
|
||||||
|
|
Loading…
Add table
Reference in a new issue