* [PATCH] Add support for PEAK System PCAN-USB Pro adapter
@ 2011-12-22 13:14 Stephane Grosjean
2011-12-23 19:57 ` Sebastian Haas
2012-01-10 11:21 ` Wolfgang Grandegger
0 siblings, 2 replies; 4+ messages in thread
From: Stephane Grosjean @ 2011-12-22 13:14 UTC (permalink / raw)
To: Oliver Hartkopp; +Cc: Linux CAN mailing list
[-- Attachment #1: Type: text/plain, Size: 36722 bytes --]
From a1b285074b883edc3dccc6aacafb18407e98e18a Mon Sep 17 00:00:00 2001
From: Stephane Grosjean <s.grosjean@peak-system.com>
Date: Thu, 22 Dec 2011 13:59:00 +0100
Subject: [PATCH] Add support for PEAK System PCAN-USB Pro adapter
---
drivers/net/can/usb/peak_usb/pcan_usb_pro.c | 1092 +++++++++++++++++++++++++++
drivers/net/can/usb/peak_usb/pcan_usb_pro.h | 352 +++++++++
2 files changed, 1444 insertions(+), 0 deletions(-)
create mode 100644 drivers/net/can/usb/peak_usb/pcan_usb_pro.c
create mode 100644 drivers/net/can/usb/peak_usb/pcan_usb_pro.h
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 0000000..0747395
--- /dev/null
+++ b/drivers/net/can/usb/peak_usb/pcan_usb_pro.c
@@ -0,0 +1,1092 @@
+/*
+ * CAN driver for PEAK System PCAN-USB Pro 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"
+#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_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
+
+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;
+};
+
+struct pcan_usb_pro_device {
+ struct peak_usb_device peak_usb_device; /* must be the first member */
+ struct pcan_usb_pro_interface *usb_if;
+};
+
+/* 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;
+};
+
+static int pcan_usb_pro_sizeof_rec(u8 data_type)
+{
+ switch (data_type) {
+ case PCAN_USBPRO_RXMSG8:
+ return sizeof(struct pcan_usb_pro_rxmsg);
+ case PCAN_USBPRO_RXMSG4:
+ return sizeof(struct pcan_usb_pro_rxmsg) - 4;
+ case PCAN_USBPRO_RXMSG0:
+ case PCAN_USBPRO_RXRTR:
+ return sizeof(struct pcan_usb_pro_rxmsg) - 8;
+ case PCAN_USBPRO_RXSTATUS:
+ return sizeof(struct pcan_usb_pro_rxstatus);
+ case PCAN_USBPRO_RXTS:
+ return sizeof(struct pcan_usb_pro_rxts);
+ case PCAN_USBPRO_TXMSG8:
+ return sizeof(struct pcan_usb_pro_txmsg);
+ case PCAN_USBPRO_TXMSG4:
+ return sizeof(struct pcan_usb_pro_txmsg) - 4;
+ case PCAN_USBPRO_TXMSG0:
+ return sizeof(struct pcan_usb_pro_txmsg) - 8;
+ case PCAN_USBPRO_GETBTR:
+ case PCAN_USBPRO_SETBTR:
+ return sizeof(struct pcan_usb_pro_btr);
+ case PCAN_USBPRO_SETSILENT:
+ return sizeof(struct pcan_usb_pro_silent);
+ case PCAN_USBPRO_SETDEVID:
+ case PCAN_USBPRO_GETDEVID:
+ return sizeof(struct pcan_usb_pro_devid);
+ case PCAN_USBPRO_GETBUSACT:
+ case PCAN_USBPRO_SETBUSACT:
+ return sizeof(struct pcan_usb_pro_busact);
+ case PCAN_USBPRO_SETWARNLIM:
+ return sizeof(struct pcan_usb_pro_warnlim);
+ case PCAN_USBPRO_SETLKUP:
+ return sizeof(struct pcan_usb_pro_lkup);
+ case PCAN_USBPRO_SETLKUPGRP:
+ return sizeof(struct pcan_usb_pro_lkupgrp);
+ case PCAN_USBPRO_SETFILTR:
+ return sizeof(struct pcan_usb_pro_filter);
+ case PCAN_USBPRO_SETRST:
+ return sizeof(struct pcan_usb_pro_reset);
+ case PCAN_USBPRO_SETERRFRM:
+ return sizeof(struct pcan_usb_pro_errfrm);
+ case PCAN_USBPRO_GETBUSSTAT:
+ return sizeof(struct pcan_usb_pro_busstat);
+ case PCAN_USBPRO_SETREG:
+ return sizeof(struct pcan_usb_pro_setreg);
+ case PCAN_USBPRO_GETREG:
+ return sizeof(struct pcan_usb_pro_getreg);
+ case PCAN_USBPRO_SETTS:
+ return sizeof(struct pcan_usb_pro_setts);
+ case PCAN_USBPRO_SETSTR:
+ return sizeof(struct pcan_usb_pro_setstr);
+ case PCAN_USBPRO_GETSTR:
+ return sizeof(struct pcan_usb_pro_getstr);
+ case PCAN_USBPRO_STRING:
+ return sizeof(struct pcan_usb_pro_str);
+ case PCAN_USBPRO_SAVE:
+ return sizeof(struct pcan_usb_pro_save);
+ case PCAN_USBPRO_PDELAY:
+ return sizeof(struct pcan_usb_pro_pdelay);
+ case PCAN_USBPRO_TSARG:
+ return sizeof(struct pcan_usb_pro_tsarg);
+ case PCAN_USBPRO_ERRID:
+ return sizeof(struct pcan_usb_pro_errid);
+ case PCAN_USBPRO_ERRNOW:
+ return sizeof(struct pcan_usb_pro_errnow);
+ case PCAN_USBPRO_SETSFILER:
+ return sizeof(struct pcan_usb_pro_sfiller);
+ case PCAN_USBPRO_SETLED:
+ return sizeof(struct pcan_usb_pro_setled);
+ default:
+ pr_info("%s: %s(%d): unsupported data type\n",
+ PCAN_USB_DRIVER_NAME, __func__, data_type);
+ break;
+ }
+
+ return -1;
+}
+
+/*
+ * initialize PCAN-USB Pro message data structure
+ */
+static u8 *pcan_usb_pro_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_usb_pro_msg_init_empty(struct pcan_usb_pro_msg *pm,
+ void *buffer_addr, int buffer_size)
+{
+ u8 *pr = pcan_usb_pro_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_usb_pro_add_rec(struct pcan_usb_pro_msg *pm, int id, ...)
+{
+ int l, 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++ = (u8)va_arg(ap, int);
+ *pc++ = (u8)va_arg(ap, int);
+ *pc++ = (u8)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_GETBUSACT:
+ case PCAN_USBPRO_GETBUSSTAT:
+ *pc++ = (u8)va_arg(ap, int);
+ break;
+
+ case PCAN_USBPRO_SETBTR:
+ case PCAN_USBPRO_GETBTR:
+ case PCAN_USBPRO_SETDEVID:
+ case PCAN_USBPRO_GETDEVID:
+ *pc++ = (u8)va_arg(ap, int);
+ pc += 2;
+ *(u32 *)pc = cpu_to_le32(va_arg(ap, u32));
+ pc += 4;
+ break;
+
+ case PCAN_USBPRO_SETBUSACT:
+ case PCAN_USBPRO_SETSILENT:
+ case PCAN_USBPRO_SETWARNLIM:
+ case PCAN_USBPRO_SETFILTR:
+ case PCAN_USBPRO_SETRST:
+ case PCAN_USBPRO_SETERRFRM:
+ case PCAN_USBPRO_TSARG:
+ case PCAN_USBPRO_ERRNOW:
+ *pc++ = (u8)va_arg(ap, int);
+ *(u16 *)pc = cpu_to_le16((u16)va_arg(ap, int));
+ pc += 2;
+ break;
+
+ case PCAN_USBPRO_SETLKUP:
+ case PCAN_USBPRO_SETLED:
+ *pc++ = (u8)va_arg(ap, int);
+ *(u16 *)pc = cpu_to_le16((u16)va_arg(ap, int));
+ pc += 2;
+ *(u32 *)pc = cpu_to_le32(va_arg(ap, u32));
+ pc += 4;
+ break;
+
+ case PCAN_USBPRO_SETLKUPGRP:
+ *pc++ = (u8)va_arg(ap, int);
+ *(u16 *)pc = cpu_to_le16((u16)va_arg(ap, int));
+ pc += 2;
+ *(u32 *)pc = cpu_to_le32(va_arg(ap, u32));
+ pc += 4;
+ *(u32 *)pc = cpu_to_le32(va_arg(ap, u32));
+ pc += 4;
+ break;
+
+ case PCAN_USBPRO_SETREG:
+ *pc++ = (u8)va_arg(ap, int);
+ pc += 2;
+ *(u32 *)pc = cpu_to_le32(va_arg(ap, u32));
+ pc += 4;
+ *(u32 *)pc = cpu_to_le32(va_arg(ap, u32));
+ pc += 4;
+ *(u32 *)pc = cpu_to_le32(va_arg(ap, u32));
+ pc += 4;
+ break;
+
+ case PCAN_USBPRO_GETREG:
+ *pc++ = (u8)va_arg(ap, int);
+ pc += 2;
+ *(u32 *)pc = cpu_to_le32(va_arg(ap, u32));
+ pc += 4;
+ *(u32 *)pc = cpu_to_le32(va_arg(ap, u32));
+ pc += 4;
+ break;
+
+ case PCAN_USBPRO_SETTS:
+ case PCAN_USBPRO_PDELAY:
+ pc++;
+ *(u16 *)pc = cpu_to_le16((u16)va_arg(ap, int));
+ pc += 2;
+ break;
+
+ case PCAN_USBPRO_SETBUSLAST:
+ *pc++ = (u8)va_arg(ap, int);
+ pc++;
+ *pc++ = (u8)va_arg(ap, int);
+ pc += 2;
+ *(u16 *)pc = cpu_to_le16(4096);
+ pc += 2;
+ break;
+
+ case PCAN_USBPRO_SETSTR:
+ *pc++ = (u8)va_arg(ap, int);
+ *pc++ = (u8)va_arg(ap, int);
+ *pc++ = (u8)va_arg(ap, int);
+ memcpy(pc, va_arg(ap, u8 *), 60);
+ pc += 60;
+ break;
+
+ case PCAN_USBPRO_GETSTR:
+ case PCAN_USBPRO_SAVE:
+ *pc++ = (u8)va_arg(ap, int);
+ pc += 2;
+ break;
+
+ case PCAN_USBPRO_STRING:
+ *pc++ = (u8)va_arg(ap, int);
+ pc += 2;
+ memcpy(pc, va_arg(ap, u8 *), 250);
+ pc += 250;
+ break;
+
+ case PCAN_USBPRO_ERRID:
+ *pc++ = (u8)va_arg(ap, int);
+ *(u16 *)pc = cpu_to_le16((u16)va_arg(ap, int));
+ pc += 2;
+ *(u32 *)pc = cpu_to_le32(va_arg(ap, u32));
+ pc += 4;
+ *(u16 *)pc = cpu_to_le16((u16)va_arg(ap, int));
+ pc += 2;
+ *(u16 *)pc = cpu_to_le16((u16)va_arg(ap, int));
+ pc += 2;
+ break;
+
+ case PCAN_USBPRO_SETSFILER:
+ *pc++ = (u8)va_arg(ap, int);
+ pc += 2;
+ *(u32 *)pc = cpu_to_le32(va_arg(ap, u32));
+ pc += 4;
+ *(u32 *)pc = cpu_to_le32(va_arg(ap, u32));
+ pc += 4;
+ break;
+
+ default:
+ pr_info("%s: %s(): unknown data type %02Xh (%d)\n",
+ PCAN_USB_DRIVER_NAME, __func__, id, id);
+ pc--;
+ break;
+ }
+
+ l = pc - pm->rec_ptr;
+ if (l > 0) {
+ *pm->u.rec_cnt = cpu_to_le32(*pm->u.rec_cnt+1);
+ *(pm->rec_ptr) = (u8)id;
+
+ pm->rec_ptr = pc;
+ pm->rec_buffer_len += l;
+ }
+
+ va_end(ap);
+
+ return l;
+}
+
+/*
+ * 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;
+ int 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;
+
+ if (actual_length < PCAN_USBPRO_MSG_HEADER_LEN) {
+ netdev_err(dev->netdev,
+ "got abnormal too small rsp (len=%d)\n",
+ actual_length);
+ err = -EBADMSG;
+ break;
+ }
+
+ pc = pcan_usb_pro_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 <= 0) {
+ netdev_err(dev->netdev,
+ "got unprocessed record in msg\n");
+ dump_mem("rcvd rsp msg", pum->u.rec_buffer,
+ actual_length);
+ err = -EBADMSG;
+ 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;
+
+ case PCAN_USBPRO_REQ_INFO:
+ 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);
+ else
+ err = 0;
+
+ return err;
+}
+
+static int pcan_usb_pro_set_ts(struct peak_usb_device *dev, u16 onoff)
+{
+ struct pcan_usb_pro_msg um;
+ u8 tmp[32];
+
+ pcan_usb_pro_msg_init_empty(&um, tmp, sizeof(tmp));
+ pcan_usb_pro_add_rec(&um, PCAN_USBPRO_SETTS, onoff);
+
+ 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;
+ u8 tmp[32];
+
+ pcan_usb_pro_msg_init_empty(&um, tmp, sizeof(tmp));
+ pcan_usb_pro_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;
+ u8 tmp[32];
+
+ pcan_usb_pro_msg_init_empty(&um, tmp, sizeof(tmp));
+ pcan_usb_pro_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;
+ u8 tmp[32];
+
+ pcan_usb_pro_msg_init_empty(&um, tmp, sizeof(tmp));
+ pcan_usb_pro_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;
+ u8 tmp[32];
+
+ pcan_usb_pro_msg_init_empty(&um, tmp, sizeof(tmp));
+ pcan_usb_pro_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_msg um;
+ struct pcan_usb_pro_devid *pdn;
+ u8 tmp[32], *pc;
+ int err;
+
+ pc = pcan_usb_pro_msg_init_empty(&um, tmp, sizeof(tmp));
+ pcan_usb_pro_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)
+{
+ struct pcan_usb_pro_msg um;
+ u8 tmp[32];
+ 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_dbg(dev->netdev, "ccbt=0x%08x\n", ccbt);
+
+ pcan_usb_pro_msg_init_empty(&um, tmp, sizeof(tmp));
+ pcan_usb_pro_add_rec(&um, PCAN_USBPRO_SETBTR, dev->ctrl_idx, ccbt);
+
+ return pcan_usb_pro_send_cmd(dev, &um);
+}
+
+static void pcan_usb_pro_drv_loaded(struct peak_usb_device *dev, int loaded)
+{
+ u8 buffer[16];
+
+ buffer[0] = 0;
+ buffer[1] = loaded ? 1 : 0;
+
+ pcan_usb_pro_send_req(dev, PCAN_USBPRO_REQ_FCT,
+ PCAN_USBPRO_FCT_DRIVER_LOADED, buffer, sizeof(buffer));
+}
+
+static inline
+struct pcan_usb_pro_interface *pcan_usb_pro_dev_if(struct peak_usb_device *dev)
+{
+ return ((struct pcan_usb_pro_device *)dev)->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_RTR)
+ can_frame->can_id |= CAN_RTR_FLAG;
+ if (rx->flags & PCAN_USBPRO_EXT)
+ can_frame->can_id |= CAN_EFF_FLAG;
+
+ 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;
+ struct sk_buff *skb;
+ struct timeval tv;
+
+ skb = alloc_can_err_skb(netdev, &can_frame);
+ if (!skb)
+ return -ENOMEM;
+
+ memset(can_frame, '\0', sizeof(struct can_frame));
+
+ if (raw_status & FW_USBPRO_STATUS_BUS_S) {
+ can_frame->can_id |= CAN_ERR_BUSOFF;
+ can_bus_off(netdev);
+
+ } else if (raw_status & FW_USBPRO_STATUS_ERROR_S) {
+ 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) {
+ can_frame->can_id |= CAN_ERR_CRTL;
+ can_frame->data[1] |= CAN_ERR_CRTL_RX_PASSIVE;
+ dev->can.can_stats.error_passive++;
+
+ } else if (rx_err_cnt > 96) {
+ can_frame->can_id |= CAN_ERR_CRTL;
+ can_frame->data[1] |= CAN_ERR_CRTL_RX_WARNING;
+ dev->can.can_stats.error_warning++;
+ }
+
+ if (tx_err_cnt > 127) {
+ can_frame->can_id |= CAN_ERR_CRTL;
+ can_frame->data[1] |= CAN_ERR_CRTL_TX_PASSIVE;
+ dev->can.can_stats.error_passive++;
+
+ } else if (tx_err_cnt > 96) {
+ can_frame->can_id |= CAN_ERR_CRTL;
+ can_frame->data[1] |= CAN_ERR_CRTL_TX_WARNING;
+ dev->can.can_stats.error_warning++;
+ }
+ }
+
+ if (raw_status & FW_USBPRO_STATUS_OVERRUN_S) {
+ can_frame->can_id |= CAN_ERR_PROT;
+ can_frame->data[2] |= CAN_ERR_PROT_OVERLOAD;
+ }
+
+ if (raw_status & FW_USBPRO_STATUS_QOVERRUN_S) {
+ can_frame->can_id |= CAN_ERR_CRTL;
+ can_frame->data[1] |= CAN_ERR_CRTL_RX_OVERFLOW;
+ }
+
+ if (can_frame->can_id != CAN_ERR_FLAG) {
+ 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++;
+ } else {
+ kfree_skb(skb);
+ }
+
+ return 0;
+}
+
+static int 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]));
+
+ return 0;
+}
+
+/*
+ * 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_usb_pro_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;
+ int sizeof_rec = pcan_usb_pro_sizeof_rec(pr->data_type);
+
+ if (sizeof_rec <= 0) {
+ 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:
+ err = 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;
+ int err = 0;
+
+ pcan_usb_pro_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;
+
+ err = pcan_usb_pro_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 = (struct pcan_usb_pro_device *)dev;
+ int err;
+
+ err = pcan_usb_pro_set_silent(dev,
+ (dev->can.ctrlmode & CAN_CTRLMODE_LISTENONLY));
+ if (err)
+ goto start_failed;
+
+ /* Set filter mode: 0-> All OFF; 1->bypass */
+ err = pcan_usb_pro_set_filter(dev, 1);
+ if (err)
+ goto start_failed;
+
+ /* 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++;
+
+start_failed:
+ 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 = (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 = (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;
+
+ /* tell the device the can driver is running */
+ pcan_usb_pro_drv_loaded(dev, 1);
+
+ if (pcan_usb_pro_send_req(dev, PCAN_USBPRO_REQ_INFO,
+ PCAN_USBPRO_INFO_FIRMWARE, &fi, sizeof(fi)) >= 0)
+ netdev_info(dev->netdev,
+ "%s fw v%d.%d.%d (%02d/%02d/%02d) fw 0x%08x\n",
+ pcan_usb_pro.name,
+ fi.version[0], fi.version[1], fi.version[2],
+ fi.day, fi.month, fi.year, fi.fw_type);
+
+ if (pcan_usb_pro_send_req(dev, PCAN_USBPRO_REQ_INFO,
+ PCAN_USBPRO_INFO_BOOTLOADER, &bi, sizeof(bi)) >= 0) {
+ netdev_info(dev->netdev,
+ "bootloader v%d.%d.%d (%02d/%02d/%02d)\n",
+ bi.version[0], bi.version[1], bi.version[2],
+ bi.day, bi.month, bi.year);
+
+ netdev_info(dev->netdev,
+ "serial %08X.%08X hw 0x%08x rev 0x%08x\n",
+ bi.serial_num_hi, bi.serial_num_lo,
+ bi.hw_type, bi.hw_rev);
+
+ dev->device_rev = (u8)bi.hw_rev;
+ }
+
+ 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;
+
+ } 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 = (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 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. All 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:
+ /* CAN usb interface unused ep */
+ case 0x83:
+ 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 commands/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,
+};
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 0000000..66952cb
--- /dev/null
+++ b/drivers/net/can/usb/peak_usb/pcan_usb_pro.h
@@ -0,0 +1,352 @@
+/*
+ * CAN driver for PEAK System PCAN-USB Pro 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.
+ */
+#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 wValue for XXX_INFO */
+#define PCAN_USBPRO_INFO_BOOTLOADER 0
+#define PCAN_USBPRO_INFO_FIRMWARE 1
+
+/* Vendor Request wValue for XXX_FCT */
+#define PCAN_USBPRO_FCT_DRIVER_LOADED 5
+
+/* PCAN_USBPRO_INFO_BOOTLOADER 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_FIRMWARE 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_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_RXBUSLAST 0x86
+#define PCAN_USBPRO_TXMSG8 0x41
+#define PCAN_USBPRO_TXMSG4 0x42
+#define PCAN_USBPRO_TXMSG0 0x43
+#define PCAN_USBPRO_GETBTR 0x01
+#define PCAN_USBPRO_SETBTR 0x02
+#define PCAN_USBPRO_GETBUSACT 0x03
+#define PCAN_USBPRO_SETBUSACT 0x04
+#define PCAN_USBPRO_SETSILENT 0x05
+#define PCAN_USBPRO_SETDEVID 0x06
+#define PCAN_USBPRO_SETWARNLIM 0x07
+#define PCAN_USBPRO_SETLKUP 0x08
+#define PCAN_USBPRO_SETLKUPGRP 0x09
+#define PCAN_USBPRO_SETFILTR 0x0a
+#define PCAN_USBPRO_SETRST 0x0b
+#define PCAN_USBPRO_SETERRFRM 0x0c
+#define PCAN_USBPRO_GETBUSSTAT 0x0D
+#define PCAN_USBPRO_SETREG 0x0e
+#define PCAN_USBPRO_GETREG 0x0f
+#define PCAN_USBPRO_SETTS 0x10
+#define PCAN_USBPRO_SETBUSLAST 0x11
+#define PCAN_USBPRO_GETDEVID 0x12
+#define PCAN_USBPRO_SETSTR 0x13
+#define PCAN_USBPRO_GETSTR 0x14
+#define PCAN_USBPRO_STRING 0x15
+#define PCAN_USBPRO_SAVE 0x16
+#define PCAN_USBPRO_PDELAY 0x17
+#define PCAN_USBPRO_TSARG 0x18
+#define PCAN_USBPRO_ERRID 0x19
+#define PCAN_USBPRO_ERRNOW 0x1A
+#define PCAN_USBPRO_SETSFILER 0x1B
+#define PCAN_USBPRO_SETLED 0x1C
+
+/* record structures */
+struct __packed pcan_usb_pro_rxmsg {
+ u8 data_type;
+ u8 client;
+ u8 flags;
+ u8 len;
+ u32 ts32;
+ u32 id;
+
+ u8 data[8];
+};
+
+#define FW_USBPRO_STATUS_ERROR_S 0x0001
+#define FW_USBPRO_STATUS_BUS_S 0x0002
+#define FW_USBPRO_STATUS_OVERRUN_S 0x0004
+#define FW_USBPRO_STATUS_QOVERRUN_S 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_buslast {
+ u8 data_type;
+ u8 channel;
+ u16 buslast_val;
+ u32 ts32;
+};
+
+struct __packed pcan_usb_pro_txmsg {
+ u8 data_type;
+ u8 client;
+ u8 flags;
+ u8 len;
+ u32 id;
+ u8 data[8];
+};
+
+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_devid {
+ u8 data_type;
+ u8 channel;
+ u16 dummy;
+ u32 serial_num;
+};
+
+struct __packed pcan_usb_pro_warnlim {
+ u8 data_type;
+ u8 channel;
+ u16 warning_limit;
+};
+
+struct __packed pcan_usb_pro_lkup {
+ u8 data_type;
+ u8 channel;
+ u16 id_type;
+ u32 id;
+};
+
+struct __packed pcan_usb_pro_lkupgrp {
+ u8 data_type;
+ u8 channel;
+ u16 id_type;
+ u32 id_start;
+ u32 id_end;
+};
+
+struct __packed pcan_usb_pro_filter {
+ u8 data_type;
+ u8 dummy;
+ u16 filter_mode;
+};
+
+struct __packed pcan_usb_pro_reset {
+ u8 data_type;
+ u8 channel;
+ u16 reset;
+};
+
+struct __packed pcan_usb_pro_errfrm {
+ u8 data_type;
+ u8 channel;
+ u16 mode;
+};
+
+struct __packed pcan_usb_pro_busstat {
+ u8 data_type;
+ u8 channel;
+ u16 status;
+};
+
+struct __packed pcan_usb_pro_setreg {
+ u8 data_type;
+ u8 irq_off;
+ u16 dummy;
+ u32 address;
+ u32 value;
+ u32 mask;
+};
+
+struct __packed pcan_usb_pro_getreg {
+ u8 data_type;
+ u8 irq_off;
+ u16 dummy;
+ u32 address;
+ u32 value;
+};
+
+struct __packed pcan_usb_pro_setts {
+ u8 data_type;
+ u8 dummy;
+ u16 mode;
+};
+
+struct __packed pcan_usb_pro_setbl {
+ u8 data_type;
+ u8 channel;
+ u8 dummy;
+ u8 mode;
+ u16 prescaler;
+ u16 sampletimequanta;
+};
+
+struct __packed pcan_usb_pro_setstr {
+ u8 data_type;
+ u8 channel;
+ u8 offset;
+ u8 len;
+ u8 data[60];
+};
+
+struct __packed pcan_usb_pro_getstr {
+ u8 data_type;
+ u8 channel;
+ u16 dummy;
+};
+
+struct __packed pcan_usb_pro_str {
+ u8 data_type;
+ u8 channel;
+ u16 dummy;
+ u8 data[250];
+};
+
+struct __packed pcan_usb_pro_save {
+ u8 data_type;
+ u8 channel;
+ u16 dummy;
+};
+
+struct __packed pcan_usb_pro_pdelay {
+ u8 data_type;
+ u8 dummy;
+ u16 delay;
+};
+
+struct __packed pcan_usb_pro_tsarg {
+ u8 data_type;
+ u8 channel;
+ u16 start_or_end;
+};
+
+struct __packed pcan_usb_pro_errid {
+ u8 data_type;
+ u8 channel;
+ u16 bit_pos;
+ u32 id;
+ u16 ok_counter;
+ u16 error_counter;
+};
+
+struct __packed pcan_usb_pro_errnow {
+ u8 data_type;
+ u8 channel;
+ u16 bit_pos;
+};
+
+struct __packed pcan_usb_pro_sfiller {
+ u8 data_type;
+ u8 channel;
+ u16 dummy;
+ u32 accmask;
+ u32 acccode;
+};
+
+struct __packed pcan_usb_pro_setled {
+ u8 data_type;
+ u8 channel;
+ u16 mode;
+ u32 timeout;
+};
+
+union pcan_usb_pro_rec {
+ u8 data_type;
+ 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_buslast rx_buslast;
+ struct pcan_usb_pro_txmsg tx_msg;
+ struct pcan_usb_pro_btr btr;
+ struct pcan_usb_pro_busact bus_act;
+ struct pcan_usb_pro_silent silent_mode;
+ struct pcan_usb_pro_devid dev_id;
+ struct pcan_usb_pro_warnlim warn_lim;
+ struct pcan_usb_pro_lkup lkup_expl;
+ struct pcan_usb_pro_lkupgrp lkup_group;
+ struct pcan_usb_pro_filter filter_mode;
+ struct pcan_usb_pro_reset rst_mode;
+ struct pcan_usb_pro_errfrm err_frame;
+ struct pcan_usb_pro_busstat bus_status;
+ struct pcan_usb_pro_setreg set_reg;
+ struct pcan_usb_pro_getreg get_reg;
+ struct pcan_usb_pro_setts ts;
+ struct pcan_usb_pro_setbl bus_last;
+ struct pcan_usb_pro_setstr set_str;
+ struct pcan_usb_pro_getstr get_str;
+ struct pcan_usb_pro_str str;
+ struct pcan_usb_pro_save save_eeprom;
+ struct pcan_usb_pro_pdelay p_delay;
+ struct pcan_usb_pro_tsarg ts_arg;
+ struct pcan_usb_pro_errid err_id;
+ struct pcan_usb_pro_errnow err_now;
+ struct pcan_usb_pro_sfiller soft_filler;
+ struct pcan_usb_pro_setled set_can_led;
+};
+
+#endif
--
1.7.1
^ permalink raw reply related [flat|nested] 4+ messages in thread
* Re: [PATCH] Add support for PEAK System PCAN-USB Pro adapter
2011-12-22 13:14 [PATCH] Add support for PEAK System PCAN-USB Pro adapter Stephane Grosjean
@ 2011-12-23 19:57 ` Sebastian Haas
2011-12-26 10:55 ` Grosjean Stephane
2012-01-10 11:21 ` Wolfgang Grandegger
1 sibling, 1 reply; 4+ messages in thread
From: Sebastian Haas @ 2011-12-23 19:57 UTC (permalink / raw)
To: Stephane Grosjean; +Cc: Oliver Hartkopp, Linux CAN mailing list
Hi Stéphane,
just some minor annotations.
Cheers and Merry Christmas,
Sebastian
Am 22.12.2011 14:14, schrieb Stephane Grosjean:
> +static int pcan_usb_pro_sizeof_rec(u8 data_type)
> +{
> + switch (data_type) {
> + case PCAN_USBPRO_RXMSG8:
> + return sizeof(struct pcan_usb_pro_rxmsg);
> + case PCAN_USBPRO_RXMSG4:
> + return sizeof(struct pcan_usb_pro_rxmsg) - 4;
> + case PCAN_USBPRO_RXMSG0:
> + case PCAN_USBPRO_RXRTR:
> + return sizeof(struct pcan_usb_pro_rxmsg) - 8;
> + case PCAN_USBPRO_RXSTATUS:
> + return sizeof(struct pcan_usb_pro_rxstatus);
...
I wonder if it is possible to use some kind of a table here to improve
readability and reduce code.
...
> + case PCAN_USBPRO_SETLED:
> + return sizeof(struct pcan_usb_pro_setled);
> + default:
> + pr_info("%s: %s(%d): unsupported data type\n",
> + PCAN_USB_DRIVER_NAME, __func__, data_type);
> + break;
> + }
> +
> + return -1;
> +}
> +static int pcan_usb_pro_set_bittiming(struct peak_usb_device *dev,
> + struct can_bittiming *bt)
> +{
> + struct pcan_usb_pro_msg um;
> + u8 tmp[32];
> + 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;
Does the PCAN-USB uses a NXP LPC21xx controller?
> +
> + netdev_dbg(dev->netdev, "ccbt=0x%08x\n", ccbt);
> +
> + pcan_usb_pro_msg_init_empty(&um, tmp, sizeof(tmp));
> + pcan_usb_pro_add_rec(&um, PCAN_USBPRO_SETBTR, dev->ctrl_idx, ccbt);
> +
> + return pcan_usb_pro_send_cmd(dev,&um);
> +}
> +/*
> + * 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_usb_pro_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;
> + int sizeof_rec = pcan_usb_pro_sizeof_rec(pr->data_type);
> +
> + if (sizeof_rec<= 0) {
> + 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:
> + err = pcan_usb_pro_handle_ts(usb_if,&pr->rx_ts);
No handling in error case, is that right?
> + 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;
> + int err = 0;
> +
> + pcan_usb_pro_msg_init_empty(&usb_msg, obuf, *size);
> +
> + if ((cf->can_id& CAN_RTR_FLAG) || (cf->can_dlc == 0))
> + data_type = PCAN_USBPRO_TXMSG0;
> +
Remove empty line.
> + 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;
> +
> + err = pcan_usb_pro_add_rec(&usb_msg, data_type, 0, flags, len,
> + cf->can_id, cf->data);
\err\ is not checked.
> +
> + *size = usb_msg.rec_buffer_len;
> +
> + 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 = (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;
> +
> + /* tell the device the can driver is running */
> + pcan_usb_pro_drv_loaded(dev, 1);
> +
> + if (pcan_usb_pro_send_req(dev, PCAN_USBPRO_REQ_INFO,
> + PCAN_USBPRO_INFO_FIRMWARE,&fi, sizeof(fi))>= 0)
> + netdev_info(dev->netdev,
> + "%s fw v%d.%d.%d (%02d/%02d/%02d) fw 0x%08x\n",
> + pcan_usb_pro.name,
> + fi.version[0], fi.version[1], fi.version[2],
> + fi.day, fi.month, fi.year, fi.fw_type);
> +
> + if (pcan_usb_pro_send_req(dev, PCAN_USBPRO_REQ_INFO,
> + PCAN_USBPRO_INFO_BOOTLOADER,&bi, sizeof(bi))>= 0) {
> + netdev_info(dev->netdev,
> + "bootloader v%d.%d.%d (%02d/%02d/%02d)\n",
> + bi.version[0], bi.version[1], bi.version[2],
> + bi.day, bi.month, bi.year);
> +
> + netdev_info(dev->netdev,
> + "serial %08X.%08X hw 0x%08x rev 0x%08x\n",
> + bi.serial_num_hi, bi.serial_num_lo,
> + bi.hw_type, bi.hw_rev);
> +
> + dev->device_rev = (u8)bi.hw_rev;
> + }
> +
> + usb_if = kzalloc(sizeof(struct pcan_usb_pro_interface),
> + GFP_KERNEL);
> + if (!usb_if)
> + return -ENOMEM;
Is it necessary to call pcan_usb_pro_drv_loaded(dev, 0) here?
> +
> + /* number of ts msgs to ignore before taking one into account */
> + usb_if->cm_ignore_count = 5;
> +
Remove empty line.
> + } 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 = (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)
> +
Remove empty line. Brackets may increase readability here.
> + /* 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 driver is being unloaded */
> + pcan_usb_pro_drv_loaded(dev, 0);
> + }
> +}
^ permalink raw reply [flat|nested] 4+ messages in thread
* Re: [PATCH] Add support for PEAK System PCAN-USB Pro adapter
2011-12-23 19:57 ` Sebastian Haas
@ 2011-12-26 10:55 ` Grosjean Stephane
0 siblings, 0 replies; 4+ messages in thread
From: Grosjean Stephane @ 2011-12-26 10:55 UTC (permalink / raw)
To: Sebastian Haas; +Cc: Oliver Hartkopp, Linux CAN mailing list
Hello Sebastian,
Le 23/12/2011 20:57, Sebastian Haas a écrit :
> Hi Stéphane,
>
> just some minor annotations.
>
> Cheers and Merry Christmas,
> Sebastian
>
> Am 22.12.2011 14:14, schrieb Stephane Grosjean:
>> +static int pcan_usb_pro_sizeof_rec(u8 data_type)
>> +{
>> + switch (data_type) {
>> + case PCAN_USBPRO_RXMSG8:
>> + return sizeof(struct pcan_usb_pro_rxmsg);
>> + case PCAN_USBPRO_RXMSG4:
>> + return sizeof(struct pcan_usb_pro_rxmsg) - 4;
>> + case PCAN_USBPRO_RXMSG0:
>> + case PCAN_USBPRO_RXRTR:
>> + return sizeof(struct pcan_usb_pro_rxmsg) - 8;
>> + case PCAN_USBPRO_RXSTATUS:
>> + return sizeof(struct pcan_usb_pro_rxstatus);
> ...
> I wonder if it is possible to use some kind of a table here to improve
> readability and reduce code.
> ...
Yes it is... You all are right: I changed that ugly function with
something like that:
/* record size array */
static u16 pcan_usb_pro_sizeof_rec[256] = {
[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),
...
and changed the (2) function calls from:
rec_len = pcan_usb_pro_sizeof_rec(x);
if (rec_len <= 0) {
to:
rec_len = pcan_usb_pro_sizeof_rec[x];
if (!rec_len) {
(knowing that "x" is always a BYTE value)
>> + case PCAN_USBPRO_SETLED:
>> + return sizeof(struct pcan_usb_pro_setled);
>> + default:
>> + pr_info("%s: %s(%d): unsupported data type\n",
>> + PCAN_USB_DRIVER_NAME, __func__, data_type);
>> + break;
>> + }
>> +
>> + return -1;
>> +}
>> +static int pcan_usb_pro_set_bittiming(struct peak_usb_device *dev,
>> + struct can_bittiming *bt)
>> +{
>> + struct pcan_usb_pro_msg um;
>> + u8 tmp[32];
>> + 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;
> Does the PCAN-USB uses a NXP LPC21xx controller?
I suppose you ask for the "PCAN-USB Pro" adapter, right? Yes it does.
>> +
>> + netdev_dbg(dev->netdev, "ccbt=0x%08x\n", ccbt);
>> +
>> + pcan_usb_pro_msg_init_empty(&um, tmp, sizeof(tmp));
>> + pcan_usb_pro_add_rec(&um, PCAN_USBPRO_SETBTR, dev->ctrl_idx, ccbt);
>> +
>> + return pcan_usb_pro_send_cmd(dev,&um);
>> +}
>> +/*
>> + * 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_usb_pro_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;
>> + int sizeof_rec = pcan_usb_pro_sizeof_rec(pr->data_type);
>> +
>> + if (sizeof_rec<= 0) {
>> + 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:
>> + err = pcan_usb_pro_handle_ts(usb_if,&pr->rx_ts);
> No handling in error case, is that right?
to be coherent, all the "pcan_usb_pro_handle_xxx()" functions return an
int... But this one always returns 0... So, I changed it into "void
pcan_usb_pro_handle_ts()" now.
>> + 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;
>> + int err = 0;
>> +
>> + pcan_usb_pro_msg_init_empty(&usb_msg, obuf, *size);
>> +
>> + if ((cf->can_id& CAN_RTR_FLAG) || (cf->can_dlc == 0))
>> + data_type = PCAN_USBPRO_TXMSG0;
>> +
> Remove empty line.
Ok.
>> + 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;
>> +
>> + err = pcan_usb_pro_add_rec(&usb_msg, data_type, 0, flags, len,
>> + cf->can_id, cf->data);
> \err\ is not checked.
Yes you're right, and it does not need to be. So I removed the "err"
local variable from the function.
>> +
>> + *size = usb_msg.rec_buffer_len;
>> +
>> + 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 = (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;
>> +
>> + /* tell the device the can driver is running */
>> + pcan_usb_pro_drv_loaded(dev, 1);
>> +
>> + if (pcan_usb_pro_send_req(dev, PCAN_USBPRO_REQ_INFO,
>> + PCAN_USBPRO_INFO_FIRMWARE,&fi, sizeof(fi))>= 0)
>> + netdev_info(dev->netdev,
>> + "%s fw v%d.%d.%d (%02d/%02d/%02d) fw 0x%08x\n",
>> + pcan_usb_pro.name,
>> + fi.version[0], fi.version[1], fi.version[2],
>> + fi.day, fi.month, fi.year, fi.fw_type);
>> +
>> + if (pcan_usb_pro_send_req(dev, PCAN_USBPRO_REQ_INFO,
>> + PCAN_USBPRO_INFO_BOOTLOADER,&bi, sizeof(bi))>= 0) {
>> + netdev_info(dev->netdev,
>> + "bootloader v%d.%d.%d (%02d/%02d/%02d)\n",
>> + bi.version[0], bi.version[1], bi.version[2],
>> + bi.day, bi.month, bi.year);
>> +
>> + netdev_info(dev->netdev,
>> + "serial %08X.%08X hw 0x%08x rev 0x%08x\n",
>> + bi.serial_num_hi, bi.serial_num_lo,
>> + bi.hw_type, bi.hw_rev);
>> +
>> + dev->device_rev = (u8)bi.hw_rev;
>> + }
>> +
>> + usb_if = kzalloc(sizeof(struct pcan_usb_pro_interface),
>> + GFP_KERNEL);
>> + if (!usb_if)
>> + return -ENOMEM;
> Is it necessary to call pcan_usb_pro_drv_loaded(dev, 0) here?
I think you're right too... But I preferred to move the (dev, 1) call
from the beginning of the block to its end (immediately after
cm_ignore_count = 5).
>> +
>> + /* number of ts msgs to ignore before taking one into
>> account */
>> + usb_if->cm_ignore_count = 5;
>> +
> Remove empty line.
Ok.
>> + } 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 = (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)
>> +
> Remove empty line. Brackets may increase readability here.
Ok and brackets added.
>> + /* 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 driver is being unloaded */
>> + pcan_usb_pro_drv_loaded(dev, 0);
>> + }
>> +}
Thanks!
^ permalink raw reply [flat|nested] 4+ messages in thread
* Re: [PATCH] Add support for PEAK System PCAN-USB Pro adapter
2011-12-22 13:14 [PATCH] Add support for PEAK System PCAN-USB Pro adapter Stephane Grosjean
2011-12-23 19:57 ` Sebastian Haas
@ 2012-01-10 11:21 ` Wolfgang Grandegger
1 sibling, 0 replies; 4+ messages in thread
From: Wolfgang Grandegger @ 2012-01-10 11:21 UTC (permalink / raw)
To: Stephane Grosjean; +Cc: Oliver Hartkopp, Linux CAN mailing list
On 12/22/2011 02:14 PM, Stephane Grosjean wrote:
>>From a1b285074b883edc3dccc6aacafb18407e98e18a Mon Sep 17 00:00:00 2001
> From: Stephane Grosjean <s.grosjean@peak-system.com>
> Date: Thu, 22 Dec 2011 13:59:00 +0100
> Subject: [PATCH] Add support for PEAK System PCAN-USB Pro adapter
>
> ---
> drivers/net/can/usb/peak_usb/pcan_usb_pro.c | 1092 +++++++++++++++++++++++++++
> drivers/net/can/usb/peak_usb/pcan_usb_pro.h | 352 +++++++++
> 2 files changed, 1444 insertions(+), 0 deletions(-)
> create mode 100644 drivers/net/can/usb/peak_usb/pcan_usb_pro.c
> create mode 100644 drivers/net/can/usb/peak_usb/pcan_usb_pro.h
>
> 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 0000000..0747395
> --- /dev/null
> +++ b/drivers/net/can/usb/peak_usb/pcan_usb_pro.c
> @@ -0,0 +1,1092 @@
> +/*
> + * CAN driver for PEAK System PCAN-USB Pro 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"
> +#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_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
> +
> +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;
> +};
> +
> +struct pcan_usb_pro_device {
> + struct peak_usb_device peak_usb_device; /* must be the first member */
This construction is deprecated. Using container_of() is usually the
better and safer solution. Is it an option?
> + struct pcan_usb_pro_interface *usb_if;
> +};
> +
> +/* 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;
> +};
> +
> +static int pcan_usb_pro_sizeof_rec(u8 data_type)
> +{
> + switch (data_type) {
> + case PCAN_USBPRO_RXMSG8:
> + return sizeof(struct pcan_usb_pro_rxmsg);
> + case PCAN_USBPRO_RXMSG4:
> + return sizeof(struct pcan_usb_pro_rxmsg) - 4;
> + case PCAN_USBPRO_RXMSG0:
> + case PCAN_USBPRO_RXRTR:
> + return sizeof(struct pcan_usb_pro_rxmsg) - 8;
> + case PCAN_USBPRO_RXSTATUS:
> + return sizeof(struct pcan_usb_pro_rxstatus);
> + case PCAN_USBPRO_RXTS:
> + return sizeof(struct pcan_usb_pro_rxts);
> + case PCAN_USBPRO_TXMSG8:
> + return sizeof(struct pcan_usb_pro_txmsg);
> + case PCAN_USBPRO_TXMSG4:
> + return sizeof(struct pcan_usb_pro_txmsg) - 4;
> + case PCAN_USBPRO_TXMSG0:
> + return sizeof(struct pcan_usb_pro_txmsg) - 8;
> + case PCAN_USBPRO_GETBTR:
> + case PCAN_USBPRO_SETBTR:
> + return sizeof(struct pcan_usb_pro_btr);
> + case PCAN_USBPRO_SETSILENT:
> + return sizeof(struct pcan_usb_pro_silent);
> + case PCAN_USBPRO_SETDEVID:
> + case PCAN_USBPRO_GETDEVID:
> + return sizeof(struct pcan_usb_pro_devid);
> + case PCAN_USBPRO_GETBUSACT:
> + case PCAN_USBPRO_SETBUSACT:
> + return sizeof(struct pcan_usb_pro_busact);
> + case PCAN_USBPRO_SETWARNLIM:
> + return sizeof(struct pcan_usb_pro_warnlim);
> + case PCAN_USBPRO_SETLKUP:
> + return sizeof(struct pcan_usb_pro_lkup);
> + case PCAN_USBPRO_SETLKUPGRP:
> + return sizeof(struct pcan_usb_pro_lkupgrp);
> + case PCAN_USBPRO_SETFILTR:
> + return sizeof(struct pcan_usb_pro_filter);
> + case PCAN_USBPRO_SETRST:
> + return sizeof(struct pcan_usb_pro_reset);
> + case PCAN_USBPRO_SETERRFRM:
> + return sizeof(struct pcan_usb_pro_errfrm);
> + case PCAN_USBPRO_GETBUSSTAT:
> + return sizeof(struct pcan_usb_pro_busstat);
> + case PCAN_USBPRO_SETREG:
> + return sizeof(struct pcan_usb_pro_setreg);
> + case PCAN_USBPRO_GETREG:
> + return sizeof(struct pcan_usb_pro_getreg);
> + case PCAN_USBPRO_SETTS:
> + return sizeof(struct pcan_usb_pro_setts);
> + case PCAN_USBPRO_SETSTR:
> + return sizeof(struct pcan_usb_pro_setstr);
> + case PCAN_USBPRO_GETSTR:
> + return sizeof(struct pcan_usb_pro_getstr);
> + case PCAN_USBPRO_STRING:
> + return sizeof(struct pcan_usb_pro_str);
> + case PCAN_USBPRO_SAVE:
> + return sizeof(struct pcan_usb_pro_save);
> + case PCAN_USBPRO_PDELAY:
> + return sizeof(struct pcan_usb_pro_pdelay);
> + case PCAN_USBPRO_TSARG:
> + return sizeof(struct pcan_usb_pro_tsarg);
> + case PCAN_USBPRO_ERRID:
> + return sizeof(struct pcan_usb_pro_errid);
> + case PCAN_USBPRO_ERRNOW:
> + return sizeof(struct pcan_usb_pro_errnow);
> + case PCAN_USBPRO_SETSFILER:
> + return sizeof(struct pcan_usb_pro_sfiller);
> + case PCAN_USBPRO_SETLED:
> + return sizeof(struct pcan_usb_pro_setled);
> + default:
> + pr_info("%s: %s(%d): unsupported data type\n",
> + PCAN_USB_DRIVER_NAME, __func__, data_type);
> + break;
> + }
> +
> + return -1;
> +}
Please use a jump table, which you already did, IIRC.
> +/*
> + * initialize PCAN-USB Pro message data structure
> + */
> +static u8 *pcan_usb_pro_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_usb_pro_msg_init_empty(struct pcan_usb_pro_msg *pm,
> + void *buffer_addr, int buffer_size)
> +{
> + u8 *pr = pcan_usb_pro_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_usb_pro_add_rec(struct pcan_usb_pro_msg *pm, int id, ...)
> +{
> + int l, i;
l or 1? Depending on your font, it will be hard to distinguish.
Therefore, please use "j", "k", or "len" instead.
> + 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++ = (u8)va_arg(ap, int);
> + *pc++ = (u8)va_arg(ap, int);
> + *pc++ = (u8)va_arg(ap, int);
Are the casts (u8) and (u16) here and below really needed?
> + *(u32 *)pc = cpu_to_le32(va_arg(ap, u32));
> + pc += 4;
> + memcpy(pc, va_arg(ap, int *), i);
> + pc += i;
> + break;
> +
> + case PCAN_USBPRO_GETBUSACT:
> + case PCAN_USBPRO_GETBUSSTAT:
> + *pc++ = (u8)va_arg(ap, int);
> + break;
> +
> + case PCAN_USBPRO_SETBTR:
> + case PCAN_USBPRO_GETBTR:
> + case PCAN_USBPRO_SETDEVID:
> + case PCAN_USBPRO_GETDEVID:
> + *pc++ = (u8)va_arg(ap, int);
> + pc += 2;
> + *(u32 *)pc = cpu_to_le32(va_arg(ap, u32));
> + pc += 4;
> + break;
> +
> + case PCAN_USBPRO_SETBUSACT:
> + case PCAN_USBPRO_SETSILENT:
> + case PCAN_USBPRO_SETWARNLIM:
> + case PCAN_USBPRO_SETFILTR:
> + case PCAN_USBPRO_SETRST:
> + case PCAN_USBPRO_SETERRFRM:
> + case PCAN_USBPRO_TSARG:
> + case PCAN_USBPRO_ERRNOW:
> + *pc++ = (u8)va_arg(ap, int);
> + *(u16 *)pc = cpu_to_le16((u16)va_arg(ap, int));
> + pc += 2;
> + break;
> +
> + case PCAN_USBPRO_SETLKUP:
> + case PCAN_USBPRO_SETLED:
> + *pc++ = (u8)va_arg(ap, int);
> + *(u16 *)pc = cpu_to_le16((u16)va_arg(ap, int));
> + pc += 2;
> + *(u32 *)pc = cpu_to_le32(va_arg(ap, u32));
> + pc += 4;
> + break;
> +
> + case PCAN_USBPRO_SETLKUPGRP:
> + *pc++ = (u8)va_arg(ap, int);
> + *(u16 *)pc = cpu_to_le16((u16)va_arg(ap, int));
> + pc += 2;
> + *(u32 *)pc = cpu_to_le32(va_arg(ap, u32));
> + pc += 4;
> + *(u32 *)pc = cpu_to_le32(va_arg(ap, u32));
> + pc += 4;
> + break;
> +
> + case PCAN_USBPRO_SETREG:
> + *pc++ = (u8)va_arg(ap, int);
> + pc += 2;
> + *(u32 *)pc = cpu_to_le32(va_arg(ap, u32));
> + pc += 4;
> + *(u32 *)pc = cpu_to_le32(va_arg(ap, u32));
> + pc += 4;
> + *(u32 *)pc = cpu_to_le32(va_arg(ap, u32));
> + pc += 4;
> + break;
> +
> + case PCAN_USBPRO_GETREG:
> + *pc++ = (u8)va_arg(ap, int);
> + pc += 2;
> + *(u32 *)pc = cpu_to_le32(va_arg(ap, u32));
> + pc += 4;
> + *(u32 *)pc = cpu_to_le32(va_arg(ap, u32));
> + pc += 4;
> + break;
> +
> + case PCAN_USBPRO_SETTS:
> + case PCAN_USBPRO_PDELAY:
> + pc++;
> + *(u16 *)pc = cpu_to_le16((u16)va_arg(ap, int));
> + pc += 2;
> + break;
> +
> + case PCAN_USBPRO_SETBUSLAST:
> + *pc++ = (u8)va_arg(ap, int);
> + pc++;
> + *pc++ = (u8)va_arg(ap, int);
> + pc += 2;
> + *(u16 *)pc = cpu_to_le16(4096);
> + pc += 2;
> + break;
> +
> + case PCAN_USBPRO_SETSTR:
> + *pc++ = (u8)va_arg(ap, int);
> + *pc++ = (u8)va_arg(ap, int);
> + *pc++ = (u8)va_arg(ap, int);
> + memcpy(pc, va_arg(ap, u8 *), 60);
> + pc += 60;
> + break;
> +
> + case PCAN_USBPRO_GETSTR:
> + case PCAN_USBPRO_SAVE:
> + *pc++ = (u8)va_arg(ap, int);
> + pc += 2;
> + break;
> +
> + case PCAN_USBPRO_STRING:
> + *pc++ = (u8)va_arg(ap, int);
> + pc += 2;
> + memcpy(pc, va_arg(ap, u8 *), 250);
> + pc += 250;
> + break;
> +
> + case PCAN_USBPRO_ERRID:
> + *pc++ = (u8)va_arg(ap, int);
> + *(u16 *)pc = cpu_to_le16((u16)va_arg(ap, int));
> + pc += 2;
> + *(u32 *)pc = cpu_to_le32(va_arg(ap, u32));
> + pc += 4;
> + *(u16 *)pc = cpu_to_le16((u16)va_arg(ap, int));
> + pc += 2;
> + *(u16 *)pc = cpu_to_le16((u16)va_arg(ap, int));
> + pc += 2;
> + break;
> +
> + case PCAN_USBPRO_SETSFILER:
> + *pc++ = (u8)va_arg(ap, int);
> + pc += 2;
> + *(u32 *)pc = cpu_to_le32(va_arg(ap, u32));
> + pc += 4;
> + *(u32 *)pc = cpu_to_le32(va_arg(ap, u32));
> + pc += 4;
> + break;
> +
> + default:
> + pr_info("%s: %s(): unknown data type %02Xh (%d)\n",
> + PCAN_USB_DRIVER_NAME, __func__, id, id);
info or error?
> + pc--;
> + break;
> + }
A jump table would make sense here as well combining it with the one
used above.
> + l = pc - pm->rec_ptr;
> + if (l > 0) {
> + *pm->u.rec_cnt = cpu_to_le32(*pm->u.rec_cnt+1);
> + *(pm->rec_ptr) = (u8)id;
> +
> + pm->rec_ptr = pc;
> + pm->rec_buffer_len += l;
> + }
> +
> + va_end(ap);
> +
> + return l;
> +}
> +
> +/*
> + * 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;
> + int 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;
> +
> + if (actual_length < PCAN_USBPRO_MSG_HEADER_LEN) {
> + netdev_err(dev->netdev,
> + "got abnormal too small rsp (len=%d)\n",
> + actual_length);
> + err = -EBADMSG;
> + break;
> + }
> +
> + pc = pcan_usb_pro_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 <= 0) {
> + netdev_err(dev->netdev,
> + "got unprocessed record in msg\n");
> + dump_mem("rcvd rsp msg", pum->u.rec_buffer,
> + actual_length);
> + err = -EBADMSG;
> + 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);
err = ?
> +
> + /* 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;
> +
> + case PCAN_USBPRO_REQ_INFO:
Not needed if it belongs to the default cases.
> + 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);
Spaces around "*".
> + if (err < 0)
> + netdev_info(dev->netdev,
> + "unable to request usb[type=%d value=%d] err=%d\n",
> + req_id, req_value, err);
> + else
> + err = 0;
> +
> + return err;
if (err < 0) {
...
return err;
}
return 0;
look better.
> +}
> +
> +static int pcan_usb_pro_set_ts(struct peak_usb_device *dev, u16 onoff)
> +{
> + struct pcan_usb_pro_msg um;
> + u8 tmp[32];
> +
> + pcan_usb_pro_msg_init_empty(&um, tmp, sizeof(tmp));
> + pcan_usb_pro_add_rec(&um, PCAN_USBPRO_SETTS, onoff);
> +
> + 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;
> + u8 tmp[32];
> +
> + pcan_usb_pro_msg_init_empty(&um, tmp, sizeof(tmp));
> + pcan_usb_pro_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;
> + u8 tmp[32];
> +
> + pcan_usb_pro_msg_init_empty(&um, tmp, sizeof(tmp));
> + pcan_usb_pro_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;
> + u8 tmp[32];
> +
> + pcan_usb_pro_msg_init_empty(&um, tmp, sizeof(tmp));
> + pcan_usb_pro_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;
> + u8 tmp[32];
> +
> + pcan_usb_pro_msg_init_empty(&um, tmp, sizeof(tmp));
> + pcan_usb_pro_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_msg um;
> + struct pcan_usb_pro_devid *pdn;
> + u8 tmp[32], *pc;
> + int err;
> +
> + pc = pcan_usb_pro_msg_init_empty(&um, tmp, sizeof(tmp));
> + pcan_usb_pro_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)
> +{
> + struct pcan_usb_pro_msg um;
> + u8 tmp[32];
> + 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_dbg(dev->netdev, "ccbt=0x%08x\n", ccbt);
Please netdev_info like all other drivers.
> +
> + pcan_usb_pro_msg_init_empty(&um, tmp, sizeof(tmp));
> + pcan_usb_pro_add_rec(&um, PCAN_USBPRO_SETBTR, dev->ctrl_idx, ccbt);
> +
> + return pcan_usb_pro_send_cmd(dev, &um);
> +}
> +
> +static void pcan_usb_pro_drv_loaded(struct peak_usb_device *dev, int loaded)
> +{
> + u8 buffer[16];
> +
> + buffer[0] = 0;
> + buffer[1] = loaded ? 1 : 0;
> +
> + pcan_usb_pro_send_req(dev, PCAN_USBPRO_REQ_FCT,
> + PCAN_USBPRO_FCT_DRIVER_LOADED, buffer, sizeof(buffer));
> +}
> +
> +static inline
> +struct pcan_usb_pro_interface *pcan_usb_pro_dev_if(struct peak_usb_device *dev)
> +{
> + return ((struct pcan_usb_pro_device *)dev)->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_RTR)
> + can_frame->can_id |= CAN_RTR_FLAG;
> + if (rx->flags & PCAN_USBPRO_EXT)
> + can_frame->can_id |= CAN_EFF_FLAG;
> +
> + memcpy(can_frame->data, rx->data, can_frame->can_dlc);
In case of RTR, we should not copy data, IIRC.
> + 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;
> + struct sk_buff *skb;
> + struct timeval tv;
> +
> + skb = alloc_can_err_skb(netdev, &can_frame);
> + if (!skb)
> + return -ENOMEM;
> +
> + memset(can_frame, '\0', sizeof(struct can_frame));
Not necessary because already done by alloc_can_err_skb().
> +
> + if (raw_status & FW_USBPRO_STATUS_BUS_S) {
> + can_frame->can_id |= CAN_ERR_BUSOFF;
> + can_bus_off(netdev);
> +
> + } else if (raw_status & FW_USBPRO_STATUS_ERROR_S) {
> + 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) {
> + can_frame->can_id |= CAN_ERR_CRTL;
> + can_frame->data[1] |= CAN_ERR_CRTL_RX_PASSIVE;
> + dev->can.can_stats.error_passive++;
> +
> + } else if (rx_err_cnt > 96) {
> + can_frame->can_id |= CAN_ERR_CRTL;
> + can_frame->data[1] |= CAN_ERR_CRTL_RX_WARNING;
> + dev->can.can_stats.error_warning++;
> + }
> +
> + if (tx_err_cnt > 127) {
> + can_frame->can_id |= CAN_ERR_CRTL;
> + can_frame->data[1] |= CAN_ERR_CRTL_TX_PASSIVE;
> + dev->can.can_stats.error_passive++;
> +
> + } else if (tx_err_cnt > 96) {
> + can_frame->can_id |= CAN_ERR_CRTL;
> + can_frame->data[1] |= CAN_ERR_CRTL_TX_WARNING;
> + dev->can.can_stats.error_warning++;
> + }
> + }
> +
> + if (raw_status & FW_USBPRO_STATUS_OVERRUN_S) {
> + can_frame->can_id |= CAN_ERR_PROT;
> + can_frame->data[2] |= CAN_ERR_PROT_OVERLOAD;
> + }
> +
> + if (raw_status & FW_USBPRO_STATUS_QOVERRUN_S) {
> + can_frame->can_id |= CAN_ERR_CRTL;
> + can_frame->data[1] |= CAN_ERR_CRTL_RX_OVERFLOW;
> + }
> +
> + if (can_frame->can_id != CAN_ERR_FLAG) {
> + 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++;
rx_bytes?
> + } else {
> + kfree_skb(skb);
> + }
> +
> + return 0;
> +}
> +
> +static int 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]));
> +
> + return 0;
> +}
> +
> +/*
> + * 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_usb_pro_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;
> + int sizeof_rec = pcan_usb_pro_sizeof_rec(pr->data_type);
> +
> + if (sizeof_rec <= 0) {
> + 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:
> + err = 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;
> + int err = 0;
> +
> + pcan_usb_pro_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;
> +
> + err = pcan_usb_pro_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 = (struct pcan_usb_pro_device *)dev;
> + int err;
> +
> + err = pcan_usb_pro_set_silent(dev,
> + (dev->can.ctrlmode & CAN_CTRLMODE_LISTENONLY));
"()" not needed.
> + if (err)
> + goto start_failed;
> +
> + /* Set filter mode: 0-> All OFF; 1->bypass */
> + err = pcan_usb_pro_set_filter(dev, 1);
> + if (err)
> + goto start_failed;
> +
> + /* 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++;
> +
> +start_failed:
> + return err;
Useless label!
> +}
> +
> +/*
> + * 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 = (struct pcan_usb_pro_device *)dev;
Hm, this cast worries me. What about using container_of?
> + /* 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 = (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;
> +
> + /* tell the device the can driver is running */
> + pcan_usb_pro_drv_loaded(dev, 1);
> +
> + if (pcan_usb_pro_send_req(dev, PCAN_USBPRO_REQ_INFO,
> + PCAN_USBPRO_INFO_FIRMWARE, &fi, sizeof(fi)) >= 0)
> + netdev_info(dev->netdev,
> + "%s fw v%d.%d.%d (%02d/%02d/%02d) fw 0x%08x\n",
> + pcan_usb_pro.name,
> + fi.version[0], fi.version[1], fi.version[2],
> + fi.day, fi.month, fi.year, fi.fw_type);
> +
> + if (pcan_usb_pro_send_req(dev, PCAN_USBPRO_REQ_INFO,
> + PCAN_USBPRO_INFO_BOOTLOADER, &bi, sizeof(bi)) >= 0) {
> + netdev_info(dev->netdev,
> + "bootloader v%d.%d.%d (%02d/%02d/%02d)\n",
> + bi.version[0], bi.version[1], bi.version[2],
> + bi.day, bi.month, bi.year);
> +
> + netdev_info(dev->netdev,
> + "serial %08X.%08X hw 0x%08x rev 0x%08x\n",
> + bi.serial_num_hi, bi.serial_num_lo,
> + bi.hw_type, bi.hw_rev);
> +
> + dev->device_rev = (u8)bi.hw_rev;
> + }
> +
> + 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;
> +
> + } 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 = (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)
> +
remove empty line.
> + /* 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 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. All 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:
> + /* CAN usb interface unused ep */
> + case 0x83:
> + 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 commands/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,
> +};
> 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 0000000..66952cb
> --- /dev/null
> +++ b/drivers/net/can/usb/peak_usb/pcan_usb_pro.h
> @@ -0,0 +1,352 @@
> +/*
> + * CAN driver for PEAK System PCAN-USB Pro 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.
> + */
> +#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 wValue for XXX_INFO */
Please correct message?
> +#define PCAN_USBPRO_INFO_BOOTLOADER 0
> +#define PCAN_USBPRO_INFO_FIRMWARE 1
> +
> +/* Vendor Request wValue for XXX_FCT */
> +#define PCAN_USBPRO_FCT_DRIVER_LOADED 5
Ditto.
> +
> +/* PCAN_USBPRO_INFO_BOOTLOADER 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_FIRMWARE 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_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_RXBUSLAST 0x86
> +#define PCAN_USBPRO_TXMSG8 0x41
> +#define PCAN_USBPRO_TXMSG4 0x42
> +#define PCAN_USBPRO_TXMSG0 0x43
> +#define PCAN_USBPRO_GETBTR 0x01
> +#define PCAN_USBPRO_SETBTR 0x02
> +#define PCAN_USBPRO_GETBUSACT 0x03
> +#define PCAN_USBPRO_SETBUSACT 0x04
> +#define PCAN_USBPRO_SETSILENT 0x05
> +#define PCAN_USBPRO_SETDEVID 0x06
> +#define PCAN_USBPRO_SETWARNLIM 0x07
> +#define PCAN_USBPRO_SETLKUP 0x08
> +#define PCAN_USBPRO_SETLKUPGRP 0x09
> +#define PCAN_USBPRO_SETFILTR 0x0a
> +#define PCAN_USBPRO_SETRST 0x0b
> +#define PCAN_USBPRO_SETERRFRM 0x0c
> +#define PCAN_USBPRO_GETBUSSTAT 0x0D
> +#define PCAN_USBPRO_SETREG 0x0e
> +#define PCAN_USBPRO_GETREG 0x0f
> +#define PCAN_USBPRO_SETTS 0x10
> +#define PCAN_USBPRO_SETBUSLAST 0x11
> +#define PCAN_USBPRO_GETDEVID 0x12
> +#define PCAN_USBPRO_SETSTR 0x13
> +#define PCAN_USBPRO_GETSTR 0x14
> +#define PCAN_USBPRO_STRING 0x15
> +#define PCAN_USBPRO_SAVE 0x16
> +#define PCAN_USBPRO_PDELAY 0x17
> +#define PCAN_USBPRO_TSARG 0x18
> +#define PCAN_USBPRO_ERRID 0x19
> +#define PCAN_USBPRO_ERRNOW 0x1A
> +#define PCAN_USBPRO_SETSFILER 0x1B
> +#define PCAN_USBPRO_SETLED 0x1C
> +
> +/* record structures */
> +struct __packed pcan_usb_pro_rxmsg {
> + u8 data_type;
> + u8 client;
> + u8 flags;
> + u8 len;
> + u32 ts32;
> + u32 id;
> +
> + u8 data[8];
> +};
> +
> +#define FW_USBPRO_STATUS_ERROR_S 0x0001
> +#define FW_USBPRO_STATUS_BUS_S 0x0002
Check tabs!
> +#define FW_USBPRO_STATUS_OVERRUN_S 0x0004
> +#define FW_USBPRO_STATUS_QOVERRUN_S 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_buslast {
> + u8 data_type;
> + u8 channel;
> + u16 buslast_val;
> + u32 ts32;
> +};
> +
> +struct __packed pcan_usb_pro_txmsg {
> + u8 data_type;
> + u8 client;
> + u8 flags;
> + u8 len;
> + u32 id;
> + u8 data[8];
> +};
> +
> +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_devid {
> + u8 data_type;
> + u8 channel;
> + u16 dummy;
> + u32 serial_num;
> +};
> +
> +struct __packed pcan_usb_pro_warnlim {
> + u8 data_type;
> + u8 channel;
> + u16 warning_limit;
> +};
> +
> +struct __packed pcan_usb_pro_lkup {
> + u8 data_type;
> + u8 channel;
> + u16 id_type;
> + u32 id;
> +};
> +
> +struct __packed pcan_usb_pro_lkupgrp {
> + u8 data_type;
> + u8 channel;
> + u16 id_type;
> + u32 id_start;
> + u32 id_end;
> +};
> +
> +struct __packed pcan_usb_pro_filter {
> + u8 data_type;
> + u8 dummy;
> + u16 filter_mode;
> +};
> +
> +struct __packed pcan_usb_pro_reset {
> + u8 data_type;
> + u8 channel;
> + u16 reset;
> +};
> +
> +struct __packed pcan_usb_pro_errfrm {
> + u8 data_type;
> + u8 channel;
> + u16 mode;
> +};
> +
> +struct __packed pcan_usb_pro_busstat {
> + u8 data_type;
> + u8 channel;
> + u16 status;
> +};
> +
> +struct __packed pcan_usb_pro_setreg {
> + u8 data_type;
> + u8 irq_off;
> + u16 dummy;
> + u32 address;
> + u32 value;
> + u32 mask;
> +};
> +
> +struct __packed pcan_usb_pro_getreg {
> + u8 data_type;
> + u8 irq_off;
> + u16 dummy;
> + u32 address;
> + u32 value;
> +};
> +
> +struct __packed pcan_usb_pro_setts {
> + u8 data_type;
> + u8 dummy;
> + u16 mode;
> +};
> +
> +struct __packed pcan_usb_pro_setbl {
> + u8 data_type;
> + u8 channel;
> + u8 dummy;
> + u8 mode;
> + u16 prescaler;
> + u16 sampletimequanta;
> +};
> +
> +struct __packed pcan_usb_pro_setstr {
> + u8 data_type;
> + u8 channel;
> + u8 offset;
> + u8 len;
> + u8 data[60];
> +};
> +
> +struct __packed pcan_usb_pro_getstr {
> + u8 data_type;
> + u8 channel;
> + u16 dummy;
> +};
> +
> +struct __packed pcan_usb_pro_str {
> + u8 data_type;
> + u8 channel;
> + u16 dummy;
> + u8 data[250];
> +};
> +
> +struct __packed pcan_usb_pro_save {
> + u8 data_type;
> + u8 channel;
> + u16 dummy;
> +};
> +
> +struct __packed pcan_usb_pro_pdelay {
> + u8 data_type;
> + u8 dummy;
> + u16 delay;
> +};
> +
> +struct __packed pcan_usb_pro_tsarg {
> + u8 data_type;
> + u8 channel;
> + u16 start_or_end;
> +};
> +
> +struct __packed pcan_usb_pro_errid {
> + u8 data_type;
> + u8 channel;
> + u16 bit_pos;
> + u32 id;
> + u16 ok_counter;
> + u16 error_counter;
> +};
> +
> +struct __packed pcan_usb_pro_errnow {
> + u8 data_type;
> + u8 channel;
> + u16 bit_pos;
> +};
> +
> +struct __packed pcan_usb_pro_sfiller {
> + u8 data_type;
> + u8 channel;
> + u16 dummy;
> + u32 accmask;
> + u32 acccode;
> +};
> +
> +struct __packed pcan_usb_pro_setled {
> + u8 data_type;
> + u8 channel;
> + u16 mode;
> + u32 timeout;
> +};
> +
> +union pcan_usb_pro_rec {
> + u8 data_type;
> + 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_buslast rx_buslast;
> + struct pcan_usb_pro_txmsg tx_msg;
> + struct pcan_usb_pro_btr btr;
Tabs?
> + struct pcan_usb_pro_busact bus_act;
> + struct pcan_usb_pro_silent silent_mode;
> + struct pcan_usb_pro_devid dev_id;
> + struct pcan_usb_pro_warnlim warn_lim;
> + struct pcan_usb_pro_lkup lkup_expl;
> + struct pcan_usb_pro_lkupgrp lkup_group;
> + struct pcan_usb_pro_filter filter_mode;
> + struct pcan_usb_pro_reset rst_mode;
> + struct pcan_usb_pro_errfrm err_frame;
> + struct pcan_usb_pro_busstat bus_status;
> + struct pcan_usb_pro_setreg set_reg;
> + struct pcan_usb_pro_getreg get_reg;
> + struct pcan_usb_pro_setts ts;
> + struct pcan_usb_pro_setbl bus_last;
> + struct pcan_usb_pro_setstr set_str;
> + struct pcan_usb_pro_getstr get_str;
> + struct pcan_usb_pro_str str;
Tabs?
> + struct pcan_usb_pro_save save_eeprom;
> + struct pcan_usb_pro_pdelay p_delay;
> + struct pcan_usb_pro_tsarg ts_arg;
> + struct pcan_usb_pro_errid err_id;
> + struct pcan_usb_pro_errnow err_now;
> + struct pcan_usb_pro_sfiller soft_filler;
> + struct pcan_usb_pro_setled set_can_led;
> +};
> +
> +#endif
Wolfgang.
^ permalink raw reply [flat|nested] 4+ messages in thread
end of thread, other threads:[~2012-01-10 11:21 UTC | newest]
Thread overview: 4+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2011-12-22 13:14 [PATCH] Add support for PEAK System PCAN-USB Pro adapter Stephane Grosjean
2011-12-23 19:57 ` Sebastian Haas
2011-12-26 10:55 ` Grosjean Stephane
2012-01-10 11:21 ` 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).