Browse Source

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>
Olivier Sobrie 11 years ago
parent
commit
e59e36e733
1 changed files with 27 additions and 22 deletions
  1. 27 22
      drivers/net/can/usb/kvaser_usb.c

+ 27 - 22
drivers/net/can/usb/kvaser_usb.c

@@ -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;