* [PATCH] Add support for PEAK System PCAN-USB adapter
@ 2011-12-22 13:13 Stephane Grosjean
2011-12-23 19:38 ` Sebastian Haas
2012-01-10 10:41 ` Wolfgang Grandegger
0 siblings, 2 replies; 5+ messages in thread
From: Stephane Grosjean @ 2011-12-22 13:13 UTC (permalink / raw)
To: Oliver Hartkopp; +Cc: Linux CAN mailing list
[-- Attachment #1: Type: text/plain, Size: 17637 bytes --]
From 2b369b236b320b4382815c86338f893fadc6476c Mon Sep 17 00:00:00 2001
From: Stephane Grosjean <s.grosjean@peak-system.com>
Date: Thu, 22 Dec 2011 13:57:04 +0100
Subject: [PATCH] Add support for PEAK System PCAN-USB adapter
---
drivers/net/can/usb/peak_usb/pcan_usb.c | 749 +++++++++++++++++++++++++++++++
1 files changed, 749 insertions(+), 0 deletions(-)
create mode 100644 drivers/net/can/usb/peak_usb/pcan_usb.c
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 0000000..1a427be
--- /dev/null
+++ b/drivers/net/can/usb/peak_usb/pcan_usb.c
@@ -0,0 +1,749 @@
+/*
+ * CAN driver for PEAK System PCAN-USB adapter
+ *
+ * Copyright (C) 2011-2012 PEAK-System GmbH
+ *
+ * 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 "peak_usb.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 parameter command */
+#define PCAN_USB_PARAMETER_LEN 14
+struct __packed pcan_usb_parameter {
+ u8 function;
+ u8 number;
+ u8 parameters[PCAN_USB_PARAMETER_LEN];
+};
+
+/* PCAN-USB command timeout (ms.) */
+#define PCAN_USB_COMMAND_TIMEOUT 1000
+
+/* 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
+#define PCAN_USB_REC_EXT 10
+
+/* private to PCAN-USB adapter */
+struct pcan_usb {
+ struct peak_usb_device dev; /* must be the first member */
+ struct peak_time_ref time_ref;
+};
+
+/* 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;
+ struct pcan_usb_parameter cmd = {
+ .function = f,
+ .number = n,
+ };
+
+ /* usb device unregistered? */
+ if (!(dev->state & PCAN_USB_STATE_CONNECTED))
+ return 0;
+
+ if (p)
+ memcpy(cmd.parameters, p, ARRAY_SIZE(cmd.parameters));
+
+ err = usb_bulk_msg(dev->udev,
+ usb_sndbulkpipe(dev->udev, PCAN_USB_EP_CMDOUT), &cmd,
+ sizeof(struct pcan_usb_parameter), &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;
+ struct pcan_usb_parameter cmd = {
+ .function = f,
+ .number = n,
+ };
+
+ /* 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), &cmd,
+ sizeof(struct pcan_usb_parameter), &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, cmd.parameters, ARRAY_SIZE(cmd.parameters));
+
+ return err;
+}
+
+static int pcan_usb_set_sja1000(struct peak_usb_device *dev, u8 mode)
+{
+ u8 args[PCAN_USB_PARAMETER_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_PARAMETER_LEN] = {
+ [0] = onoff ? 1 : 0,
+ };
+
+ 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_PARAMETER_LEN] = {
+ [0] = onoff ? 1 : 0,
+ };
+
+ 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_PARAMETER_LEN] = {
+ [0] = onoff ? 1 : 0,
+ };
+
+ 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_PARAMETER_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;
+
+ args[0] = btr1;
+ args[1] = btr0;
+
+ netdev_dbg(dev->netdev, "btr0=0x%02x btr1=0x%02x\n", btr0, btr1);
+
+ 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);
+
+ return err;
+}
+
+/*
+ * read serial number from device
+ */
+static int pcan_usb_get_serial(struct peak_usb_device *dev, u32 *serial_number)
+{
+ u8 args[PCAN_USB_PARAMETER_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_PARAMETER_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;
+}
+
+/*
+ * 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);
+ struct sk_buff *skb;
+ struct can_frame *cf;
+ struct timeval tv;
+ u8 f, n;
+
+ /* check whether function and number can be read */
+ if ((mc->ptr + 2) > mc->end)
+ return -EINVAL;
+
+ f = mc->ptr[0];
+ n = mc->ptr[1];
+ mc->ptr += 2;
+
+ 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:
+ /* no status flag => ignore record */
+ if (!n)
+ break;
+
+ /* ignore this error until 1st ts received */
+ if (n == PCAN_USB_ERROR_QOVR)
+ if (!mc->pdev->time_ref.tick_count)
+ break;
+
+ /* allocate an skb to store the error frame */
+ skb = alloc_can_err_skb(mc->netdev, &cf);
+ if (!skb)
+ return -ENOMEM;
+
+ if (n & (PCAN_USB_ERROR_RXQOVR | PCAN_USB_ERROR_QOVR)) {
+ 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++;
+ }
+ if (n & PCAN_USB_ERROR_BUS_OFF) {
+ cf->can_id |= CAN_ERR_BUSOFF;
+ can_bus_off(mc->netdev);
+ }
+ if (n & PCAN_USB_ERROR_BUS_HEAVY) {
+ cf->can_id |= CAN_ERR_CRTL;
+ cf->data[1] |= CAN_ERR_CRTL_RX_PASSIVE;
+ mc->pdev->dev.can.can_stats.error_passive++;
+ }
+ if (n & PCAN_USB_ERROR_BUS_LIGHT) {
+ cf->can_id |= CAN_ERR_CRTL;
+ cf->data[1] |= CAN_ERR_CRTL_RX_WARNING;
+ mc->pdev->dev.can.can_stats.error_warning++;
+ }
+
+ if (cf->can_id != CAN_ERR_FLAG) {
+ 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++;
+ } else {
+ kfree_skb(skb);
+ }
+
+ 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_info(mc->netdev, "device Tx queue full)\n");
+ break;
+
+ case PCAN_USB_REC_EXT:
+ /* future... */
+ 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:
+ 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 = (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);
+ tmp32 <<= 3;
+ *pc |= PCAN_USB_STATUSLEN_EXT_ID;
+ memcpy(++pc, &tmp32, 4);
+ pc += 4;
+ } else {
+ __le16 tmp16 = cpu_to_le32(cf->can_id & CAN_ERR_MASK);
+ tmp16 <<= 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 = (struct pcan_usb *)dev;
+ int err;
+
+ /* 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) {
+ err = pcan_usb_set_silent(dev,
+ (dev->can.ctrlmode & CAN_CTRLMODE_LISTENONLY));
+ if (err)
+ goto start_failed;
+ }
+
+ err = pcan_usb_set_ext_vcc(dev, 0);
+ if (err)
+ goto start_failed;
+
+ return 0;
+
+start_failed:
+ return err;
+}
+
+static int pcan_usb_init(struct peak_usb_device *dev)
+{
+ u32 serial_number;
+ int err;
+
+ err = pcan_usb_get_serial(dev, &serial_number);
+ if (!err)
+ netdev_info(dev->netdev, "serial %08X\n", serial_number);
+
+ return err;
+}
+
+/*
+ * 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 commands/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,
+};
--
1.7.1
^ permalink raw reply related [flat|nested] 5+ messages in thread
* Re: [PATCH] Add support for PEAK System PCAN-USB adapter
2011-12-22 13:13 [PATCH] Add support for PEAK System PCAN-USB adapter Stephane Grosjean
@ 2011-12-23 19:38 ` Sebastian Haas
2011-12-26 11:08 ` Grosjean Stephane
2012-01-10 10:41 ` Wolfgang Grandegger
1 sibling, 1 reply; 5+ messages in thread
From: Sebastian Haas @ 2011-12-23 19:38 UTC (permalink / raw)
To: Stephane Grosjean; +Cc: Oliver Hartkopp, Linux-can Mailing List
Hi Stéphane,
find a few comments from me below.
Cheers,
Sebastian
Am 22.12.2011 14:13, schrieb Stephane Grosjean:
> +/*
> + * read serial number from device
> + */
> +static int pcan_usb_get_serial(struct peak_usb_device *dev, u32 *serial_number)
> +{
> + u8 args[PCAN_USB_PARAMETER_LEN];
> + int err;
> +
> + err = pcan_usb_wait_rsp(dev, 6, 1, args);
> + if (err)
> + netdev_err(dev->netdev, "getting serial failure: %d\n", err);
> +
Remove empty line an but the initial if() also in brackets.
> + 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_PARAMETER_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);
> +
Empty line.
> + else if (device_id)
> + *device_id = args[0];
> +
> + return err;
> +}
> +
> +/*
> + * 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);
Brackets are useless.
> + struct sk_buff *skb;
> + struct can_frame *cf;
> + struct timeval tv;
> + u8 f, n;
> +
> + /* check whether function and number can be read */
> + if ((mc->ptr + 2)> mc->end)
> + return -EINVAL;
> +
> + f = mc->ptr[0];
> + n = mc->ptr[1];
> + mc->ptr += 2;
> +
> + 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:
> + /* no status flag => ignore record */
> + if (!n)
> + break;
> +
> + /* ignore this error until 1st ts received */
> + if (n == PCAN_USB_ERROR_QOVR)
> + if (!mc->pdev->time_ref.tick_count)
> + break;
> +
> + /* allocate an skb to store the error frame */
> + skb = alloc_can_err_skb(mc->netdev,&cf);
> + if (!skb)
> + return -ENOMEM;
> +
> + if (n& (PCAN_USB_ERROR_RXQOVR | PCAN_USB_ERROR_QOVR)) {
> + 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++;
> + }
> + if (n& PCAN_USB_ERROR_BUS_OFF) {
> + cf->can_id |= CAN_ERR_BUSOFF;
> + can_bus_off(mc->netdev);
> + }
> + if (n& PCAN_USB_ERROR_BUS_HEAVY) {
> + cf->can_id |= CAN_ERR_CRTL;
> + cf->data[1] |= CAN_ERR_CRTL_RX_PASSIVE;
> + mc->pdev->dev.can.can_stats.error_passive++;
> + }
> + if (n& PCAN_USB_ERROR_BUS_LIGHT) {
> + cf->can_id |= CAN_ERR_CRTL;
> + cf->data[1] |= CAN_ERR_CRTL_RX_WARNING;
> + mc->pdev->dev.can.can_stats.error_warning++;
> + }
> +
> + if (cf->can_id != CAN_ERR_FLAG) {
> + 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++;
> + } else {
> + kfree_skb(skb);
> + }
> +
> + 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_info(mc->netdev, "device Tx queue full)\n");
> + break;
> +
> + case PCAN_USB_REC_EXT:
> + /* future... */
> + 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;
> +}
> +
> +/*
> + * 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 = (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);
> +
Remove empty line.
> + /* 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);
> +
Dito.
> + } else if (urb->actual_length> 0) {
> + netdev_err(dev->netdev, "usb message length error (%u)\n",
> + urb->actual_length);
> + err = -EINVAL;
> + }
> +
> + return err;
> +}
> +
> +/*
> + * start interface
> + */
> +static int pcan_usb_start(struct peak_usb_device *dev)
> +{
> + struct pcan_usb *pdev = (struct pcan_usb *)dev;
> + int err;
Initialize err with 0 here.
> +
> + /* 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) {
> + err = pcan_usb_set_silent(dev,
> + (dev->can.ctrlmode& CAN_CTRLMODE_LISTENONLY));
Remove useless brackets for ctrlmode & LISTENONLY are useless.
> + if (err)
> + goto start_failed;
Return with err.
> + }
> +
> + err = pcan_usb_set_ext_vcc(dev, 0);
> + if (err)
> + goto start_failed;
> +
> + return 0;
> +
> +start_failed:
Remove the 6 lines above.
> + return err;
> +}
^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [PATCH] Add support for PEAK System PCAN-USB adapter
2011-12-23 19:38 ` Sebastian Haas
@ 2011-12-26 11:08 ` Grosjean Stephane
2011-12-26 14:21 ` Sebastian Haas
0 siblings, 1 reply; 5+ messages in thread
From: Grosjean Stephane @ 2011-12-26 11:08 UTC (permalink / raw)
To: Sebastian Haas; +Cc: Oliver Hartkopp, Linux-can Mailing List
Hi Sebastian,
Le 23/12/2011 20:38, Sebastian Haas a écrit :
> Hi Stéphane,
>
> find a few comments from me below.
>
> Cheers,
> Sebastian
>
> Am 22.12.2011 14:13, schrieb Stephane Grosjean:
>> +/*
>> + * read serial number from device
>> + */
>> +static int pcan_usb_get_serial(struct peak_usb_device *dev, u32
>> *serial_number)
>> +{
>> + u8 args[PCAN_USB_PARAMETER_LEN];
>> + int err;
>> +
>> + err = pcan_usb_wait_rsp(dev, 6, 1, args);
>> + if (err)
>> + netdev_err(dev->netdev, "getting serial failure: %d\n", err);
>> +
> Remove empty line an but the initial if() also in brackets.
Ok.
>> + 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_PARAMETER_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);
>> +
> Empty line.
Ok.
>> + else if (device_id)
>> + *device_id = args[0];
>> +
>> + return err;
>> +}
>> +
>> +/*
>> + * 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);
> Brackets are useless.
Ok.
>> + struct sk_buff *skb;
>> + struct can_frame *cf;
>> + struct timeval tv;
>> + u8 f, n;
>> +
>> + /* check whether function and number can be read */
>> + if ((mc->ptr + 2)> mc->end)
>> + return -EINVAL;
>> +
>> + f = mc->ptr[0];
>> + n = mc->ptr[1];
>> + mc->ptr += 2;
>> +
>> + 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:
>> + /* no status flag => ignore record */
>> + if (!n)
>> + break;
>> +
>> + /* ignore this error until 1st ts received */
>> + if (n == PCAN_USB_ERROR_QOVR)
>> + if (!mc->pdev->time_ref.tick_count)
>> + break;
>> +
>> + /* allocate an skb to store the error frame */
>> + skb = alloc_can_err_skb(mc->netdev,&cf);
>> + if (!skb)
>> + return -ENOMEM;
>> +
>> + if (n& (PCAN_USB_ERROR_RXQOVR | PCAN_USB_ERROR_QOVR)) {
>> + 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++;
>> + }
>> + if (n& PCAN_USB_ERROR_BUS_OFF) {
>> + cf->can_id |= CAN_ERR_BUSOFF;
>> + can_bus_off(mc->netdev);
>> + }
>> + if (n& PCAN_USB_ERROR_BUS_HEAVY) {
>> + cf->can_id |= CAN_ERR_CRTL;
>> + cf->data[1] |= CAN_ERR_CRTL_RX_PASSIVE;
>> + mc->pdev->dev.can.can_stats.error_passive++;
>> + }
>> + if (n& PCAN_USB_ERROR_BUS_LIGHT) {
>> + cf->can_id |= CAN_ERR_CRTL;
>> + cf->data[1] |= CAN_ERR_CRTL_RX_WARNING;
>> + mc->pdev->dev.can.can_stats.error_warning++;
>> + }
>> +
>> + if (cf->can_id != CAN_ERR_FLAG) {
>> + 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++;
>> + } else {
>> + kfree_skb(skb);
>> + }
>> +
>> + 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_info(mc->netdev, "device Tx queue full)\n");
>> + break;
>> +
>> + case PCAN_USB_REC_EXT:
>> + /* future... */
>> + 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;
>> +}
>> +
>> +/*
>> + * 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 = (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);
>> +
> Remove empty line.
Ok.
>> + /* 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);
>> +
> Dito.
>> + } else if (urb->actual_length> 0) {
>> + netdev_err(dev->netdev, "usb message length error (%u)\n",
>> + urb->actual_length);
>> + err = -EINVAL;
>> + }
>> +
>> + return err;
>> +}
>> +
>> +/*
>> + * start interface
>> + */
>> +static int pcan_usb_start(struct peak_usb_device *dev)
>> +{
>> + struct pcan_usb *pdev = (struct pcan_usb *)dev;
>> + int err;
> Initialize err with 0 here.
Why?
>> +
>> + /* 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) {
>> + err = pcan_usb_set_silent(dev,
>> + (dev->can.ctrlmode& CAN_CTRLMODE_LISTENONLY));
> Remove useless brackets for ctrlmode & LISTENONLY are useless.
Ok.
>> + if (err)
>> + goto start_failed;
> Return with err.
Ok.
>> + }
>> +
>> + err = pcan_usb_set_ext_vcc(dev, 0);
>> + if (err)
>> + goto start_failed;
>> +
>> + return 0;
>> +
>> +start_failed:
> Remove the 6 lines above.
Ok.
>> + return err;
>> +}
So, what do you think about that:
/*
* start interface
*/
static int pcan_usb_start(struct peak_usb_device *dev)
{
struct pcan_usb *pdev = (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);
}
?
Regards,
Stéphane
^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [PATCH] Add support for PEAK System PCAN-USB adapter
2011-12-26 11:08 ` Grosjean Stephane
@ 2011-12-26 14:21 ` Sebastian Haas
0 siblings, 0 replies; 5+ messages in thread
From: Sebastian Haas @ 2011-12-26 14:21 UTC (permalink / raw)
To: s.grosjean; +Cc: Oliver Hartkopp, Linux-can Mailing List
Hi Stéphane,
Am 26.12.2011 12:08, schrieb Grosjean Stephane:
>>> +/*
>>> + * start interface
>>> + */
>>> +static int pcan_usb_start(struct peak_usb_device *dev)
>>> +{
>>> + struct pcan_usb *pdev = (struct pcan_usb *)dev;
>>> + int err;
>> Initialize err with 0 here.
> Why?
You are right. Forget it.
>>> +
>>> + /* 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) {
>>> + err = pcan_usb_set_silent(dev,
>>> + (dev->can.ctrlmode& CAN_CTRLMODE_LISTENONLY));
>> Remove useless brackets for ctrlmode & LISTENONLY are useless.
> Ok.
>>> + if (err)
>>> + goto start_failed;
>> Return with err.
> Ok.
>>> + }
>>> +
>>> + err = pcan_usb_set_ext_vcc(dev, 0);
>>> + if (err)
>>> + goto start_failed;
>>> +
>>> + return 0;
>>> +
>>> +start_failed:
>> Remove the 6 lines above.
> Ok.
>>> + return err;
>>> +}
>
> So, what do you think about that:
>
> /*
> * start interface
> */
> static int pcan_usb_start(struct peak_usb_device *dev)
> {
> struct pcan_usb *pdev = (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);
> }
>
> ?
Much more cleaner. Thanks.
Cheers,
Sebastian
^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [PATCH] Add support for PEAK System PCAN-USB adapter
2011-12-22 13:13 [PATCH] Add support for PEAK System PCAN-USB adapter Stephane Grosjean
2011-12-23 19:38 ` Sebastian Haas
@ 2012-01-10 10:41 ` Wolfgang Grandegger
1 sibling, 0 replies; 5+ messages in thread
From: Wolfgang Grandegger @ 2012-01-10 10:41 UTC (permalink / raw)
To: Stephane Grosjean; +Cc: Oliver Hartkopp, Linux CAN mailing list
Also please send a *series* of patches next time, e.g.:
[PATCH 1/3 v2] ....
On 12/22/2011 02:13 PM, Stephane Grosjean wrote:
>>From 2b369b236b320b4382815c86338f893fadc6476c Mon Sep 17 00:00:00 2001
> From: Stephane Grosjean <s.grosjean@peak-system.com>
> Date: Thu, 22 Dec 2011 13:57:04 +0100
> Subject: [PATCH] Add support for PEAK System PCAN-USB adapter
>
> ---
> drivers/net/can/usb/peak_usb/pcan_usb.c | 749 +++++++++++++++++++++++++++++++
> 1 files changed, 749 insertions(+), 0 deletions(-)
> create mode 100644 drivers/net/can/usb/peak_usb/pcan_usb.c
>
> 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 0000000..1a427be
> --- /dev/null
> +++ b/drivers/net/can/usb/peak_usb/pcan_usb.c
> @@ -0,0 +1,749 @@
> +/*
> + * CAN driver for PEAK System PCAN-USB adapter
> + *
> + * Copyright (C) 2011-2012 PEAK-System GmbH
> + *
> + * 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 "peak_usb.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 parameter command */
> +#define PCAN_USB_PARAMETER_LEN 14
> +struct __packed pcan_usb_parameter {
> + u8 function;
> + u8 number;
> + u8 parameters[PCAN_USB_PARAMETER_LEN];
> +};
> +
> +/* PCAN-USB command timeout (ms.) */
> +#define PCAN_USB_COMMAND_TIMEOUT 1000
> +
> +/* 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
> +#define PCAN_USB_REC_EXT 10
> +
> +/* private to PCAN-USB adapter */
> +struct pcan_usb {
> + struct peak_usb_device dev; /* must be the first member */
> + struct peak_time_ref time_ref;
> +};
> +
> +/* 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;
> + struct pcan_usb_parameter cmd = {
> + .function = f,
> + .number = n,
> + };
> +
> + /* usb device unregistered? */
> + if (!(dev->state & PCAN_USB_STATE_CONNECTED))
> + return 0;
> +
> + if (p)
> + memcpy(cmd.parameters, p, ARRAY_SIZE(cmd.parameters));
> +
> + err = usb_bulk_msg(dev->udev,
> + usb_sndbulkpipe(dev->udev, PCAN_USB_EP_CMDOUT), &cmd,
> + sizeof(struct pcan_usb_parameter), &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;
> + struct pcan_usb_parameter cmd = {
> + .function = f,
> + .number = n,
> + };
> +
> + /* 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), &cmd,
> + sizeof(struct pcan_usb_parameter), &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, cmd.parameters, ARRAY_SIZE(cmd.parameters));
> +
> + return err;
> +}
> +
> +static int pcan_usb_set_sja1000(struct peak_usb_device *dev, u8 mode)
> +{
> + u8 args[PCAN_USB_PARAMETER_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_PARAMETER_LEN] = {
> + [0] = onoff ? 1 : 0,
> + };
> +
> + 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_PARAMETER_LEN] = {
> + [0] = onoff ? 1 : 0,
> + };
> +
> + 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_PARAMETER_LEN] = {
> + [0] = onoff ? 1 : 0,
> + };
> +
> + 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_PARAMETER_LEN];
> + u8 btr0, btr1;
> +
> + btr0 = ((bt->brp - 1) & 0x3f) | (((bt->sjw - 1) & 0x3) << 6);
> + btr1 = ((bt->prop_seg + bt->phase_seg1 - 1) & 0xf) \
No need for "\"
> + | (((bt->phase_seg2 - 1) & 0x7) << 4);
> + if (dev->can.ctrlmode & CAN_CTRLMODE_3_SAMPLES)
> + btr1 |= 0x80;
> +
> + args[0] = btr1;
> + args[1] = btr0;
> +
> + netdev_dbg(dev->netdev, "btr0=0x%02x btr1=0x%02x\n", btr0, btr1);
Please use netdev_info here, like all other drivers.
> +
> + 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);
> +
> + return err;
> +}
> +
> +/*
> + * read serial number from device
> + */
> +static int pcan_usb_get_serial(struct peak_usb_device *dev, u32 *serial_number)
> +{
> + u8 args[PCAN_USB_PARAMETER_LEN];
> + int err;
> +
> + err = pcan_usb_wait_rsp(dev, 6, 1, args);
> + if (err)
> + netdev_err(dev->netdev, "getting serial failure: %d\n", err);
> +
Remove empty line.
> + else if (serial_number) {
> + u32 tmp32;
Add empty line.
> + 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_PARAMETER_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)
Spaces around "+"
> + 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)
Ditto
> + 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;
> +}
> +
> +/*
> + * 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);
> + struct sk_buff *skb;
> + struct can_frame *cf;
> + struct timeval tv;
> + u8 f, n;
> +
> + /* check whether function and number can be read */
> + if ((mc->ptr + 2) > mc->end)
> + return -EINVAL;
> +
> + f = mc->ptr[0];
> + n = mc->ptr[1];
> + mc->ptr += 2;
> +
> + if (status_len & PCAN_USB_STATUSLEN_TIMESTAMP) {
> + int err = pcan_usb_decode_ts(mc, !mc->rec_idx);
Add empty line .
> + if (err)
> + return err;
> + }
> +
> + switch (f) {
> + case PCAN_USB_REC_ERROR:
> + /* no status flag => ignore record */
> + if (!n)
> + break;
> +
> + /* ignore this error until 1st ts received */
> + if (n == PCAN_USB_ERROR_QOVR)
> + if (!mc->pdev->time_ref.tick_count)
> + break;
> +
> + /* allocate an skb to store the error frame */
> + skb = alloc_can_err_skb(mc->netdev, &cf);
> + if (!skb)
> + return -ENOMEM;
> +
> + if (n & (PCAN_USB_ERROR_RXQOVR | PCAN_USB_ERROR_QOVR)) {
> + 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++;
> + }
> + if (n & PCAN_USB_ERROR_BUS_OFF) {
> + cf->can_id |= CAN_ERR_BUSOFF;
> + can_bus_off(mc->netdev);
> + }
> + if (n & PCAN_USB_ERROR_BUS_HEAVY) {
> + cf->can_id |= CAN_ERR_CRTL;
> + cf->data[1] |= CAN_ERR_CRTL_RX_PASSIVE;
As you don't know the direction. Please add "| CAN_ERR_CRTL_TX_PASSIVE"
> + mc->pdev->dev.can.can_stats.error_passive++;
> + }
> + if (n & PCAN_USB_ERROR_BUS_LIGHT) {
> + cf->can_id |= CAN_ERR_CRTL;
> + cf->data[1] |= CAN_ERR_CRTL_RX_WARNING;
> + mc->pdev->dev.can.can_stats.error_warning++;
Similar here.
> + }
> +
> + if (cf->can_id != CAN_ERR_FLAG) {
> + 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++;
What about rx_bytes?
> + } else {
> + kfree_skb(skb);
> + }
> +
> + 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_info(mc->netdev, "device Tx queue full)\n");
Can this happen frequently? netdev_dbg() or ratelimiting?
> + break;
> +
> + case PCAN_USB_REC_EXT:
> + /* future... */
> + break;
Please remove if it's not really needed!
> + 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);
"()" not needed.
> + 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:
> + 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 = (struct pcan_usb *)dev,
Is the cast really necessary?
> + };
> + 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);
> +
Remove empty line.
> + /* 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);
Empty line.
> + tmp32 <<= 3;
> + *pc |= PCAN_USB_STATUSLEN_EXT_ID;
> + memcpy(++pc, &tmp32, 4);
> + pc += 4;
> + } else {
> + __le16 tmp16 = cpu_to_le32(cf->can_id & CAN_ERR_MASK);
Ditto.
> + tmp16 <<= 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 = (struct pcan_usb *)dev;
> + int err;
> +
> + /* 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) {
> + err = pcan_usb_set_silent(dev,
> + (dev->can.ctrlmode & CAN_CTRLMODE_LISTENONLY));
"()" not needed!
> + if (err)
> + goto start_failed;
> + }
> +
> + err = pcan_usb_set_ext_vcc(dev, 0);
> + if (err)
> + goto start_failed;
> +
> + return 0;
> +
> +start_failed:
> + return err;
This label is not really useful.
> +}
> +
> +static int pcan_usb_init(struct peak_usb_device *dev)
> +{
> + u32 serial_number;
> + int err;
> +
> + err = pcan_usb_get_serial(dev, &serial_number);
> + if (!err)
> + netdev_info(dev->netdev, "serial %08X\n", serial_number);
> +
> + return err;
> +}
> +
> +/*
> + * 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,
Spaces around "/"
> + },
> + .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 commands/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,
> +};
Wolfgang.
^ permalink raw reply [flat|nested] 5+ messages in thread
end of thread, other threads:[~2012-01-10 10:41 UTC | newest]
Thread overview: 5+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2011-12-22 13:13 [PATCH] Add support for PEAK System PCAN-USB adapter Stephane Grosjean
2011-12-23 19:38 ` Sebastian Haas
2011-12-26 11:08 ` Grosjean Stephane
2011-12-26 14:21 ` Sebastian Haas
2012-01-10 10:41 ` Wolfgang Grandegger
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).