summaryrefslogtreecommitdiff
path: root/drivers/net/can/usb
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/can/usb')
-rw-r--r--drivers/net/can/usb/Kconfig6
-rw-r--r--drivers/net/can/usb/Makefile1
-rw-r--r--drivers/net/can/usb/ems_usb.c63
-rw-r--r--drivers/net/can/usb/esd_usb2.c27
-rw-r--r--drivers/net/can/usb/peak_usb/Makefile2
-rw-r--r--drivers/net/can/usb/peak_usb/pcan_usb.c899
-rw-r--r--drivers/net/can/usb/peak_usb/pcan_usb_core.c951
-rw-r--r--drivers/net/can/usb/peak_usb/pcan_usb_core.h146
-rw-r--r--drivers/net/can/usb/peak_usb/pcan_usb_pro.c1036
-rw-r--r--drivers/net/can/usb/peak_usb/pcan_usb_pro.h178
10 files changed, 3258 insertions, 51 deletions
diff --git a/drivers/net/can/usb/Kconfig b/drivers/net/can/usb/Kconfig
index 04525495b15..0a6876841c2 100644
--- a/drivers/net/can/usb/Kconfig
+++ b/drivers/net/can/usb/Kconfig
@@ -13,4 +13,10 @@ config CAN_ESD_USB2
This driver supports the CAN-USB/2 interface
from esd electronic system design gmbh (http://www.esd.eu).
+config CAN_PEAK_USB
+ tristate "PEAK PCAN-USB/USB Pro interfaces"
+ ---help---
+ This driver supports the PCAN-USB and PCAN-USB Pro adapters
+ from PEAK-System Technik (http://www.peak-system.com).
+
endmenu
diff --git a/drivers/net/can/usb/Makefile b/drivers/net/can/usb/Makefile
index fce3cf11719..da6d1d3b296 100644
--- a/drivers/net/can/usb/Makefile
+++ b/drivers/net/can/usb/Makefile
@@ -4,5 +4,6 @@
obj-$(CONFIG_CAN_EMS_USB) += ems_usb.o
obj-$(CONFIG_CAN_ESD_USB2) += esd_usb2.o
+obj-$(CONFIG_CAN_PEAK_USB) += peak_usb/
ccflags-$(CONFIG_CAN_DEBUG_DEVICES) := -DDEBUG
diff --git a/drivers/net/can/usb/ems_usb.c b/drivers/net/can/usb/ems_usb.c
index 7dae64d44e8..7ae65fc8003 100644
--- a/drivers/net/can/usb/ems_usb.c
+++ b/drivers/net/can/usb/ems_usb.c
@@ -288,8 +288,7 @@ static void ems_usb_read_interrupt_callback(struct urb *urb)
return;
default:
- dev_info(netdev->dev.parent, "Rx interrupt aborted %d\n",
- urb->status);
+ netdev_info(netdev, "Rx interrupt aborted %d\n", urb->status);
break;
}
@@ -298,8 +297,7 @@ static void ems_usb_read_interrupt_callback(struct urb *urb)
if (err == -ENODEV)
netif_device_detach(netdev);
else if (err)
- dev_err(netdev->dev.parent,
- "failed resubmitting intr urb: %d\n", err);
+ netdev_err(netdev, "failed resubmitting intr urb: %d\n", err);
}
static void ems_usb_rx_can_msg(struct ems_usb *dev, struct ems_cpc_msg *msg)
@@ -431,8 +429,7 @@ static void ems_usb_read_bulk_callback(struct urb *urb)
return;
default:
- dev_info(netdev->dev.parent, "Rx URB aborted (%d)\n",
- urb->status);
+ netdev_info(netdev, "Rx URB aborted (%d)\n", urb->status);
goto resubmit_urb;
}
@@ -477,7 +474,7 @@ static void ems_usb_read_bulk_callback(struct urb *urb)
msg_count--;
if (start > urb->transfer_buffer_length) {
- dev_err(netdev->dev.parent, "format error\n");
+ netdev_err(netdev, "format error\n");
break;
}
}
@@ -493,8 +490,8 @@ resubmit_urb:
if (retval == -ENODEV)
netif_device_detach(netdev);
else if (retval)
- dev_err(netdev->dev.parent,
- "failed resubmitting read bulk urb: %d\n", retval);
+ netdev_err(netdev,
+ "failed resubmitting read bulk urb: %d\n", retval);
}
/*
@@ -521,8 +518,7 @@ static void ems_usb_write_bulk_callback(struct urb *urb)
return;
if (urb->status)
- dev_info(netdev->dev.parent, "Tx URB aborted (%d)\n",
- urb->status);
+ netdev_info(netdev, "Tx URB aborted (%d)\n", urb->status);
netdev->trans_start = jiffies;
@@ -605,18 +601,18 @@ static int ems_usb_start(struct ems_usb *dev)
/* create a URB, and a buffer for it */
urb = usb_alloc_urb(0, GFP_KERNEL);
if (!urb) {
- dev_err(netdev->dev.parent,
- "No memory left for URBs\n");
- return -ENOMEM;
+ netdev_err(netdev, "No memory left for URBs\n");
+ err = -ENOMEM;
+ break;
}
buf = usb_alloc_coherent(dev->udev, RX_BUFFER_SIZE, GFP_KERNEL,
&urb->transfer_dma);
if (!buf) {
- dev_err(netdev->dev.parent,
- "No memory left for USB buffer\n");
+ netdev_err(netdev, "No memory left for USB buffer\n");
usb_free_urb(urb);
- return -ENOMEM;
+ err = -ENOMEM;
+ break;
}
usb_fill_bulk_urb(urb, dev->udev, usb_rcvbulkpipe(dev->udev, 2),
@@ -639,13 +635,13 @@ static int ems_usb_start(struct ems_usb *dev)
/* Did we submit any URBs */
if (i == 0) {
- dev_warn(netdev->dev.parent, "couldn't setup read URBs\n");
+ netdev_warn(netdev, "couldn't setup read URBs\n");
return err;
}
/* Warn if we've couldn't transmit all the URBs */
if (i < MAX_RX_URBS)
- dev_warn(netdev->dev.parent, "rx performance may be slow\n");
+ netdev_warn(netdev, "rx performance may be slow\n");
/* Setup and start interrupt URB */
usb_fill_int_urb(dev->intr_urb, dev->udev,
@@ -656,8 +652,7 @@ static int ems_usb_start(struct ems_usb *dev)
err = usb_submit_urb(dev->intr_urb, GFP_KERNEL);
if (err) {
- dev_warn(netdev->dev.parent, "intr URB submit failed: %d\n",
- err);
+ netdev_warn(netdev, "intr URB submit failed: %d\n", err);
return err;
}
@@ -686,7 +681,7 @@ static int ems_usb_start(struct ems_usb *dev)
return 0;
failed:
- dev_warn(netdev->dev.parent, "couldn't submit control: %d\n", err);
+ netdev_warn(netdev, "couldn't submit control: %d\n", err);
return err;
}
@@ -726,8 +721,7 @@ static int ems_usb_open(struct net_device *netdev)
if (err == -ENODEV)
netif_device_detach(dev->netdev);
- dev_warn(netdev->dev.parent, "couldn't start device: %d\n",
- err);
+ netdev_warn(netdev, "couldn't start device: %d\n", err);
close_candev(netdev);
@@ -760,13 +754,13 @@ static netdev_tx_t ems_usb_start_xmit(struct sk_buff *skb, struct net_device *ne
/* create a URB, and a buffer for it, and copy the data to the URB */
urb = usb_alloc_urb(0, GFP_ATOMIC);
if (!urb) {
- dev_err(netdev->dev.parent, "No memory left for URBs\n");
+ netdev_err(netdev, "No memory left for URBs\n");
goto nomem;
}
buf = usb_alloc_coherent(dev->udev, size, GFP_ATOMIC, &urb->transfer_dma);
if (!buf) {
- dev_err(netdev->dev.parent, "No memory left for USB buffer\n");
+ netdev_err(netdev, "No memory left for USB buffer\n");
usb_free_urb(urb);
goto nomem;
}
@@ -809,7 +803,7 @@ static netdev_tx_t ems_usb_start_xmit(struct sk_buff *skb, struct net_device *ne
usb_unanchor_urb(urb);
usb_free_coherent(dev->udev, size, buf, urb->transfer_dma);
- dev_warn(netdev->dev.parent, "couldn't find free context\n");
+ netdev_warn(netdev, "couldn't find free context\n");
return NETDEV_TX_BUSY;
}
@@ -840,7 +834,7 @@ static netdev_tx_t ems_usb_start_xmit(struct sk_buff *skb, struct net_device *ne
if (err == -ENODEV) {
netif_device_detach(netdev);
} else {
- dev_warn(netdev->dev.parent, "failed tx_urb %d\n", err);
+ netdev_warn(netdev, "failed tx_urb %d\n", err);
stats->tx_dropped++;
}
@@ -880,7 +874,7 @@ static int ems_usb_close(struct net_device *netdev)
/* Set CAN controller to reset mode */
if (ems_usb_write_mode(dev, SJA1000_MOD_RM))
- dev_warn(netdev->dev.parent, "couldn't stop device");
+ netdev_warn(netdev, "couldn't stop device");
close_candev(netdev);
@@ -917,7 +911,7 @@ static int ems_usb_set_mode(struct net_device *netdev, enum can_mode mode)
switch (mode) {
case CAN_MODE_START:
if (ems_usb_write_mode(dev, SJA1000_MOD_NORMAL))
- dev_warn(netdev->dev.parent, "couldn't start device");
+ netdev_warn(netdev, "couldn't start device");
if (netif_queue_stopped(netdev))
netif_wake_queue(netdev);
@@ -942,8 +936,7 @@ static int ems_usb_set_bittiming(struct net_device *netdev)
if (dev->can.ctrlmode & CAN_CTRLMODE_3_SAMPLES)
btr1 |= 0x80;
- dev_info(netdev->dev.parent, "setting BTR0=0x%02x BTR1=0x%02x\n",
- btr0, btr1);
+ netdev_info(netdev, "setting BTR0=0x%02x BTR1=0x%02x\n", btr0, btr1);
dev->active_params.msg.can_params.cc_params.sja1000.btr0 = btr0;
dev->active_params.msg.can_params.cc_params.sja1000.btr1 = btr1;
@@ -1048,15 +1041,13 @@ static int ems_usb_probe(struct usb_interface *intf,
err = ems_usb_command_msg(dev, &dev->active_params);
if (err) {
- dev_err(netdev->dev.parent,
- "couldn't initialize controller: %d\n", err);
+ netdev_err(netdev, "couldn't initialize controller: %d\n", err);
goto cleanup_tx_msg_buffer;
}
err = register_candev(netdev);
if (err) {
- dev_err(netdev->dev.parent,
- "couldn't register CAN device: %d\n", err);
+ netdev_err(netdev, "couldn't register CAN device: %d\n", err);
goto cleanup_tx_msg_buffer;
}
diff --git a/drivers/net/can/usb/esd_usb2.c b/drivers/net/can/usb/esd_usb2.c
index 92774637aad..09b1da5bc51 100644
--- a/drivers/net/can/usb/esd_usb2.c
+++ b/drivers/net/can/usb/esd_usb2.c
@@ -470,8 +470,7 @@ static void esd_usb2_write_bulk_callback(struct urb *urb)
return;
if (urb->status)
- dev_info(netdev->dev.parent, "Tx URB aborted (%d)\n",
- urb->status);
+ netdev_info(netdev, "Tx URB aborted (%d)\n", urb->status);
netdev->trans_start = jiffies;
}
@@ -651,7 +650,7 @@ failed:
if (err == -ENODEV)
netif_device_detach(netdev);
- dev_err(netdev->dev.parent, "couldn't start device: %d\n", err);
+ netdev_err(netdev, "couldn't start device: %d\n", err);
return err;
}
@@ -687,8 +686,7 @@ static int esd_usb2_open(struct net_device *netdev)
/* finally start device */
err = esd_usb2_start(priv);
if (err) {
- dev_warn(netdev->dev.parent,
- "couldn't start device: %d\n", err);
+ netdev_warn(netdev, "couldn't start device: %d\n", err);
close_candev(netdev);
return err;
}
@@ -721,7 +719,7 @@ static netdev_tx_t esd_usb2_start_xmit(struct sk_buff *skb,
/* create a URB, and a buffer for it, and copy the data to the URB */
urb = usb_alloc_urb(0, GFP_ATOMIC);
if (!urb) {
- dev_err(netdev->dev.parent, "No memory left for URBs\n");
+ netdev_err(netdev, "No memory left for URBs\n");
stats->tx_dropped++;
dev_kfree_skb(skb);
goto nourbmem;
@@ -730,7 +728,7 @@ static netdev_tx_t esd_usb2_start_xmit(struct sk_buff *skb,
buf = usb_alloc_coherent(dev->udev, size, GFP_ATOMIC,
&urb->transfer_dma);
if (!buf) {
- dev_err(netdev->dev.parent, "No memory left for USB buffer\n");
+ netdev_err(netdev, "No memory left for USB buffer\n");
stats->tx_dropped++;
dev_kfree_skb(skb);
goto nobufmem;
@@ -766,7 +764,7 @@ static netdev_tx_t esd_usb2_start_xmit(struct sk_buff *skb,
* This may never happen.
*/
if (!context) {
- dev_warn(netdev->dev.parent, "couldn't find free context\n");
+ netdev_warn(netdev, "couldn't find free context\n");
ret = NETDEV_TX_BUSY;
goto releasebuf;
}
@@ -806,7 +804,7 @@ static netdev_tx_t esd_usb2_start_xmit(struct sk_buff *skb,
if (err == -ENODEV)
netif_device_detach(netdev);
else
- dev_warn(netdev->dev.parent, "failed tx_urb %d\n", err);
+ netdev_warn(netdev, "failed tx_urb %d\n", err);
goto releasebuf;
}
@@ -845,7 +843,7 @@ static int esd_usb2_close(struct net_device *netdev)
for (i = 0; i <= ESD_MAX_ID_SEGMENT; i++)
msg.msg.filter.mask[i] = 0;
if (esd_usb2_send_msg(priv->usb2, &msg) < 0)
- dev_err(netdev->dev.parent, "sending idadd message failed\n");
+ netdev_err(netdev, "sending idadd message failed\n");
/* set CAN controller to reset mode */
msg.msg.hdr.len = 2;
@@ -854,7 +852,7 @@ static int esd_usb2_close(struct net_device *netdev)
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)
- dev_err(netdev->dev.parent, "sending setbaud message failed\n");
+ netdev_err(netdev, "sending setbaud message failed\n");
priv->can.state = CAN_STATE_STOPPED;
@@ -910,7 +908,7 @@ static int esd_usb2_set_bittiming(struct net_device *netdev)
msg.msg.setbaud.rsvd = 0;
msg.msg.setbaud.baud = cpu_to_le32(canbtr);
- dev_info(netdev->dev.parent, "setting BTR=%#x\n", canbtr);
+ netdev_info(netdev, "setting BTR=%#x\n", canbtr);
return esd_usb2_send_msg(priv->usb2, &msg);
}
@@ -988,15 +986,14 @@ static int esd_usb2_probe_one_net(struct usb_interface *intf, int index)
err = register_candev(netdev);
if (err) {
- dev_err(&intf->dev,
- "couldn't register CAN device: %d\n", err);
+ dev_err(&intf->dev, "couldn't register CAN device: %d\n", err);
free_candev(netdev);
err = -ENOMEM;
goto done;
}
dev->nets[index] = priv;
- dev_info(netdev->dev.parent, "device %s registered\n", netdev->name);
+ netdev_info(netdev, "device %s registered\n", netdev->name);
done:
return err;
diff --git a/drivers/net/can/usb/peak_usb/Makefile b/drivers/net/can/usb/peak_usb/Makefile
new file mode 100644
index 00000000000..1aefbc88d64
--- /dev/null
+++ b/drivers/net/can/usb/peak_usb/Makefile
@@ -0,0 +1,2 @@
+obj-$(CONFIG_CAN_PEAK_USB) += peak_usb.o
+peak_usb-y = pcan_usb_core.o pcan_usb.o pcan_usb_pro.o
diff --git a/drivers/net/can/usb/peak_usb/pcan_usb.c b/drivers/net/can/usb/peak_usb/pcan_usb.c
new file mode 100644
index 00000000000..86f26a1ede4
--- /dev/null
+++ b/drivers/net/can/usb/peak_usb/pcan_usb.c
@@ -0,0 +1,899 @@
+/*
+ * CAN driver for PEAK System PCAN-USB adapter
+ * Derived from the PCAN project file driver/src/pcan_usb.c
+ *
+ * Copyright (C) 2003-2010 PEAK System-Technik GmbH
+ * Copyright (C) 2011-2012 Stephane Grosjean <s.grosjean@peak-system.com>
+ *
+ * Many thanks to Klaus Hitschler <klaus.hitschler@gmx.de>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published
+ * 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.
+ */
+#include <linux/netdevice.h>
+#include <linux/usb.h>
+#include <linux/module.h>
+
+#include <linux/can.h>
+#include <linux/can/dev.h>
+#include <linux/can/error.h>
+
+#include "pcan_usb_core.h"
+
+MODULE_SUPPORTED_DEVICE("PEAK-System PCAN-USB adapter");
+
+/* PCAN-USB Endpoints */
+#define PCAN_USB_EP_CMDOUT 1
+#define PCAN_USB_EP_CMDIN (PCAN_USB_EP_CMDOUT | USB_DIR_IN)
+#define PCAN_USB_EP_MSGOUT 2
+#define PCAN_USB_EP_MSGIN (PCAN_USB_EP_MSGOUT | USB_DIR_IN)
+
+/* PCAN-USB command struct */
+#define PCAN_USB_CMD_FUNC 0
+#define PCAN_USB_CMD_NUM 1
+#define PCAN_USB_CMD_ARGS 2
+#define PCAN_USB_CMD_ARGS_LEN 14
+#define PCAN_USB_CMD_LEN (PCAN_USB_CMD_ARGS + \
+ PCAN_USB_CMD_ARGS_LEN)
+
+/* PCAN-USB command timeout (ms.) */
+#define PCAN_USB_COMMAND_TIMEOUT 1000
+
+/* PCAN-USB startup timeout (ms.) */
+#define PCAN_USB_STARTUP_TIMEOUT 10
+
+/* PCAN-USB rx/tx buffers size */
+#define PCAN_USB_RX_BUFFER_SIZE 64
+#define PCAN_USB_TX_BUFFER_SIZE 64
+
+#define PCAN_USB_MSG_HEADER_LEN 2
+
+/* PCAN-USB adapter internal clock (MHz) */
+#define PCAN_USB_CRYSTAL_HZ 16000000
+
+/* PCAN-USB USB message record status/len field */
+#define PCAN_USB_STATUSLEN_TIMESTAMP (1 << 7)
+#define PCAN_USB_STATUSLEN_INTERNAL (1 << 6)
+#define PCAN_USB_STATUSLEN_EXT_ID (1 << 5)
+#define PCAN_USB_STATUSLEN_RTR (1 << 4)
+#define PCAN_USB_STATUSLEN_DLC (0xf)
+
+/* PCAN-USB error flags */
+#define PCAN_USB_ERROR_TXFULL 0x01
+#define PCAN_USB_ERROR_RXQOVR 0x02
+#define PCAN_USB_ERROR_BUS_LIGHT 0x04
+#define PCAN_USB_ERROR_BUS_HEAVY 0x08
+#define PCAN_USB_ERROR_BUS_OFF 0x10
+#define PCAN_USB_ERROR_RXQEMPTY 0x20
+#define PCAN_USB_ERROR_QOVR 0x40
+#define PCAN_USB_ERROR_TXQFULL 0x80
+
+/* SJA1000 modes */
+#define SJA1000_MODE_NORMAL 0x00
+#define SJA1000_MODE_INIT 0x01
+
+/*
+ * tick duration = 42.666 us =>
+ * (tick_number * 44739243) >> 20 ~ (tick_number * 42666) / 1000
+ * accuracy = 10^-7
+ */
+#define PCAN_USB_TS_DIV_SHIFTER 20
+#define PCAN_USB_TS_US_PER_TICK 44739243
+
+/* PCAN-USB messages record types */
+#define PCAN_USB_REC_ERROR 1
+#define PCAN_USB_REC_ANALOG 2
+#define PCAN_USB_REC_BUSLOAD 3
+#define PCAN_USB_REC_TS 4
+#define PCAN_USB_REC_BUSEVT 5
+
+/* private to PCAN-USB adapter */
+struct pcan_usb {
+ struct peak_usb_device dev;
+ struct peak_time_ref time_ref;
+ struct timer_list restart_timer;
+};
+
+/* incoming message context for decoding */
+struct pcan_usb_msg_context {
+ u16 ts16;
+ u8 prev_ts8;
+ u8 *ptr;
+ u8 *end;
+ u8 rec_cnt;
+ u8 rec_idx;
+ u8 rec_data_idx;
+ struct net_device *netdev;
+ struct pcan_usb *pdev;
+};
+
+/*
+ * send a command
+ */
+static int pcan_usb_send_cmd(struct peak_usb_device *dev, u8 f, u8 n, u8 *p)
+{
+ int err;
+ int actual_length;
+
+ /* usb device unregistered? */
+ if (!(dev->state & PCAN_USB_STATE_CONNECTED))
+ return 0;
+
+ dev->cmd_buf[PCAN_USB_CMD_FUNC] = f;
+ dev->cmd_buf[PCAN_USB_CMD_NUM] = n;
+
+ if (p)
+ memcpy(dev->cmd_buf + PCAN_USB_CMD_ARGS,
+ p, PCAN_USB_CMD_ARGS_LEN);
+
+ err = usb_bulk_msg(dev->udev,
+ usb_sndbulkpipe(dev->udev, PCAN_USB_EP_CMDOUT),
+ dev->cmd_buf, PCAN_USB_CMD_LEN, &actual_length,
+ PCAN_USB_COMMAND_TIMEOUT);
+ if (err)
+ netdev_err(dev->netdev,
+ "sending cmd f=0x%x n=0x%x failure: %d\n",
+ f, n, err);
+ return err;
+}
+
+/*
+ * send a command then wait for its response
+ */
+static int pcan_usb_wait_rsp(struct peak_usb_device *dev, u8 f, u8 n, u8 *p)
+{
+ int err;
+ int actual_length;
+
+ /* usb device unregistered? */
+ if (!(dev->state & PCAN_USB_STATE_CONNECTED))
+ return 0;
+
+ /* first, send command */
+ err = pcan_usb_send_cmd(dev, f, n, NULL);
+ if (err)
+ return err;
+
+ err = usb_bulk_msg(dev->udev,
+ usb_rcvbulkpipe(dev->udev, PCAN_USB_EP_CMDIN),
+ dev->cmd_buf, PCAN_USB_CMD_LEN, &actual_length,
+ PCAN_USB_COMMAND_TIMEOUT);
+ if (err)
+ netdev_err(dev->netdev,
+ "waiting rsp f=0x%x n=0x%x failure: %d\n", f, n, err);
+ else if (p)
+ memcpy(p, dev->cmd_buf + PCAN_USB_CMD_ARGS,
+ PCAN_USB_CMD_ARGS_LEN);
+
+ return err;
+}
+
+static int pcan_usb_set_sja1000(struct peak_usb_device *dev, u8 mode)
+{
+ u8 args[PCAN_USB_CMD_ARGS_LEN] = {
+ [1] = mode,
+ };
+
+ return pcan_usb_send_cmd(dev, 9, 2, args);
+}
+
+static int pcan_usb_set_bus(struct peak_usb_device *dev, u8 onoff)
+{
+ u8 args[PCAN_USB_CMD_ARGS_LEN] = {
+ [0] = !!onoff,
+ };
+
+ return pcan_usb_send_cmd(dev, 3, 2, args);
+}
+
+static int pcan_usb_set_silent(struct peak_usb_device *dev, u8 onoff)
+{
+ u8 args[PCAN_USB_CMD_ARGS_LEN] = {
+ [0] = !!onoff,
+ };
+
+ return pcan_usb_send_cmd(dev, 3, 3, args);
+}
+
+static int pcan_usb_set_ext_vcc(struct peak_usb_device *dev, u8 onoff)
+{
+ u8 args[PCAN_USB_CMD_ARGS_LEN] = {
+ [0] = !!onoff,
+ };
+
+ return pcan_usb_send_cmd(dev, 10, 2, args);
+}
+
+/*
+ * set bittiming value to can
+ */
+static int pcan_usb_set_bittiming(struct peak_usb_device *dev,
+ struct can_bittiming *bt)
+{
+ u8 args[PCAN_USB_CMD_ARGS_LEN];
+ u8 btr0, btr1;
+
+ btr0 = ((bt->brp - 1) & 0x3f) | (((bt->sjw - 1) & 0x3) << 6);
+ btr1 = ((bt->prop_seg + bt->phase_seg1 - 1) & 0xf) |
+ (((bt->phase_seg2 - 1) & 0x7) << 4);
+ if (dev->can.ctrlmode & CAN_CTRLMODE_3_SAMPLES)
+ btr1 |= 0x80;
+
+ netdev_info(dev->netdev, "setting BTR0=0x%02x BTR1=0x%02x\n",
+ btr0, btr1);
+
+ args[0] = btr1;
+ args[1] = btr0;
+
+ return pcan_usb_send_cmd(dev, 1, 2, args);
+}
+
+/*
+ * init/reset can
+ */
+static int pcan_usb_write_mode(struct peak_usb_device *dev, u8 onoff)
+{
+ int err;
+
+ err = pcan_usb_set_bus(dev, onoff);
+ if (err)
+ return err;
+
+ if (!onoff) {
+ err = pcan_usb_set_sja1000(dev, SJA1000_MODE_INIT);
+ } else {
+ /* the PCAN-USB needs time to init */
+ set_current_state(TASK_INTERRUPTIBLE);
+ schedule_timeout(msecs_to_jiffies(PCAN_USB_STARTUP_TIMEOUT));
+ }
+
+ return err;
+}
+
+/*
+ * handle end of waiting for the device to reset
+ */
+static void pcan_usb_restart(unsigned long arg)
+{
+ /* notify candev and netdev */
+ peak_usb_restart_complete((struct peak_usb_device *)arg);
+}
+
+/*
+ * handle the submission of the restart urb
+ */
+static void pcan_usb_restart_pending(struct urb *urb)
+{
+ struct pcan_usb *pdev = urb->context;
+
+ /* the PCAN-USB needs time to restart */
+ mod_timer(&pdev->restart_timer,
+ jiffies + msecs_to_jiffies(PCAN_USB_STARTUP_TIMEOUT));
+
+ /* can delete usb resources */
+ peak_usb_async_complete(urb);
+}
+
+/*
+ * handle asynchronous restart
+ */
+static int pcan_usb_restart_async(struct peak_usb_device *dev, struct urb *urb,
+ u8 *buf)
+{
+ struct pcan_usb *pdev = container_of(dev, struct pcan_usb, dev);
+
+ if (timer_pending(&pdev->restart_timer))
+ return -EBUSY;
+
+ /* set bus on */
+ buf[PCAN_USB_CMD_FUNC] = 3;
+ buf[PCAN_USB_CMD_NUM] = 2;
+ buf[PCAN_USB_CMD_ARGS] = 1;
+
+ usb_fill_bulk_urb(urb, dev->udev,
+ usb_sndbulkpipe(dev->udev, PCAN_USB_EP_CMDOUT),
+ buf, PCAN_USB_CMD_LEN,
+ pcan_usb_restart_pending, pdev);
+
+ return usb_submit_urb(urb, GFP_ATOMIC);
+}
+
+/*
+ * read serial number from device
+ */
+static int pcan_usb_get_serial(struct peak_usb_device *dev, u32 *serial_number)
+{
+ u8 args[PCAN_USB_CMD_ARGS_LEN];
+ int err;
+
+ err = pcan_usb_wait_rsp(dev, 6, 1, args);
+ if (err) {
+ netdev_err(dev->netdev, "getting serial failure: %d\n", err);
+ } else if (serial_number) {
+ u32 tmp32;
+
+ memcpy(&tmp32, args, 4);
+ *serial_number = le32_to_cpu(tmp32);
+ }
+
+ return err;
+}
+
+/*
+ * read device id from device
+ */
+static int pcan_usb_get_device_id(struct peak_usb_device *dev, u32 *device_id)
+{
+ u8 args[PCAN_USB_CMD_ARGS_LEN];
+ int err;
+
+ err = pcan_usb_wait_rsp(dev, 4, 1, args);
+ if (err)
+ netdev_err(dev->netdev, "getting device id failure: %d\n", err);
+ else if (device_id)
+ *device_id = args[0];
+
+ return err;
+}
+
+/*
+ * update current time ref with received timestamp
+ */
+static int pcan_usb_update_ts(struct pcan_usb_msg_context *mc)
+{
+ u16 tmp16;
+
+ if ((mc->ptr+2) > mc->end)
+ return -EINVAL;
+
+ memcpy(&tmp16, mc->ptr, 2);
+
+ mc->ts16 = le16_to_cpu(tmp16);
+
+ if (mc->rec_idx > 0)
+ peak_usb_update_ts_now(&mc->pdev->time_ref, mc->ts16);
+ else
+ peak_usb_set_ts_now(&mc->pdev->time_ref, mc->ts16);
+
+ return 0;
+}
+
+/*
+ * decode received timestamp
+ */
+static int pcan_usb_decode_ts(struct pcan_usb_msg_context *mc, u8 first_packet)
+{
+ /* only 1st packet supplies a word timestamp */
+ if (first_packet) {
+ u16 tmp16;
+
+ if ((mc->ptr + 2) > mc->end)
+ return -EINVAL;
+
+ memcpy(&tmp16, mc->ptr, 2);
+ mc->ptr += 2;
+
+ mc->ts16 = le16_to_cpu(tmp16);
+ mc->prev_ts8 = mc->ts16 & 0x00ff;
+ } else {
+ u8 ts8;
+
+ if ((mc->ptr + 1) > mc->end)
+ return -EINVAL;
+
+ ts8 = *mc->ptr++;
+
+ if (ts8 < mc->prev_ts8)
+ mc->ts16 += 0x100;
+
+ mc->ts16 &= 0xff00;
+ mc->ts16 |= ts8;
+ mc->prev_ts8 = ts8;
+ }
+
+ return 0;
+}
+
+static int pcan_usb_decode_error(struct pcan_usb_msg_context *mc, u8 n,
+ u8 status_len)
+{
+ struct sk_buff *skb;
+ struct can_frame *cf;
+ struct timeval tv;
+ enum can_state new_state;
+
+ /* ignore this error until 1st ts received */
+ if (n == PCAN_USB_ERROR_QOVR)
+ if (!mc->pdev->time_ref.tick_count)
+ return 0;
+
+ new_state = mc->pdev->dev.can.state;
+
+ switch (mc->pdev->dev.can.state) {
+ case CAN_STATE_ERROR_ACTIVE:
+ if (n & PCAN_USB_ERROR_BUS_LIGHT) {
+ new_state = CAN_STATE_ERROR_WARNING;
+ break;
+ }
+
+ case CAN_STATE_ERROR_WARNING:
+ if (n & PCAN_USB_ERROR_BUS_HEAVY) {
+ new_state = CAN_STATE_ERROR_PASSIVE;
+ break;
+ }
+ if (n & PCAN_USB_ERROR_BUS_OFF) {
+ new_state = CAN_STATE_BUS_OFF;
+ break;
+ }
+ if (n & (PCAN_USB_ERROR_RXQOVR | PCAN_USB_ERROR_QOVR)) {
+ /*
+ * trick to bypass next comparison and process other
+ * errors
+ */
+ new_state = CAN_STATE_MAX;
+ break;
+ }
+ if ((n & PCAN_USB_ERROR_BUS_LIGHT) == 0) {
+ /* no error (back to active state) */
+ mc->pdev->dev.can.state = CAN_STATE_ERROR_ACTIVE;
+ return 0;
+ }
+ break;
+
+ case CAN_STATE_ERROR_PASSIVE:
+ if (n & PCAN_USB_ERROR_BUS_OFF) {
+ new_state = CAN_STATE_BUS_OFF;
+ break;
+ }
+ if (n & PCAN_USB_ERROR_BUS_LIGHT) {
+ new_state = CAN_STATE_ERROR_WARNING;
+ break;
+ }
+ if (n & (PCAN_USB_ERROR_RXQOVR | PCAN_USB_ERROR_QOVR)) {
+ /*
+ * trick to bypass next comparison and process other
+ * errors
+ */
+ new_state = CAN_STATE_MAX;
+ break;
+ }
+
+ if ((n & PCAN_USB_ERROR_BUS_HEAVY) == 0) {
+ /* no error (back to active state) */
+ mc->pdev->dev.can.state = CAN_STATE_ERROR_ACTIVE;
+ return 0;
+ }
+ break;
+
+ default:
+ /* do nothing waiting for restart */
+ return 0;
+ }
+
+ /* donot post any error if current state didn't change */
+ if (mc->pdev->dev.can.state == new_state)
+ return 0;
+
+ /* allocate an skb to store the error frame */
+ skb = alloc_can_err_skb(mc->netdev, &cf);
+ if (!skb)
+ return -ENOMEM;
+
+ switch (new_state) {
+ case CAN_STATE_BUS_OFF:
+ cf->can_id |= CAN_ERR_BUSOFF;
+ can_bus_off(mc->netdev);
+ break;
+
+ case CAN_STATE_ERROR_PASSIVE:
+ cf->can_id |= CAN_ERR_CRTL;
+ cf->data[1] |= CAN_ERR_CRTL_TX_PASSIVE |
+ CAN_ERR_CRTL_RX_PASSIVE;
+ mc->pdev->dev.can.can_stats.error_passive++;
+ break;
+
+ case CAN_STATE_ERROR_WARNING:
+ cf->can_id |= CAN_ERR_CRTL;
+ cf->data[1] |= CAN_ERR_CRTL_TX_WARNING |
+ CAN_ERR_CRTL_RX_WARNING;
+ mc->pdev->dev.can.can_stats.error_warning++;
+ break;
+
+ default:
+ /* CAN_STATE_MAX (trick to handle other errors) */
+ cf->can_id |= CAN_ERR_CRTL;
+ cf->data[1] |= CAN_ERR_CRTL_RX_OVERFLOW;
+ mc->netdev->stats.rx_over_errors++;
+ mc->netdev->stats.rx_errors++;
+
+ new_state = mc->pdev->dev.can.state;
+ break;
+ }
+
+ mc->pdev->dev.can.state = new_state;
+
+ if (status_len & PCAN_USB_STATUSLEN_TIMESTAMP) {
+ peak_usb_get_ts_tv(&mc->pdev->time_ref, mc->ts16, &tv);
+ skb->tstamp = timeval_to_ktime(tv);
+ }
+
+ netif_rx(skb);
+ mc->netdev->stats.rx_packets++;
+ mc->netdev->stats.rx_bytes += cf->can_dlc;
+
+ return 0;
+}
+
+/*
+ * decode non-data usb message
+ */
+static int pcan_usb_decode_status(struct pcan_usb_msg_context *mc,
+ u8 status_len)
+{
+ u8 rec_len = status_len & PCAN_USB_STATUSLEN_DLC;
+ u8 f, n;
+ int err;
+
+ /* check whether function and number can be read */
+ if ((mc->ptr + 2) > mc->end)
+ return -EINVAL;
+
+ f = mc->ptr[PCAN_USB_CMD_FUNC];
+ n = mc->ptr[PCAN_USB_CMD_NUM];
+ mc->ptr += PCAN_USB_CMD_ARGS;
+
+ if (status_len & PCAN_USB_STATUSLEN_TIMESTAMP) {
+ int err = pcan_usb_decode_ts(mc, !mc->rec_idx);
+
+ if (err)
+ return err;
+ }
+
+ switch (f) {
+ case PCAN_USB_REC_ERROR:
+ err = pcan_usb_decode_error(mc, n, status_len);
+ if (err)
+ return err;
+ break;
+
+ case PCAN_USB_REC_ANALOG:
+ /* analog values (ignored) */
+ rec_len = 2;
+ break;
+
+ case PCAN_USB_REC_BUSLOAD:
+ /* bus load (ignored) */
+ rec_len = 1;
+ break;
+
+ case PCAN_USB_REC_TS:
+ /* only timestamp */
+ if (pcan_usb_update_ts(mc))
+ return -EINVAL;
+ break;
+
+ case PCAN_USB_REC_BUSEVT:
+ /* error frame/bus event */
+ if (n & PCAN_USB_ERROR_TXQFULL)
+ netdev_dbg(mc->netdev, "device Tx queue full)\n");
+ break;
+ default:
+ netdev_err(mc->netdev, "unexpected function %u\n", f);
+ break;
+ }
+
+ if ((mc->ptr + rec_len) > mc->end)
+ return -EINVAL;
+
+ mc->ptr += rec_len;
+
+ return 0;
+}
+
+/*
+ * decode data usb message
+ */
+static int pcan_usb_decode_data(struct pcan_usb_msg_context *mc, u8 status_len)
+{
+ u8 rec_len = status_len & PCAN_USB_STATUSLEN_DLC;
+ struct sk_buff *skb;
+ struct can_frame *cf;
+ struct timeval tv;
+
+ skb = alloc_can_skb(mc->netdev, &cf);
+ if (!skb)
+ return -ENOMEM;
+
+ if (status_len & PCAN_USB_STATUSLEN_EXT_ID) {
+ u32 tmp32;
+
+ if ((mc->ptr + 4) > mc->end)
+ goto decode_failed;
+
+ memcpy(&tmp32, mc->ptr, 4);
+ mc->ptr += 4;
+
+ cf->can_id = le32_to_cpu(tmp32 >> 3) | CAN_EFF_FLAG;
+ } else {
+ u16 tmp16;
+
+ if ((mc->ptr + 2) > mc->end)
+ goto decode_failed;
+
+ memcpy(&tmp16, mc->ptr, 2);
+ mc->ptr += 2;
+
+ cf->can_id = le16_to_cpu(tmp16 >> 5);
+ }
+
+ cf->can_dlc = get_can_dlc(rec_len);
+
+ /* first data packet timestamp is a word */
+ if (pcan_usb_decode_ts(mc, !mc->rec_data_idx))
+ goto decode_failed;
+
+ /* read data */
+ memset(cf->data, 0x0, sizeof(cf->data));
+ if (status_len & PCAN_USB_STATUSLEN_RTR) {
+ cf->can_id |= CAN_RTR_FLAG;
+ } else {
+ if ((mc->ptr + rec_len) > mc->end)
+ goto decode_failed;
+
+ memcpy(cf->data, mc->ptr, rec_len);
+ mc->ptr += rec_len;
+ }
+
+ /* convert timestamp into kernel time */
+ peak_usb_get_ts_tv(&mc->pdev->time_ref, mc->ts16, &tv);
+ skb->tstamp = timeval_to_ktime(tv);
+
+ /* push the skb */
+ netif_rx(skb);
+
+ /* update statistics */
+ mc->netdev->stats.rx_packets++;
+ mc->netdev->stats.rx_bytes += cf->can_dlc;
+
+ return 0;
+
+decode_failed:
+ dev_kfree_skb(skb);
+ return -EINVAL;
+}
+
+/*
+ * process incoming message
+ */
+static int pcan_usb_decode_msg(struct peak_usb_device *dev, u8 *ibuf, u32 lbuf)
+{
+ struct pcan_usb_msg_context mc = {
+ .rec_cnt = ibuf[1],
+ .ptr = ibuf + PCAN_USB_MSG_HEADER_LEN,
+ .end = ibuf + lbuf,
+ .netdev = dev->netdev,
+ .pdev = container_of(dev, struct pcan_usb, dev),
+ };
+ int err;
+
+ for (err = 0; mc.rec_idx < mc.rec_cnt && !err; mc.rec_idx++) {
+ u8 sl = *mc.ptr++;
+
+ /* handle status and error frames here */
+ if (sl & PCAN_USB_STATUSLEN_INTERNAL) {
+ err = pcan_usb_decode_status(&mc, sl);
+ /* handle normal can frames here */
+ } else {
+ err = pcan_usb_decode_data(&mc, sl);
+ mc.rec_data_idx++;
+ }
+ }
+
+ return err;
+}
+
+/*
+ * process any incoming buffer
+ */
+static int pcan_usb_decode_buf(struct peak_usb_device *dev, struct urb *urb)
+{
+ int err = 0;
+
+ if (urb->actual_length > PCAN_USB_MSG_HEADER_LEN) {
+ err = pcan_usb_decode_msg(dev, urb->transfer_buffer,
+ urb->actual_length);
+
+ } else if (urb->actual_length > 0) {
+ netdev_err(dev->netdev, "usb message length error (%u)\n",
+ urb->actual_length);
+ err = -EINVAL;
+ }
+
+ return err;
+}
+
+/*
+ * process outgoing packet
+ */
+static int pcan_usb_encode_msg(struct peak_usb_device *dev, struct sk_buff *skb,
+ u8 *obuf, size_t *size)
+{
+ struct net_device *netdev = dev->netdev;
+ struct net_device_stats *stats = &netdev->stats;
+ struct can_frame *cf = (struct can_frame *)skb->data;
+ u8 *pc;
+
+ obuf[0] = 2;
+ obuf[1] = 1;
+
+ pc = obuf + PCAN_USB_MSG_HEADER_LEN;
+
+ /* status/len byte */
+ *pc = cf->can_dlc;
+ if (cf->can_id & CAN_RTR_FLAG)
+ *pc |= PCAN_USB_STATUSLEN_RTR;
+
+ /* can id */
+ if (cf->can_id & CAN_EFF_FLAG) {
+ __le32 tmp32 = cpu_to_le32((cf->can_id & CAN_ERR_MASK) << 3);
+
+ *pc |= PCAN_USB_STATUSLEN_EXT_ID;
+ memcpy(++pc, &tmp32, 4);
+ pc += 4;
+ } else {
+ __le16 tmp16 = cpu_to_le16((cf->can_id & CAN_ERR_MASK) << 5);
+
+ memcpy(++pc, &tmp16, 2);
+ pc += 2;
+ }
+
+ /* can data */
+ if (!(cf->can_id & CAN_RTR_FLAG)) {
+ memcpy(pc, cf->data, cf->can_dlc);
+ pc += cf->can_dlc;
+ }
+
+ obuf[(*size)-1] = (u8)(stats->tx_packets & 0xff);
+
+ return 0;
+}
+
+/*
+ * start interface
+ */
+static int pcan_usb_start(struct peak_usb_device *dev)
+{
+ struct pcan_usb *pdev = container_of(dev, struct pcan_usb, dev);
+
+ /* number of bits used in timestamps read from adapter struct */
+ peak_usb_init_time_ref(&pdev->time_ref, &pcan_usb);
+
+ /* if revision greater than 3, can put silent mode on/off */
+ if (dev->device_rev > 3) {
+ int err;
+
+ err = pcan_usb_set_silent(dev,
+ dev->can.ctrlmode & CAN_CTRLMODE_LISTENONLY);
+ if (err)
+ return err;
+ }
+
+ return pcan_usb_set_ext_vcc(dev, 0);
+}
+
+static int pcan_usb_init(struct peak_usb_device *dev)
+{
+ struct pcan_usb *pdev = container_of(dev, struct pcan_usb, dev);
+ u32 serial_number;
+ int err;
+
+ /* initialize a timer needed to wait for hardware restart */
+ init_timer(&pdev->restart_timer);
+ pdev->restart_timer.function = pcan_usb_restart;
+ pdev->restart_timer.data = (unsigned long)dev;
+
+ /*
+ * explicit use of dev_xxx() instead of netdev_xxx() here:
+ * information displayed are related to the device itself, not
+ * to the canx netdevice.
+ */
+ err = pcan_usb_get_serial(dev, &serial_number);
+ if (err) {
+ dev_err(dev->netdev->dev.parent,
+ "unable to read %s serial number (err %d)\n",
+ pcan_usb.name, err);
+ return err;
+ }
+
+ dev_info(dev->netdev->dev.parent,
+ "PEAK-System %s adapter hwrev %u serial %08X (%u channel)\n",
+ pcan_usb.name, dev->device_rev, serial_number,
+ pcan_usb.ctrl_count);
+
+ return 0;
+}
+
+/*
+ * probe function for new PCAN-USB usb interface
+ */
+static int pcan_usb_probe(struct usb_interface *intf)
+{
+ struct usb_host_interface *if_desc;
+ int i;
+
+ if_desc = intf->altsetting;
+
+ /* check interface endpoint addresses */
+ for (i = 0; i < if_desc->desc.bNumEndpoints; i++) {
+ struct usb_endpoint_descriptor *ep = &if_desc->endpoint[i].desc;
+
+ switch (ep->bEndpointAddress) {
+ case PCAN_USB_EP_CMDOUT:
+ case PCAN_USB_EP_CMDIN:
+ case PCAN_USB_EP_MSGOUT:
+ case PCAN_USB_EP_MSGIN:
+ break;
+ default:
+ return -ENODEV;
+ }
+ }
+
+ return 0;
+}
+
+/*
+ * describe the PCAN-USB adapter
+ */
+struct peak_usb_adapter pcan_usb = {
+ .name = "PCAN-USB",
+ .device_id = PCAN_USB_PRODUCT_ID,
+ .ctrl_count = 1,
+ .clock = {
+ .freq = PCAN_USB_CRYSTAL_HZ / 2 ,
+ },
+ .bittiming_const = {
+ .name = "pcan_usb",
+ .tseg1_min = 1,
+ .tseg1_max = 16,
+ .tseg2_min = 1,
+ .tseg2_max = 8,
+ .sjw_max = 4,
+ .brp_min = 1,
+ .brp_max = 64,
+ .brp_inc = 1,
+ },
+
+ /* size of device private data */
+ .sizeof_dev_private = sizeof(struct pcan_usb),
+
+ /* timestamps usage */
+ .ts_used_bits = 16,
+ .ts_period = 24575, /* calibration period in ts. */
+ .us_per_ts_scale = PCAN_USB_TS_US_PER_TICK, /* us=(ts*scale) */
+ .us_per_ts_shift = PCAN_USB_TS_DIV_SHIFTER, /* >> shift */
+
+ /* give here messages in/out endpoints */
+ .ep_msg_in = PCAN_USB_EP_MSGIN,
+ .ep_msg_out = {PCAN_USB_EP_MSGOUT},
+
+ /* size of rx/tx usb buffers */
+ .rx_buffer_size = PCAN_USB_RX_BUFFER_SIZE,
+ .tx_buffer_size = PCAN_USB_TX_BUFFER_SIZE,
+
+ /* device callbacks */
+ .intf_probe = pcan_usb_probe,
+ .dev_init = pcan_usb_init,
+ .dev_set_bus = pcan_usb_write_mode,
+ .dev_set_bittiming = pcan_usb_set_bittiming,
+ .dev_get_device_id = pcan_usb_get_device_id,
+ .dev_decode_buf = pcan_usb_decode_buf,
+ .dev_encode_msg = pcan_usb_encode_msg,
+ .dev_start = pcan_usb_start,
+ .dev_restart_async = pcan_usb_restart_async,
+};
diff --git a/drivers/net/can/usb/peak_usb/pcan_usb_core.c b/drivers/net/can/usb/peak_usb/pcan_usb_core.c
new file mode 100644
index 00000000000..d2f91f73787
--- /dev/null
+++ b/drivers/net/can/usb/peak_usb/pcan_usb_core.c
@@ -0,0 +1,951 @@
+/*
+ * CAN driver for PEAK System USB adapters
+ * Derived from the PCAN project file driver/src/pcan_usb_core.c
+ *
+ * Copyright (C) 2003-2010 PEAK System-Technik GmbH
+ * Copyright (C) 2010-2012 Stephane Grosjean <s.grosjean@peak-system.com>
+ *
+ * Many thanks to Klaus Hitschler <klaus.hitschler@gmx.de>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published
+ * 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.
+ */
+#include <linux/init.h>
+#include <linux/signal.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/netdevice.h>
+#include <linux/usb.h>
+
+#include <linux/can.h>
+#include <linux/can/dev.h>
+#include <linux/can/error.h>
+
+#include "pcan_usb_core.h"
+
+MODULE_AUTHOR("Stephane Grosjean <s.grosjean@peak-system.com>");
+MODULE_DESCRIPTION("CAN driver for PEAK-System USB adapters");
+MODULE_LICENSE("GPL v2");
+
+/* Table of devices that work with this driver */
+static struct usb_device_id peak_usb_table[] = {
+ {USB_DEVICE(PCAN_USB_VENDOR_ID, PCAN_USB_PRODUCT_ID)},
+ {USB_DEVICE(PCAN_USB_VENDOR_ID, PCAN_USBPRO_PRODUCT_ID)},
+ {} /* Terminating entry */
+};
+
+MODULE_DEVICE_TABLE(usb, peak_usb_table);
+
+/* List of supported PCAN-USB adapters (NULL terminated list) */
+static struct peak_usb_adapter *peak_usb_adapters_list[] = {
+ &pcan_usb,
+ &pcan_usb_pro,
+ NULL,
+};
+
+/*
+ * dump memory
+ */
+#define DUMP_WIDTH 16
+void dump_mem(char *prompt, void *p, int l)
+{
+ pr_info("%s dumping %s (%d bytes):\n",
+ PCAN_USB_DRIVER_NAME, prompt ? prompt : "memory", l);
+ print_hex_dump(KERN_INFO, PCAN_USB_DRIVER_NAME " ", DUMP_PREFIX_NONE,
+ DUMP_WIDTH, 1, p, l, false);
+}
+
+/*
+ * initialize a time_ref object with usb adapter own settings
+ */
+void peak_usb_init_time_ref(struct peak_time_ref *time_ref,
+ struct peak_usb_adapter *adapter)
+{
+ if (time_ref) {
+ memset(time_ref, 0, sizeof(struct peak_time_ref));
+ time_ref->adapter = adapter;
+ }
+}
+
+static void peak_usb_add_us(struct timeval *tv, u32 delta_us)
+{
+ /* number of s. to add to final time */
+ u32 delta_s = delta_us / 1000000;
+
+ delta_us -= delta_s * 1000000;
+
+ tv->tv_usec += delta_us;
+ if (tv->tv_usec >= 1000000) {
+ tv->tv_usec -= 1000000;
+ delta_s++;
+ }
+ tv->tv_sec += delta_s;
+}
+
+/*
+ * sometimes, another now may be more recent than current one...
+ */
+void peak_usb_update_ts_now(struct peak_time_ref *time_ref, u32 ts_now)
+{
+ time_ref->ts_dev_2 = ts_now;
+
+ /* should wait at least two passes before computing */
+ if (time_ref->tv_host.tv_sec > 0) {
+ u32 delta_ts = time_ref->ts_dev_2 - time_ref->ts_dev_1;
+
+ if (time_ref->ts_dev_2 < time_ref->ts_dev_1)
+ delta_ts &= (1 << time_ref->adapter->ts_used_bits) - 1;
+
+ time_ref->ts_total += delta_ts;
+ }
+}
+
+/*
+ * register device timestamp as now
+ */
+void peak_usb_set_ts_now(struct peak_time_ref *time_ref, u32 ts_now)
+{
+ if (time_ref->tv_host_0.tv_sec == 0) {
+ /* use monotonic clock to correctly compute further deltas */
+ time_ref->tv_host_0 = ktime_to_timeval(ktime_get());
+ time_ref->tv_host.tv_sec = 0;
+ } else {
+ /*
+ * delta_us should not be >= 2^32 => delta_s should be < 4294
+ * handle 32-bits wrapping here: if count of s. reaches 4200,
+ * reset counters and change time base
+ */
+ if (time_ref->tv_host.tv_sec != 0) {
+ u32 delta_s = time_ref->tv_host.tv_sec
+ - time_ref->tv_host_0.tv_sec;
+ if (delta_s > 4200) {
+ time_ref->tv_host_0 = time_ref->tv_host;
+ time_ref->ts_total = 0;
+ }
+ }
+
+ time_ref->tv_host = ktime_to_timeval(ktime_get());
+ time_ref->tick_count++;
+ }
+
+ time_ref->ts_dev_1 = time_ref->ts_dev_2;
+ peak_usb_update_ts_now(time_ref, ts_now);
+}
+
+/*
+ * compute timeval according to current ts and time_ref data
+ */
+void peak_usb_get_ts_tv(struct peak_time_ref *time_ref, u32 ts,
+ struct timeval *tv)
+{
+ /* protect from getting timeval before setting now */
+ if (time_ref->tv_host.tv_sec > 0) {
+ u64 delta_us;
+
+ delta_us = ts - time_ref->ts_dev_2;
+ if (ts < time_ref->ts_dev_2)
+ delta_us &= (1 << time_ref->adapter->ts_used_bits) - 1;
+
+ delta_us += time_ref->ts_total;
+
+ delta_us *= time_ref->adapter->us_per_ts_scale;
+ delta_us >>= time_ref->adapter->us_per_ts_shift;
+
+ *tv = time_ref->tv_host_0;
+ peak_usb_add_us(tv, (u32)delta_us);
+ } else {
+ *tv = ktime_to_timeval(ktime_get());
+ }
+}
+
+/*
+ * callback for bulk Rx urb
+ */
+static void peak_usb_read_bulk_callback(struct urb *urb)
+{
+ struct peak_usb_device *dev = urb->context;
+ struct net_device *netdev;
+ int err;
+
+ netdev = dev->netdev;
+
+ if (!netif_device_present(netdev))
+ return;
+
+ /* check reception status */
+ switch (urb->status) {
+ case 0:
+ /* success */
+ break;
+
+ case -EILSEQ:
+ case -ENOENT:
+ case -ECONNRESET:
+ case -ESHUTDOWN:
+ return;
+
+ default:
+ if (net_ratelimit())
+ netdev_err(netdev,
+ "Rx urb aborted (%d)\n", urb->status);
+ goto resubmit_urb;
+ }
+
+ /* protect from any incoming empty msgs */
+ if ((urb->actual_length > 0) && (dev->adapter->dev_decode_buf)) {
+ /* handle these kinds of msgs only if _start callback called */
+ if (dev->state & PCAN_USB_STATE_STARTED) {
+ err = dev->adapter->dev_decode_buf(dev, urb);
+ if (err)
+ dump_mem("received usb message",
+ urb->transfer_buffer,
+ urb->transfer_buffer_length);
+ }
+ }
+
+resubmit_urb:
+ usb_fill_bulk_urb(urb, dev->udev,
+ usb_rcvbulkpipe(dev->udev, dev->ep_msg_in),
+ urb->transfer_buffer, dev->adapter->rx_buffer_size,
+ peak_usb_read_bulk_callback, dev);
+
+ usb_anchor_urb(urb, &dev->rx_submitted);
+ err = usb_submit_urb(urb, GFP_ATOMIC);
+ if (!err)
+ return;
+
+ usb_unanchor_urb(urb);
+
+ if (err == -ENODEV)
+ netif_device_detach(netdev);
+ else
+ netdev_err(netdev, "failed resubmitting read bulk urb: %d\n",
+ err);
+}
+
+/*
+ * callback for bulk Tx urb
+ */
+static void peak_usb_write_bulk_callback(struct urb *urb)
+{
+ struct peak_tx_urb_context *context = urb->context;
+ struct peak_usb_device *dev;
+ struct net_device *netdev;
+
+ BUG_ON(!context);
+
+ dev = context->dev;
+ netdev = dev->netdev;
+
+ atomic_dec(&dev->active_tx_urbs);
+
+ if (!netif_device_present(netdev))
+ return;
+
+ /* check tx status */
+ switch (urb->status) {
+ case 0:
+ /* transmission complete */
+ netdev->stats.tx_packets++;
+ netdev->stats.tx_bytes += context->dlc;
+
+ /* prevent tx timeout */
+ netdev->trans_start = jiffies;
+ break;
+
+ default:
+ if (net_ratelimit())
+ netdev_err(netdev, "Tx urb aborted (%d)\n",
+ urb->status);
+ case -EPROTO:
+ case -ENOENT:
+ case -ECONNRESET:
+ case -ESHUTDOWN:
+
+ break;
+ }
+
+ /* should always release echo skb and corresponding context */
+ can_get_echo_skb(netdev, context->echo_index);
+ context->echo_index = PCAN_USB_MAX_TX_URBS;
+
+ /* do wakeup tx queue in case of success only */
+ if (!urb->status)
+ netif_wake_queue(netdev);
+}
+
+/*
+ * called by netdev to send one skb on the CAN interface.
+ */
+static netdev_tx_t peak_usb_ndo_start_xmit(struct sk_buff *skb,
+ struct net_device *netdev)
+{
+ struct peak_usb_device *dev = netdev_priv(netdev);
+ struct peak_tx_urb_context *context = NULL;
+ struct net_device_stats *stats = &netdev->stats;
+ struct can_frame *cf = (struct can_frame *)skb->data;
+ struct urb *urb;
+ u8 *obuf;
+ int i, err;
+ size_t size = dev->adapter->tx_buffer_size;
+
+ if (can_dropped_invalid_skb(netdev, skb))
+ return NETDEV_TX_OK;
+
+ for (i = 0; i < PCAN_USB_MAX_TX_URBS; i++)
+ if (dev->tx_contexts[i].echo_index == PCAN_USB_MAX_TX_URBS) {
+ context = dev->tx_contexts + i;
+ break;
+ }
+
+ if (!context) {
+ /* should not occur except during restart */
+ return NETDEV_TX_BUSY;
+ }
+
+ urb = context->urb;
+ obuf = urb->transfer_buffer;
+
+ err = dev->adapter->dev_encode_msg(dev, skb, obuf, &size);
+ if (err) {
+ if (net_ratelimit())
+ netdev_err(netdev, "packet dropped\n");
+ dev_kfree_skb(skb);
+ stats->tx_dropped++;
+ return NETDEV_TX_OK;
+ }
+
+ context->echo_index = i;
+ context->dlc = cf->can_dlc;
+
+ usb_anchor_urb(urb, &dev->tx_submitted);
+
+ can_put_echo_skb(skb, netdev, context->echo_index);
+
+ atomic_inc(&dev->active_tx_urbs);
+
+ err = usb_submit_urb(urb, GFP_ATOMIC);
+ if (err) {
+ can_free_echo_skb(netdev, context->echo_index);
+
+ usb_unanchor_urb(urb);
+
+ /* this context is not used in fact */
+ context->echo_index = PCAN_USB_MAX_TX_URBS;
+
+ atomic_dec(&dev->active_tx_urbs);
+
+ switch (err) {
+ case -ENODEV:
+ netif_device_detach(netdev);
+ break;
+ default:
+ netdev_warn(netdev, "tx urb submitting failed err=%d\n",
+ err);
+ case -ENOENT:
+ /* cable unplugged */
+ stats->tx_dropped++;
+ }
+ } else {
+ netdev->trans_start = jiffies;
+
+ /* slow down tx path */
+ if (atomic_read(&dev->active_tx_urbs) >= PCAN_USB_MAX_TX_URBS)
+ netif_stop_queue(netdev);
+ }
+
+ return NETDEV_TX_OK;
+}
+
+/*
+ * start the CAN interface.
+ * Rx and Tx urbs are allocated here. Rx urbs are submitted here.
+ */
+static int peak_usb_start(struct peak_usb_device *dev)
+{
+ struct net_device *netdev = dev->netdev;
+ int err, i;
+
+ for (i = 0; i < PCAN_USB_MAX_RX_URBS; i++) {
+ struct urb *urb;
+ u8 *buf;
+
+ /* create a URB, and a buffer for it, to receive usb messages */
+ urb = usb_alloc_urb(0, GFP_KERNEL);
+ if (!urb) {
+ netdev_err(netdev, "No memory left for URBs\n");
+ err = -ENOMEM;
+ break;
+ }
+
+ buf = kmalloc(dev->adapter->rx_buffer_size, GFP_KERNEL);
+ if (!buf) {
+ netdev_err(netdev, "No memory left for USB buffer\n");
+ usb_free_urb(urb);
+ err = -ENOMEM;
+ break;
+ }
+
+ usb_fill_bulk_urb(urb, dev->udev,
+ usb_rcvbulkpipe(dev->udev, dev->ep_msg_in),
+ buf, dev->adapter->rx_buffer_size,
+ peak_usb_read_bulk_callback, dev);
+
+ /* ask last usb_free_urb() to also kfree() transfer_buffer */
+ urb->transfer_flags |= URB_FREE_BUFFER;
+ usb_anchor_urb(urb, &dev->rx_submitted);
+
+ err = usb_submit_urb(urb, GFP_KERNEL);
+ if (err) {
+ if (err == -ENODEV)
+ netif_device_detach(dev->netdev);
+
+ usb_unanchor_urb(urb);
+ kfree(buf);
+ usb_free_urb(urb);
+ break;
+ }
+
+ /* drop reference, USB core will take care of freeing it */
+ usb_free_urb(urb);
+ }
+
+ /* did we submit any URBs? Warn if we was not able to submit all urbs */
+ if (i < PCAN_USB_MAX_RX_URBS) {
+ if (i == 0) {
+ netdev_err(netdev, "couldn't setup any rx URB\n");
+ return err;
+ }
+
+ netdev_warn(netdev, "rx performance may be slow\n");
+ }
+
+ /* pre-alloc tx buffers and corresponding urbs */
+ for (i = 0; i < PCAN_USB_MAX_TX_URBS; i++) {
+ struct peak_tx_urb_context *context;
+ struct urb *urb;
+ u8 *buf;
+
+ /* create a URB and a buffer for it, to transmit usb messages */
+ urb = usb_alloc_urb(0, GFP_KERNEL);
+ if (!urb) {
+ netdev_err(netdev, "No memory left for URBs\n");
+ err = -ENOMEM;
+ break;
+ }
+
+ buf = kmalloc(dev->adapter->tx_buffer_size, GFP_KERNEL);
+ if (!buf) {
+ netdev_err(netdev, "No memory left for USB buffer\n");
+ usb_free_urb(urb);
+ err = -ENOMEM;
+ break;
+ }
+
+ context = dev->tx_contexts + i;
+ context->dev = dev;
+ context->urb = urb;
+
+ usb_fill_bulk_urb(urb, dev->udev,
+ usb_sndbulkpipe(dev->udev, dev->ep_msg_out),
+ buf, dev->adapter->tx_buffer_size,
+ peak_usb_write_bulk_callback, context);
+
+ /* ask last usb_free_urb() to also kfree() transfer_buffer */
+ urb->transfer_flags |= URB_FREE_BUFFER;
+ }
+
+ /* warn if we were not able to allocate enough tx contexts */
+ if (i < PCAN_USB_MAX_TX_URBS) {
+ if (i == 0) {
+ netdev_err(netdev, "couldn't setup any tx URB\n");
+ return err;
+ }
+
+ netdev_warn(netdev, "tx performance may be slow\n");
+ }
+
+ if (dev->adapter->dev_start) {
+ err = dev->adapter->dev_start(dev);
+ if (err)
+ goto failed;
+ }
+
+ dev->state |= PCAN_USB_STATE_STARTED;
+
+ /* can set bus on now */
+ if (dev->adapter->dev_set_bus) {
+ err = dev->adapter->dev_set_bus(dev, 1);
+ if (err)
+ goto failed;
+ }
+
+ dev->can.state = CAN_STATE_ERROR_ACTIVE;
+
+ return 0;
+
+failed:
+ if (err == -ENODEV)
+ netif_device_detach(dev->netdev);
+
+ netdev_warn(netdev, "couldn't submit control: %d\n", err);
+
+ return err;
+}
+
+/*
+ * called by netdev to open the corresponding CAN interface.
+ */
+static int peak_usb_ndo_open(struct net_device *netdev)
+{
+ struct peak_usb_device *dev = netdev_priv(netdev);
+ int err;
+
+ /* common open */
+ err = open_candev(netdev);
+ if (err)
+ return err;
+
+ /* finally start device */
+ err = peak_usb_start(dev);
+ if (err) {
+ netdev_err(netdev, "couldn't start device: %d\n", err);
+ close_candev(netdev);
+ return err;
+ }
+
+ dev->open_time = jiffies;
+ netif_start_queue(netdev);
+
+ return 0;
+}
+
+/*
+ * unlink in-flight Rx and Tx urbs and free their memory.
+ */
+static void peak_usb_unlink_all_urbs(struct peak_usb_device *dev)
+{
+ int i;
+
+ /* free all Rx (submitted) urbs */
+ usb_kill_anchored_urbs(&dev->rx_submitted);
+
+ /* free unsubmitted Tx urbs first */
+ for (i = 0; i < PCAN_USB_MAX_TX_URBS; i++) {
+ struct urb *urb = dev->tx_contexts[i].urb;
+
+ if (!urb ||
+ dev->tx_contexts[i].echo_index != PCAN_USB_MAX_TX_URBS) {
+ /*
+ * this urb is already released or always submitted,
+ * let usb core free by itself
+ */
+ continue;
+ }
+
+ usb_free_urb(urb);
+ dev->tx_contexts[i].urb = NULL;
+ }
+
+ /* then free all submitted Tx urbs */
+ usb_kill_anchored_urbs(&dev->tx_submitted);
+ atomic_set(&dev->active_tx_urbs, 0);
+}
+
+/*
+ * called by netdev to close the corresponding CAN interface.
+ */
+static int peak_usb_ndo_stop(struct net_device *netdev)
+{
+ struct peak_usb_device *dev = netdev_priv(netdev);
+
+ dev->state &= ~PCAN_USB_STATE_STARTED;
+ netif_stop_queue(netdev);
+
+ /* unlink all pending urbs and free used memory */
+ peak_usb_unlink_all_urbs(dev);
+
+ if (dev->adapter->dev_stop)
+ dev->adapter->dev_stop(dev);
+
+ close_candev(netdev);
+
+ dev->open_time = 0;
+ dev->can.state = CAN_STATE_STOPPED;
+
+ /* can set bus off now */
+ if (dev->adapter->dev_set_bus) {
+ int err = dev->adapter->dev_set_bus(dev, 0);
+ if (err)
+ return err;
+ }
+
+ return 0;
+}
+
+/*
+ * handle end of waiting for the device to reset
+ */
+void peak_usb_restart_complete(struct peak_usb_device *dev)
+{
+ /* finally MUST update can state */
+ dev->can.state = CAN_STATE_ERROR_ACTIVE;
+
+ /* netdev queue can be awaken now */
+ netif_wake_queue(dev->netdev);
+}
+
+void peak_usb_async_complete(struct urb *urb)
+{
+ kfree(urb->transfer_buffer);
+ usb_free_urb(urb);
+}
+
+/*
+ * device (auto-)restart mechanism runs in a timer context =>
+ * MUST handle restart with asynchronous usb transfers
+ */
+static int peak_usb_restart(struct peak_usb_device *dev)
+{
+ struct urb *urb;
+ int err;
+ u8 *buf;
+
+ /*
+ * if device doesn't define any asynchronous restart handler, simply
+ * wake the netdev queue up
+ */
+ if (!dev->adapter->dev_restart_async) {
+ peak_usb_restart_complete(dev);
+ return 0;
+ }
+
+ /* first allocate a urb to handle the asynchronous steps */
+ urb = usb_alloc_urb(0, GFP_ATOMIC);
+ if (!urb) {
+ netdev_err(dev->netdev, "no memory left for urb\n");
+ return -ENOMEM;
+ }
+
+ /* also allocate enough space for the commands to send */
+ buf = kmalloc(PCAN_USB_MAX_CMD_LEN, GFP_ATOMIC);
+ if (!buf) {
+ netdev_err(dev->netdev, "no memory left for async cmd\n");
+ usb_free_urb(urb);
+ return -ENOMEM;
+ }
+
+ /* call the device specific handler for the restart */
+ err = dev->adapter->dev_restart_async(dev, urb, buf);
+ if (!err)
+ return 0;
+
+ kfree(buf);
+ usb_free_urb(urb);
+
+ return err;
+}
+
+/*
+ * candev callback used to change CAN mode.
+ * Warning: this is called from a timer context!
+ */
+static int peak_usb_set_mode(struct net_device *netdev, enum can_mode mode)
+{
+ struct peak_usb_device *dev = netdev_priv(netdev);
+ int err = 0;
+
+ if (!dev->open_time)
+ return -EINVAL;
+
+ switch (mode) {
+ case CAN_MODE_START:
+ err = peak_usb_restart(dev);
+ if (err)
+ netdev_err(netdev, "couldn't start device (err %d)\n",
+ err);
+ break;
+
+ default:
+ return -EOPNOTSUPP;
+ }
+
+ return err;
+}
+
+/*
+ * candev callback used to set device bitrate.
+ */
+static int peak_usb_set_bittiming(struct net_device *netdev)
+{
+ struct peak_usb_device *dev = netdev_priv(netdev);
+ struct can_bittiming *bt = &dev->can.bittiming;
+
+ if (dev->adapter->dev_set_bittiming) {
+ int err = dev->adapter->dev_set_bittiming(dev, bt);
+
+ if (err)
+ netdev_info(netdev, "couldn't set bitrate (err %d)\n",
+ err);
+ return err;
+ }
+
+ return 0;
+}
+
+static const struct net_device_ops peak_usb_netdev_ops = {
+ .ndo_open = peak_usb_ndo_open,
+ .ndo_stop = peak_usb_ndo_stop,
+ .ndo_start_xmit = peak_usb_ndo_start_xmit,
+};
+
+/*
+ * create one device which is attached to CAN controller #ctrl_idx of the
+ * usb adapter.
+ */
+static int peak_usb_create_dev(struct peak_usb_adapter *peak_usb_adapter,
+ struct usb_interface *intf, int ctrl_idx)
+{
+ struct usb_device *usb_dev = interface_to_usbdev(intf);
+ int sizeof_candev = peak_usb_adapter->sizeof_dev_private;
+ struct peak_usb_device *dev;
+ struct net_device *netdev;
+ int i, err;
+ u16 tmp16;
+
+ if (sizeof_candev < sizeof(struct peak_usb_device))
+ sizeof_candev = sizeof(struct peak_usb_device);
+
+ netdev = alloc_candev(sizeof_candev, PCAN_USB_MAX_TX_URBS);
+ if (!netdev) {
+ dev_err(&intf->dev, "%s: couldn't alloc candev\n",
+ PCAN_USB_DRIVER_NAME);
+ return -ENOMEM;
+ }
+
+ dev = netdev_priv(netdev);
+
+ /* allocate a buffer large enough to send commands */
+ dev->cmd_buf = kmalloc(PCAN_USB_MAX_CMD_LEN, GFP_KERNEL);
+ if (!dev->cmd_buf) {
+ dev_err(&intf->dev, "%s: couldn't alloc cmd buffer\n",
+ PCAN_USB_DRIVER_NAME);
+ err = -ENOMEM;
+ goto lbl_set_intf_data;
+ }
+
+ dev->udev = usb_dev;
+ dev->netdev = netdev;
+ dev->adapter = peak_usb_adapter;
+ dev->ctrl_idx = ctrl_idx;
+ dev->state = PCAN_USB_STATE_CONNECTED;
+
+ dev->ep_msg_in = peak_usb_adapter->ep_msg_in;
+ dev->ep_msg_out = peak_usb_adapter->ep_msg_out[ctrl_idx];
+
+ dev->can.clock = peak_usb_adapter->clock;
+ dev->can.bittiming_const = &peak_usb_adapter->bittiming_const;
+ dev->can.do_set_bittiming = peak_usb_set_bittiming;
+ dev->can.do_set_mode = peak_usb_set_mode;
+ dev->can.ctrlmode_supported = CAN_CTRLMODE_3_SAMPLES |
+ CAN_CTRLMODE_LISTENONLY;
+
+ netdev->netdev_ops = &peak_usb_netdev_ops;
+
+ netdev->flags |= IFF_ECHO; /* we support local echo */
+
+ init_usb_anchor(&dev->rx_submitted);
+
+ init_usb_anchor(&dev->tx_submitted);
+ atomic_set(&dev->active_tx_urbs, 0);
+
+ for (i = 0; i < PCAN_USB_MAX_TX_URBS; i++)
+ dev->tx_contexts[i].echo_index = PCAN_USB_MAX_TX_URBS;
+
+ dev->prev_siblings = usb_get_intfdata(intf);
+ usb_set_intfdata(intf, dev);
+
+ SET_NETDEV_DEV(netdev, &intf->dev);
+
+ err = register_candev(netdev);
+ if (err) {
+ dev_err(&intf->dev, "couldn't register CAN device: %d\n", err);
+ goto lbl_free_cmd_buf;
+ }
+
+ if (dev->prev_siblings)
+ (dev->prev_siblings)->next_siblings = dev;
+
+ /* keep hw revision into the netdevice */
+ tmp16 = le16_to_cpu(usb_dev->descriptor.bcdDevice);
+ dev->device_rev = tmp16 >> 8;
+
+ if (dev->adapter->dev_init) {
+ err = dev->adapter->dev_init(dev);
+ if (err)
+ goto lbl_free_cmd_buf;
+ }
+
+ /* set bus off */
+ if (dev->adapter->dev_set_bus) {
+ err = dev->adapter->dev_set_bus(dev, 0);
+ if (err)
+ goto lbl_free_cmd_buf;
+ }
+
+ /* get device number early */
+ if (dev->adapter->dev_get_device_id)
+ dev->adapter->dev_get_device_id(dev, &dev->device_number);
+
+ netdev_info(netdev, "attached to %s channel %u (device %u)\n",
+ peak_usb_adapter->name, ctrl_idx, dev->device_number);
+
+ return 0;
+
+lbl_free_cmd_buf:
+ kfree(dev->cmd_buf);
+
+lbl_set_intf_data:
+ usb_set_intfdata(intf, dev->prev_siblings);
+ free_candev(netdev);
+
+ return err;
+}
+
+/*
+ * called by the usb core when the device is unplugged from the system
+ */
+static void peak_usb_disconnect(struct usb_interface *intf)
+{
+ struct peak_usb_device *dev;
+
+ /* unregister as many netdev devices as siblings */
+ for (dev = usb_get_intfdata(intf); dev; dev = dev->prev_siblings) {
+ struct net_device *netdev = dev->netdev;
+ char name[IFNAMSIZ];
+
+ dev->state &= ~PCAN_USB_STATE_CONNECTED;
+ strncpy(name, netdev->name, IFNAMSIZ);
+
+ unregister_netdev(netdev);
+ free_candev(netdev);
+
+ kfree(dev->cmd_buf);
+ dev->next_siblings = NULL;
+ if (dev->adapter->dev_free)
+ dev->adapter->dev_free(dev);
+
+ dev_info(&intf->dev, "%s removed\n", name);
+ }
+
+ usb_set_intfdata(intf, NULL);
+}
+
+/*
+ * probe function for new PEAK-System devices
+ */
+static int peak_usb_probe(struct usb_interface *intf,
+ const struct usb_device_id *id)
+{
+ struct usb_device *usb_dev = interface_to_usbdev(intf);
+ struct peak_usb_adapter *peak_usb_adapter, **pp;
+ int i, err = -ENOMEM;
+
+ usb_dev = interface_to_usbdev(intf);
+
+ /* get corresponding PCAN-USB adapter */
+ for (pp = peak_usb_adapters_list; *pp; pp++)
+ if ((*pp)->device_id == usb_dev->descriptor.idProduct)
+ break;
+
+ peak_usb_adapter = *pp;
+ if (!peak_usb_adapter) {
+ /* should never come except device_id bad usage in this file */
+ pr_err("%s: didn't find device id. 0x%x in devices list\n",
+ PCAN_USB_DRIVER_NAME, usb_dev->descriptor.idProduct);
+ return -ENODEV;
+ }
+
+ /* got corresponding adapter: check if it handles current interface */
+ if (peak_usb_adapter->intf_probe) {
+ err = peak_usb_adapter->intf_probe(intf);
+ if (err)
+ return err;
+ }
+
+ for (i = 0; i < peak_usb_adapter->ctrl_count; i++) {
+ err = peak_usb_create_dev(peak_usb_adapter, intf, i);
+ if (err) {
+ /* deregister already created devices */
+ peak_usb_disconnect(intf);
+ break;
+ }
+ }
+
+ return err;
+}
+
+/* usb specific object needed to register this driver with the usb subsystem */
+static struct usb_driver peak_usb_driver = {
+ .name = PCAN_USB_DRIVER_NAME,
+ .disconnect = peak_usb_disconnect,
+ .probe = peak_usb_probe,
+ .id_table = peak_usb_table,
+};
+
+static int __init peak_usb_init(void)
+{
+ int err;
+
+ /* register this driver with the USB subsystem */
+ err = usb_register(&peak_usb_driver);
+ if (err)
+ pr_err("%s: usb_register failed (err %d)\n",
+ PCAN_USB_DRIVER_NAME, err);
+
+ return err;
+}
+
+static int peak_usb_do_device_exit(struct device *d, void *arg)
+{
+ struct usb_interface *intf = to_usb_interface(d);
+ struct peak_usb_device *dev;
+
+ /* stop as many netdev devices as siblings */
+ for (dev = usb_get_intfdata(intf); dev; dev = dev->prev_siblings) {
+ struct net_device *netdev = dev->netdev;
+
+ if (netif_device_present(netdev))
+ if (dev->adapter->dev_exit)
+ dev->adapter->dev_exit(dev);
+ }
+
+ return 0;
+}
+
+static void __exit peak_usb_exit(void)
+{
+ int err;
+
+ /* last chance do send any synchronous commands here */
+ err = driver_for_each_device(&peak_usb_driver.drvwrap.driver, NULL,
+ NULL, peak_usb_do_device_exit);
+ if (err)
+ pr_err("%s: failed to stop all can devices (err %d)\n",
+ PCAN_USB_DRIVER_NAME, err);
+
+ /* deregister this driver with the USB subsystem */
+ usb_deregister(&peak_usb_driver);
+
+ pr_info("%s: PCAN-USB interfaces driver unloaded\n",
+ PCAN_USB_DRIVER_NAME);
+}
+
+module_init(peak_usb_init);
+module_exit(peak_usb_exit);
diff --git a/drivers/net/can/usb/peak_usb/pcan_usb_core.h b/drivers/net/can/usb/peak_usb/pcan_usb_core.h
new file mode 100644
index 00000000000..a948c5a8940
--- /dev/null
+++ b/drivers/net/can/usb/peak_usb/pcan_usb_core.h
@@ -0,0 +1,146 @@
+/*
+ * CAN driver for PEAK System USB adapters
+ * Derived from the PCAN project file driver/src/pcan_usb_core.c
+ *
+ * Copyright (C) 2003-2010 PEAK System-Technik GmbH
+ * Copyright (C) 2010-2012 Stephane Grosjean <s.grosjean@peak-system.com>
+ *
+ * Many thanks to Klaus Hitschler <klaus.hitschler@gmx.de>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published
+ * 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.
+ */
+#ifndef PCAN_USB_CORE_H
+#define PCAN_USB_CORE_H
+
+/* PEAK-System vendor id. */
+#define PCAN_USB_VENDOR_ID 0x0c72
+
+/* supported device ids. */
+#define PCAN_USB_PRODUCT_ID 0x000c
+#define PCAN_USBPRO_PRODUCT_ID 0x000d
+
+#define PCAN_USB_DRIVER_NAME "peak_usb"
+
+/* number of urbs that are submitted for rx/tx per channel */
+#define PCAN_USB_MAX_RX_URBS 4
+#define PCAN_USB_MAX_TX_URBS 10
+
+/* usb adapters maximum channels per usb interface */
+#define PCAN_USB_MAX_CHANNEL 2
+
+/* maximum length of the usb commands sent to/received from the devices */
+#define PCAN_USB_MAX_CMD_LEN 32
+
+struct peak_usb_device;
+
+/* PEAK-System USB adapter descriptor */
+struct peak_usb_adapter {
+ char *name;
+ u32 device_id;
+ struct can_clock clock;
+ struct can_bittiming_const bittiming_const;
+ unsigned int ctrl_count;
+
+ int (*intf_probe)(struct usb_interface *intf);
+
+ int (*dev_init)(struct peak_usb_device *dev);
+ void (*dev_exit)(struct peak_usb_device *dev);
+ void (*dev_free)(struct peak_usb_device *dev);
+ int (*dev_open)(struct peak_usb_device *dev);
+ int (*dev_close)(struct peak_usb_device *dev);
+ int (*dev_set_bittiming)(struct peak_usb_device *dev,
+ struct can_bittiming *bt);
+ int (*dev_set_bus)(struct peak_usb_device *dev, u8 onoff);
+ int (*dev_get_device_id)(struct peak_usb_device *dev, u32 *device_id);
+ int (*dev_decode_buf)(struct peak_usb_device *dev, struct urb *urb);
+ int (*dev_encode_msg)(struct peak_usb_device *dev, struct sk_buff *skb,
+ u8 *obuf, size_t *size);
+ int (*dev_start)(struct peak_usb_device *dev);
+ int (*dev_stop)(struct peak_usb_device *dev);
+ int (*dev_restart_async)(struct peak_usb_device *dev, struct urb *urb,
+ u8 *buf);
+ u8 ep_msg_in;
+ u8 ep_msg_out[PCAN_USB_MAX_CHANNEL];
+ u8 ts_used_bits;
+ u32 ts_period;
+ u8 us_per_ts_shift;
+ u32 us_per_ts_scale;
+
+ int rx_buffer_size;
+ int tx_buffer_size;
+ int sizeof_dev_private;
+};
+
+extern struct peak_usb_adapter pcan_usb;
+extern struct peak_usb_adapter pcan_usb_pro;
+
+struct peak_time_ref {
+ struct timeval tv_host_0, tv_host;
+ u32 ts_dev_1, ts_dev_2;
+ u64 ts_total;
+ u32 tick_count;
+ struct peak_usb_adapter *adapter;
+};
+
+struct peak_tx_urb_context {
+ struct peak_usb_device *dev;
+ u32 echo_index;
+ u8 dlc;
+ struct urb *urb;
+};
+
+#define PCAN_USB_STATE_CONNECTED 0x00000001
+#define PCAN_USB_STATE_STARTED 0x00000002
+
+/* PEAK-System USB device */
+struct peak_usb_device {
+ struct can_priv can;
+ struct peak_usb_adapter *adapter;
+ unsigned int ctrl_idx;
+ int open_time;
+ u32 state;
+
+ struct sk_buff *echo_skb[PCAN_USB_MAX_TX_URBS];
+
+ struct usb_device *udev;
+ struct net_device *netdev;
+
+ atomic_t active_tx_urbs;
+ struct usb_anchor tx_submitted;
+ struct peak_tx_urb_context tx_contexts[PCAN_USB_MAX_TX_URBS];
+
+ u8 *cmd_buf;
+ struct usb_anchor rx_submitted;
+
+ u32 device_number;
+ u8 device_rev;
+
+ u8 ep_msg_in;
+ u8 ep_msg_out;
+
+ u16 bus_load;
+
+ struct peak_usb_device *prev_siblings;
+ struct peak_usb_device *next_siblings;
+};
+
+void dump_mem(char *prompt, void *p, int l);
+
+/* common timestamp management */
+void peak_usb_init_time_ref(struct peak_time_ref *time_ref,
+ struct peak_usb_adapter *adapter);
+void peak_usb_update_ts_now(struct peak_time_ref *time_ref, u32 ts_now);
+void peak_usb_set_ts_now(struct peak_time_ref *time_ref, u32 ts_now);
+void peak_usb_get_ts_tv(struct peak_time_ref *time_ref, u32 ts,
+ struct timeval *tv);
+
+void peak_usb_async_complete(struct urb *urb);
+void peak_usb_restart_complete(struct peak_usb_device *dev);
+#endif
diff --git a/drivers/net/can/usb/peak_usb/pcan_usb_pro.c b/drivers/net/can/usb/peak_usb/pcan_usb_pro.c
new file mode 100644
index 00000000000..5234586dff1
--- /dev/null
+++ b/drivers/net/can/usb/peak_usb/pcan_usb_pro.c
@@ -0,0 +1,1036 @@
+/*
+ * CAN driver for PEAK System PCAN-USB Pro adapter
+ * Derived from the PCAN project file driver/src/pcan_usbpro.c
+ *
+ * Copyright (C) 2003-2011 PEAK System-Technik GmbH
+ * Copyright (C) 2011-2012 Stephane Grosjean <s.grosjean@peak-system.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published
+ * 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.
+ */
+#include <linux/netdevice.h>
+#include <linux/usb.h>
+#include <linux/module.h>
+
+#include <linux/can.h>
+#include <linux/can/dev.h>
+#include <linux/can/error.h>
+
+#include "pcan_usb_core.h"
+#include "pcan_usb_pro.h"
+
+MODULE_SUPPORTED_DEVICE("PEAK-System PCAN-USB Pro adapter");
+
+/* PCAN-USB Pro Endpoints */
+#define PCAN_USBPRO_EP_CMDOUT 1
+#define PCAN_USBPRO_EP_CMDIN (PCAN_USBPRO_EP_CMDOUT | USB_DIR_IN)
+#define PCAN_USBPRO_EP_MSGOUT_0 2
+#define PCAN_USBPRO_EP_MSGIN (PCAN_USBPRO_EP_MSGOUT_0 | USB_DIR_IN)
+#define PCAN_USBPRO_EP_MSGOUT_1 3
+#define PCAN_USBPRO_EP_UNUSED (PCAN_USBPRO_EP_MSGOUT_1 | USB_DIR_IN)
+
+#define PCAN_USBPRO_CHANNEL_COUNT 2
+
+/* PCAN-USB Pro adapter internal clock (MHz) */
+#define PCAN_USBPRO_CRYSTAL_HZ 56000000
+
+/* PCAN-USB Pro command timeout (ms.) */
+#define PCAN_USBPRO_COMMAND_TIMEOUT 1000
+
+/* PCAN-USB Pro rx/tx buffers size */
+#define PCAN_USBPRO_RX_BUFFER_SIZE 1024
+#define PCAN_USBPRO_TX_BUFFER_SIZE 64
+
+#define PCAN_USBPRO_MSG_HEADER_LEN 4
+
+/* some commands responses need to be re-submitted */
+#define PCAN_USBPRO_RSP_SUBMIT_MAX 2
+
+#define PCAN_USBPRO_RTR 0x01
+#define PCAN_USBPRO_EXT 0x02
+
+#define PCAN_USBPRO_CMD_BUFFER_SIZE 512
+
+/* handle device specific info used by the netdevices */
+struct pcan_usb_pro_interface {
+ struct peak_usb_device *dev[PCAN_USBPRO_CHANNEL_COUNT];
+ struct peak_time_ref time_ref;
+ int cm_ignore_count;
+ int dev_opened_count;
+};
+
+/* device information */
+struct pcan_usb_pro_device {
+ struct peak_usb_device dev;
+ struct pcan_usb_pro_interface *usb_if;
+ u32 cached_ccbt;
+};
+
+/* internal structure used to handle messages sent to bulk urb */
+struct pcan_usb_pro_msg {
+ u8 *rec_ptr;
+ int rec_buffer_size;
+ int rec_buffer_len;
+ union {
+ u16 *rec_cnt_rd;
+ u32 *rec_cnt;
+ u8 *rec_buffer;
+ } u;
+};
+
+/* records sizes table indexed on message id. (8-bits value) */
+static u16 pcan_usb_pro_sizeof_rec[256] = {
+ [PCAN_USBPRO_SETBTR] = sizeof(struct pcan_usb_pro_btr),
+ [PCAN_USBPRO_SETBUSACT] = sizeof(struct pcan_usb_pro_busact),
+ [PCAN_USBPRO_SETSILENT] = sizeof(struct pcan_usb_pro_silent),
+ [PCAN_USBPRO_SETFILTR] = sizeof(struct pcan_usb_pro_filter),
+ [PCAN_USBPRO_SETTS] = sizeof(struct pcan_usb_pro_setts),
+ [PCAN_USBPRO_GETDEVID] = sizeof(struct pcan_usb_pro_devid),
+ [PCAN_USBPRO_SETLED] = sizeof(struct pcan_usb_pro_setled),
+ [PCAN_USBPRO_RXMSG8] = sizeof(struct pcan_usb_pro_rxmsg),
+ [PCAN_USBPRO_RXMSG4] = sizeof(struct pcan_usb_pro_rxmsg) - 4,
+ [PCAN_USBPRO_RXMSG0] = sizeof(struct pcan_usb_pro_rxmsg) - 8,
+ [PCAN_USBPRO_RXRTR] = sizeof(struct pcan_usb_pro_rxmsg) - 8,
+ [PCAN_USBPRO_RXSTATUS] = sizeof(struct pcan_usb_pro_rxstatus),
+ [PCAN_USBPRO_RXTS] = sizeof(struct pcan_usb_pro_rxts),
+ [PCAN_USBPRO_TXMSG8] = sizeof(struct pcan_usb_pro_txmsg),
+ [PCAN_USBPRO_TXMSG4] = sizeof(struct pcan_usb_pro_txmsg) - 4,
+ [PCAN_USBPRO_TXMSG0] = sizeof(struct pcan_usb_pro_txmsg) - 8,
+};
+
+/*
+ * initialize PCAN-USB Pro message data structure
+ */
+static u8 *pcan_msg_init(struct pcan_usb_pro_msg *pm, void *buffer_addr,
+ int buffer_size)
+{
+ if (buffer_size < PCAN_USBPRO_MSG_HEADER_LEN)
+ return NULL;
+
+ pm->u.rec_buffer = (u8 *)buffer_addr;
+ pm->rec_buffer_size = pm->rec_buffer_len = buffer_size;
+ pm->rec_ptr = pm->u.rec_buffer + PCAN_USBPRO_MSG_HEADER_LEN;
+
+ return pm->rec_ptr;
+}
+
+static u8 *pcan_msg_init_empty(struct pcan_usb_pro_msg *pm,
+ void *buffer_addr, int buffer_size)
+{
+ u8 *pr = pcan_msg_init(pm, buffer_addr, buffer_size);
+
+ if (pr) {
+ pm->rec_buffer_len = PCAN_USBPRO_MSG_HEADER_LEN;
+ *pm->u.rec_cnt = 0;
+ }
+ return pr;
+}
+
+/*
+ * add one record to a message being built
+ */
+static int pcan_msg_add_rec(struct pcan_usb_pro_msg *pm, u8 id, ...)
+{
+ int len, i;
+ u8 *pc;
+ va_list ap;
+
+ va_start(ap, id);
+
+ pc = pm->rec_ptr + 1;
+
+ i = 0;
+ switch (id) {
+ case PCAN_USBPRO_TXMSG8:
+ i += 4;
+ case PCAN_USBPRO_TXMSG4:
+ i += 4;
+ case PCAN_USBPRO_TXMSG0:
+ *pc++ = va_arg(ap, int);
+ *pc++ = va_arg(ap, int);
+ *pc++ = va_arg(ap, int);
+ *(u32 *)pc = cpu_to_le32(va_arg(ap, u32));
+ pc += 4;
+ memcpy(pc, va_arg(ap, int *), i);
+ pc += i;
+ break;
+
+ case PCAN_USBPRO_SETBTR:
+ case PCAN_USBPRO_GETDEVID:
+ *pc++ = va_arg(ap, int);
+ pc += 2;
+ *(u32 *)pc = cpu_to_le32(va_arg(ap, u32));
+ pc += 4;
+ break;
+
+ case PCAN_USBPRO_SETFILTR:
+ case PCAN_USBPRO_SETBUSACT:
+ case PCAN_USBPRO_SETSILENT:
+ *pc++ = va_arg(ap, int);
+ *(u16 *)pc = cpu_to_le16(va_arg(ap, int));
+ pc += 2;
+ break;
+
+ case PCAN_USBPRO_SETLED:
+ *pc++ = va_arg(ap, int);
+ *(u16 *)pc = cpu_to_le16(va_arg(ap, int));
+ pc += 2;
+ *(u32 *)pc = cpu_to_le32(va_arg(ap, u32));
+ pc += 4;
+ break;
+
+ case PCAN_USBPRO_SETTS:
+ pc++;
+ *(u16 *)pc = cpu_to_le16(va_arg(ap, int));
+ pc += 2;
+ break;
+
+ default:
+ pr_err("%s: %s(): unknown data type %02Xh (%d)\n",
+ PCAN_USB_DRIVER_NAME, __func__, id, id);
+ pc--;
+ break;
+ }
+
+ len = pc - pm->rec_ptr;
+ if (len > 0) {
+ *pm->u.rec_cnt = cpu_to_le32(*pm->u.rec_cnt+1);
+ *pm->rec_ptr = id;
+
+ pm->rec_ptr = pc;
+ pm->rec_buffer_len += len;
+ }
+
+ va_end(ap);
+
+ return len;
+}
+
+/*
+ * send PCAN-USB Pro command synchronously
+ */
+static int pcan_usb_pro_send_cmd(struct peak_usb_device *dev,
+ struct pcan_usb_pro_msg *pum)
+{
+ int actual_length;
+ int err;
+
+ /* usb device unregistered? */
+ if (!(dev->state & PCAN_USB_STATE_CONNECTED))
+ return 0;
+
+ err = usb_bulk_msg(dev->udev,
+ usb_sndbulkpipe(dev->udev, PCAN_USBPRO_EP_CMDOUT),
+ pum->u.rec_buffer, pum->rec_buffer_len,
+ &actual_length, PCAN_USBPRO_COMMAND_TIMEOUT);
+ if (err)
+ netdev_err(dev->netdev, "sending command failure: %d\n", err);
+
+ return err;
+}
+
+/*
+ * wait for PCAN-USB Pro command response
+ */
+static int pcan_usb_pro_wait_rsp(struct peak_usb_device *dev,
+ struct pcan_usb_pro_msg *pum)
+{
+ u8 req_data_type, req_channel;
+ int actual_length;
+ int i, err = 0;
+
+ /* usb device unregistered? */
+ if (!(dev->state & PCAN_USB_STATE_CONNECTED))
+ return 0;
+
+ req_data_type = pum->u.rec_buffer[4];
+ req_channel = pum->u.rec_buffer[5];
+
+ *pum->u.rec_cnt = 0;
+ for (i = 0; !err && i < PCAN_USBPRO_RSP_SUBMIT_MAX; i++) {
+ struct pcan_usb_pro_msg rsp;
+ union pcan_usb_pro_rec *pr;
+ u32 r, rec_cnt;
+ u16 rec_len;
+ u8 *pc;
+
+ err = usb_bulk_msg(dev->udev,
+ usb_rcvbulkpipe(dev->udev, PCAN_USBPRO_EP_CMDIN),
+ pum->u.rec_buffer, pum->rec_buffer_len,
+ &actual_length, PCAN_USBPRO_COMMAND_TIMEOUT);
+ if (err) {
+ netdev_err(dev->netdev, "waiting rsp error %d\n", err);
+ break;
+ }
+
+ if (actual_length == 0)
+ continue;
+
+ err = -EBADMSG;
+ if (actual_length < PCAN_USBPRO_MSG_HEADER_LEN) {
+ netdev_err(dev->netdev,
+ "got abnormal too small rsp (len=%d)\n",
+ actual_length);
+ break;
+ }
+
+ pc = pcan_msg_init(&rsp, pum->u.rec_buffer,
+ actual_length);
+
+ rec_cnt = le32_to_cpu(*rsp.u.rec_cnt);
+
+ /* loop on records stored into message */
+ for (r = 0; r < rec_cnt; r++) {
+ pr = (union pcan_usb_pro_rec *)pc;
+ rec_len = pcan_usb_pro_sizeof_rec[pr->data_type];
+ if (!rec_len) {
+ netdev_err(dev->netdev,
+ "got unprocessed record in msg\n");
+ dump_mem("rcvd rsp msg", pum->u.rec_buffer,
+ actual_length);
+ break;
+ }
+
+ /* check if response corresponds to request */
+ if (pr->data_type != req_data_type)
+ netdev_err(dev->netdev,
+ "got unwanted rsp %xh: ignored\n",
+ pr->data_type);
+
+ /* check if channel in response corresponds too */
+ else if ((req_channel != 0xff) && \
+ (pr->bus_act.channel != req_channel))
+ netdev_err(dev->netdev,
+ "got rsp %xh but on chan%u: ignored\n",
+ req_data_type, pr->bus_act.channel);
+
+ /* got the response */
+ else
+ return 0;
+
+ /* otherwise, go on with next record in message */
+ pc += rec_len;
+ }
+ }
+
+ return (i >= PCAN_USBPRO_RSP_SUBMIT_MAX) ? -ERANGE : err;
+}
+
+static int pcan_usb_pro_send_req(struct peak_usb_device *dev, int req_id,
+ int req_value, void *req_addr, int req_size)
+{
+ int err;
+ u8 req_type;
+ unsigned int p;
+
+ /* usb device unregistered? */
+ if (!(dev->state & PCAN_USB_STATE_CONNECTED))
+ return 0;
+
+ memset(req_addr, '\0', req_size);
+
+ req_type = USB_TYPE_VENDOR | USB_RECIP_OTHER;
+
+ switch (req_id) {
+ case PCAN_USBPRO_REQ_FCT:
+ p = usb_sndctrlpipe(dev->udev, 0);
+ break;
+
+ default:
+ p = usb_rcvctrlpipe(dev->udev, 0);
+ req_type |= USB_DIR_IN;
+ break;
+ }
+
+ err = usb_control_msg(dev->udev, p, req_id, req_type, req_value, 0,
+ req_addr, req_size, 2 * USB_CTRL_GET_TIMEOUT);
+ if (err < 0) {
+ netdev_info(dev->netdev,
+ "unable to request usb[type=%d value=%d] err=%d\n",
+ req_id, req_value, err);
+ return err;
+ }
+
+ return 0;
+}
+
+static int pcan_usb_pro_set_ts(struct peak_usb_device *dev, u16 onoff)
+{
+ struct pcan_usb_pro_msg um;
+
+ pcan_msg_init_empty(&um, dev->cmd_buf, PCAN_USB_MAX_CMD_LEN);
+ pcan_msg_add_rec(&um, PCAN_USBPRO_SETTS, onoff);
+
+ return pcan_usb_pro_send_cmd(dev, &um);
+}
+
+static int pcan_usb_pro_set_bitrate(struct peak_usb_device *dev, u32 ccbt)
+{
+ struct pcan_usb_pro_device *pdev =
+ container_of(dev, struct pcan_usb_pro_device, dev);
+ struct pcan_usb_pro_msg um;
+
+ pcan_msg_init_empty(&um, dev->cmd_buf, PCAN_USB_MAX_CMD_LEN);
+ pcan_msg_add_rec(&um, PCAN_USBPRO_SETBTR, dev->ctrl_idx, ccbt);
+
+ /* cache the CCBT value to reuse it before next buson */
+ pdev->cached_ccbt = ccbt;
+
+ return pcan_usb_pro_send_cmd(dev, &um);
+}
+
+static int pcan_usb_pro_set_bus(struct peak_usb_device *dev, u8 onoff)
+{
+ struct pcan_usb_pro_msg um;
+
+ /* if bus=on, be sure the bitrate being set before! */
+ if (onoff) {
+ struct pcan_usb_pro_device *pdev =
+ container_of(dev, struct pcan_usb_pro_device, dev);
+
+ pcan_usb_pro_set_bitrate(dev, pdev->cached_ccbt);
+ }
+
+ pcan_msg_init_empty(&um, dev->cmd_buf, PCAN_USB_MAX_CMD_LEN);
+ pcan_msg_add_rec(&um, PCAN_USBPRO_SETBUSACT, dev->ctrl_idx, onoff);
+
+ return pcan_usb_pro_send_cmd(dev, &um);
+}
+
+static int pcan_usb_pro_set_silent(struct peak_usb_device *dev, u8 onoff)
+{
+ struct pcan_usb_pro_msg um;
+
+ pcan_msg_init_empty(&um, dev->cmd_buf, PCAN_USB_MAX_CMD_LEN);
+ pcan_msg_add_rec(&um, PCAN_USBPRO_SETSILENT, dev->ctrl_idx, onoff);
+
+ return pcan_usb_pro_send_cmd(dev, &um);
+}
+
+static int pcan_usb_pro_set_filter(struct peak_usb_device *dev, u16 filter_mode)
+{
+ struct pcan_usb_pro_msg um;
+
+ pcan_msg_init_empty(&um, dev->cmd_buf, PCAN_USB_MAX_CMD_LEN);
+ pcan_msg_add_rec(&um, PCAN_USBPRO_SETFILTR, dev->ctrl_idx, filter_mode);
+
+ return pcan_usb_pro_send_cmd(dev, &um);
+}
+
+static int pcan_usb_pro_set_led(struct peak_usb_device *dev, u8 mode,
+ u32 timeout)
+{
+ struct pcan_usb_pro_msg um;
+
+ pcan_msg_init_empty(&um, dev->cmd_buf, PCAN_USB_MAX_CMD_LEN);
+ pcan_msg_add_rec(&um, PCAN_USBPRO_SETLED, dev->ctrl_idx, mode, timeout);
+
+ return pcan_usb_pro_send_cmd(dev, &um);
+}
+
+static int pcan_usb_pro_get_device_id(struct peak_usb_device *dev,
+ u32 *device_id)
+{
+ struct pcan_usb_pro_devid *pdn;
+ struct pcan_usb_pro_msg um;
+ int err;
+ u8 *pc;
+
+ pc = pcan_msg_init_empty(&um, dev->cmd_buf, PCAN_USB_MAX_CMD_LEN);
+ pcan_msg_add_rec(&um, PCAN_USBPRO_GETDEVID, dev->ctrl_idx);
+
+ err = pcan_usb_pro_send_cmd(dev, &um);
+ if (err)
+ return err;
+
+ err = pcan_usb_pro_wait_rsp(dev, &um);
+ if (err)
+ return err;
+
+ pdn = (struct pcan_usb_pro_devid *)pc;
+ if (device_id)
+ *device_id = le32_to_cpu(pdn->serial_num);
+
+ return err;
+}
+
+static int pcan_usb_pro_set_bittiming(struct peak_usb_device *dev,
+ struct can_bittiming *bt)
+{
+ u32 ccbt;
+
+ ccbt = (dev->can.ctrlmode & CAN_CTRLMODE_3_SAMPLES) ? 0x00800000 : 0;
+ ccbt |= (bt->sjw - 1) << 24;
+ ccbt |= (bt->phase_seg2 - 1) << 20;
+ ccbt |= (bt->prop_seg + bt->phase_seg1 - 1) << 16; /* = tseg1 */
+ ccbt |= bt->brp - 1;
+
+ netdev_info(dev->netdev, "setting ccbt=0x%08x\n", ccbt);
+
+ return pcan_usb_pro_set_bitrate(dev, ccbt);
+}
+
+static void pcan_usb_pro_restart_complete(struct urb *urb)
+{
+ /* can delete usb resources */
+ peak_usb_async_complete(urb);
+
+ /* notify candev and netdev */
+ peak_usb_restart_complete(urb->context);
+}
+
+/*
+ * handle restart but in asynchronously way
+ */
+static int pcan_usb_pro_restart_async(struct peak_usb_device *dev,
+ struct urb *urb, u8 *buf)
+{
+ struct pcan_usb_pro_msg um;
+
+ pcan_msg_init_empty(&um, buf, PCAN_USB_MAX_CMD_LEN);
+ pcan_msg_add_rec(&um, PCAN_USBPRO_SETBUSACT, dev->ctrl_idx, 1);
+
+ usb_fill_bulk_urb(urb, dev->udev,
+ usb_sndbulkpipe(dev->udev, PCAN_USBPRO_EP_CMDOUT),
+ buf, PCAN_USB_MAX_CMD_LEN,
+ pcan_usb_pro_restart_complete, dev);
+
+ return usb_submit_urb(urb, GFP_ATOMIC);
+}
+
+static void pcan_usb_pro_drv_loaded(struct peak_usb_device *dev, int loaded)
+{
+ u8 buffer[16];
+
+ buffer[0] = 0;
+ buffer[1] = !!loaded;
+
+ pcan_usb_pro_send_req(dev, PCAN_USBPRO_REQ_FCT,
+ PCAN_USBPRO_FCT_DRVLD, buffer, sizeof(buffer));
+}
+
+static inline
+struct pcan_usb_pro_interface *pcan_usb_pro_dev_if(struct peak_usb_device *dev)
+{
+ struct pcan_usb_pro_device *pdev =
+ container_of(dev, struct pcan_usb_pro_device, dev);
+ return pdev->usb_if;
+}
+
+static int pcan_usb_pro_handle_canmsg(struct pcan_usb_pro_interface *usb_if,
+ struct pcan_usb_pro_rxmsg *rx)
+{
+ const unsigned int ctrl_idx = (rx->len >> 4) & 0x0f;
+ struct peak_usb_device *dev = usb_if->dev[ctrl_idx];
+ struct net_device *netdev = dev->netdev;
+ struct can_frame *can_frame;
+ struct sk_buff *skb;
+ struct timeval tv;
+
+ skb = alloc_can_skb(netdev, &can_frame);
+ if (!skb)
+ return -ENOMEM;
+
+ can_frame->can_id = le32_to_cpu(rx->id);
+ can_frame->can_dlc = rx->len & 0x0f;
+
+ if (rx->flags & PCAN_USBPRO_EXT)
+ can_frame->can_id |= CAN_EFF_FLAG;
+
+ if (rx->flags & PCAN_USBPRO_RTR)
+ can_frame->can_id |= CAN_RTR_FLAG;
+ else
+ memcpy(can_frame->data, rx->data, can_frame->can_dlc);
+
+ peak_usb_get_ts_tv(&usb_if->time_ref, le32_to_cpu(rx->ts32), &tv);
+ skb->tstamp = timeval_to_ktime(tv);
+
+ netif_rx(skb);
+ netdev->stats.rx_packets++;
+ netdev->stats.rx_bytes += can_frame->can_dlc;
+
+ return 0;
+}
+
+static int pcan_usb_pro_handle_error(struct pcan_usb_pro_interface *usb_if,
+ struct pcan_usb_pro_rxstatus *er)
+{
+ const u32 raw_status = le32_to_cpu(er->status);
+ const unsigned int ctrl_idx = (er->channel >> 4) & 0x0f;
+ struct peak_usb_device *dev = usb_if->dev[ctrl_idx];
+ struct net_device *netdev = dev->netdev;
+ struct can_frame *can_frame;
+ enum can_state new_state = CAN_STATE_ERROR_ACTIVE;
+ u8 err_mask = 0;
+ struct sk_buff *skb;
+ struct timeval tv;
+
+ /* nothing should be sent while in BUS_OFF state */
+ if (dev->can.state == CAN_STATE_BUS_OFF)
+ return 0;
+
+ if (!raw_status) {
+ /* no error bit (back to active state) */
+ dev->can.state = CAN_STATE_ERROR_ACTIVE;
+ return 0;
+ }
+
+ if (raw_status & (PCAN_USBPRO_STATUS_OVERRUN |
+ PCAN_USBPRO_STATUS_QOVERRUN)) {
+ /* trick to bypass next comparison and process other errors */
+ new_state = CAN_STATE_MAX;
+ }
+
+ if (raw_status & PCAN_USBPRO_STATUS_BUS) {
+ new_state = CAN_STATE_BUS_OFF;
+ } else if (raw_status & PCAN_USBPRO_STATUS_ERROR) {
+ u32 rx_err_cnt = (le32_to_cpu(er->err_frm) & 0x00ff0000) >> 16;
+ u32 tx_err_cnt = (le32_to_cpu(er->err_frm) & 0xff000000) >> 24;
+
+ if (rx_err_cnt > 127)
+ err_mask |= CAN_ERR_CRTL_RX_PASSIVE;
+ else if (rx_err_cnt > 96)
+ err_mask |= CAN_ERR_CRTL_RX_WARNING;
+
+ if (tx_err_cnt > 127)
+ err_mask |= CAN_ERR_CRTL_TX_PASSIVE;
+ else if (tx_err_cnt > 96)
+ err_mask |= CAN_ERR_CRTL_TX_WARNING;
+
+ if (err_mask & (CAN_ERR_CRTL_RX_WARNING |
+ CAN_ERR_CRTL_TX_WARNING))
+ new_state = CAN_STATE_ERROR_WARNING;
+ else if (err_mask & (CAN_ERR_CRTL_RX_PASSIVE |
+ CAN_ERR_CRTL_TX_PASSIVE))
+ new_state = CAN_STATE_ERROR_PASSIVE;
+ }
+
+ /* donot post any error if current state didn't change */
+ if (dev->can.state == new_state)
+ return 0;
+
+ /* allocate an skb to store the error frame */
+ skb = alloc_can_err_skb(netdev, &can_frame);
+ if (!skb)
+ return -ENOMEM;
+
+ switch (new_state) {
+ case CAN_STATE_BUS_OFF:
+ can_frame->can_id |= CAN_ERR_BUSOFF;
+ can_bus_off(netdev);
+ break;
+
+ case CAN_STATE_ERROR_PASSIVE:
+ can_frame->can_id |= CAN_ERR_CRTL;
+ can_frame->data[1] |= err_mask;
+ dev->can.can_stats.error_passive++;
+ break;
+
+ case CAN_STATE_ERROR_WARNING:
+ can_frame->can_id |= CAN_ERR_CRTL;
+ can_frame->data[1] |= err_mask;
+ dev->can.can_stats.error_warning++;
+ break;
+
+ case CAN_STATE_ERROR_ACTIVE:
+ break;
+
+ default:
+ /* CAN_STATE_MAX (trick to handle other errors) */
+ if (raw_status & PCAN_USBPRO_STATUS_OVERRUN) {
+ can_frame->can_id |= CAN_ERR_PROT;
+ can_frame->data[2] |= CAN_ERR_PROT_OVERLOAD;
+ netdev->stats.rx_over_errors++;
+ netdev->stats.rx_errors++;
+ }
+
+ if (raw_status & PCAN_USBPRO_STATUS_QOVERRUN) {
+ can_frame->can_id |= CAN_ERR_CRTL;
+ can_frame->data[1] |= CAN_ERR_CRTL_RX_OVERFLOW;
+ netdev->stats.rx_over_errors++;
+ netdev->stats.rx_errors++;
+ }
+
+ new_state = CAN_STATE_ERROR_ACTIVE;
+ break;
+ }
+
+ dev->can.state = new_state;
+
+ peak_usb_get_ts_tv(&usb_if->time_ref, le32_to_cpu(er->ts32), &tv);
+ skb->tstamp = timeval_to_ktime(tv);
+ netif_rx(skb);
+ netdev->stats.rx_packets++;
+ netdev->stats.rx_bytes += can_frame->can_dlc;
+
+ return 0;
+}
+
+static void pcan_usb_pro_handle_ts(struct pcan_usb_pro_interface *usb_if,
+ struct pcan_usb_pro_rxts *ts)
+{
+ /* should wait until clock is stabilized */
+ if (usb_if->cm_ignore_count > 0)
+ usb_if->cm_ignore_count--;
+ else
+ peak_usb_set_ts_now(&usb_if->time_ref,
+ le32_to_cpu(ts->ts64[1]));
+}
+
+/*
+ * callback for bulk IN urb
+ */
+static int pcan_usb_pro_decode_buf(struct peak_usb_device *dev, struct urb *urb)
+{
+ struct pcan_usb_pro_interface *usb_if = pcan_usb_pro_dev_if(dev);
+ struct net_device *netdev = dev->netdev;
+ struct pcan_usb_pro_msg usb_msg;
+ u8 *rec_ptr, *msg_end;
+ u16 rec_cnt;
+ int err = 0;
+
+ rec_ptr = pcan_msg_init(&usb_msg, urb->transfer_buffer,
+ urb->actual_length);
+ if (!rec_ptr) {
+ netdev_err(netdev, "bad msg hdr len %d\n", urb->actual_length);
+ return -EINVAL;
+ }
+
+ /* loop reading all the records from the incoming message */
+ msg_end = urb->transfer_buffer + urb->actual_length;
+ rec_cnt = le16_to_cpu(*usb_msg.u.rec_cnt_rd);
+ for (; rec_cnt > 0; rec_cnt--) {
+ union pcan_usb_pro_rec *pr = (union pcan_usb_pro_rec *)rec_ptr;
+ u16 sizeof_rec = pcan_usb_pro_sizeof_rec[pr->data_type];
+
+ if (!sizeof_rec) {
+ netdev_err(netdev,
+ "got unsupported rec in usb msg:\n");
+ err = -ENOTSUPP;
+ break;
+ }
+
+ /* check if the record goes out of current packet */
+ if (rec_ptr + sizeof_rec > msg_end) {
+ netdev_err(netdev,
+ "got frag rec: should inc usb rx buf size\n");
+ err = -EBADMSG;
+ break;
+ }
+
+ switch (pr->data_type) {
+ case PCAN_USBPRO_RXMSG8:
+ case PCAN_USBPRO_RXMSG4:
+ case PCAN_USBPRO_RXMSG0:
+ case PCAN_USBPRO_RXRTR:
+ err = pcan_usb_pro_handle_canmsg(usb_if, &pr->rx_msg);
+ if (err < 0)
+ goto fail;
+ break;
+
+ case PCAN_USBPRO_RXSTATUS:
+ err = pcan_usb_pro_handle_error(usb_if, &pr->rx_status);
+ if (err < 0)
+ goto fail;
+ break;
+
+ case PCAN_USBPRO_RXTS:
+ pcan_usb_pro_handle_ts(usb_if, &pr->rx_ts);
+ break;
+
+ default:
+ netdev_err(netdev,
+ "unhandled rec type 0x%02x (%d): ignored\n",
+ pr->data_type, pr->data_type);
+ break;
+ }
+
+ rec_ptr += sizeof_rec;
+ }
+
+fail:
+ if (err)
+ dump_mem("received msg",
+ urb->transfer_buffer, urb->actual_length);
+
+ return err;
+}
+
+static int pcan_usb_pro_encode_msg(struct peak_usb_device *dev,
+ struct sk_buff *skb, u8 *obuf, size_t *size)
+{
+ struct can_frame *cf = (struct can_frame *)skb->data;
+ u8 data_type, len, flags;
+ struct pcan_usb_pro_msg usb_msg;
+
+ pcan_msg_init_empty(&usb_msg, obuf, *size);
+
+ if ((cf->can_id & CAN_RTR_FLAG) || (cf->can_dlc == 0))
+ data_type = PCAN_USBPRO_TXMSG0;
+ else if (cf->can_dlc <= 4)
+ data_type = PCAN_USBPRO_TXMSG4;
+ else
+ data_type = PCAN_USBPRO_TXMSG8;
+
+ len = (dev->ctrl_idx << 4) | (cf->can_dlc & 0x0f);
+
+ flags = 0;
+ if (cf->can_id & CAN_EFF_FLAG)
+ flags |= 0x02;
+ if (cf->can_id & CAN_RTR_FLAG)
+ flags |= 0x01;
+
+ pcan_msg_add_rec(&usb_msg, data_type, 0, flags, len, cf->can_id,
+ cf->data);
+
+ *size = usb_msg.rec_buffer_len;
+
+ return 0;
+}
+
+static int pcan_usb_pro_start(struct peak_usb_device *dev)
+{
+ struct pcan_usb_pro_device *pdev =
+ container_of(dev, struct pcan_usb_pro_device, dev);
+ int err;
+
+ err = pcan_usb_pro_set_silent(dev,
+ dev->can.ctrlmode & CAN_CTRLMODE_LISTENONLY);
+ if (err)
+ return err;
+
+ /* filter mode: 0-> All OFF; 1->bypass */
+ err = pcan_usb_pro_set_filter(dev, 1);
+ if (err)
+ return err;
+
+ /* opening first device: */
+ if (pdev->usb_if->dev_opened_count == 0) {
+ /* reset time_ref */
+ peak_usb_init_time_ref(&pdev->usb_if->time_ref, &pcan_usb_pro);
+
+ /* ask device to send ts messages */
+ err = pcan_usb_pro_set_ts(dev, 1);
+ }
+
+ pdev->usb_if->dev_opened_count++;
+
+ return err;
+}
+
+/*
+ * stop interface
+ * (last chance before set bus off)
+ */
+static int pcan_usb_pro_stop(struct peak_usb_device *dev)
+{
+ struct pcan_usb_pro_device *pdev =
+ container_of(dev, struct pcan_usb_pro_device, dev);
+
+ /* turn off ts msgs for that interface if no other dev opened */
+ if (pdev->usb_if->dev_opened_count == 1)
+ pcan_usb_pro_set_ts(dev, 0);
+
+ pdev->usb_if->dev_opened_count--;
+
+ return 0;
+}
+
+/*
+ * called when probing to initialize a device object.
+ */
+static int pcan_usb_pro_init(struct peak_usb_device *dev)
+{
+ struct pcan_usb_pro_interface *usb_if;
+ struct pcan_usb_pro_device *pdev =
+ container_of(dev, struct pcan_usb_pro_device, dev);
+
+ /* do this for 1st channel only */
+ if (!dev->prev_siblings) {
+ struct pcan_usb_pro_fwinfo fi;
+ struct pcan_usb_pro_blinfo bi;
+ int err;
+
+ /* allocate netdevices common structure attached to first one */
+ usb_if = kzalloc(sizeof(struct pcan_usb_pro_interface),
+ GFP_KERNEL);
+ if (!usb_if)
+ return -ENOMEM;
+
+ /* number of ts msgs to ignore before taking one into account */
+ usb_if->cm_ignore_count = 5;
+
+ /*
+ * explicit use of dev_xxx() instead of netdev_xxx() here:
+ * information displayed are related to the device itself, not
+ * to the canx netdevices.
+ */
+ err = pcan_usb_pro_send_req(dev, PCAN_USBPRO_REQ_INFO,
+ PCAN_USBPRO_INFO_FW,
+ &fi, sizeof(fi));
+ if (err) {
+ dev_err(dev->netdev->dev.parent,
+ "unable to read %s firmware info (err %d)\n",
+ pcan_usb_pro.name, err);
+ return err;
+ }
+
+ err = pcan_usb_pro_send_req(dev, PCAN_USBPRO_REQ_INFO,
+ PCAN_USBPRO_INFO_BL,
+ &bi, sizeof(bi));
+ if (err) {
+ dev_err(dev->netdev->dev.parent,
+ "unable to read %s bootloader info (err %d)\n",
+ pcan_usb_pro.name, err);
+ return err;
+ }
+
+ dev_info(dev->netdev->dev.parent,
+ "PEAK-System %s hwrev %u serial %08X.%08X (%u channels)\n",
+ pcan_usb_pro.name,
+ bi.hw_rev, bi.serial_num_hi, bi.serial_num_lo,
+ pcan_usb_pro.ctrl_count);
+
+ /* tell the device the can driver is running */
+ pcan_usb_pro_drv_loaded(dev, 1);
+ } else {
+ usb_if = pcan_usb_pro_dev_if(dev->prev_siblings);
+ }
+
+ pdev->usb_if = usb_if;
+ usb_if->dev[dev->ctrl_idx] = dev;
+
+ /* set LED in default state (end of init phase) */
+ pcan_usb_pro_set_led(dev, 0, 1);
+
+ return 0;
+}
+
+static void pcan_usb_pro_exit(struct peak_usb_device *dev)
+{
+ struct pcan_usb_pro_device *pdev =
+ container_of(dev, struct pcan_usb_pro_device, dev);
+
+ /*
+ * when rmmod called before unplug and if down, should reset things
+ * before leaving
+ */
+ if (dev->can.state != CAN_STATE_STOPPED) {
+ /* set bus off on the corresponding channel */
+ pcan_usb_pro_set_bus(dev, 0);
+ }
+
+ /* if channel #0 (only) */
+ if (dev->ctrl_idx == 0) {
+ /* turn off calibration message if any device were opened */
+ if (pdev->usb_if->dev_opened_count > 0)
+ pcan_usb_pro_set_ts(dev, 0);
+
+ /* tell the PCAN-USB Pro device the driver is being unloaded */
+ pcan_usb_pro_drv_loaded(dev, 0);
+ }
+}
+
+/*
+ * called when PCAN-USB Pro adapter is unplugged
+ */
+static void pcan_usb_pro_free(struct peak_usb_device *dev)
+{
+ /* last device: can free pcan_usb_pro_interface object now */
+ if (!dev->prev_siblings && !dev->next_siblings)
+ kfree(pcan_usb_pro_dev_if(dev));
+}
+
+/*
+ * probe function for new PCAN-USB Pro usb interface
+ */
+static int pcan_usb_pro_probe(struct usb_interface *intf)
+{
+ struct usb_host_interface *if_desc;
+ int i;
+
+ if_desc = intf->altsetting;
+
+ /* check interface endpoint addresses */
+ for (i = 0; i < if_desc->desc.bNumEndpoints; i++) {
+ struct usb_endpoint_descriptor *ep = &if_desc->endpoint[i].desc;
+
+ /*
+ * below is the list of valid ep addreses. Any other ep address
+ * is considered as not-CAN interface address => no dev created
+ */
+ switch (ep->bEndpointAddress) {
+ case PCAN_USBPRO_EP_CMDOUT:
+ case PCAN_USBPRO_EP_CMDIN:
+ case PCAN_USBPRO_EP_MSGOUT_0:
+ case PCAN_USBPRO_EP_MSGOUT_1:
+ case PCAN_USBPRO_EP_MSGIN:
+ case PCAN_USBPRO_EP_UNUSED:
+ break;
+ default:
+ return -ENODEV;
+ }
+ }
+
+ return 0;
+}
+
+/*
+ * describe the PCAN-USB Pro adapter
+ */
+struct peak_usb_adapter pcan_usb_pro = {
+ .name = "PCAN-USB Pro",
+ .device_id = PCAN_USBPRO_PRODUCT_ID,
+ .ctrl_count = PCAN_USBPRO_CHANNEL_COUNT,
+ .clock = {
+ .freq = PCAN_USBPRO_CRYSTAL_HZ,
+ },
+ .bittiming_const = {
+ .name = "pcan_usb_pro",
+ .tseg1_min = 1,
+ .tseg1_max = 16,
+ .tseg2_min = 1,
+ .tseg2_max = 8,
+ .sjw_max = 4,
+ .brp_min = 1,
+ .brp_max = 1024,
+ .brp_inc = 1,
+ },
+
+ /* size of device private data */
+ .sizeof_dev_private = sizeof(struct pcan_usb_pro_device),
+
+ /* timestamps usage */
+ .ts_used_bits = 32,
+ .ts_period = 1000000, /* calibration period in ts. */
+ .us_per_ts_scale = 1, /* us = (ts * scale) >> shift */
+ .us_per_ts_shift = 0,
+
+ /* give here messages in/out endpoints */
+ .ep_msg_in = PCAN_USBPRO_EP_MSGIN,
+ .ep_msg_out = {PCAN_USBPRO_EP_MSGOUT_0, PCAN_USBPRO_EP_MSGOUT_1},
+
+ /* size of rx/tx usb buffers */
+ .rx_buffer_size = PCAN_USBPRO_RX_BUFFER_SIZE,
+ .tx_buffer_size = PCAN_USBPRO_TX_BUFFER_SIZE,
+
+ /* device callbacks */
+ .intf_probe = pcan_usb_pro_probe,
+ .dev_init = pcan_usb_pro_init,
+ .dev_exit = pcan_usb_pro_exit,
+ .dev_free = pcan_usb_pro_free,
+ .dev_set_bus = pcan_usb_pro_set_bus,
+ .dev_set_bittiming = pcan_usb_pro_set_bittiming,
+ .dev_get_device_id = pcan_usb_pro_get_device_id,
+ .dev_decode_buf = pcan_usb_pro_decode_buf,
+ .dev_encode_msg = pcan_usb_pro_encode_msg,
+ .dev_start = pcan_usb_pro_start,
+ .dev_stop = pcan_usb_pro_stop,
+ .dev_restart_async = pcan_usb_pro_restart_async,
+};
diff --git a/drivers/net/can/usb/peak_usb/pcan_usb_pro.h b/drivers/net/can/usb/peak_usb/pcan_usb_pro.h
new file mode 100644
index 00000000000..a869918c562
--- /dev/null
+++ b/drivers/net/can/usb/peak_usb/pcan_usb_pro.h
@@ -0,0 +1,178 @@
+/*
+ * CAN driver for PEAK System PCAN-USB Pro adapter
+ * Derived from the PCAN project file driver/src/pcan_usbpro_fw.h
+ *
+ * Copyright (C) 2003-2011 PEAK System-Technik GmbH
+ * Copyright (C) 2011-2012 Stephane Grosjean <s.grosjean@peak-system.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published
+ * 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.
+ */
+#ifndef PCAN_USB_PRO_H
+#define PCAN_USB_PRO_H
+
+/*
+ * USB Vendor request data types
+ */
+#define PCAN_USBPRO_REQ_INFO 0
+#define PCAN_USBPRO_REQ_FCT 2
+
+/* Vendor Request value for XXX_INFO */
+#define PCAN_USBPRO_INFO_BL 0
+#define PCAN_USBPRO_INFO_FW 1
+
+/* Vendor Request value for XXX_FCT */
+#define PCAN_USBPRO_FCT_DRVLD 5 /* tell device driver is loaded */
+
+/* PCAN_USBPRO_INFO_BL vendor request record type */
+struct __packed pcan_usb_pro_blinfo {
+ u32 ctrl_type;
+ u8 version[4];
+ u8 day;
+ u8 month;
+ u8 year;
+ u8 dummy;
+ u32 serial_num_hi;
+ u32 serial_num_lo;
+ u32 hw_type;
+ u32 hw_rev;
+};
+
+/* PCAN_USBPRO_INFO_FW vendor request record type */
+struct __packed pcan_usb_pro_fwinfo {
+ u32 ctrl_type;
+ u8 version[4];
+ u8 day;
+ u8 month;
+ u8 year;
+ u8 dummy;
+ u32 fw_type;
+};
+
+/*
+ * USB Command record types
+ */
+#define PCAN_USBPRO_SETBTR 0x02
+#define PCAN_USBPRO_SETBUSACT 0x04
+#define PCAN_USBPRO_SETSILENT 0x05
+#define PCAN_USBPRO_SETFILTR 0x0a
+#define PCAN_USBPRO_SETTS 0x10
+#define PCAN_USBPRO_GETDEVID 0x12
+#define PCAN_USBPRO_SETLED 0x1C
+#define PCAN_USBPRO_RXMSG8 0x80
+#define PCAN_USBPRO_RXMSG4 0x81
+#define PCAN_USBPRO_RXMSG0 0x82
+#define PCAN_USBPRO_RXRTR 0x83
+#define PCAN_USBPRO_RXSTATUS 0x84
+#define PCAN_USBPRO_RXTS 0x85
+#define PCAN_USBPRO_TXMSG8 0x41
+#define PCAN_USBPRO_TXMSG4 0x42
+#define PCAN_USBPRO_TXMSG0 0x43
+
+/* record structures */
+struct __packed pcan_usb_pro_btr {
+ u8 data_type;
+ u8 channel;
+ u16 dummy;
+ u32 CCBT;
+};
+
+struct __packed pcan_usb_pro_busact {
+ u8 data_type;
+ u8 channel;
+ u16 onoff;
+};
+
+struct __packed pcan_usb_pro_silent {
+ u8 data_type;
+ u8 channel;
+ u16 onoff;
+};
+
+struct __packed pcan_usb_pro_filter {
+ u8 data_type;
+ u8 dummy;
+ u16 filter_mode;
+};
+
+struct __packed pcan_usb_pro_setts {
+ u8 data_type;
+ u8 dummy;
+ u16 mode;
+};
+
+struct __packed pcan_usb_pro_devid {
+ u8 data_type;
+ u8 channel;
+ u16 dummy;
+ u32 serial_num;
+};
+
+struct __packed pcan_usb_pro_setled {
+ u8 data_type;
+ u8 channel;
+ u16 mode;
+ u32 timeout;
+};
+
+struct __packed pcan_usb_pro_rxmsg {
+ u8 data_type;
+ u8 client;
+ u8 flags;
+ u8 len;
+ u32 ts32;
+ u32 id;
+
+ u8 data[8];
+};
+
+#define PCAN_USBPRO_STATUS_ERROR 0x0001
+#define PCAN_USBPRO_STATUS_BUS 0x0002
+#define PCAN_USBPRO_STATUS_OVERRUN 0x0004
+#define PCAN_USBPRO_STATUS_QOVERRUN 0x0008
+
+struct __packed pcan_usb_pro_rxstatus {
+ u8 data_type;
+ u8 channel;
+ u16 status;
+ u32 ts32;
+ u32 err_frm;
+};
+
+struct __packed pcan_usb_pro_rxts {
+ u8 data_type;
+ u8 dummy[3];
+ u32 ts64[2];
+};
+
+struct __packed pcan_usb_pro_txmsg {
+ u8 data_type;
+ u8 client;
+ u8 flags;
+ u8 len;
+ u32 id;
+ u8 data[8];
+};
+
+union pcan_usb_pro_rec {
+ u8 data_type;
+ struct pcan_usb_pro_btr btr;
+ struct pcan_usb_pro_busact bus_act;
+ struct pcan_usb_pro_silent silent_mode;
+ struct pcan_usb_pro_filter filter_mode;
+ struct pcan_usb_pro_setts ts;
+ struct pcan_usb_pro_devid dev_id;
+ struct pcan_usb_pro_setled set_led;
+ struct pcan_usb_pro_rxmsg rx_msg;
+ struct pcan_usb_pro_rxstatus rx_status;
+ struct pcan_usb_pro_rxts rx_ts;
+ struct pcan_usb_pro_txmsg tx_msg;
+};
+
+#endif