lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Date:   Mon, 20 Jun 2022 22:26:03 +0200
From:   Frank Jungclaus <frank.jungclaus@....eu>
To:     linux-can@...r.kernel.org, Marc Kleine-Budde <mkl@...gutronix.de>,
        Wolfgang Grandegger <wg@...ndegger.com>,
        Vincent Mailhol <mailhol.vincent@...adoo.fr>
Cc:     Stefan Mätje <stefan.maetje@....eu>,
        netdev@...r.kernel.org, linux-kernel@...r.kernel.org,
        Frank Jungclaus <frank.jungclaus@....eu>
Subject: [PATCH 1/1] can/esd_usb2: Added support for esd CAN-USB/3

This patch adds support for the newly available esd CAN-USB/3.
---
 drivers/net/can/usb/esd_usb2.c | 647 ++++++++++++++++++++++++---------
 1 file changed, 467 insertions(+), 180 deletions(-)

diff --git a/drivers/net/can/usb/esd_usb2.c b/drivers/net/can/usb/esd_usb2.c
index 286daaaea0b8..062f3dd922d2 100644
--- a/drivers/net/can/usb/esd_usb2.c
+++ b/drivers/net/can/usb/esd_usb2.c
@@ -1,9 +1,11 @@
 // SPDX-License-Identifier: GPL-2.0-only
 /*
- * CAN driver for esd CAN-USB/2 and CAN-USB/Micro
+ * CAN driver for esd CAN-USB/2, CAN-USB/3 and CAN-USB/Micro
  *
- * Copyright (C) 2010-2012 Matthias Fuchs <matthias.fuchs@....eu>, esd gmbh
+ * Copyright (C) 2010-     Matthias Fuchs                          , esd gmbh
+ * Copyright (C) 2022-     Frank Jungclaus <frank.jungclaus@....eu>, esd gmbh
  */
+
 #include <linux/signal.h>
 #include <linux/slab.h>
 #include <linux/module.h>
@@ -14,20 +16,25 @@
 #include <linux/can/dev.h>
 #include <linux/can/error.h>
 
-MODULE_AUTHOR("Matthias Fuchs <matthias.fuchs@....eu>");
-MODULE_DESCRIPTION("CAN driver for esd CAN-USB/2 and CAN-USB/Micro interfaces");
+MODULE_AUTHOR("Frank Jungclaus <frank.jungclaus@....eu>");
+MODULE_DESCRIPTION("CAN driver for esd CAN-USB/2, CAN-USB/3 and CAN-USB/Micro interfaces");
 MODULE_LICENSE("GPL v2");
 
-/* Define these values to match your devices */
+/* USB vendor and product ID */
 #define USB_ESDGMBH_VENDOR_ID	0x0ab4
 #define USB_CANUSB2_PRODUCT_ID	0x0010
 #define USB_CANUSBM_PRODUCT_ID	0x0011
+#define USB_CANUSB3_PRODUCT_ID	0x0014
 
+/* CAN controller clock frequencies */
 #define ESD_USB2_CAN_CLOCK	60000000
 #define ESD_USBM_CAN_CLOCK	36000000
-#define ESD_USB2_MAX_NETS	2
+#define ESD_USB3_CAN_CLOCK	80000000
+
+/* Maximum number of CAN nets */
+#define ESD_USB_MAX_NETS	2
 
-/* USB2 commands */
+/* USB commands */
 #define CMD_VERSION		1 /* also used for VERSION_REPLY */
 #define CMD_CAN_RX		2 /* device to host only */
 #define CMD_CAN_TX		3 /* also used for TX_DONE */
@@ -36,20 +43,29 @@ MODULE_LICENSE("GPL v2");
 #define CMD_IDADD		6 /* also used for IDADD_REPLY */
 
 /* esd CAN message flags - dlc field */
-#define ESD_RTR			0x10
+#define ESD_DLC_RTR		0x10
+#define ESD_DLC_NO_BRS		0x10
+#define ESD_DLC_ESI		0x20
+#define ESD_DLC_FD		0x80
+
 
 /* esd CAN message flags - id field */
 #define ESD_EXTID		0x20000000
 #define ESD_EVENT		0x40000000
 #define ESD_IDMASK		0x1fffffff
 
-/* esd CAN event ids used by this driver */
-#define ESD_EV_CAN_ERROR_EXT	2
+/* esd CAN event ids */
+#define ESD_EV_CAN_ERROR	0 /* General bus diagnostics data */
+#define ESD_EV_BAUD_CHANGE	1 /* Bit rate change event (unused within this driver) */
+#define ESD_EV_CAN_ERROR_EXT	2 /* CAN controller specific diagnostic data */
+#define ESD_EV_BUSLOAD		3 /* Busload event (unused within this driver) */
 
-/* baudrate message flags */
+/* Baudrate message flags */
 #define ESD_USB2_UBR		0x80000000
 #define ESD_USB2_LOM		0x40000000
 #define ESD_USB2_NO_BAUDRATE	0x7fffffff
+
+/* Bit timing CAN-USB/2 */
 #define ESD_USB2_TSEG1_MIN	1
 #define ESD_USB2_TSEG1_MAX	16
 #define ESD_USB2_TSEG1_SHIFT	16
@@ -64,6 +80,28 @@ MODULE_LICENSE("GPL v2");
 #define ESD_USB2_BRP_INC	1
 #define ESD_USB2_3_SAMPLES	0x00800000
 
+/* Bit timing CAN-USB/3 */
+#define ESD_USB3_TSEG1_MIN	1
+#define ESD_USB3_TSEG1_MAX	256
+#define ESD_USB3_TSEG2_MIN	1
+#define ESD_USB3_TSEG2_MAX	128
+#define ESD_USB3_SJW_MAX	128
+#define ESD_USB3_BRP_MIN	1
+#define ESD_USB3_BRP_MAX	1024
+#define ESD_USB3_BRP_INC	1
+/* Bit timing CAN-USB/3, data phase */
+#define ESD_USB3_DATA_TSEG1_MIN	1
+#define ESD_USB3_DATA_TSEG1_MAX	32
+#define ESD_USB3_DATA_TSEG2_MIN	1
+#define ESD_USB3_DATA_TSEG2_MAX	16
+#define ESD_USB3_DATA_SJW_MAX	8
+#define ESD_USB3_DATA_BRP_MIN	1
+#define ESD_USB3_DATA_BRP_MAX	32
+#define ESD_USB3_DATA_BRP_INC	1
+
+/* Transmitter Delay Compensation */
+#define ESD_TDC_MODE_AUTO       0
+
 /* esd IDADD message */
 #define ESD_ID_ENABLE		0x80
 #define ESD_MAX_ID_SEGMENT	64
@@ -78,15 +116,31 @@ MODULE_LICENSE("GPL v2");
 #define SJA1000_ECC_MASK	0xc0
 
 /* esd bus state event codes */
-#define ESD_BUSSTATE_MASK	0xc0
+#define ESD_BUSSTATE_OK         0x00
 #define ESD_BUSSTATE_WARN	0x40
 #define ESD_BUSSTATE_ERRPASSIVE	0x80
 #define ESD_BUSSTATE_BUSOFF	0xc0
+#define ESD_BUSSTATE_MASK	0xc0
 
 #define RX_BUFFER_SIZE		1024
 #define MAX_RX_URBS		4
 #define MAX_TX_URBS		16 /* must be power of 2 */
 
