Commit 45f04e82 authored by Frank Schaefer's avatar Frank Schaefer Committed by Mauro Carvalho Chehab

[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: default avatarFrank Schäfer <fschaefer.oss@googlemail.com>
Signed-off-by: default avatarMauro Carvalho Chehab <mchehab@redhat.com>
parent eaf33c40
...@@ -101,7 +101,7 @@ int em28xx_read_reg_req_len(struct em28xx *dev, u8 req, u16 reg, ...@@ -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, ...@@ -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) ...@@ -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) ...@@ -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;
} 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); msleep(5);
/* 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 wrcount; return -EIO;
} }
/* /*
...@@ -198,15 +230,40 @@ static int em28xx_i2c_recv_bytes(struct em28xx *dev, u16 addr, u8 *buf, u16 len) ...@@ -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) {
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) { if (ret < 0) {
em28xx_warn("reading i2c device failed (error=%i)\n", ret); 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) {
return -ENODEV; if (ret == 0x10) {
return ret; return -ENODEV;
} 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) ...@@ -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 0;
return ret; return (ret < 0) ? ret : -EIO;
}
if (dev->em28xx_read_reg(dev, 0x5) != 0)
return -ENODEV;
return 0;
} }
/* /*
...@@ -249,11 +303,11 @@ static int em28xx_i2c_xfer(struct i2c_adapter *i2c_adap, ...@@ -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, ...@@ -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
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment