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 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).