From: Marc Kleine-Budde <mkl@pengutronix.de>
To: "s.grosjean@peak-system.com" <s.grosjean@peak-system.com>
Cc: "socketcan@hartkopp.net" <socketcan@hartkopp.net>,
"linux-can@vger.kernel.org" <linux-can@vger.kernel.org>
Subject: Re: "[PATCH] Add support for PEAK-System GmbH CAN USB adapters (v2) "
Date: Fri, 16 Dec 2011 13:41:10 +0100 [thread overview]
Message-ID: <4EEB3C66.1020303@pengutronix.de> (raw)
In-Reply-To: <301939.630738588-sendEmail@ubuntu-i386>
[-- Attachment #1: Type: text/plain, Size: 24906 bytes --]
On 12/16/2011 11:19 AM, s.grosjean@peak-system.com wrote:
> From 1cee3be3875f27a2ee3942b00d611450f4369325 Mon Sep 17 00:00:00 2001
> From: Stephane Grosjean <s.grosjean@peak-system.com>
> Date: Fri, 16 Dec 2011 11:11:37 +0100
> Subject: [PATCH] Add support for PEAK-System GmbH CAN USB adapters (v2)
The driver has some unusal coding style, please use checkpatch and do
sparse checking (compile the drivers with C=2). Make use of C99
initialisers. Use foo->bar not &foo->bar[0] to get the pointer for the
first array element
more comments inline.
Marc
>
> v2 includes:
> change dev_xxx() into netdev_xxx() macros
> add missing include linux/module.h
> pre-allocate urbs and buffers for tx path at _open() and free them at _close()
> rather than into _start_xmit()
> remove some unused code and (boring) #ifdef/#endif
> use "menuconfig" in Kconfig rather than "config" entry
> ---
> drivers/net/can/usb/Kconfig | 20 +
> drivers/net/can/usb/Makefile | 12 +
> drivers/net/can/usb/pcan_usb.c | 654 +++++++++++++++++++
> drivers/net/can/usb/pcan_usb_core.c | 895 ++++++++++++++++++++++++++
> drivers/net/can/usb/pcan_usb_pro.c | 1207 +++++++++++++++++++++++++++++++++++
> drivers/net/can/usb/pcan_usb_pro.h | 468 ++++++++++++++
> drivers/net/can/usb/peak_usb.h | 148 +++++
> 7 files changed, 3404 insertions(+), 0 deletions(-)
> create mode 100644 drivers/net/can/usb/pcan_usb.c
> create mode 100644 drivers/net/can/usb/pcan_usb_core.c
> create mode 100644 drivers/net/can/usb/pcan_usb_pro.c
> create mode 100644 drivers/net/can/usb/pcan_usb_pro.h
> create mode 100644 drivers/net/can/usb/peak_usb.h
>
> diff --git a/drivers/net/can/usb/Kconfig b/drivers/net/can/usb/Kconfig
> index 0452549..cb5f91c 100644
> --- a/drivers/net/can/usb/Kconfig
> +++ b/drivers/net/can/usb/Kconfig
> @@ -13,4 +13,24 @@ config CAN_ESD_USB2
> This driver supports the CAN-USB/2 interface
> from esd electronic system design gmbh (http://www.esd.eu).
>
> +menuconfig CAN_PEAK_USB
> + tristate "PEAK-System USB adapters"
> + ---help---
> + This driver is for PCAN USB interfaces from PEAK-System
> + (http://www.peak-system.com).
> +
> +config CAN_PCAN_USB
> + tristate "PEAK PCAN-USB adapter"
> + depends on CAN_PEAK_USB
> + ---help---
> + This driver is for the one channel PCAN-USB interface
> + from PEAK-System (http://www.peak-system.com).
> +
> +config CAN_PCAN_USB_PRO
> + tristate "PEAK PCAN-USB Pro adapter"
> + depends on CAN_PEAK_USB
> + ---help---
> + This driver is for the two channels PCAN-USB Pro interface
> + from PEAK-System (http://www.peak-system.com).
> +
> endmenu
> diff --git a/drivers/net/can/usb/Makefile b/drivers/net/can/usb/Makefile
> index fce3cf1..a6f1cf6 100644
> --- a/drivers/net/can/usb/Makefile
> +++ b/drivers/net/can/usb/Makefile
> @@ -5,4 +5,16 @@
> obj-$(CONFIG_CAN_EMS_USB) += ems_usb.o
> obj-$(CONFIG_CAN_ESD_USB2) += esd_usb2.o
>
> +obj-$(CONFIG_CAN_PEAK_USB) += peak_usb.o
> +peak_usb-y = pcan_usb_core.o
> +
> +ifneq ($(CONFIG_CAN_PCAN_USB),)
> +peak_usb-y += pcan_usb.o
> +endif
> +
> +ifneq ($(CONFIG_CAN_PCAN_USB_PRO),)
> +peak_usb-y += pcan_usb_pro.o
> +endif
> +
> +ccflags-$(CONFIG_CAN_DEBUG_DEVICES) := -DDEBUG
> ccflags-$(CONFIG_CAN_DEBUG_DEVICES) := -DDEBUG
^^^^^^^^^^
one ccflag should be enough :)
> diff --git a/drivers/net/can/usb/pcan_usb.c b/drivers/net/can/usb/pcan_usb.c
> new file mode 100644
> index 0000000..ec46da6
> --- /dev/null
> +++ b/drivers/net/can/usb/pcan_usb.c
> @@ -0,0 +1,654 @@
> +/*
> + * CAN driver for PEAK System PCAN-USB adapter
> + *
> + * Copyright (C) 2011-2012 PEAK-System GmbH
> + *
> + * This program is free software; you can redistribute it and/or modify it
> + * under the terms of the GNU General Public License as published
> + * by the Free Software Foundation; version 2 of the License.
> + *
> + * This program is distributed in the hope that it will be useful, but
> + * WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
> + * General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License along
> + * with this program; if not, write to the Free Software Foundation, Inc.,
> + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
please remove the address
> + */
> +#include <linux/netdevice.h>
> +#include <linux/usb.h>
> +#include <linux/module.h>
> +
> +#include <linux/can.h>
> +#include <linux/can/dev.h>
> +#include <linux/can/error.h>
> +
> +#include "peak_usb.h"
> +
> +MODULE_SUPPORTED_DEVICE("PEAK-System PCAN-USB adapter");
> +
> +/* PCAN-USB Endpoints */
> +#define PCAN_USB_EP_CMDOUT 1
> +#define PCAN_USB_EP_CMDIN (PCAN_USB_EP_CMDOUT|USB_DIR_IN)
> +#define PCAN_USB_EP_MSGOUT 2
> +#define PCAN_USB_EP_MSGIN (PCAN_USB_EP_MSGOUT|USB_DIR_IN)
^^^
please add spaces around the |
> +
> +/* PCAN-USB parameter command */
> +#define PCAN_USB_PARAMETER_LEN 14
> +struct __packed pcan_usb_parameter {
> + u8 function;
> + u8 number;
^^^
please use one space
> + u8 parameters[PCAN_USB_PARAMETER_LEN];
> +};
> +
> +/* PCAN-USB command timeout (ms.) */
> +#define PCAN_USB_COMMAND_TIMEOUT 1000
> +
> +/* PCAN-USB rx/tx buffers size */
> +#define PCAN_USB_RX_BUFFER_SIZE 64
> +#define PCAN_USB_TX_BUFFER_SIZE 64
> +
> +#define PCAN_USB_MSG_HEADER_LEN 2 /* Packet type information (1xbyte)
> + + count of messages (1xbyte) */
> +
> +/* PCAN-USB adapter internal clock (MHz) */
> +#define PCAN_USB_CRYSTAL_HZ 16000000
> +
> +/* PCAN-USB USB message record status/len field */
> +#define PCAN_USB_STATUSLEN_TIMESTAMP (1 << 7)
> +#define PCAN_USB_STATUSLEN_INTERNAL (1 << 6)
> +#define PCAN_USB_STATUSLEN_EXT_ID (1 << 5)
> +#define PCAN_USB_STATUSLEN_RTR (1 << 4)
> +#define PCAN_USB_STATUSLEN_DLC (0xf)
> +
> +/* PCAN-USB error flags */
> +#define PCAN_USB_ERROR_TXFULL 0x01
> +#define PCAN_USB_ERROR_RXQOVR 0x02
> +#define PCAN_USB_ERROR_BUS_LIGHT 0x04
> +#define PCAN_USB_ERROR_BUS_HEAVY 0x08
> +#define PCAN_USB_ERROR_BUS_OFF 0x10
> +#define PCAN_USB_ERROR_RXQEMPTY 0x20
> +#define PCAN_USB_ERROR_QOVR 0x40
> +#define PCAN_USB_ERROR_TXQFULL 0x80
> +
> +/* SJA1000 modes */
> +#define SJA1000_MODE_NORMAL 0x00
> +#define SJA1000_MODE_INIT 0x01
> +
> +/* tick duration = 42.666 us =>
> + * (tick_number * 44739243) >> 20 ~ (tick_number * 42666) / 1000
> + * accuracy = 10^-7
> + */
> +#define PCAN_USB_TS_DIV_SHIFTER 20
> +#define PCAN_USB_TS_US_PER_TICK 44739243
If you want to align the #defines please use tab between symbol and value
> +
> +struct pcan_usb {
> + struct peak_usb_device pcandev; /* must be the first member */
> + struct peak_time_ref time_ref;
> +};
> +
> +/*
> + * Send the given PCAN-USB command synchronously
> + */
> +static int pcan_usb_send_command(struct peak_usb_device *dev, u8 f, u8 n, u8 *p)
> +{
> + int actual_length;
> + struct pcan_usb_parameter cmd;
> + int err;
> +
> + /* usb device unregistered? */
> + if (!(dev->state & PCAN_USB_STATE_CONNECTED)) return 0;
> +
> + cmd.function = f;
> + cmd.number = n;
you can use C99 initialisers instead:
struct pcan_usb_parameter cmd = {
.function = f,
.number = n,
};
then parameters in automatically set with 0x0....
> +
> + if (p != NULL)
if (p)
> + memcpy(&cmd.parameters[0], p, PCAN_USB_PARAMETER_LEN);
I'd write memcpy(cmd.parameters, p, ARRAY_SIZE(cmd.parameters))
> + else
> + memset(&cmd.parameters[0], '\0', PCAN_USB_PARAMETER_LEN);
...and you can remove the memset here.
> +
> + err = usb_bulk_msg(dev->udev,
> + usb_sndbulkpipe(dev->udev, PCAN_USB_EP_CMDOUT),
> + &cmd, sizeof(struct pcan_usb_parameter),
> + &actual_length, PCAN_USB_COMMAND_TIMEOUT);
> + if (err)
> + netdev_err(dev->netdev,
> + "sending command function=0x%x number=0x%x failure: %d\n",
> + f, n, err);
> +
> + return err;
> +}
> +
> +static int pcan_usb_wait_response(struct peak_usb_device *dev, u8 f, u8 n, u8 *p)
> +{
> + int actual_length;
> + struct pcan_usb_parameter cmd;
> + int err;
> +
> + /* usb device unregistered? */
> + if (!(dev->state & PCAN_USB_STATE_CONNECTED)) return 0;
please put the return in a seperate line.
> +
> + /* first, send command */
> + err = pcan_usb_send_command(dev, f, n, NULL);
> + if (err) {
> + return err;
> + }
please remove the { }
> +
> + cmd.function = f;
> + cmd.number = n;
> + memset(&cmd.parameters[0], '\0', PCAN_USB_PARAMETER_LEN);
please use C99 initialisers
> +
> + /* then, wait for the response */
> + mdelay(5);
> + err = usb_bulk_msg(dev->udev,
> + usb_rcvbulkpipe(dev->udev, PCAN_USB_EP_CMDIN),
> + &cmd, sizeof(struct pcan_usb_parameter),
> + &actual_length, PCAN_USB_COMMAND_TIMEOUT);
> + if (err)
> + netdev_err(dev->netdev,
> + "waiting response function=0x%x number=0x%x failure: %d\n",
> + f, n, err);
> + else if (p) memcpy(p, &cmd.parameters[0], PCAN_USB_PARAMETER_LEN);
please put the memcpy in a seperate line. I'd use cmd.parameters instead
of &cmd.parameters[0], please use ARRAY_SIZE.
> +
> + return err;
> +}
> +
> +static int pcan_usb_set_sja1000(struct peak_usb_device *dev, u8 mode)
> +{
> + u8 args[PCAN_USB_PARAMETER_LEN];
> +
> + args[0] = 0;
> + args[1] = mode;
the array can be initializes in C99 style, too:
u8 args[PCAN_USB_PARAMETER_LEN] = {
[0] = 0,
[1] = mode,
};
The [0] can be skipped, by you might want to include it for
documentation purpose.
Please add a newline in before return
> + return pcan_usb_send_command(dev, 9, 2, args);
> +}
> +
> +static int pcan_usb_set_bus(struct peak_usb_device *dev, u8 onoff)
> +{
> + u8 args[PCAN_USB_PARAMETER_LEN];
> +
> + args[0] = onoff ? 1 : 0;
> + return pcan_usb_send_command(dev, 3, 2, args);
please use/add C99 initialisers + newline, too
> +}
> +
> +static int pcan_usb_set_silent(struct peak_usb_device *dev, u8 onoff)
> +{
> + u8 args[PCAN_USB_PARAMETER_LEN];
> +
> + args[0] = onoff ? 1 : 0;
> + return pcan_usb_send_command(dev, 3, 3, args);
dito
> +}
> +
> +static int pcan_usb_set_ext_vcc(struct peak_usb_device *dev, u8 onoff)
> +{
> + u8 args[PCAN_USB_PARAMETER_LEN];
> +
> + args[0] = onoff ? 1 : 0;
> + return pcan_usb_send_command(dev, 10, 2, args);
dito
I see some magic numbers for the command here, does it make sense to
define an enum for them?
> +}
> +
> +/*
> + * This routine was stolen from drivers/net/can/sja1000/sja1000.c
> + */
Nice for crediting this, but IMHO no need to write it into the code.
> +static int pcan_usb_set_bittiming(struct peak_usb_device *dev, struct can_bittiming *bt)
> +{
> + u8 args[PCAN_USB_PARAMETER_LEN];
> + u8 btr0, btr1;
> +
> + btr0 = ((bt->brp - 1) & 0x3f) | (((bt->sjw - 1) & 0x3) << 6);
> + btr1 = ((bt->prop_seg + bt->phase_seg1 - 1) & 0xf) \
> + | (((bt->phase_seg2 - 1) & 0x7) << 4);
> + if (dev->can.ctrlmode & CAN_CTRLMODE_3_SAMPLES)
> + btr1 |= 0x80;
> +
> + args[0] = btr1;
> + args[1] = btr0;
> +
> + printk("btr0=0x%02x btr1=0x%02x", btr0, btr1);
Please use netdev_LEVEL() instead of printk
> +
> + return pcan_usb_send_command(dev, 1, 2, args);
> +}
> +
> +static int pcan_usb_write_mode(struct peak_usb_device *dev, u8 onoff)
> +{
> + int err;
> +
> + err = pcan_usb_set_bus(dev, onoff);
> + if (err)
> + return err;
> +
> + if (!onoff) {
> + err = pcan_usb_set_sja1000(dev, SJA1000_MODE_INIT);
> + }
please remove the { }
> +
> + return err;
> +}
> +
> +static int pcan_usb_get_serial_number(struct peak_usb_device *dev, u32 *serial_number)
> +{
> + u8 args[PCAN_USB_PARAMETER_LEN];
> + int err;
> +
> + err = pcan_usb_wait_response(dev, 6, 1, args);
> + if (err)
> + netdev_err(dev->netdev, "getting serial number failure: %d\n", err);
> + else {
> + if (serial_number) memcpy(serial_number, &args[0], 4);
> + }
please remove the { }, no command after the if, please.
Hmmm that serial number to u32 memcpy looks fishy, I smell endianess
problem. Can you test your driver on an big endian machine, like powerpc?
> +
> + return err;
> +}
> +
> +static int pcan_usb_get_device_number(struct peak_usb_device *dev, u32 *device_number)
> +{
> + u8 args[PCAN_USB_PARAMETER_LEN];
> + int err;
> +
> + err = pcan_usb_wait_response(dev, 4, 1, args);
> + if (err)
> + netdev_err(dev->netdev, "getting device number failure: %d\n", err);
> + else {
> + if (device_number) *device_number = args[0];
please remove the { }, no command in the same line as the "if"
> + }
> +
> + return err;
> +}
> +
> +static void pcan_usb_update_time_word(struct pcan_usb *pdev, u16 ts16, u8 s)
> +{
> +
> + if (s == 0)
> + peak_usb_set_timestamp_now(&pdev->time_ref, ts16);
> + else
> + peak_usb_update_timestamp_now(&pdev->time_ref, ts16);
> +}
> +
> +/*
> + * callback for bulk IN urb
> + */
> +static int pcan_usb_decode_msg(struct peak_usb_device *dev, struct urb *urb)
> +{
> + struct pcan_usb *pdev = (struct pcan_usb *)dev;
> + struct net_device *netdev = dev->netdev;
> + int err = 0;
> +
> + if (urb->actual_length > PCAN_USB_MSG_HEADER_LEN) {
> + struct net_device_stats *stats = &netdev->stats;
> +
> + u8 *ibuf = urb->transfer_buffer;
> + const u8 msg_count = ibuf[1];
> + int frm_count = 0;
> + u8 i;
> +
> + ibuf += PCAN_USB_MSG_HEADER_LEN;
> +
> + for (i = 0; i < msg_count && !err; i++) {
> +
please remove that extra blame line
> + struct sk_buff *skb;
> + struct can_frame *cf;
> + struct timeval tv;
> + u16 tmp16, ts16=0, dts=0, prev_ts8=0;
please add spaces around =
> + u8 sl = *ibuf++;
> + u8 rec_len = (sl & PCAN_USB_STATUSLEN_DLC);
> +
> + /* handle error frames here */
I suggest to put the error handling in a sub function. If you have
> + if (sl & PCAN_USB_STATUSLEN_INTERNAL) {
> + u8 f = *ibuf++;
> + u8 n = *ibuf++;
> +
> + if (sl & PCAN_USB_STATUSLEN_TIMESTAMP) {
> + /* only the first packet supplies a word timestamp */
> + if (i == 0) {
> + memcpy(&tmp16, ibuf, 2);
> + ibuf += 2;
> + ts16 = le16_to_cpu(tmp16);
> + dts = 0;
> + }
> + else {
> + u8 ts8 = *ibuf++;
> +
> + if (dts) {
> + dts &= 0xff00;
> + if (ts8 < prev_ts8)
> + dts += 0x100;
> + }
> +
> + dts |= ts8;
> + prev_ts8 = ts8;
> +
> + }
> + }
> +
> + switch (f) {
> +
> + case 1:
> +
please reove these two empty lines. I think you should define an enum
for the functions.
> + /* allocate an skb to store the error frame */
> + skb = alloc_can_err_skb(netdev, &cf);
> + if (skb == NULL) {
!skb
please talk to Wolfgang for the error handling, he is the expert now :)
> + err = -ENOMEM;
> + break;
> + }
> +
> + if (n & (PCAN_USB_ERROR_RXQOVR|PCAN_USB_ERROR_QOVR)) {
> + cf->can_id |= CAN_ERR_CRTL;
> + cf->data[1] |= CAN_ERR_CRTL_RX_OVERFLOW;
> + stats->rx_over_errors++;
> + stats->rx_errors++;
> + }
> + if (n & PCAN_USB_ERROR_BUS_OFF) {
> + cf->can_id |= CAN_ERR_BUSOFF;
> + can_bus_off(netdev);
> + }
> + if (n & PCAN_USB_ERROR_BUS_HEAVY) {
> + cf->can_id |= CAN_ERR_CRTL;
> + cf->data[1] |= CAN_ERR_CRTL_RX_PASSIVE;
> + dev->can.can_stats.error_passive++;
> + }
> + if (n & PCAN_USB_ERROR_BUS_LIGHT) {
> + cf->can_id |= CAN_ERR_CRTL;
> + cf->data[1] |= CAN_ERR_CRTL_RX_WARNING;
> + dev->can.can_stats.error_warning++;
> + }
> +
> + if (cf->can_id != CAN_ERR_FLAG) {
> + if (sl & PCAN_USB_STATUSLEN_TIMESTAMP) {
> + peak_usb_get_timestamp_tv(&pdev->time_ref, ts16+dts, &tv);
> + skb->tstamp = timeval_to_ktime(tv);
> + }
> + netif_rx(skb);
> + stats->rx_packets++;
> + }
> +
> + /* v3: sometimes the telegram carries 3 additional data */
> + /* without note in ucStatusLen. */
> + ibuf += rec_len;
> + break;
> +
> + case 2:
> + /* analog values (ignored) */
> + ibuf += 2;
> + break;
> +
> + case 3:
> + /* bus load (ignored) */
> + ibuf++;
> + break;
> +
> + case 4:
> + /* only timestamp */
> + memcpy(&tmp16, ibuf, 2);
> + ibuf += 2;
> + ts16 = le16_to_cpu(tmp16);
> + pcan_usb_update_time_word(pdev, ts16, i);
> + break;
> +
> + case 5:
> + /* error frame/bus event */
> + if (n & PCAN_USB_ERROR_TXQFULL) {
> + netdev_info(netdev, "device Tx queue full)\n");
> + }
remove { }
> + ibuf += rec_len;
> + break;
> +
> + case 10:
> + /* future... */
> + break;
> +
> + default:
> + netdev_err(netdev, "unexpected function %u\n", f);
> + break;
> + }
> + }
> +
> + /* handle normal can frames here */
please use an extra fucntion for normal frames
> + else {
> +
> + u8 d = 0;
> +
> + skb = alloc_can_skb(netdev, &cf);
> + if (skb == NULL) {
> + err = -ENOMEM;
> + break;
> + }
> +
> + if (sl & PCAN_USB_STATUSLEN_EXT_ID) {
> + u32 tmp32;
> + memcpy(&tmp32, ibuf, 4);
> + ibuf += 4;
> + cf->can_id = le32_to_cpu(tmp32 >> 3) | CAN_EFF_FLAG;
> + }
> + else {
> + memcpy(&tmp16, ibuf, 2);
> + ibuf += 2;
> + cf->can_id = le16_to_cpu(tmp16 >> 5);
> + }
> +
> + cf->can_dlc = get_can_dlc(rec_len);
> +
> + /* first data packet timestamp is a word */
> + if (!frm_count++) {
> + memcpy(&tmp16, ibuf, 2);
> + ibuf += 2;
> + ts16 = le16_to_cpu(tmp16);
> + dts = 0;
> + }
> + else {
the preferred coding style is
} else {
> + u8 ts8 = *ibuf++;
> +
> + if (dts) {
> + dts &= 0xff00;
> + if (ts8 < prev_ts8)
> + dts += 0x100;
> + }
> +
> + dts |= ts8;
> + prev_ts8 = ts8;
I think I've seen this code before, please add a function for it.
> +
> + }
> +
> + /* read data */
> + if (sl & PCAN_USB_STATUSLEN_RTR) {
> + cf->can_id |= CAN_RTR_FLAG;
> + }
> + else {
} else { - or better get remove the { }
> + for (; d < rec_len; d++)
> + cf->data[d] = *ibuf++;
> + }
> +
> + for (; d < 8; d++) {
> + cf->data[d] = 0;
> + }
memset?
> +
> + peak_usb_get_timestamp_tv(&pdev->time_ref, ts16+dts, &tv);
> + skb->tstamp = timeval_to_ktime(tv);
> + netif_rx(skb);
> +
> + stats->rx_packets++;
> + stats->rx_bytes += cf->can_dlc;
> + }
> +
> + if ((ibuf - (u8 *)urb->transfer_buffer) > urb->transfer_buffer_length) {
What does this check do? You should do bounds checking of ibuf before
accessing it.
> + netdev_err(netdev, "usb message format error\n");
> + err = -EINVAL;
> + break;
> + }
> + }
> + }
> + else if (urb->actual_length > 0) {
> + netdev_err(netdev, "usb message length error (%u)\n", urb->actual_length);
> + err = -EINVAL;
> + }
I'd move the error checking to the beginning of the function. Return
early if you detect an error, so that you can get rid of (at least) one
indention level.
> +
> + return err;
> +}
> +
> +static int pcan_usb_encode_msg(struct peak_usb_device *dev, struct sk_buff *skb, u8 *obuf, size_t *size)
> +{
> + struct net_device *netdev = dev->netdev;
> + struct net_device_stats *stats = &netdev->stats;
> + struct can_frame *cf = (struct can_frame *)skb->data;
> + u8 *pc;
> +
> + obuf[0] = 2;
> + obuf[1] = 1;
> +
> + pc = &obuf[PCAN_USB_MSG_HEADER_LEN];
> +
> + /* status/len byte */
> + *pc = cf->can_dlc;
> + if (cf->can_id & CAN_RTR_FLAG)
> + *pc |= PCAN_USB_STATUSLEN_RTR;
> +
> + /* can id */
> + if (cf->can_id & CAN_EFF_FLAG) {
> + u32 tmp32 = cpu_to_le32(cf->can_id & CAN_ERR_MASK);
^^^ should be __le32 then
> + tmp32 <<= 3;
> + *pc |= PCAN_USB_STATUSLEN_EXT_ID;
> + memcpy(++pc, &tmp32, 4);
> + pc += 4;
> + }
> + else {
} else {
> + u16 tmp16 = (u16 )cpu_to_le32(cf->can_id & CAN_ERR_MASK);
^^^^^^^^^^^^^^^^^
why convert to le32 and then cast to u16?
> + tmp16 <<= 5;
> + memcpy(++pc, &tmp16, 2);
> + pc += 2;
> + }
> +
> + /* can data */
> + if ((cf->can_id & CAN_RTR_FLAG) == 0) {
if (cf->can_id & CAN_RTR_FLAG)
> + memcpy(pc, &cf->data[0], cf->can_dlc);
memcpy(pc, cf->data, cf->can_dlc);
> + pc += cf->can_dlc;
> + }
> +
> + /* Hmm... pcan driver sets the count of messages sent in the last byte... */
> + obuf[(*size)-1] = (u8 )(stats->tx_packets & 0xff);
> +
> + return 0;
> +}
> +
> +/*
> + * Start interface
> + */
> +static int pcan_usb_start(struct peak_usb_device *dev)
> +{
> + struct pcan_usb *pdev = (struct pcan_usb *)dev;
> + int err;
> +
> + /* number of bits used in timestamps read from adapter struct */
> + peak_usb_init_time_ref(&pdev->time_ref, &pcan_usb);
> +
> + /* If revision greater than 3, can put silent mode on/off*/
> + if (dev->device_rev > 3) {
> +
> + err = pcan_usb_set_silent(dev,
> + (dev->can.ctrlmode & CAN_CTRLMODE_LISTENONLY));
> + if (err)
> + goto failed;
> + }
> +
> + err = pcan_usb_set_ext_vcc(dev, 0);
> + if (err)
> + goto failed;
> +
> + return 0;
> +
> +failed:
> +
> + return err;
> +}
> +
> +static int pcan_usb_init(struct peak_usb_device *dev)
> +{
> + u32 serial_number;
> + int err;
> +
> + err = pcan_usb_get_serial_number(dev, &serial_number);
> + if (!err)
> + netdev_info(dev->netdev, "serial %08X\n", serial_number);
> +
> + return err;
> +}
> +
> +/*
> + * probe function for new PCAN-USB usb interface
> + */
> +static int pcan_usb_probe(struct usb_interface *intf)
> +{
> + struct usb_host_interface *iface_desc;
> + int i;
> +
> + /* check endpoint addresses (numbers) and associated max data length */
> + /* (only from setting 0) */
> + iface_desc = &intf->altsetting[0];
> +
> + /* check interface endpoint addresses */
> + for (i = 0; i < iface_desc->desc.bNumEndpoints; i++) {
> + struct usb_endpoint_descriptor *endpoint = &iface_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 (endpoint->bEndpointAddress) {
> + case PCAN_USB_EP_CMDOUT:
> + case PCAN_USB_EP_CMDIN:
> + case PCAN_USB_EP_MSGOUT:
> + case PCAN_USB_EP_MSGIN:
> + break;
> + default:
> + return -ENODEV;
> + }
> + }
> +
> + return 0;
> +}
> +
> +/*
> + * Describe the PCAN-USB adapter
> + */
> +struct peak_usb_adapter pcan_usb = {
> + .name = "PCAN-USB",
> + .device_id = PCAN_USB_PRODUCT_ID,
> + .ctrl_count = 1,
> + .clock = {
> + .freq = PCAN_USB_CRYSTAL_HZ/2,
> + },
> + .bittiming_const = {
> + .name = "pcan_usb",
> + .tseg1_min = 1,
> + .tseg1_max = 16,
> + .tseg2_min = 1,
> + .tseg2_max = 8,
> + .sjw_max = 4,
> + .brp_min = 1,
> + .brp_max = 64,
> + .brp_inc = 1,
> + },
> +
> + /* size of device private data */
> + .sizeof_dev_private = sizeof(struct pcan_usb),
> +
> + /* timestamps usage */
> + .ts_used_bits = 16,
> + .ts_period = 24575, /* calibration period in ts. */
> + .us_per_ts_scale = PCAN_USB_TS_US_PER_TICK, /* us = (ts * scale) >> shift */
> + .us_per_ts_shift = PCAN_USB_TS_DIV_SHIFTER,
> +
> + /* give here commands/messages in/out endpoints */
> + .ep_msg_in = PCAN_USB_EP_MSGIN,
> + .ep_msg_out = {PCAN_USB_EP_MSGOUT},
> +
> + /* size of rx/tx usb buffers */
> + .rx_buffer_size = PCAN_USB_RX_BUFFER_SIZE,
> + .tx_buffer_size = PCAN_USB_TX_BUFFER_SIZE,
> +
> + /* device callbacks */
> + .intf_probe = pcan_usb_probe,
> + .device_init = pcan_usb_init,
> + .device_set_bus = pcan_usb_write_mode,
> + .device_set_bittiming = pcan_usb_set_bittiming,
> + .device_get_device_number = pcan_usb_get_device_number,
> + .device_decode_msg = pcan_usb_decode_msg,
> + .device_encode_msg = pcan_usb_encode_msg,
> + .device_start = pcan_usb_start,
> +};
> +
that's it for now
Marc
--
Pengutronix e.K. | Marc Kleine-Budde |
Industrial Linux Solutions | Phone: +49-231-2826-924 |
Vertretung West/Dortmund | Fax: +49-5121-206917-5555 |
Amtsgericht Hildesheim, HRA 2686 | http://www.pengutronix.de |
[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 262 bytes --]
next prev parent reply other threads:[~2011-12-16 12:41 UTC|newest]
Thread overview: 9+ messages / expand[flat|nested] mbox.gz Atom feed top
2011-12-16 10:19 "[PATCH] Add support for PEAK-System GmbH CAN USB adapters (v2) " s.grosjean
2011-12-16 11:34 ` Wolfgang Grandegger
2011-12-16 12:41 ` Marc Kleine-Budde [this message]
2011-12-20 12:10 ` Grosjean Stephane
2011-12-20 15:57 ` Wolfgang Grandegger
2011-12-20 20:50 ` Marc Kleine-Budde
2011-12-17 13:17 ` Sebastian Haas
2011-12-19 17:03 ` Stephane Grosjean
2011-12-21 9:33 ` Wolfgang Grandegger
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=4EEB3C66.1020303@pengutronix.de \
--to=mkl@pengutronix.de \
--cc=linux-can@vger.kernel.org \
--cc=s.grosjean@peak-system.com \
--cc=socketcan@hartkopp.net \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.