diff options
author | Frank Schaefer <fschaefer.oss@googlemail.com> | 2013-01-03 12:27:05 -0500 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab@redhat.com> | 2013-01-04 22:18:25 -0500 |
commit | 45f04e82d035006afe5023850393e9b3b74b85c2 (patch) | |
tree | 2679cd0361ad64a61f08c58820ada06c59a10a53 | |
parent | eaf33c404cd60ba4b442324766abbb5da8c94381 (diff) |
[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>
-rw-r--r-- | drivers/media/usb/em28xx/em28xx-core.c | 5 | ||||
-rw-r--r-- | drivers/media/usb/em28xx/em28xx-i2c.c | 116 |
2 files changed, 89 insertions, 32 deletions
diff --git a/drivers/media/usb/em28xx/em28xx-core.c b/drivers/media/usb/em28xx/em28xx-core.c index 6916e87bc624..80f87bbbd554 100644 --- a/drivers/media/usb/em28xx/em28xx-core.c +++ b/drivers/media/usb/em28xx/em28xx-core.c | |||
@@ -101,7 +101,7 @@ int em28xx_read_reg_req_len(struct em28xx *dev, u8 req, u16 reg, | |||
101 | if (reg_debug) | 101 | if (reg_debug) |
102 | printk(" failed!\n"); | 102 | printk(" failed!\n"); |
103 | mutex_unlock(&dev->ctrl_urb_lock); | 103 | mutex_unlock(&dev->ctrl_urb_lock); |
104 | return ret; | 104 | return usb_translate_errors(ret); |
105 | } | 105 | } |
106 | 106 | ||
107 | if (len) | 107 | if (len) |
@@ -182,6 +182,9 @@ int em28xx_write_regs_req(struct em28xx *dev, u8 req, u16 reg, char *buf, | |||
182 | 0x0000, reg, dev->urb_buf, len, HZ); | 182 | 0x0000, reg, dev->urb_buf, len, HZ); |
183 | mutex_unlock(&dev->ctrl_urb_lock); | 183 | mutex_unlock(&dev->ctrl_urb_lock); |
184 | 184 | ||
185 | if (ret < 0) | ||
186 | return usb_translate_errors(ret); | ||
187 | |||
185 | if (dev->wait_after_write) | 188 | if (dev->wait_after_write) |
186 | msleep(dev->wait_after_write); | 189 | msleep(dev->wait_after_write); |
187 | 190 | ||
diff --git a/drivers/media/usb/em28xx/em28xx-i2c.c b/drivers/media/usb/em28xx/em28xx-i2c.c index 4a24ed08e46a..f784b516ae1c 100644 --- a/drivers/media/usb/em28xx/em28xx-i2c.c +++ b/drivers/media/usb/em28xx/em28xx-i2c.c | |||
@@ -76,18 +76,26 @@ static int em2800_i2c_send_bytes(struct em28xx *dev, u8 addr, u8 *buf, u16 len) | |||
76 | /* trigger write */ | 76 | /* trigger write */ |
77 | ret = dev->em28xx_write_regs(dev, 4 - len, &b2[4 - len], 2 + len); | 77 | ret = dev->em28xx_write_regs(dev, 4 - len, &b2[4 - len], 2 + len); |
78 | if (ret != 2 + len) { | 78 | if (ret != 2 + len) { |
79 | em28xx_warn("writing to i2c device failed (error=%i)\n", ret); | 79 | em28xx_warn("failed to trigger write to i2c address 0x%x " |
80 | return -EIO; | 80 | "(error=%i)\n", addr, ret); |
81 | return (ret < 0) ? ret : -EIO; | ||
81 | } | 82 | } |
82 | /* wait for completion */ | 83 | /* wait for completion */ |
83 | for (write_timeout = EM2800_I2C_XFER_TIMEOUT; write_timeout > 0; | 84 | for (write_timeout = EM2800_I2C_XFER_TIMEOUT; write_timeout > 0; |
84 | write_timeout -= 5) { | 85 | write_timeout -= 5) { |
85 | ret = dev->em28xx_read_reg(dev, 0x05); | 86 | ret = dev->em28xx_read_reg(dev, 0x05); |
86 | if (ret == 0x80 + len - 1) | 87 | if (ret == 0x80 + len - 1) { |
87 | return len; | 88 | return len; |
89 | } else if (ret == 0x94 + len - 1) { | ||
90 | return -ENODEV; | ||
91 | } else if (ret < 0) { | ||
92 | em28xx_warn("failed to get i2c transfer status from " | ||
93 | "bridge register (error=%i)\n", ret); | ||
94 | return ret; | ||
95 | } | ||
88 | msleep(5); | 96 | msleep(5); |
89 | } | 97 | } |
90 | em28xx_warn("i2c write timed out\n"); | 98 | em28xx_warn("write to i2c device at 0x%x timed out\n", addr); |
91 | return -EIO; | 99 | return -EIO; |
92 | } | 100 | } |
93 | 101 | ||
@@ -168,24 +176,48 @@ static int em2800_i2c_check_for_device(struct em28xx *dev, u8 addr) | |||
168 | static int em28xx_i2c_send_bytes(struct em28xx *dev, u16 addr, u8 *buf, | 176 | static int em28xx_i2c_send_bytes(struct em28xx *dev, u16 addr, u8 *buf, |
169 | u16 len, int stop) | 177 | u16 len, int stop) |
170 | { | 178 | { |
171 | int wrcount = 0; | ||
172 | int write_timeout, ret; | 179 | int write_timeout, ret; |
173 | 180 | ||
174 | if (len < 1 || len > 64) | 181 | if (len < 1 || len > 64) |
175 | return -EOPNOTSUPP; | 182 | return -EOPNOTSUPP; |
183 | /* NOTE: limited by the USB ctrl message constraints | ||
184 | * Zero length reads always succeed, even if no device is connected */ | ||
176 | 185 | ||
177 | wrcount = dev->em28xx_write_regs_req(dev, stop ? 2 : 3, addr, buf, len); | 186 | /* Write to i2c device */ |
187 | ret = dev->em28xx_write_regs_req(dev, stop ? 2 : 3, addr, buf, len); | ||
188 | if (ret != len) { | ||
189 | if (ret < 0) { | ||
190 | em28xx_warn("writing to i2c device at 0x%x failed " | ||
191 | "(error=%i)\n", addr, ret); | ||
192 | return ret; | ||
193 | } else { | ||
194 | em28xx_warn("%i bytes write to i2c device at 0x%x " | ||
195 | "requested, but %i bytes written\n", | ||
196 | len, addr, ret); | ||
197 | return -EIO; | ||
198 | } | ||
199 | } | ||
178 | 200 | ||
179 | /* Seems to be required after a write */ | 201 | /* Check success of the i2c operation */ |
180 | for (write_timeout = EM2800_I2C_XFER_TIMEOUT; write_timeout > 0; | 202 | for (write_timeout = EM2800_I2C_XFER_TIMEOUT; write_timeout > 0; |
181 | write_timeout -= 5) { | 203 | write_timeout -= 5) { |
182 | ret = dev->em28xx_read_reg(dev, 0x05); | 204 | ret = dev->em28xx_read_reg(dev, 0x05); |
183 | if (!ret) | 205 | if (ret == 0) { /* success */ |
184 | break; | 206 | return len; |
207 | } else if (ret == 0x10) { | ||
208 | return -ENODEV; | ||
209 | } else if (ret < 0) { | ||
210 | em28xx_warn("failed to read i2c transfer status from " | ||
211 | "bridge (error=%i)\n", ret); | ||
212 | return ret; | ||
213 | } | ||
185 | msleep(5); | 214 | msleep(5); |
215 | /* NOTE: do we really have to wait for success ? | ||
216 | Never seen anything else than 0x00 or 0x10 | ||
217 | (even with high payload) ... */ | ||
186 | } | 218 | } |
187 | 219 | em28xx_warn("write to i2c device at 0x%x timed out\n", addr); | |
188 | return wrcount; | 220 | return -EIO; |
189 | } | 221 | } |
190 | 222 | ||
191 | /* | 223 | /* |
@@ -198,15 +230,40 @@ static int em28xx_i2c_recv_bytes(struct em28xx *dev, u16 addr, u8 *buf, u16 len) | |||
198 | 230 | ||
199 | if (len < 1 || len > 64) | 231 | if (len < 1 || len > 64) |
200 | return -EOPNOTSUPP; | 232 | return -EOPNOTSUPP; |
233 | /* NOTE: limited by the USB ctrl message constraints | ||
234 | * Zero length reads always succeed, even if no device is connected */ | ||
201 | 235 | ||
236 | /* Read data from i2c device */ | ||
202 | ret = dev->em28xx_read_reg_req_len(dev, 2, addr, buf, len); | 237 | ret = dev->em28xx_read_reg_req_len(dev, 2, addr, buf, len); |
238 | if (ret != len) { | ||
239 | if (ret < 0) { | ||
240 | em28xx_warn("reading from i2c device at 0x%x failed " | ||
241 | "(error=%i)\n", addr, ret); | ||
242 | return ret; | ||
243 | } else { | ||
244 | em28xx_warn("%i bytes requested from i2c device at " | ||
245 | "0x%x, but %i bytes received\n", | ||
246 | len, addr, ret); | ||
247 | return -EIO; | ||
248 | } | ||
249 | } | ||
250 | |||
251 | /* Check success of the i2c operation */ | ||
252 | ret = dev->em28xx_read_reg(dev, 0x05); | ||
203 | if (ret < 0) { | 253 | if (ret < 0) { |
204 | em28xx_warn("reading i2c device failed (error=%i)\n", ret); | 254 | em28xx_warn("failed to read i2c transfer status from " |
255 | "bridge (error=%i)\n", ret); | ||
205 | return ret; | 256 | return ret; |
206 | } | 257 | } |
207 | if (dev->em28xx_read_reg(dev, 0x5) != 0) | 258 | if (ret > 0) { |
208 | return -ENODEV; | 259 | if (ret == 0x10) { |
209 | return ret; | 260 | return -ENODEV; |
261 | } else { | ||
262 | em28xx_warn("unknown i2c error (status=%i)\n", ret); | ||
263 | return -EIO; | ||
264 | } | ||
265 | } | ||
266 | return len; | ||
210 | } | 267 | } |
211 | 268 | ||
212 | /* | 269 | /* |
@@ -216,15 +273,12 @@ static int em28xx_i2c_recv_bytes(struct em28xx *dev, u16 addr, u8 *buf, u16 len) | |||
216 | static int em28xx_i2c_check_for_device(struct em28xx *dev, u16 addr) | 273 | static int em28xx_i2c_check_for_device(struct em28xx *dev, u16 addr) |
217 | { | 274 | { |
218 | int ret; | 275 | int ret; |
276 | u8 buf; | ||
219 | 277 | ||
220 | ret = dev->em28xx_read_reg_req(dev, 2, addr); | 278 | ret = em28xx_i2c_recv_bytes(dev, addr, &buf, 1); |
221 | if (ret < 0) { | 279 | if (ret == 1) |
222 | em28xx_warn("reading from i2c device failed (error=%i)\n", ret); | 280 | return 0; |
223 | return ret; | 281 | return (ret < 0) ? ret : -EIO; |
224 | } | ||
225 | if (dev->em28xx_read_reg(dev, 0x5) != 0) | ||
226 | return -ENODEV; | ||
227 | return 0; | ||
228 | } | 282 | } |
229 | 283 | ||
230 | /* | 284 | /* |
@@ -249,11 +303,11 @@ static int em28xx_i2c_xfer(struct i2c_adapter *i2c_adap, | |||
249 | rc = em2800_i2c_check_for_device(dev, addr); | 303 | rc = em2800_i2c_check_for_device(dev, addr); |
250 | else | 304 | else |
251 | rc = em28xx_i2c_check_for_device(dev, addr); | 305 | rc = em28xx_i2c_check_for_device(dev, addr); |
252 | if (rc < 0) { | 306 | if (rc == -ENODEV) { |
253 | dprintk2(2, " no device\n"); | 307 | if (i2c_debug >= 2) |
308 | printk(" no device\n"); | ||
254 | return rc; | 309 | return rc; |
255 | } | 310 | } |
256 | |||
257 | } else if (msgs[i].flags & I2C_M_RD) { | 311 | } else if (msgs[i].flags & I2C_M_RD) { |
258 | /* read bytes */ | 312 | /* read bytes */ |
259 | if (dev->board.is_em2800) | 313 | if (dev->board.is_em2800) |
@@ -284,16 +338,16 @@ static int em28xx_i2c_xfer(struct i2c_adapter *i2c_adap, | |||
284 | msgs[i].len, | 338 | msgs[i].len, |
285 | i == num - 1); | 339 | i == num - 1); |
286 | } | 340 | } |
287 | if (rc < 0) | 341 | if (rc < 0) { |
288 | goto err; | 342 | if (i2c_debug >= 2) |
343 | printk(" ERROR: %i\n", rc); | ||
344 | return rc; | ||
345 | } | ||
289 | if (i2c_debug >= 2) | 346 | if (i2c_debug >= 2) |
290 | printk("\n"); | 347 | printk("\n"); |
291 | } | 348 | } |
292 | 349 | ||
293 | return num; | 350 | return num; |
294 | err: | ||
295 | dprintk2(2, " ERROR: %i\n", rc); | ||
296 | return rc; | ||
297 | } | 351 | } |
298 | 352 | ||
299 | /* based on linux/sunrpc/svcauth.h and linux/hash.h | 353 | /* based on linux/sunrpc/svcauth.h and linux/hash.h |