can: kvaser_usb: add retries/timeout to kvaser_usb_wait_msg()
authorOlivier Sobrie <olivier@sobrie.be>
Thu, 10 Apr 2014 19:44:21 +0000 (21:44 +0200)
committerMarc Kleine-Budde <mkl@pengutronix.de>
Thu, 24 Apr 2014 20:54:16 +0000 (22:54 +0200)
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>
drivers/net/can/usb/kvaser_usb.c

index 4ca46edc061d761169a85fc58937dee449a4776f..7a1c5ec232688f8e263bc81ee9e070c63aa67816 100644 (file)
@@ -379,38 +379,43 @@ static int kvaser_usb_wait_msg(const struct kvaser_usb *dev, u8 id,
        void *buf;
        int actual_len;
        int err;
-       int pos = 0;
+       int pos;
+       unsigned long to = jiffies + msecs_to_jiffies(USB_RECV_TIMEOUT);
 
        buf = kzalloc(RX_BUFFER_SIZE, GFP_KERNEL);
        if (!buf)
                return -ENOMEM;
 
-       err = usb_bulk_msg(dev->udev,
-                          usb_rcvbulkpipe(dev->udev,
-                                          dev->bulk_in->bEndpointAddress),
-                          buf, RX_BUFFER_SIZE, &actual_len,
-                          USB_RECV_TIMEOUT);
-       if (err < 0)
-               goto end;
+       do {
+               err = usb_bulk_msg(dev->udev,
+                                  usb_rcvbulkpipe(dev->udev,
+                                       dev->bulk_in->bEndpointAddress),
+                                  buf, RX_BUFFER_SIZE, &actual_len,
+                                  USB_RECV_TIMEOUT);
+               if (err < 0)
+                       goto end;
 
-       while (pos <= actual_len - MSG_HEADER_LEN) {
-               tmp = buf + pos;
+               pos = 0;
+               while (pos <= actual_len - MSG_HEADER_LEN) {
+                       tmp = buf + pos;
 
-               if (!tmp->len)
-                       break;
+                       if (!tmp->len)
+                               break;
 
-               if (pos + tmp->len > actual_len) {
-                       dev_err(dev->udev->dev.parent, "Format error\n");
-                       break;
-               }
+                       if (pos + tmp->len > actual_len) {
+                               dev_err(dev->udev->dev.parent,
+                                       "Format error\n");
+                               break;
+                       }
 
-               if (tmp->id == id) {
-                       memcpy(msg, tmp, tmp->len);
-                       goto end;
-               }
+                       if (tmp->id == id) {
+                               memcpy(msg, tmp, tmp->len);
+                               goto end;
+                       }
 
-               pos += tmp->len;
-       }
+                       pos += tmp->len;
+               }
+       } while (time_before(jiffies, to));
 
        err = -EINVAL;