diff options
| author | Olivier Sobrie <olivier@sobrie.be> | 2014-04-10 15:44:21 -0400 |
|---|---|---|
| committer | Marc Kleine-Budde <mkl@pengutronix.de> | 2014-04-24 16:54:16 -0400 |
| commit | e59e36e7333702d1d835113ced85243bb7f30f99 (patch) | |
| tree | d440b886917c2095cacb9259634eaa6d7c602314 | |
| parent | 869ba1e67a894f45ba3da32af66f25104fab7d8f (diff) | |
can: kvaser_usb: add retries/timeout to kvaser_usb_wait_msg()
On some Kvaser hardware, the firmware returns extra messages after the
request for card info. For instance on a Leaf Light v2:
--> CMD_GET_CARD_INFO
<-- CMD_USB_THROTTLE
<-- CMD_GET_CARD_INFO2
<-- CMD_GET_CARD_INFO_REQ
When it happens, the probing function fails because we only read
the first usb message.
To overcome this issue, we add a mechanism of retries to the
kvaser_usb_wait_msg() function.
I tested this patch with the following hardware:
- Kvaser Leaf Light
- Kvaser Leaf Light v2
- Kvaser USBCan R
This patch is necessary for the Leaf Light v2 hardware.
Signed-off-by: Olivier Sobrie <olivier@sobrie.be>
Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
| -rw-r--r-- | drivers/net/can/usb/kvaser_usb.c | 49 |
1 files changed, 27 insertions, 22 deletions
diff --git a/drivers/net/can/usb/kvaser_usb.c b/drivers/net/can/usb/kvaser_usb.c index 4ca46edc061d..7a1c5ec23268 100644 --- a/drivers/net/can/usb/kvaser_usb.c +++ b/drivers/net/can/usb/kvaser_usb.c | |||
| @@ -379,38 +379,43 @@ static int kvaser_usb_wait_msg(const struct kvaser_usb *dev, u8 id, | |||
| 379 | void *buf; | 379 | void *buf; |
| 380 | int actual_len; | 380 | int actual_len; |
| 381 | int err; | 381 | int err; |
| 382 | int pos = 0; | 382 | int pos; |
| 383 | unsigned long to = jiffies + msecs_to_jiffies(USB_RECV_TIMEOUT); | ||
| 383 | 384 | ||
| 384 | buf = kzalloc(RX_BUFFER_SIZE, GFP_KERNEL); | 385 | buf = kzalloc(RX_BUFFER_SIZE, GFP_KERNEL); |
| 385 | if (!buf) | 386 | if (!buf) |
| 386 | return -ENOMEM; | 387 | return -ENOMEM; |
| 387 | 388 | ||
| 388 | err = usb_bulk_msg(dev->udev, | 389 | do { |
| 389 | usb_rcvbulkpipe(dev->udev, | 390 | err = usb_bulk_msg(dev->udev, |
| 390 | dev->bulk_in->bEndpointAddress), | 391 | usb_rcvbulkpipe(dev->udev, |
| 391 | buf, RX_BUFFER_SIZE, &actual_len, | 392 | dev->bulk_in->bEndpointAddress), |
| 392 | USB_RECV_TIMEOUT); | 393 | buf, RX_BUFFER_SIZE, &actual_len, |
| 393 | if (err < 0) | 394 | USB_RECV_TIMEOUT); |
| 394 | goto end; | 395 | if (err < 0) |
| 396 | goto end; | ||
| 395 | 397 | ||
| 396 | while (pos <= actual_len - MSG_HEADER_LEN) { | 398 | pos = 0; |
| 397 | tmp = buf + pos; | 399 | while (pos <= actual_len - MSG_HEADER_LEN) { |
| 400 | tmp = buf + pos; | ||
| 398 | 401 | ||
| 399 | if (!tmp->len) | 402 | if (!tmp->len) |
| 400 | break; | 403 | break; |
| 401 | 404 | ||
| 402 | if (pos + tmp->len > actual_len) { | 405 | if (pos + tmp->len > actual_len) { |
| 403 | dev_err(dev->udev->dev.parent, "Format error\n"); | 406 | dev_err(dev->udev->dev.parent, |
| 404 | break; | 407 | "Format error\n"); |
| 405 | } | 408 | break; |
| 409 | } | ||
| 406 | 410 | ||
| 407 | if (tmp->id == id) { | 411 | if (tmp->id == id) { |
| 408 | memcpy(msg, tmp, tmp->len); | 412 | memcpy(msg, tmp, tmp->len); |
| 409 | goto end; | 413 | goto end; |
| 410 | } | 414 | } |
| 411 | 415 | ||
| 412 | pos += tmp->len; | 416 | pos += tmp->len; |
| 413 | } | 417 | } |
| 418 | } while (time_before(jiffies, to)); | ||
| 414 | 419 | ||
| 415 | err = -EINVAL; | 420 | err = -EINVAL; |
| 416 | 421 | ||
