Skip to contentSkip to conversation

usb_8dev: Add support for USB2CAN interface from 8 devices

PATCH In review Bernd Krumboeck 5 participants 9 messages Dec 4, 2012 – Dec 5, 2012 3 messages not in the archive CAN network drivers

lore
Share & tools
lore
#0 lore raw

PATCH v4 1/1 usb_8dev: Add support for USB2CAN interface from 8 devices

Add device driver for USB2CAN interface from "8 devices" (http://www.8devices.com).

---
 drivers/net/can/usb/Kconfig    |    6 +
 drivers/net/can/usb/Makefile   |    1 +
 drivers/net/can/usb/usb_8dev.c | 1089 ++++++++++++++++++++++++++++++++++++++++
 3 files changed, 1096 insertions(+)
 create mode 100644 drivers/net/can/usb/usb_8dev.c
drivers/net/can/usb/Kconfig +6 -0
index a4e4bee..2162233 100644
@@ -48,4 +48,10 @@ config CAN_PEAK_USB
 	  This driver supports the PCAN-USB and PCAN-USB Pro adapters
 	  from PEAK-System Technik (http://www.peak-system.com).
 
+config CAN_8DEV_USB
+	tristate "8 devices USB2CAN interface"
+	---help---
+	  This driver supports the USB2CAN interface
+	  from 8 devices (http://www.8devices.com).
+
 endmenu
drivers/net/can/usb/Makefile +1 -0
index 80a2ee4..becef46 100644
@@ -6,5 +6,6 @@ obj-$(CONFIG_CAN_EMS_USB) += ems_usb.o
 obj-$(CONFIG_CAN_ESD_USB2) += esd_usb2.o
 obj-$(CONFIG_CAN_KVASER_USB) += kvaser_usb.o
 obj-$(CONFIG_CAN_PEAK_USB) += peak_usb/
+obj-$(CONFIG_CAN_8DEV_USB) += usb_8dev.o
 
 ccflags-$(CONFIG_CAN_DEBUG_DEVICES) := -DDEBUG
drivers/net/can/usb/usb_8dev.c new file +1089 -0

1,089 lines not on this page · raw message

Signature · 1 line
1.7.10.4

A message that is not in the archive (sent off-list or not yet received): [email protected]

#2 lore raw
Quoted 4 lines · Bernd Krumboeck

Add device driver for USB2CAN interface from "8 devices"
(http://www.8devices.com).

Please use git send-email.

A changelog would be nice, in the form of:

changes since v4:
- done this, deleted that

If you post v5, changes since v4 are sufficient.

Quoted 48 lines
---
 drivers/net/can/usb/Kconfig    |    6 +
 drivers/net/can/usb/Makefile   |    1 +
 drivers/net/can/usb/usb_8dev.c | 1089
++++++++++++++++++++++++++++++++++++++++
 3 files changed, 1096 insertions(+)
 create mode 100644 drivers/net/can/usb/usb_8dev.c
drivers/net/can/usb/Kconfig +6 -0
index a4e4bee..2162233 100644
@@ -48,4 +48,10 @@ config CAN_PEAK_USB
       This driver supports the PCAN-USB and PCAN-USB Pro adapters
       from PEAK-System Technik (http://www.peak-system.com).
 
+config CAN_8DEV_USB
+    tristate "8 devices USB2CAN interface"
+    ---help---
+      This driver supports the USB2CAN interface
+      from 8 devices (http://www.8devices.com).
+
 endmenu
drivers/net/can/usb/Makefile +1 -0
index 80a2ee4..becef46 100644
@@ -6,5 +6,6 @@ obj-$(CONFIG_CAN_EMS_USB) += ems_usb.o
 obj-$(CONFIG_CAN_ESD_USB2) += esd_usb2.o
 obj-$(CONFIG_CAN_KVASER_USB) += kvaser_usb.o
 obj-$(CONFIG_CAN_PEAK_USB) += peak_usb/
+obj-$(CONFIG_CAN_8DEV_USB) += usb_8dev.o
 
 ccflags-$(CONFIG_CAN_DEBUG_DEVICES) := -DDEBUG
drivers/net/can/usb/usb_8dev.c new file +7 -0
new file mode 100644
index 0000000..b3a7eee
@@ -0,0 +1,1089 @@
+/*
+ * CAN driver for "8 devices" USB2CAN converter
+ *
+ * Copyright (C) 2012 Bernd Krumboeck ([email protected])
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published

drivers/net/can/usb/usb_8dev.c line 17

Quoted 10 lines
drivers/net/can/usb/usb_8dev.c new file +10 -0
+ * by the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.

you can remove the address here.

Quoted 9 lines
drivers/net/can/usb/usb_8dev.c new file +2 -0
+ *
+ * This driver is inspired by the 3.2.0 version of

drivers/net/can/usb/ems_usb.c
+ * and drivers/net/can/usb/esd_usb2.c
+ *
+ * Many thanks to Gerhard Bertelsmann ([email protected])
+ * for testing and fixing this driver. Also many thanks to "8 devices",
+ * who were very cooperative and answered my questions.
+ */

Marc

Signature · 4 lines
Pengutronix e.K.                  | Marc Kleine-Budde           |
Industrial Linux Solutions        | Phone: +49-231-2826-924     |
Vertretung West/Dortmund          | Fax:   +49-5121-206917-5555 |
Amtsgericht Hildesheim, HRA 2686  | http://www.pengutronix.de   |
#3 lore raw
Quoted 1 line · Marc Kleine-Budde

On 12/04/2012 11:43 PM, Bernd Krumboeck wrote:

                ^^^^^^^^

btw: your clock is wrong by about 1h :)

Marc

Signature · 4 lines
Pengutronix e.K.                  | Marc Kleine-Budde           |
Industrial Linux Solutions        | Phone: +49-231-2826-924     |
Vertretung West/Dortmund          | Fax:   +49-5121-206917-5555 |
Amtsgericht Hildesheim, HRA 2686  | http://www.pengutronix.de   |
#4 lore raw
Quoted 5 lines · Marc Kleine-Budde
Quoted 1 line · Bernd Krumboeck
                ^^^^^^^^

btw: your clock is wrong by about 1h :)

Corrected. I like UTC system clock, but Windows doesn't.

Bernd

#5 lore raw
In reply to a message not in the archive

Hi Bernd,

still a few issues with error handling.

Quoted 11 lines
drivers/net/can/usb/usb_8dev.c new file +11 -0
+/* Send open command to device */
+static int usb_8dev_cmd_open(struct usb_8dev *dev)
+{
+    struct can_bittiming *bt = &dev->can.bittiming;
+    struct usb_8dev_cmd_msg outmsg;
+    struct usb_8dev_cmd_msg inmsg;
+    u32 flags = 0;
+    u32 beflags;
+    u16 bebrp;
+    u32 ctrlmode = dev->can.ctrlmode;
+

drivers/net/can/usb/usb_8dev.c line 283

Quoted 10 lines
drivers/net/can/usb/usb_8dev.c new file +10 -0
+    if (ctrlmode & CAN_CTRLMODE_LOOPBACK)
+        flags |= USB_8DEV_LOOPBACK;
+    if (ctrlmode & CAN_CTRLMODE_LISTENONLY)
+        flags |= USB_8DEV_SILENT;
+    if (ctrlmode & CAN_CTRLMODE_ONE_SHOT)
+        flags |= USB_8DEV_DISABLE_AUTO_RESTRANS;
+
+    flags |= USB_8DEV_STATUS_FRAME;
+
+    memset(&outmsg, 0, sizeof(struct usb_8dev_cmd_msg));

sizeof(outmsg) is better, here and maybe in other places.

drivers/net/can/usb/usb_8dev.c line 286

Quoted 3 lines
drivers/net/can/usb/usb_8dev.c new file +3 -0
+    outmsg.command = USB_8DEV_OPEN;
+    outmsg.opt1 = USB_8DEV_BAUD_MANUAL;
+    outmsg.data[0] = (bt->prop_seg + bt->phase_seg1);

Minor issue. Brackets not needed.

Quoted 13 lines
drivers/net/can/usb/usb_8dev.c new file +13 -0
+    outmsg.data[1] = bt->phase_seg2;
+    outmsg.data[2] = bt->sjw;
+
+    /* BRP */
+    bebrp = cpu_to_be16((u16) bt->brp);
+    memcpy(&outmsg.data[3], &bebrp, sizeof(bebrp));
+
+    /* flags */
+    beflags = cpu_to_be32(flags);
+    memcpy(&outmsg.data[5], &beflags, sizeof(beflags));
+
+    return usb_8dev_send_cmd(dev, &outmsg, &inmsg);
+}

...

Quoted 48 lines
drivers/net/can/usb/usb_8dev.c new file +48 -0
+
+/* Read data and status frames */
+static void usb_8dev_rx_can_msg(struct usb_8dev *dev,
+                struct usb_8dev_rx_msg *msg)
+{
+    struct can_frame *cf;
+    struct sk_buff *skb;
+    struct net_device_stats *stats = &dev->netdev->stats;
+
+    if (msg->type == USB_8DEV_TYPE_CAN_FRAME) {
+        skb = alloc_can_skb(dev->netdev, &cf);
+        if (!skb)
+            return;
+
+        cf->can_id = be32_to_cpu(msg->id);
+        cf->can_dlc = get_can_dlc(msg->dlc & 0xF);
+
+        if (msg->flags & USB_8DEV_EXTID)
+            cf->can_id |= CAN_EFF_FLAG;
+
+        if (msg->flags & USB_8DEV_RTR)
+            cf->can_id |= CAN_RTR_FLAG;
+        else
+            memcpy(cf->data, msg->data, cf->can_dlc);
+    } else if (msg->type == USB_8DEV_TYPE_ERROR_FRAME &&
+           msg->flags == USB_8DEV_ERR_FLAG) {
+
+        /*
+         * Error message:
+         * byte 0: Status
+         * byte 1: bit   7: Receive Passive
+         * byte 1: bit 0-6: Receive Error Counter
+         * byte 2: Transmit Error Counter
+         * byte 3: Always 0 (maybe reserved for future use)
+         */
+
+        u8 state = msg->data[0];
+        u8 rxerr = msg->data[1] & USB_8DEV_RP_MASK;
+        u8 txerr = msg->data[2];
+        int rx_errors = 0;
+        int tx_errors = 0;
+
+        skb = alloc_can_err_skb(dev->netdev, &cf);
+        if (!skb)
+            return;
+
+        switch (state) {
+        case USB_8DEV_STATUSMSG_OK:

drivers/net/can/usb/usb_8dev.c line 467

Quoted 10 lines
drivers/net/can/usb/usb_8dev.c new file +10 -0
+            dev->can.state = CAN_STATE_ERROR_ACTIVE;
+            cf->can_id |= CAN_ERR_PROT;
+            cf->data[2] = CAN_ERR_PROT_ACTIVE;
+            break;
+        case USB_8DEV_STATUSMSG_BUSOFF:
+            dev->can.state = CAN_STATE_BUS_OFF;
+            cf->can_id |= CAN_ERR_BUSOFF;
+            can_bus_off(dev->netdev);
+            break;
+        case USB_8DEV_STATUSMSG_OVERRUN:

Overrun is not a bus-erroror state change. It should be treated separately. More below...

drivers/net/can/usb/usb_8dev.c line 470

Quoted 3 lines
drivers/net/can/usb/usb_8dev.c new file +3 -0
+        case USB_8DEV_STATUSMSG_BUSLIGHT:
+        case USB_8DEV_STATUSMSG_BUSHEAVY:
+            dev->can.state = CAN_STATE_ERROR_WARNING;

Please set the state below when you re-treat BUSLIGHT and BUSHEAVY.

drivers/net/can/usb/usb_8dev.c line 474

Quoted 4 lines
drivers/net/can/usb/usb_8dev.c new file +4 -0
+            cf->can_id |= CAN_ERR_CRTL;
+            break;
+        default:
+            dev->can.state = CAN_STATE_ERROR_WARNING;

Bus-errors do not necessarily change the state. Please remove.

Quoted 26 lines
drivers/net/can/usb/usb_8dev.c new file +26 -0
+            cf->can_id |= CAN_ERR_PROT | CAN_ERR_BUSERROR;
+            dev->can.can_stats.bus_error++;
+            break;
+        }
+
+        switch (state) {
+        case USB_8DEV_STATUSMSG_ACK:
+            cf->can_id |= CAN_ERR_ACK;
+            tx_errors = 1;
+            break;
+        case USB_8DEV_STATUSMSG_CRC:
+            cf->data[2] |= CAN_ERR_PROT_BIT;
+            rx_errors = 1;
+            break;
+        case USB_8DEV_STATUSMSG_BIT0:
+            cf->data[2] |= CAN_ERR_PROT_BIT0;
+            tx_errors = 1;
+            break;
+        case USB_8DEV_STATUSMSG_BIT1:
+            cf->data[2] |= CAN_ERR_PROT_BIT1;
+            tx_errors = 1;
+            break;
+        case USB_8DEV_STATUSMSG_FORM:
+            cf->data[2] |= CAN_ERR_PROT_FORM;
+            rx_errors = 1;
+            break;

drivers/net/can/usb/usb_8dev.c line 510

Quoted 10 lines
drivers/net/can/usb/usb_8dev.c new file +10 -0
+        case USB_8DEV_STATUSMSG_STUFF:
+            cf->data[2] |= CAN_ERR_PROT_STUFF;
+            rx_errors = 1;
+            break;
+        case USB_8DEV_STATUSMSG_OVERRUN:
+            cf->data[1] = (txerr > rxerr) ?
+                CAN_ERR_CRTL_TX_OVERFLOW :
+                CAN_ERR_CRTL_RX_OVERFLOW;
+            cf->data[2] |= CAN_ERR_PROT_OVERLOAD;
+            stats->rx_over_errors++;

The overrun normally means the a message could not be received because the hardware was busy (FIFO full). It does not depend on the tx/rxerrs and we only set CAN_ERR_CRTL_RX_OVERFLOW. As good example please check:

http://lxr.linux.no/#linux+v3.6.9/drivers/net/can/usb/ems_usb.c#L335

Review

Quoted 2 lines
(quoted diff) +2 -0
+            break;
+        case USB_8DEV_STATUSMSG_BUSLIGHT:
               dev->can.state = CAN_STATE_ERROR_WARNING;

drivers/net/can/usb/usb_8dev.c line 518

Quoted 6 lines
drivers/net/can/usb/usb_8dev.c new file +6 -0
+            cf->data[1] = (txerr > rxerr) ?
+                CAN_ERR_CRTL_TX_WARNING :
+                CAN_ERR_CRTL_RX_WARNING;
+            dev->can.can_stats.error_warning++;
+            break;
+        case USB_8DEV_STATUSMSG_BUSHEAVY:
               dev->can.state = CAN_STATE_ERROR_PASSIVE;
Quoted 22 lines
drivers/net/can/usb/usb_8dev.c new file +22 -0
+            cf->data[1] = (txerr > rxerr) ?
+                CAN_ERR_CRTL_TX_PASSIVE :
+                CAN_ERR_CRTL_RX_PASSIVE;
+            dev->can.can_stats.error_passive++;
+            break;
+        }
+
+        if (tx_errors) {
+            cf->data[2] |= CAN_ERR_PROT_TX;
+            stats->tx_errors++;
+        }
+
+        if (rx_errors)
+            stats->rx_errors++;
+
+        cf->data[6] = txerr;
+        cf->data[7] = rxerr;
+
+        dev->bec.txerr = txerr;
+        dev->bec.rxerr = rxerr;
+
+    } else {

drivers/net/can/usb/usb_8dev.c line 550

Quoted 10 lines
drivers/net/can/usb/usb_8dev.c new file +10 -0
+        netdev_warn(dev->netdev, "frame type %d unknown",
+             msg->type);
+        return;
+    }
+
+    netif_rx(skb);
+
+    stats->rx_packets++;
+    stats->rx_bytes += cf->can_dlc;
+}

Wolfgang.

--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html

#6 lore raw
Quoted 9 lines · Wolfgang Grandegger

drivers/net/can/usb/usb_8dev.c line 286

Quoted 3 lines
drivers/net/can/usb/usb_8dev.c new file +3 -0
+    outmsg.command = USB_8DEV_OPEN;
+    outmsg.opt1 = USB_8DEV_BAUD_MANUAL;
+    outmsg.data[0] = (bt->prop_seg + bt->phase_seg1);

Minor issue. Brackets not needed.

Quoted 3 lines
drivers/net/can/usb/usb_8dev.c new file +3 -0
+    outmsg.data[1] = bt->phase_seg2;
+    outmsg.data[2] = bt->sjw;
+

That's correct from a compilers point of view.
But in this case i would preserve the [0] as it is better to read in conjunction with the two lines below ( ..[1] ..[2] )

The semantic has to be understood by humans ;-)

Regards,
Oliver

A message that is not in the archive (sent off-list or not yet received): [email protected]

#8 lore raw
Quoted 12 lines · Oliver Hartkopp
Quoted 9 lines · Wolfgang Grandegger

drivers/net/can/usb/usb_8dev.c line 286

Quoted 3 lines
drivers/net/can/usb/usb_8dev.c new file +3 -0
+    outmsg.command = USB_8DEV_OPEN;
+    outmsg.opt1 = USB_8DEV_BAUD_MANUAL;
+    outmsg.data[0] = (bt->prop_seg + bt->phase_seg1);

Minor issue. Brackets not needed.

Quoted 3 lines
drivers/net/can/usb/usb_8dev.c new file +3 -0
+    outmsg.data[1] = bt->phase_seg2;
+    outmsg.data[2] = bt->sjw;
+
Quoted 5 lines

That's correct from a compilers point of view.
But in this case i would preserve the [0] as it is better to read in conjunction with the two lines below ( ..[1] ..[2] )

The semantic has to be understood by humans ;-)

I think Wolfgang was talking about the round bracket not the square bracket. :D

Marc

Signature · 4 lines
Pengutronix e.K.                  | Marc Kleine-Budde           |
Industrial Linux Solutions        | Phone: +49-231-2826-924     |
Vertretung West/Dortmund          | Fax:   +49-5121-206917-5555 |
Amtsgericht Hildesheim, HRA 2686  | http://www.pengutronix.de   |

A message that is not in the archive (sent off-list or not yet received): [email protected]

#10 lore raw
Quoted 13 lines · Marc Kleine-Budde
Quoted 12 lines · Oliver Hartkopp
Quoted 9 lines · Wolfgang Grandegger

Review

Quoted 3 lines
(quoted diff) +3 -0
+    outmsg.command = USB_8DEV_OPEN;
+    outmsg.opt1 = USB_8DEV_BAUD_MANUAL;
+    outmsg.data[0] = (bt->prop_seg + bt->phase_seg1);

Minor issue. Brackets not needed.

Quoted 3 lines
(quoted diff) +3 -0
+    outmsg.data[1] = bt->phase_seg2;
+    outmsg.data[2] = bt->sjw;
+
Quoted 8 lines
Quoted 5 lines

That's correct from a compilers point of view.
But in this case i would preserve the [0] as it is better to read in conjunction with the two lines below ( ..[1] ..[2] )

The semantic has to be understood by humans ;-)

I think Wolfgang was talking about the round bracket not the square bracket. :D

Yep. Sorry for confusion.

Wolfgang.

--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html

#11 lore raw
In reply to a message not in the archive
Quoted 2 lines · Bernd Krumboeck

Add device driver for USB2CAN interface from "8 devices"
(http://www.8devices.com).

[...]

drivers/net/can/usb/usb_8dev.c line 657

Quoted 5 lines
drivers/net/can/usb/usb_8dev.c new file +5 -0
+/* Send data to device */
+static netdev_tx_t usb_8dev_start_xmit(struct sk_buff *skb,
+                      struct net_device *netdev)
+{
+    struct usb_8dev *dev = netdev_priv(netdev);

I just noticed, it's unusual to name you private data pointer "dev", I suggest to name it priv. Maybe you can rename your private data struct
to: "struct usb_8dev_priv".

drivers/net/can/usb/usb_8dev.c line 662

Quoted 5 lines
drivers/net/can/usb/usb_8dev.c new file +5 -0
+    struct net_device_stats *stats = &netdev->stats;
+    struct can_frame *cf = (struct can_frame *) skb->data;
+    struct usb_8dev_tx_msg *msg;
+    struct urb *urb;
+    struct usb_8dev_tx_urb_context *context = NULL;

Marc

Signature · 4 lines
Pengutronix e.K.                  | Marc Kleine-Budde           |
Industrial Linux Solutions        | Phone: +49-231-2826-924     |
Vertretung West/Dortmund          | Fax:   +49-5121-206917-5555 |
Amtsgericht Hildesheim, HRA 2686  | http://www.pengutronix.de   |