+/* Modes for NTCAN_BAUDRATE_X */
+#define ESD_BAUDRATE_MODE_DISABLE          0      /* Remove from bus        */
+#define ESD_BAUDRATE_MODE_INDEX            1      /* ESD (CiA) bit rate idx */
+#define ESD_BAUDRATE_MODE_BTR_CTRL         2      /* BTR values (Controller)*/
+#define ESD_BAUDRATE_MODE_BTR_CANONICAL    3      /* BTR values (Canonical) */
+#define ESD_BAUDRATE_MODE_NUM              4      /* Numerical bit rate     */
+#define ESD_BAUDRATE_MODE_AUTOBAUD         5      /* Autobaud               */
+
+/* Flags for NTCAN_BAUDRATE_X */
+#define ESD_BAUDRATE_FLAG_FD     0x0001        /* Enable CAN FD Mode        */
+#define ESD_BAUDRATE_FLAG_LOM    0x0002        /* Enable Listen Only mode   */
+#define ESD_BAUDRATE_FLAG_STM    0x0004        /* Enable Self test mode     */
+#define ESD_BAUDRATE_FLAG_TRS    0x0008        /* Enable Triple Sampling    */
+#define ESD_BAUDRATE_FLAG_TXP    0x0010        /* Enable Transmit Pause     */
+
 struct header_msg {
 	u8 len; /* len is always the total message length in 32bit words */
 	u8 cmd;
@@ -119,7 +173,10 @@ struct rx_msg {
 	u8 dlc;
 	__le32 ts;
 	__le32 id; /* upper 3 bits contain flags */
-	u8 data[8];
+	union {
+		u8 cc[8];  /* classic CAN */
+		u8 fd[64]; /* CAN FD */
+	} data;
 };
 
 struct tx_msg {
@@ -127,9 +184,12 @@ struct tx_msg {
 	u8 cmd;
 	u8 net;
 	u8 dlc;
-	u32 hnd;	/* opaque handle, not used by device */
+	u32 hnd;   /* opaque handle, not used by device */
 	__le32 id; /* upper 3 bits contain flags */
-	u8 data[8];
+	union {
+		u8 cc[8];  /* classic CAN */
+		u8 fd[64]; /* CAN FD */
+	} data;
 };
 
 struct tx_done_msg {
@@ -149,16 +209,41 @@ struct id_filter_msg {
 	__le32 mask[ESD_MAX_ID_SEGMENT + 1];
 };
 
+struct baudrate_x_cfg {
+	__le16 brp;          /* Bit rate pre-scaler                   */
+	__le16 tseg1;        /* TSEG1 register                        */
+	__le16 tseg2;        /* TSEG2 register                        */
+	__le16 sjw;          /* SJW register                          */
+};
+
+struct tdc_cfg {
+	u8 tdc_mode;    /* Transmitter Delay Compensation mode  */
+	u8 ssp_offset;  /* Secondary Sample Point offset in mtq */
+	s8 ssp_shift;   /* Secondary Sample Point shift in mtq  */
+	u8 tdc_filter;  /* Transmitter Delay Compensation       */
+};
+
+struct baudrate_x {
+	__le16 mode;        /* Mode word                          */
+	__le16 flags;       /* Control flags                      */
+	struct tdc_cfg tdc; /* TDC configuration                  */
+	struct baudrate_x_cfg arb;  /* Bit rate during arbitration phase  */
+	struct baudrate_x_cfg data; /* Bit rate during data phase         */
+};
+
 struct set_baudrate_msg {
 	u8 len;
 	u8 cmd;
 	u8 net;
 	u8 rsvd;
-	__le32 baud;
+	union {
+		__le32 baud;
+		struct baudrate_x baud_x;
+	} u;
 };
 
 /* Main message type used between library and application */
-struct __attribute__ ((packed)) esd_usb2_msg {
+struct __packed esd_usb_msg {
 	union {
 		struct header_msg hdr;
 		struct version_msg version;
@@ -171,23 +256,24 @@ struct __attribute__ ((packed)) esd_usb2_msg {
 	} msg;
 };
 
-static struct usb_device_id esd_usb2_table[] = {
+static struct usb_device_id esd_usb_table[] = {
 	{USB_DEVICE(USB_ESDGMBH_VENDOR_ID, USB_CANUSB2_PRODUCT_ID)},
 	{USB_DEVICE(USB_ESDGMBH_VENDOR_ID, USB_CANUSBM_PRODUCT_ID)},
+	{USB_DEVICE(USB_ESDGMBH_VENDOR_ID, USB_CANUSB3_PRODUCT_ID)},
 	{}
 };
-MODULE_DEVICE_TABLE(usb, esd_usb2_table);
+MODULE_DEVICE_TABLE(usb, esd_usb_table);
 
-struct esd_usb2_net_priv;
+struct esd_usb_net_priv;
 
 struct esd_tx_urb_context {
-	struct esd_usb2_net_priv *priv;
+	struct esd_usb_net_priv *priv;
 	u32 echo_index;
 };
 
-struct esd_usb2 {
+struct esd_usb {
 	struct usb_device *udev;
-	struct esd_usb2_net_priv *nets[ESD_USB2_MAX_NETS];
+	struct esd_usb_net_priv *nets[ESD_USB_MAX_NETS];
 
 	struct usb_anchor rx_submitted;
 
@@ -198,36 +284,64 @@ struct esd_usb2 {
 	dma_addr_t rxbuf_dma[MAX_RX_URBS];
 };
 
-struct esd_usb2_net_priv {
+struct esd_usb_net_priv {
 	struct can_priv can; /* must be the first member */
 
 	atomic_t active_tx_jobs;
 	struct usb_anchor tx_submitted;
 	struct esd_tx_urb_context tx_contexts[MAX_TX_URBS];
 
-	struct esd_usb2 *usb2;
+	struct esd_usb *usb;
 	struct net_device *netdev;
 	int index;
 	u8 old_state;
 	struct can_berr_counter bec;
 };
 
-static void esd_usb2_rx_event(struct esd_usb2_net_priv *priv,
-			      struct esd_usb2_msg *msg)
+static void esd_usb_rx_event(struct esd_usb_net_priv *priv, struct esd_usb_msg *msg)
 {
 	struct net_device_stats *stats = &priv->netdev->stats;
 	struct can_frame *cf;
 	struct sk_buff *skb;
 	u32 id = le32_to_cpu(msg->msg.rx.id) & ESD_IDMASK;
 
+#if defined(DEBUG)
+	{
+		static struct esd_usb_msg old_msg;
+		static u32 rx_event_cnt;
+
+		msg->msg.rx.ts = 0;
+		if (memcmp(msg, &old_msg, 16)) {
+			netdev_info(priv->netdev,
+				    "EVENT:%08d: id=%#02x dlc=%#02x %02x %02x %02x %02x - %02x %02x %02x %02x\n",
+				    rx_event_cnt,
+				    id,
+				    msg->msg.rx.dlc,
+				    msg->msg.rx.data.cc[0],
+				    msg->msg.rx.data.cc[1],
+				    msg->msg.rx.data.cc[2],
+				    msg->msg.rx.data.cc[3],
+				    msg->msg.rx.data.cc[4],
+				    msg->msg.rx.data.cc[5],
+				    msg->msg.rx.data.cc[6],
+				    msg->msg.rx.data.cc[7]);
+			memcpy(&old_msg, msg, 16);
+		}
+		rx_event_cnt++;
+	}
+#endif /* DEBUG */
+
 	if (id == ESD_EV_CAN_ERROR_EXT) {
-		u8 state = msg->msg.rx.data[0];
-		u8 ecc = msg->msg.rx.data[1];
-		u8 rxerr = msg->msg.rx.data[2];
-		u8 txerr = msg->msg.rx.data[3];
+		/* Here, for ESD_EV_CAN_ERROR_EXT we don't need
+		 * any special treatment for EVMSG_X
+		 */
+		u8 state = msg->msg.rx.data.cc[0];
+		u8 ecc	 = msg->msg.rx.data.cc[1];
+		u8 rxerr = msg->msg.rx.data.cc[2];
+		u8 txerr = msg->msg.rx.data.cc[3];
 
 		skb = alloc_can_err_skb(priv->netdev, &cf);
-		if (skb == NULL) {
+		if (!skb) {
 			stats->rx_dropped++;
 			return;
 		}
@@ -280,7 +394,7 @@ static void esd_usb2_rx_event(struct esd_usb2_net_priv *priv,
 				cf->data[2] |= CAN_ERR_PROT_TX;
 
 			if (priv->can.state == CAN_STATE_ERROR_WARNING ||
-			    priv->can.state == CAN_STATE_ERROR_PASSIVE) {
+				priv->can.state == CAN_STATE_ERROR_PASSIVE) {
 				cf->data[1] = (txerr > rxerr) ?
 					CAN_ERR_CRTL_TX_PASSIVE :
 					CAN_ERR_CRTL_RX_PASSIVE;
@@ -293,16 +407,40 @@ static void esd_usb2_rx_event(struct esd_usb2_net_priv *priv,
 		priv->bec.rxerr = rxerr;
 
 		netif_rx(skb);
+
+	} else if (id == ESD_EV_CAN_ERROR) {
+		u8 state = msg->msg.rx.data.cc[1];
+
+		/* Switching back to Error Warn and back to Error Passive
+		 * only is announced by means of a non-extended Error Event ...
+		 */
+		switch (state & ESD_BUSSTATE_MASK) {
+		case ESD_BUSSTATE_OK:
+			priv->old_state = state;
+			priv->can.state = CAN_STATE_ERROR_ACTIVE;
+			priv->bec.txerr = 0;
+			priv->bec.rxerr = 0;
+			break;
+		case ESD_BUSSTATE_WARN:
+			/* ... intentionally, don't set priv->old_state here! */
+			priv->can.state = CAN_STATE_ERROR_WARNING;
+			break;
+		default:
+			/* Do nothing ... */
+			break;
+		}
 	}
 }
 
-static void esd_usb2_rx_can_msg(struct esd_usb2_net_priv *priv,
-				struct esd_usb2_msg *msg)
+static void esd_usb_rx_can_msg(struct esd_usb_net_priv *priv, struct esd_usb_msg *msg)
 {
 	struct net_device_stats *stats = &priv->netdev->stats;
-	struct can_frame *cf;
+	/* can.h:
+	 *	  ... the struct can_frame and struct canfd_frame intentionally
+	 *	      share the same layout ...
+	 */
+	struct canfd_frame *cfd;
 	struct sk_buff *skb;
-	int i;
 	u32 id;
 
 	if (!netif_device_present(priv->netdev))
@@ -311,39 +449,63 @@ static void esd_usb2_rx_can_msg(struct esd_usb2_net_priv *priv,
 	id = le32_to_cpu(msg->msg.rx.id);
 
 	if (id & ESD_EVENT) {
-		esd_usb2_rx_event(priv, msg);
+		esd_usb_rx_event(priv, msg);
 	} else {
-		skb = alloc_can_skb(priv->netdev, &cf);
-		if (skb == NULL) {
-			stats->rx_dropped++;
-			return;
-		}
 
-		cf->can_id = id & ESD_IDMASK;
-		can_frame_set_cc_len(cf, msg->msg.rx.dlc & ~ESD_RTR,
-				     priv->can.ctrlmode);
+		if (msg->msg.rx.dlc & ESD_DLC_FD) {
+			/* CAN FD */
+			skb = alloc_canfd_skb(priv->netdev, &cfd);
+			if (!skb) {
+				stats->rx_dropped++;
+				return;
+			}
 
-		if (id & ESD_EXTID)
-			cf->can_id |= CAN_EFF_FLAG;
+			/* Masking by 0x0F is already done within can_fd_dlc2len()! */
+			cfd->len = can_fd_dlc2len(msg->msg.rx.dlc);
+
+			if ((msg->msg.rx.dlc & ESD_DLC_NO_BRS) == 0)
+				cfd->flags |= CANFD_BRS;
+
+			if (msg->msg.rx.dlc & ESD_DLC_ESI)
+				cfd->flags |= CANFD_ESI;
 
-		if (msg->msg.rx.dlc & ESD_RTR) {
-			cf->can_id |= CAN_RTR_FLAG;
+			memcpy(cfd->data, msg->msg.rx.data.fd, cfd->len);
+			stats->rx_bytes += cfd->len;
 		} else {
-			for (i = 0; i < cf->len; i++)
-				cf->data[i] = msg->msg.rx.data[i];
+			/* Classic CAN */
+			skb = alloc_can_skb(priv->netdev, (struct can_frame **)&cfd);
+			if (!skb) {
+				stats->rx_dropped++;
+				return;
+			}
 
-			stats->rx_bytes += cf->len;
+			can_frame_set_cc_len((struct can_frame *)cfd,
+					     msg->msg.rx.dlc & 0x0F,
+					     priv->can.ctrlmode);
+
+			if (msg->msg.rx.dlc & ESD_DLC_RTR) {
+				/* No data copy for a RTR frame */
+				cfd->can_id |= CAN_RTR_FLAG; // ok, due to memset(0)
+							     // in alloc_can_skb()
+			} else {
+				memcpy(cfd->data, msg->msg.rx.data.cc, cfd->len);
+				stats->rx_bytes += cfd->len;
+			}
 		}
-		stats->rx_packets++;
 
+		/* Common part for CAN FD and CAN classic ... */
+		cfd->can_id |= id & ESD_IDMASK;
+
+		if (id & ESD_EXTID)
+			cfd->can_id |= CAN_EFF_FLAG;
+
+		stats->rx_packets++;
 		netif_rx(skb);
 	}
 
-	return;
 }
 
-static void esd_usb2_tx_done_msg(struct esd_usb2_net_priv *priv,
-				 struct esd_usb2_msg *msg)
+static void esd_usb_tx_done_msg(struct esd_usb_net_priv *priv, struct esd_usb_msg *msg)
 {
 	struct net_device_stats *stats = &priv->netdev->stats;
 	struct net_device *netdev = priv->netdev;
@@ -356,8 +518,7 @@ static void esd_usb2_tx_done_msg(struct esd_usb2_net_priv *priv,
 
 	if (!msg->msg.txdone.status) {
 		stats->tx_packets++;
-		stats->tx_bytes += can_get_echo_skb(netdev, context->echo_index,
-						    NULL);
+		stats->tx_bytes += can_get_echo_skb(netdev, context->echo_index, NULL);
 	} else {
 		stats->tx_errors++;
 		can_free_echo_skb(netdev, context->echo_index, NULL);
@@ -370,9 +531,9 @@ static void esd_usb2_tx_done_msg(struct esd_usb2_net_priv *priv,
 	netif_wake_queue(netdev);
 }
 
-static void esd_usb2_read_bulk_callback(struct urb *urb)
+static void esd_usb_read_bulk_callback(struct urb *urb)
 {
-	struct esd_usb2 *dev = urb->context;
+	struct esd_usb *dev = urb->context;
 	int retval;
 	int pos = 0;
 	int i;
@@ -394,9 +555,9 @@ static void esd_usb2_read_bulk_callback(struct urb *urb)
 	}
 
 	while (pos < urb->actual_length) {
-		struct esd_usb2_msg *msg;
+		struct esd_usb_msg *msg;
 
-		msg = (struct esd_usb2_msg *)(urb->transfer_buffer + pos);
+		msg = (struct esd_usb_msg *)(urb->transfer_buffer + pos);
 
 		switch (msg->msg.hdr.cmd) {
 		case CMD_CAN_RX:
@@ -405,7 +566,7 @@ static void esd_usb2_read_bulk_callback(struct urb *urb)
 				break;
 			}
 
-			esd_usb2_rx_can_msg(dev->nets[msg->msg.rx.net], msg);
+			esd_usb_rx_can_msg(dev->nets[msg->msg.rx.net], msg);
 			break;
 
 		case CMD_CAN_TX:
@@ -414,8 +575,7 @@ static void esd_usb2_read_bulk_callback(struct urb *urb)
 				break;
 			}
 
-			esd_usb2_tx_done_msg(dev->nets[msg->msg.txdone.net],
-					     msg);
+			esd_usb_tx_done_msg(dev->nets[msg->msg.txdone.net], msg);
 			break;
 		}
 
@@ -429,8 +589,8 @@ static void esd_usb2_read_bulk_callback(struct urb *urb)
 
 resubmit_urb:
 	usb_fill_bulk_urb(urb, dev->udev, usb_rcvbulkpipe(dev->udev, 1),
-			  urb->transfer_buffer, RX_BUFFER_SIZE,
-			  esd_usb2_read_bulk_callback, dev);
+			urb->transfer_buffer, RX_BUFFER_SIZE,
+			esd_usb_read_bulk_callback, dev);
 
 	retval = usb_submit_urb(urb, GFP_ATOMIC);
 	if (retval == -ENODEV) {
@@ -443,18 +603,17 @@ static void esd_usb2_read_bulk_callback(struct urb *urb)
 			"failed resubmitting read bulk urb: %d\n", retval);
 	}
 
-	return;
 }
 
 /*
  * callback for bulk IN urb
  */
-static void esd_usb2_write_bulk_callback(struct urb *urb)
+static void esd_usb_write_bulk_callback(struct urb *urb)
 {
 	struct esd_tx_urb_context *context = urb->context;
-	struct esd_usb2_net_priv *priv;
+	struct esd_usb_net_priv *priv;
 	struct net_device *netdev;
-	size_t size = sizeof(struct esd_usb2_msg);
+	size_t size = sizeof(struct esd_usb_msg);
 
 	WARN_ON(!context);
 
@@ -478,7 +637,7 @@ static ssize_t firmware_show(struct device *d,
 			     struct device_attribute *attr, char *buf)
 {
 	struct usb_interface *intf = to_usb_interface(d);
-	struct esd_usb2 *dev = usb_get_intfdata(intf);
+	struct esd_usb *dev = usb_get_intfdata(intf);
 
 	return sprintf(buf, "%d.%d.%d\n",
 		       (dev->version >> 12) & 0xf,
@@ -491,7 +650,7 @@ static ssize_t hardware_show(struct device *d,
 			     struct device_attribute *attr, char *buf)
 {
 	struct usb_interface *intf = to_usb_interface(d);
-	struct esd_usb2 *dev = usb_get_intfdata(intf);
+	struct esd_usb *dev = usb_get_intfdata(intf);
 
 	return sprintf(buf, "%d.%d.%d\n",
 		       (dev->version >> 28) & 0xf,
@@ -504,13 +663,13 @@ static ssize_t nets_show(struct device *d,
 			 struct device_attribute *attr, char *buf)
 {
 	struct usb_interface *intf = to_usb_interface(d);
-	struct esd_usb2 *dev = usb_get_intfdata(intf);
+	struct esd_usb *dev = usb_get_intfdata(intf);
 
 	return sprintf(buf, "%d", dev->net_count);
 }
 static DEVICE_ATTR_RO(nets);
 
-static int esd_usb2_send_msg(struct esd_usb2 *dev, struct esd_usb2_msg *msg)
+static int esd_usb_send_msg(struct esd_usb *dev, struct esd_usb_msg *msg)
 {
 	int actual_length;
 
@@ -522,8 +681,7 @@ static int esd_usb2_send_msg(struct esd_usb2 *dev, struct esd_usb2_msg *msg)
 			    1000);
 }
 
-static int esd_usb2_wait_msg(struct esd_usb2 *dev,
-			     struct esd_usb2_msg *msg)
+static int esd_usb_wait_msg(struct esd_usb *dev, struct esd_usb_msg *msg)
 {
 	int actual_length;
 
@@ -535,7 +693,7 @@ static int esd_usb2_wait_msg(struct esd_usb2 *dev,
 			    1000);
 }
 
-static int esd_usb2_setup_rx_urbs(struct esd_usb2 *dev)
+static int esd_usb_setup_rx_urbs(struct esd_usb *dev)
 {
 	int i, err = 0;
 
@@ -554,8 +712,7 @@ static int esd_usb2_setup_rx_urbs(struct esd_usb2 *dev)
 			break;
 		}
 
-		buf = usb_alloc_coherent(dev->udev, RX_BUFFER_SIZE, GFP_KERNEL,
-					 &buf_dma);
+		buf = usb_alloc_coherent(dev->udev, RX_BUFFER_SIZE, GFP_KERNEL, &buf_dma);
 		if (!buf) {
 			dev_warn(dev->udev->dev.parent,
 				 "No memory left for USB buffer\n");
@@ -568,15 +725,14 @@ static int esd_usb2_setup_rx_urbs(struct esd_usb2 *dev)
 		usb_fill_bulk_urb(urb, dev->udev,
 				  usb_rcvbulkpipe(dev->udev, 1),
 				  buf, RX_BUFFER_SIZE,
-				  esd_usb2_read_bulk_callback, dev);
+				  esd_usb_read_bulk_callback, dev);
 		urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
 		usb_anchor_urb(urb, &dev->rx_submitted);
 
 		err = usb_submit_urb(urb, GFP_KERNEL);
 		if (err) {
 			usb_unanchor_urb(urb);
-			usb_free_coherent(dev->udev, RX_BUFFER_SIZE, buf,
-					  urb->transfer_dma);
+			usb_free_coherent(dev->udev, RX_BUFFER_SIZE, buf, urb->transfer_dma);
 			goto freeurb;
 		}
 
@@ -609,11 +765,11 @@ static int esd_usb2_setup_rx_urbs(struct esd_usb2 *dev)
 /*
  * Start interface
  */
-static int esd_usb2_start(struct esd_usb2_net_priv *priv)
+static int esd_usb_start(struct esd_usb_net_priv *priv)
 {
-	struct esd_usb2 *dev = priv->usb2;
+	struct esd_usb *dev = priv->usb;
 	struct net_device *netdev = priv->netdev;
-	struct esd_usb2_msg *msg;
+	struct esd_usb_msg *msg;
 	int err, i;
 
 	msg = kmalloc(sizeof(*msg), GFP_KERNEL);
@@ -624,7 +780,7 @@ static int esd_usb2_start(struct esd_usb2_net_priv *priv)
 
 	/*
 	 * Enable all IDs
-	 * The IDADD message takes up to 64 32 bit bitmasks (2048 bits).
+	 * The IDADD message takes up to 64 32-bit bitmasks (2048 bits).
 	 * Each bit represents one 11 bit CAN identifier. A set bit
 	 * enables reception of the corresponding CAN identifier. A cleared
 	 * bit disabled this identifier. An additional bitmask value
@@ -641,14 +797,15 @@ static int esd_usb2_start(struct esd_usb2_net_priv *priv)
 	msg->msg.filter.option = ESD_ID_ENABLE; /* start with segment 0 */
 	for (i = 0; i < ESD_MAX_ID_SEGMENT; i++)
 		msg->msg.filter.mask[i] = cpu_to_le32(0xffffffff);
+
 	/* enable 29bit extended IDs */
 	msg->msg.filter.mask[ESD_MAX_ID_SEGMENT] = cpu_to_le32(0x00000001);
 
-	err = esd_usb2_send_msg(dev, msg);
+	err = esd_usb_send_msg(dev, msg);
 	if (err)
 		goto out;
 
-	err = esd_usb2_setup_rx_urbs(dev);
+	err = esd_usb_setup_rx_urbs(dev);
 	if (err)
 		goto out;
 
@@ -664,16 +821,16 @@ static int esd_usb2_start(struct esd_usb2_net_priv *priv)
 	return err;
 }
 
-static void unlink_all_urbs(struct esd_usb2 *dev)
+static void unlink_all_urbs(struct esd_usb *dev)
 {
-	struct esd_usb2_net_priv *priv;
+	struct esd_usb_net_priv *priv;
 	int i, j;
 
 	usb_kill_anchored_urbs(&dev->rx_submitted);
 
 	for (i = 0; i < MAX_RX_URBS; ++i)
-		usb_free_coherent(dev->udev, RX_BUFFER_SIZE,
-				  dev->rxbuf[i], dev->rxbuf_dma[i]);
+		usb_free_coherent(dev->udev, RX_BUFFER_SIZE, dev->rxbuf[i], dev->rxbuf_dma[i]);
+
 
 	for (i = 0; i < dev->net_count; i++) {
 		priv = dev->nets[i];
@@ -687,9 +844,9 @@ static void unlink_all_urbs(struct esd_usb2 *dev)
 	}
 }
 
-static int esd_usb2_open(struct net_device *netdev)
+static int esd_usb_open(struct net_device *netdev)
 {
-	struct esd_usb2_net_priv *priv = netdev_priv(netdev);
+	struct esd_usb_net_priv *priv = netdev_priv(netdev);
 	int err;
 
 	/* common open */
@@ -698,7 +855,7 @@ static int esd_usb2_open(struct net_device *netdev)
 		return err;
 
 	/* finally start device */
-	err = esd_usb2_start(priv);
+	err = esd_usb_start(priv);
 	if (err) {
 		netdev_warn(netdev, "couldn't start device: %d\n", err);
 		close_candev(netdev);
@@ -710,20 +867,23 @@ static int esd_usb2_open(struct net_device *netdev)
 	return 0;
 }
 
-static netdev_tx_t esd_usb2_start_xmit(struct sk_buff *skb,
-				      struct net_device *netdev)
+static netdev_tx_t esd_usb_start_xmit(struct sk_buff *skb, struct net_device *netdev)
 {
-	struct esd_usb2_net_priv *priv = netdev_priv(netdev);
-	struct esd_usb2 *dev = priv->usb2;
+	struct esd_usb_net_priv *priv = netdev_priv(netdev);
+	struct esd_usb *dev = priv->usb;
 	struct esd_tx_urb_context *context = NULL;
 	struct net_device_stats *stats = &netdev->stats;
-	struct can_frame *cf = (struct can_frame *)skb->data;
-	struct esd_usb2_msg *msg;
+	/* can.h:
+	 *    ... the struct can_frame and struct canfd_frame intentionally
+	 *	  share the same layout ...
+	 */
+	struct canfd_frame *cfd = (struct canfd_frame *)skb->data;
+	struct esd_usb_msg *msg;
 	struct urb *urb;
 	u8 *buf;
 	int i, err;
 	int ret = NETDEV_TX_OK;
-	size_t size = sizeof(struct esd_usb2_msg);
+	size_t size = sizeof(struct esd_usb_msg);
 
 	if (can_dropped_invalid_skb(netdev, skb))
 		return NETDEV_TX_OK;
@@ -736,8 +896,7 @@ static netdev_tx_t esd_usb2_start_xmit(struct sk_buff *skb,
 		goto nourbmem;
 	}
 
-	buf = usb_alloc_coherent(dev->udev, size, GFP_ATOMIC,
-				 &urb->transfer_dma);
+	buf = usb_alloc_coherent(dev->udev, size, GFP_ATOMIC, &urb->transfer_dma);
 	if (!buf) {
 		netdev_err(netdev, "No memory left for USB buffer\n");
 		stats->tx_dropped++;
@@ -745,24 +904,35 @@ static netdev_tx_t esd_usb2_start_xmit(struct sk_buff *skb,
 		goto nobufmem;
 	}
 
-	msg = (struct esd_usb2_msg *)buf;
+	msg = (struct esd_usb_msg *)buf;
 
 	msg->msg.hdr.len = 3; /* minimal length */
 	msg->msg.hdr.cmd = CMD_CAN_TX;
 	msg->msg.tx.net = priv->index;
-	msg->msg.tx.dlc = can_get_cc_dlc(cf, priv->can.ctrlmode);
-	msg->msg.tx.id = cpu_to_le32(cf->can_id & CAN_ERR_MASK);
 
-	if (cf->can_id & CAN_RTR_FLAG)
-		msg->msg.tx.dlc |= ESD_RTR;
+	if (can_is_canfd_skb(skb)) {
+		/* CAN FD */
+		msg->msg.tx.dlc = can_fd_len2dlc(cfd->len);
+		msg->msg.tx.dlc |= ESD_DLC_FD;
 
-	if (cf->can_id & CAN_EFF_FLAG)
-		msg->msg.tx.id |= cpu_to_le32(ESD_EXTID);
+		if ((cfd->flags & CANFD_BRS) == 0)
+			msg->msg.tx.dlc |= ESD_DLC_NO_BRS;
+	} else {
+		/* Classic CAN */
+		msg->msg.tx.dlc = can_get_cc_dlc((struct can_frame *)cfd, priv->can.ctrlmode);
+
+		if (cfd->can_id & CAN_RTR_FLAG)
+			msg->msg.tx.dlc |= ESD_DLC_RTR;
+	}
 
-	for (i = 0; i < cf->len; i++)
-		msg->msg.tx.data[i] = cf->data[i];
+	/* Common for classic CAN and CAN FD */
+	msg->msg.hdr.len += (cfd->len + 3) >> 2;
 
-	msg->msg.hdr.len += (cf->len + 3) >> 2;
+	msg->msg.tx.id	= cpu_to_le32(cfd->can_id & CAN_ERR_MASK);
+	if (cfd->can_id & CAN_EFF_FLAG)
+		msg->msg.tx.id |= cpu_to_le32(ESD_EXTID);
+
+	memcpy(msg->msg.tx.data.fd, cfd->data, cfd->len);
 
 	for (i = 0; i < MAX_TX_URBS; i++) {
 		if (priv->tx_contexts[i].echo_index == MAX_TX_URBS) {
@@ -788,7 +958,7 @@ static netdev_tx_t esd_usb2_start_xmit(struct sk_buff *skb,
 
 	usb_fill_bulk_urb(urb, dev->udev, usb_sndbulkpipe(dev->udev, 2), buf,
 			  msg->msg.hdr.len << 2,
-			  esd_usb2_write_bulk_callback, context);
+			  esd_usb_write_bulk_callback, context);
 
 	urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
 
@@ -839,33 +1009,34 @@ static netdev_tx_t esd_usb2_start_xmit(struct sk_buff *skb,
 	return ret;
 }
 
-static int esd_usb2_close(struct net_device *netdev)
+static int esd_usb_close(struct net_device *netdev)
 {
-	struct esd_usb2_net_priv *priv = netdev_priv(netdev);
-	struct esd_usb2_msg *msg;
+	struct esd_usb_net_priv *priv = netdev_priv(netdev);
+	struct esd_usb_msg *msg;
 	int i;
 
 	msg = kmalloc(sizeof(*msg), GFP_KERNEL);
 	if (!msg)
 		return -ENOMEM;
 
-	/* Disable all IDs (see esd_usb2_start()) */
+	/* Disable all IDs (see esd_usb_start()) */
 	msg->msg.hdr.cmd = CMD_IDADD;
 	msg->msg.hdr.len = 2 + ESD_MAX_ID_SEGMENT;
 	msg->msg.filter.net = priv->index;
 	msg->msg.filter.option = ESD_ID_ENABLE; /* start with segment 0 */
 	for (i = 0; i <= ESD_MAX_ID_SEGMENT; i++)
 		msg->msg.filter.mask[i] = 0;
-	if (esd_usb2_send_msg(priv->usb2, msg) < 0)
+	if (esd_usb_send_msg(priv->usb, msg) < 0)
 		netdev_err(netdev, "sending idadd message failed\n");
 
-	/* set CAN controller to reset mode */
+	/* Set CAN controller to reset mode */
 	msg->msg.hdr.len = 2;
 	msg->msg.hdr.cmd = CMD_SETBAUD;
 	msg->msg.setbaud.net = priv->index;
 	msg->msg.setbaud.rsvd = 0;
-	msg->msg.setbaud.baud = cpu_to_le32(ESD_USB2_NO_BAUDRATE);
-	if (esd_usb2_send_msg(priv->usb2, msg) < 0)
+	/* Sending ESD_USB2_NO_BAUDRATE is sufficient for CAN-USB/3, even in CAN FD mode, too */
+	msg->msg.setbaud.u.baud = cpu_to_le32(ESD_USB2_NO_BAUDRATE);
+	if (esd_usb_send_msg(priv->usb, msg) < 0)
 		netdev_err(netdev, "sending setbaud message failed\n");
 
 	priv->can.state = CAN_STATE_STOPPED;
@@ -879,10 +1050,10 @@ static int esd_usb2_close(struct net_device *netdev)
 	return 0;
 }
 
-static const struct net_device_ops esd_usb2_netdev_ops = {
-	.ndo_open = esd_usb2_open,
-	.ndo_stop = esd_usb2_close,
-	.ndo_start_xmit = esd_usb2_start_xmit,
+static const struct net_device_ops esd_usb_netdev_ops = {
+	.ndo_open = esd_usb_open,
+	.ndo_stop = esd_usb_close,
+	.ndo_start_xmit = esd_usb_start_xmit,
 	.ndo_change_mtu = can_change_mtu,
 };
 
@@ -898,11 +1069,35 @@ static const struct can_bittiming_const esd_usb2_bittiming_const = {
 	.brp_inc = ESD_USB2_BRP_INC,
 };
 
+static const struct can_bittiming_const esd_usb3_bittiming_const = {
+	.name = "esd_usb3",
+	.tseg1_min = ESD_USB3_TSEG1_MIN,
+	.tseg1_max = ESD_USB3_TSEG1_MAX,
+	.tseg2_min = ESD_USB3_TSEG2_MIN,
+	.tseg2_max = ESD_USB3_TSEG2_MAX,
+	.sjw_max = ESD_USB3_SJW_MAX,
+	.brp_min = ESD_USB3_BRP_MIN,
+	.brp_max = ESD_USB3_BRP_MAX,
+	.brp_inc = ESD_USB3_BRP_INC,
+};
+
+static const struct can_bittiming_const esd_usb3_data_bittiming_const = {
+	.name = "esd_usb3",
+	.tseg1_min = ESD_USB3_DATA_TSEG1_MIN,
+	.tseg1_max = ESD_USB3_DATA_TSEG1_MAX,
+	.tseg2_min = ESD_USB3_DATA_TSEG2_MIN,
+	.tseg2_max = ESD_USB3_DATA_TSEG2_MAX,
+	.sjw_max = ESD_USB3_DATA_SJW_MAX,
+	.brp_min = ESD_USB3_DATA_BRP_MIN,
+	.brp_max = ESD_USB3_DATA_BRP_MAX,
+	.brp_inc = ESD_USB3_DATA_BRP_INC,
+};
+
 static int esd_usb2_set_bittiming(struct net_device *netdev)
 {
-	struct esd_usb2_net_priv *priv = netdev_priv(netdev);
+	struct esd_usb_net_priv *priv = netdev_priv(netdev);
 	struct can_bittiming *bt = &priv->can.bittiming;
-	struct esd_usb2_msg *msg;
+	struct esd_usb_msg *msg;
 	int err;
 	u32 canbtr;
 	int sjw_shift;
@@ -913,19 +1108,15 @@ static int esd_usb2_set_bittiming(struct net_device *netdev)
 
 	canbtr |= (bt->brp - 1) & (ESD_USB2_BRP_MAX - 1);
 
-	if (le16_to_cpu(priv->usb2->udev->descriptor.idProduct) ==
-	    USB_CANUSBM_PRODUCT_ID)
+	if (le16_to_cpu(priv->usb->udev->descriptor.idProduct) == USB_CANUSBM_PRODUCT_ID)
 		sjw_shift = ESD_USBM_SJW_SHIFT;
 	else
 		sjw_shift = ESD_USB2_SJW_SHIFT;
 
-	canbtr |= ((bt->sjw - 1) & (ESD_USB2_SJW_MAX - 1))
-		<< sjw_shift;
-	canbtr |= ((bt->prop_seg + bt->phase_seg1 - 1)
-		   & (ESD_USB2_TSEG1_MAX - 1))
+	canbtr |= ((bt->sjw - 1) & (ESD_USB2_SJW_MAX - 1)) << sjw_shift;
+	canbtr |= ((bt->prop_seg + bt->phase_seg1 - 1) & (ESD_USB2_TSEG1_MAX - 1))
 		<< ESD_USB2_TSEG1_SHIFT;
-	canbtr |= ((bt->phase_seg2 - 1) & (ESD_USB2_TSEG2_MAX - 1))
-		<< ESD_USB2_TSEG2_SHIFT;
+	canbtr |= ((bt->phase_seg2 - 1) & (ESD_USB2_TSEG2_MAX - 1)) << ESD_USB2_TSEG2_SHIFT;
 	if (priv->can.ctrlmode & CAN_CTRLMODE_3_SAMPLES)
 		canbtr |= ESD_USB2_3_SAMPLES;
 
@@ -937,20 +1128,97 @@ static int esd_usb2_set_bittiming(struct net_device *netdev)
 	msg->msg.hdr.cmd = CMD_SETBAUD;
 	msg->msg.setbaud.net = priv->index;
 	msg->msg.setbaud.rsvd = 0;
-	msg->msg.setbaud.baud = cpu_to_le32(canbtr);
+	msg->msg.setbaud.u.baud = cpu_to_le32(canbtr);
 
 	netdev_info(netdev, "setting BTR=%#x\n", canbtr);
 
-	err = esd_usb2_send_msg(priv->usb2, msg);
+	err = esd_usb_send_msg(priv->usb, msg);
+
+	kfree(msg);
+	return err;
+}
+
+static int esd_usb3_set_bittiming(struct net_device *netdev)
+{
+	struct esd_usb_net_priv *priv = netdev_priv(netdev);
+	struct can_bittiming *bt   = &priv->can.bittiming;
+	struct can_bittiming *d_bt = &priv->can.data_bittiming;
+	struct esd_usb_msg *msg;
+	int err;
+	u16 mode;
+	u16 flags = 0;
+	u16 brp, tseg1, tseg2, sjw;
+	u16 d_brp, d_tseg1, d_tseg2, d_sjw;
+
+	msg = kmalloc(sizeof(*msg), GFP_KERNEL);
+	if (!msg)
+		return -ENOMEM;
+
+	/* Canonical is the most reasonable mode for SocketCAN on CAN-USB/3 ... */
+	mode = ESD_BAUDRATE_MODE_BTR_CANONICAL;
+
+	if (priv->can.ctrlmode & CAN_CTRLMODE_LISTENONLY)
+		flags |= ESD_BAUDRATE_FLAG_LOM;
+
+	if (priv->can.ctrlmode & CAN_CTRLMODE_3_SAMPLES)
+		flags |= ESD_BAUDRATE_FLAG_TRS;
+
+	brp = bt->brp & (ESD_USB3_BRP_MAX - 1);
+	sjw = bt->sjw & (ESD_USB3_SJW_MAX - 1);
+	tseg1 = (bt->prop_seg + bt->phase_seg1) & (ESD_USB3_TSEG1_MAX - 1);
+	tseg2 = bt->phase_seg2 & (ESD_USB3_TSEG2_MAX - 1);
+
+	msg->msg.setbaud.u.baud_x.arb.brp   = cpu_to_le16(brp);
+	msg->msg.setbaud.u.baud_x.arb.sjw   = cpu_to_le16(sjw);
+	msg->msg.setbaud.u.baud_x.arb.tseg1 = cpu_to_le16(tseg1);
+	msg->msg.setbaud.u.baud_x.arb.tseg2 = cpu_to_le16(tseg2);
+
+	if (priv->can.ctrlmode & CAN_CTRLMODE_FD) {
+		d_brp = d_bt->brp & (ESD_USB3_DATA_BRP_MAX - 1);
+		d_sjw = d_bt->sjw & (ESD_USB3_DATA_SJW_MAX - 1);
+		d_tseg1 = (d_bt->prop_seg + d_bt->phase_seg1) & (ESD_USB3_DATA_TSEG1_MAX - 1);
+		d_tseg2 = d_bt->phase_seg2 & (ESD_USB3_DATA_TSEG2_MAX - 1);
+		flags |= ESD_BAUDRATE_FLAG_FD;
+	} else {
+		d_brp   = 0;
+		d_sjw   = 0;
+		d_tseg1 = 0;
+		d_tseg2 = 0;
+	}
+
+	msg->msg.setbaud.u.baud_x.data.brp   = cpu_to_le16(d_brp);
+	msg->msg.setbaud.u.baud_x.data.sjw   = cpu_to_le16(d_sjw);
+	msg->msg.setbaud.u.baud_x.data.tseg1 = cpu_to_le16(d_tseg1);
+	msg->msg.setbaud.u.baud_x.data.tseg2 = cpu_to_le16(d_tseg2);
+	msg->msg.setbaud.u.baud_x.mode	     = cpu_to_le16(mode);
+	msg->msg.setbaud.u.baud_x.flags	     = cpu_to_le16(flags);
+	msg->msg.setbaud.u.baud_x.tdc.tdc_mode   = ESD_TDC_MODE_AUTO;
+	msg->msg.setbaud.u.baud_x.tdc.ssp_offset = 0;
+	msg->msg.setbaud.u.baud_x.tdc.ssp_shift  = 0;
+	msg->msg.setbaud.u.baud_x.tdc.tdc_filter = 0;
+
+	msg->msg.hdr.len = 7;
+	msg->msg.hdr.cmd = CMD_SETBAUD;
+
+	msg->msg.setbaud.net = priv->index;
+	msg->msg.setbaud.rsvd = 0;
+
+	netdev_info(netdev,
+		    "ctrlmode:{ is:%#x, spprted:%#x },  esd-net:%u, esd-mode:%#x, esd-flg:%#x, arb:{ brp:%u, ts1:%u, ts2:%u, sjw:%u }, data:{ dbrp:%u, dts1:%u, dts2:%u dsjw:%u }\n",
+		    priv->can.ctrlmode, priv->can.ctrlmode_supported,
+		    priv->index, mode, flags,
+		    brp, tseg1, tseg2, sjw,
+		    d_brp, d_tseg1, d_tseg2, d_sjw);
+
+	err = esd_usb_send_msg(priv->usb, msg);
 
 	kfree(msg);
 	return err;
 }
 
-static int esd_usb2_get_berr_counter(const struct net_device *netdev,
-				     struct can_berr_counter *bec)
+static int esd_usb_get_berr_counter(const struct net_device *netdev, struct can_berr_counter *bec)
 {
-	struct esd_usb2_net_priv *priv = netdev_priv(netdev);
+	struct esd_usb_net_priv *priv = netdev_priv(netdev);
 
 	bec->txerr = priv->bec.txerr;
 	bec->rxerr = priv->bec.rxerr;
@@ -958,7 +1226,7 @@ static int esd_usb2_get_berr_counter(const struct net_device *netdev,
 	return 0;
 }
 
-static int esd_usb2_set_mode(struct net_device *netdev, enum can_mode mode)
+static int esd_usb_set_mode(struct net_device *netdev, enum can_mode mode)
 {
 	switch (mode) {
 	case CAN_MODE_START:
@@ -972,11 +1240,11 @@ static int esd_usb2_set_mode(struct net_device *netdev, enum can_mode mode)
 	return 0;
 }
 
-static int esd_usb2_probe_one_net(struct usb_interface *intf, int index)
+static int esd_usb_probe_one_net(struct usb_interface *intf, int index)
 {
-	struct esd_usb2 *dev = usb_get_intfdata(intf);
+	struct esd_usb *dev = usb_get_intfdata(intf);
 	struct net_device *netdev;
-	struct esd_usb2_net_priv *priv;
+	struct esd_usb_net_priv *priv;
 	int err = 0;
 	int i;
 
@@ -995,30 +1263,45 @@ static int esd_usb2_probe_one_net(struct usb_interface *intf, int index)
 	for (i = 0; i < MAX_TX_URBS; i++)
 		priv->tx_contexts[i].echo_index = MAX_TX_URBS;
 
-	priv->usb2 = dev;
+	priv->usb = dev;
 	priv->netdev = netdev;
 	priv->index = index;
 
 	priv->can.state = CAN_STATE_STOPPED;
-	priv->can.ctrlmode_supported = CAN_CTRLMODE_LISTENONLY |
-		CAN_CTRLMODE_CC_LEN8_DLC;
+	priv->can.ctrlmode_supported = CAN_CTRLMODE_LISTENONLY | CAN_CTRLMODE_CC_LEN8_DLC;
+
+	switch (le16_to_cpu(dev->udev->descriptor.idProduct)) {
+	case USB_CANUSB3_PRODUCT_ID:
+		priv->can.clock.freq = ESD_USB3_CAN_CLOCK;
+		priv->can.ctrlmode_supported |= CAN_CTRLMODE_3_SAMPLES;
+		priv->can.ctrlmode_supported |= CAN_CTRLMODE_FD;
+		priv->can.bittiming_const = &esd_usb3_bittiming_const;
+		priv->can.data_bittiming_const = &esd_usb3_data_bittiming_const;
+		priv->can.do_set_bittiming = esd_usb3_set_bittiming;
+		priv->can.do_set_data_bittiming = esd_usb3_set_bittiming;
+		break;
 
-	if (le16_to_cpu(dev->udev->descriptor.idProduct) ==
-	    USB_CANUSBM_PRODUCT_ID)
+	case USB_CANUSBM_PRODUCT_ID:
 		priv->can.clock.freq = ESD_USBM_CAN_CLOCK;
-	else {
+		priv->can.bittiming_const = &esd_usb2_bittiming_const;
+		priv->can.do_set_bittiming = esd_usb2_set_bittiming;
+		break;
+
+	case USB_CANUSB2_PRODUCT_ID:
+	default:
 		priv->can.clock.freq = ESD_USB2_CAN_CLOCK;
 		priv->can.ctrlmode_supported |= CAN_CTRLMODE_3_SAMPLES;
+		priv->can.bittiming_const = &esd_usb2_bittiming_const;
+		priv->can.do_set_bittiming = esd_usb2_set_bittiming;
+		break;
 	}
 
-	priv->can.bittiming_const = &esd_usb2_bittiming_const;
-	priv->can.do_set_bittiming = esd_usb2_set_bittiming;
-	priv->can.do_set_mode = esd_usb2_set_mode;
-	priv->can.do_get_berr_counter = esd_usb2_get_berr_counter;
+	priv->can.do_set_mode = esd_usb_set_mode;
+	priv->can.do_get_berr_counter = esd_usb_get_berr_counter;
 
 	netdev->flags |= IFF_ECHO; /* we support local echo */
 
-	netdev->netdev_ops = &esd_usb2_netdev_ops;
+	netdev->netdev_ops = &esd_usb_netdev_ops;
 
 	SET_NETDEV_DEV(netdev, &intf->dev);
 	netdev->dev_id = index;
@@ -1044,11 +1327,10 @@ static int esd_usb2_probe_one_net(struct usb_interface *intf, int index)
  * check version information and number of available
  * CAN interfaces
  */
-static int esd_usb2_probe(struct usb_interface *intf,
-			 const struct usb_device_id *id)
+static int esd_usb_probe(struct usb_interface *intf, const struct usb_device_id *id)
 {
-	struct esd_usb2 *dev;
-	struct esd_usb2_msg *msg;
+	struct esd_usb *dev;
+	struct esd_usb_msg *msg;
 	int i, err;
 
 	dev = kzalloc(sizeof(*dev), GFP_KERNEL);
@@ -1076,13 +1358,13 @@ static int esd_usb2_probe(struct usb_interface *intf,
 	msg->msg.version.flags = 0;
 	msg->msg.version.drv_version = 0;
 
-	err = esd_usb2_send_msg(dev, msg);
+	err = esd_usb_send_msg(dev, msg);
 	if (err < 0) {
 		dev_err(&intf->dev, "sending version message failed\n");
 		goto free_msg;
 	}
 
-	err = esd_usb2_wait_msg(dev, msg);
+	err = esd_usb_wait_msg(dev, msg);
 	if (err < 0) {
 		dev_err(&intf->dev, "no version message answer\n");
 		goto free_msg;
@@ -1091,21 +1373,26 @@ static int esd_usb2_probe(struct usb_interface *intf,
 	dev->net_count = (int)msg->msg.version_reply.nets;
 	dev->version = le32_to_cpu(msg->msg.version_reply.version);
 
+	dev_info(&intf->dev, "version:{ hw:%d.%d.%d fw:%d.%d.%d }\n",
+		 (dev->version >> 28) & 0xf,
+		 (dev->version >> 24) & 0xf,
+		 (dev->version >> 16) & 0xff,
+		 (dev->version >> 12) & 0xf,
+		 (dev->version >>  8) & 0xf,
+		 (dev->version)       & 0xff);
+
 	if (device_create_file(&intf->dev, &dev_attr_firmware))
-		dev_err(&intf->dev,
-			"Couldn't create device file for firmware\n");
+		dev_err(&intf->dev, "Couldn't create device file for firmware\n");
 
 	if (device_create_file(&intf->dev, &dev_attr_hardware))
-		dev_err(&intf->dev,
-			"Couldn't create device file for hardware\n");
+		dev_err(&intf->dev, "Couldn't create device file for hardware\n");
 
 	if (device_create_file(&intf->dev, &dev_attr_nets))
-		dev_err(&intf->dev,
-			"Couldn't create device file for nets\n");
+		dev_err(&intf->dev, "Couldn't create device file for nets\n");
 
 	/* do per device probing */
 	for (i = 0; i < dev->net_count; i++)
-		esd_usb2_probe_one_net(intf, i);
+		esd_usb_probe_one_net(intf, i);
 
 free_msg:
 	kfree(msg);
@@ -1118,9 +1405,9 @@ static int esd_usb2_probe(struct usb_interface *intf,
 /*
  * called by the usb core when the device is removed from the system
  */
-static void esd_usb2_disconnect(struct usb_interface *intf)
+static void esd_usb_disconnect(struct usb_interface *intf)
 {
-	struct esd_usb2 *dev = usb_get_intfdata(intf);
+	struct esd_usb *dev = usb_get_intfdata(intf);
 	struct net_device *netdev;
 	int i;
 
@@ -1144,11 +1431,11 @@ static void esd_usb2_disconnect(struct usb_interface *intf)
 }
 
 /* usb specific object needed to register this driver with the usb subsystem */
-static struct usb_driver esd_usb2_driver = {
-	.name = "esd_usb2",
-	.probe = esd_usb2_probe,
-	.disconnect = esd_usb2_disconnect,
-	.id_table = esd_usb2_table,
+static struct usb_driver esd_usb_driver = {
+	.name = "esd_usb",
+	.probe = esd_usb_probe,
+	.disconnect = esd_usb_disconnect,
+	.id_table = esd_usb_table,
 };
 
-module_usb_driver(esd_usb2_driver);
+module_usb_driver(esd_usb_driver);
-- 
2.25.1

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