From: Wolfgang Grandegger <wg@grandegger.com>
To: Stephane Grosjean <s.grosjean@peak-system.com>
Cc: Oliver Hartkopp <socketcan@hartkopp.net>,
Linux CAN mailing list <linux-can@vger.kernel.org>
Subject: Re: [PATCH] Add support for PEAK System PCAN-USB adapter
Date: Tue, 10 Jan 2012 11:41:45 +0100 [thread overview]
Message-ID: <4F0C15E9.1000704@grandegger.com> (raw)
In-Reply-To: <570511.804984079-sendEmail@ubuntu-i386>
Also please send a *series* of patches next time, e.g.:
[PATCH 1/3 v2] ....
On 12/22/2011 02:13 PM, Stephane Grosjean wrote:
>>From 2b369b236b320b4382815c86338f893fadc6476c Mon Sep 17 00:00:00 2001
> From: Stephane Grosjean <s.grosjean@peak-system.com>
> Date: Thu, 22 Dec 2011 13:57:04 +0100
> Subject: [PATCH] Add support for PEAK System PCAN-USB adapter
>
> ---
> drivers/net/can/usb/peak_usb/pcan_usb.c | 749 +++++++++++++++++++++++++++++++
> 1 files changed, 749 insertions(+), 0 deletions(-)
> create mode 100644 drivers/net/can/usb/peak_usb/pcan_usb.c
>
> diff --git a/drivers/net/can/usb/peak_usb/pcan_usb.c b/drivers/net/can/usb/peak_usb/pcan_usb.c
> new file mode 100644
> index 0000000..1a427be
> --- /dev/null
> +++ b/drivers/net/can/usb/peak_usb/pcan_usb.c
> @@ -0,0 +1,749 @@
> +/*
> + * CAN driver for PEAK System PCAN-USB adapter
> + *
> + * Copyright (C) 2011-2012 PEAK-System GmbH
> + *
> + * This program is free software; you can redistribute it and/or modify it
> + * under the terms of the GNU General Public License as published
> + * by the Free Software Foundation; version 2 of the License.
> + *
> + * This program is distributed in the hope that it will be useful, but
> + * WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
> + * General Public License for more details.
> + */
> +#include <linux/netdevice.h>
> +#include <linux/usb.h>
> +#include <linux/module.h>
> +
> +#include <linux/can.h>
> +#include <linux/can/dev.h>
> +#include <linux/can/error.h>
> +
> +#include "peak_usb.h"
> +
> +MODULE_SUPPORTED_DEVICE("PEAK-System PCAN-USB adapter");
> +
> +/* PCAN-USB Endpoints */
> +#define PCAN_USB_EP_CMDOUT 1
> +#define PCAN_USB_EP_CMDIN (PCAN_USB_EP_CMDOUT | USB_DIR_IN)
> +#define PCAN_USB_EP_MSGOUT 2
> +#define PCAN_USB_EP_MSGIN (PCAN_USB_EP_MSGOUT | USB_DIR_IN)
> +
> +/* PCAN-USB parameter command */
> +#define PCAN_USB_PARAMETER_LEN 14
> +struct __packed pcan_usb_parameter {
> + u8 function;
> + u8 number;
> + u8 parameters[PCAN_USB_PARAMETER_LEN];
> +};
> +
> +/* PCAN-USB command timeout (ms.) */
> +#define PCAN_USB_COMMAND_TIMEOUT 1000
> +
> +/* PCAN-USB rx/tx buffers size */
> +#define PCAN_USB_RX_BUFFER_SIZE 64
> +#define PCAN_USB_TX_BUFFER_SIZE 64
> +
> +#define PCAN_USB_MSG_HEADER_LEN 2
> +
> +/* PCAN-USB adapter internal clock (MHz) */
> +#define PCAN_USB_CRYSTAL_HZ 16000000
> +
> +/* PCAN-USB USB message record status/len field */
> +#define PCAN_USB_STATUSLEN_TIMESTAMP (1 << 7)
> +#define PCAN_USB_STATUSLEN_INTERNAL (1 << 6)
> +#define PCAN_USB_STATUSLEN_EXT_ID (1 << 5)
> +#define PCAN_USB_STATUSLEN_RTR (1 << 4)
> +#define PCAN_USB_STATUSLEN_DLC (0xf)
> +
> +/* PCAN-USB error flags */
> +#define PCAN_USB_ERROR_TXFULL 0x01
> +#define PCAN_USB_ERROR_RXQOVR 0x02
> +#define PCAN_USB_ERROR_BUS_LIGHT 0x04
> +#define PCAN_USB_ERROR_BUS_HEAVY 0x08
> +#define PCAN_USB_ERROR_BUS_OFF 0x10
> +#define PCAN_USB_ERROR_RXQEMPTY 0x20
> +#define PCAN_USB_ERROR_QOVR 0x40
> +#define PCAN_USB_ERROR_TXQFULL 0x80
> +
> +/* SJA1000 modes */
> +#define SJA1000_MODE_NORMAL 0x00
> +#define SJA1000_MODE_INIT 0x01
> +
> +/*
> + * tick duration = 42.666 us =>
> + * (tick_number * 44739243) >> 20 ~ (tick_number * 42666) / 1000
> + * accuracy = 10^-7
> + */
> +#define PCAN_USB_TS_DIV_SHIFTER 20
> +#define PCAN_USB_TS_US_PER_TICK 44739243
> +
> +/* PCAN-USB messages record types */
> +#define PCAN_USB_REC_ERROR 1
> +#define PCAN_USB_REC_ANALOG 2
> +#define PCAN_USB_REC_BUSLOAD 3
> +#define PCAN_USB_REC_TS 4
> +#define PCAN_USB_REC_BUSEVT 5
> +#define PCAN_USB_REC_EXT 10
> +
> +/* private to PCAN-USB adapter */
> +struct pcan_usb {
> + struct peak_usb_device dev; /* must be the first member */
> + struct peak_time_ref time_ref;
> +};
> +
> +/* incoming message context for decoding */
> +struct pcan_usb_msg_context {
> + u16 ts16;
> + u8 prev_ts8;
> + u8 *ptr;
> + u8 *end;
> + u8 rec_cnt;
> + u8 rec_idx;
> + u8 rec_data_idx;
> + struct net_device *netdev;
> + struct pcan_usb *pdev;
> +};
> +
> +/*
> + * send a command
> + */
> +static int pcan_usb_send_cmd(struct peak_usb_device *dev, u8 f, u8 n, u8 *p)
> +{
> + int err;
> + int actual_length;
> + struct pcan_usb_parameter cmd = {
> + .function = f,
> + .number = n,
> + };
> +
> + /* usb device unregistered? */
> + if (!(dev->state & PCAN_USB_STATE_CONNECTED))
> + return 0;
> +
> + if (p)
> + memcpy(cmd.parameters, p, ARRAY_SIZE(cmd.parameters));
> +
> + err = usb_bulk_msg(dev->udev,
> + usb_sndbulkpipe(dev->udev, PCAN_USB_EP_CMDOUT), &cmd,
> + sizeof(struct pcan_usb_parameter), &actual_length,
> + PCAN_USB_COMMAND_TIMEOUT);
> + if (err)
> + netdev_err(dev->netdev,
> + "sending cmd f=0x%x n=0x%x failure: %d\n",
> + f, n, err);
> +
> + return err;
> +}
> +
> +/*
> + * send a command then wait for its response
> + */
> +static int pcan_usb_wait_rsp(struct peak_usb_device *dev, u8 f, u8 n, u8 *p)
> +{
> + int err;
> + int actual_length;
> + struct pcan_usb_parameter cmd = {
> + .function = f,
> + .number = n,
> + };
> +
> + /* usb device unregistered? */
> + if (!(dev->state & PCAN_USB_STATE_CONNECTED))
> + return 0;
> +
> + /* first, send command */
> + err = pcan_usb_send_cmd(dev, f, n, NULL);
> + if (err)
> + return err;
> +
> + err = usb_bulk_msg(dev->udev,
> + usb_rcvbulkpipe(dev->udev, PCAN_USB_EP_CMDIN), &cmd,
> + sizeof(struct pcan_usb_parameter), &actual_length,
> + PCAN_USB_COMMAND_TIMEOUT);
> + if (err)
> + netdev_err(dev->netdev,
> + "waiting rsp f=0x%x n=0x%x failure: %d\n", f, n, err);
> + else if (p)
> + memcpy(p, cmd.parameters, ARRAY_SIZE(cmd.parameters));
> +
> + return err;
> +}
> +
> +static int pcan_usb_set_sja1000(struct peak_usb_device *dev, u8 mode)
> +{
> + u8 args[PCAN_USB_PARAMETER_LEN] = {
> + [1] = mode,
> + };
> +
> + return pcan_usb_send_cmd(dev, 9, 2, args);
> +}
> +
> +static int pcan_usb_set_bus(struct peak_usb_device *dev, u8 onoff)
> +{
> + u8 args[PCAN_USB_PARAMETER_LEN] = {
> + [0] = onoff ? 1 : 0,
> + };
> +
> + return pcan_usb_send_cmd(dev, 3, 2, args);
> +}
> +
> +static int pcan_usb_set_silent(struct peak_usb_device *dev, u8 onoff)
> +{
> + u8 args[PCAN_USB_PARAMETER_LEN] = {
> + [0] = onoff ? 1 : 0,
> + };
> +
> + return pcan_usb_send_cmd(dev, 3, 3, args);
> +}
> +
> +static int pcan_usb_set_ext_vcc(struct peak_usb_device *dev, u8 onoff)
> +{
> + u8 args[PCAN_USB_PARAMETER_LEN] = {
> + [0] = onoff ? 1 : 0,
> + };
> +
> + return pcan_usb_send_cmd(dev, 10, 2, args);
> +}
> +
> +/*
> + * set bittiming value to can
> + */
> +static int pcan_usb_set_bittiming(struct peak_usb_device *dev,
> + struct can_bittiming *bt)
> +{
> + u8 args[PCAN_USB_PARAMETER_LEN];
> + u8 btr0, btr1;
> +
> + btr0 = ((bt->brp - 1) & 0x3f) | (((bt->sjw - 1) & 0x3) << 6);
> + btr1 = ((bt->prop_seg + bt->phase_seg1 - 1) & 0xf) \
No need for "\"
> + | (((bt->phase_seg2 - 1) & 0x7) << 4);
> + if (dev->can.ctrlmode & CAN_CTRLMODE_3_SAMPLES)
> + btr1 |= 0x80;
> +
> + args[0] = btr1;
> + args[1] = btr0;
> +
> + netdev_dbg(dev->netdev, "btr0=0x%02x btr1=0x%02x\n", btr0, btr1);
Please use netdev_info here, like all other drivers.
> +
> + return pcan_usb_send_cmd(dev, 1, 2, args);
> +}
> +
> +/*
> + * init/reset can
> + */
> +static int pcan_usb_write_mode(struct peak_usb_device *dev, u8 onoff)
> +{
> + int err;
> +
> + err = pcan_usb_set_bus(dev, onoff);
> + if (err)
> + return err;
> +
> + if (!onoff)
> + err = pcan_usb_set_sja1000(dev, SJA1000_MODE_INIT);
> +
> + return err;
> +}
> +
> +/*
> + * read serial number from device
> + */
> +static int pcan_usb_get_serial(struct peak_usb_device *dev, u32 *serial_number)
> +{
> + u8 args[PCAN_USB_PARAMETER_LEN];
> + int err;
> +
> + err = pcan_usb_wait_rsp(dev, 6, 1, args);
> + if (err)
> + netdev_err(dev->netdev, "getting serial failure: %d\n", err);
> +
Remove empty line.
> + else if (serial_number) {
> + u32 tmp32;
Add empty line.
> + memcpy(&tmp32, args, 4);
> + *serial_number = le32_to_cpu(tmp32);
> + }
> +
> + return err;
> +}
> +
> +/*
> + * read device id from device
> + */
> +static int pcan_usb_get_device_id(struct peak_usb_device *dev, u32 *device_id)
> +{
> + u8 args[PCAN_USB_PARAMETER_LEN];
> + int err;
> +
> + err = pcan_usb_wait_rsp(dev, 4, 1, args);
> + if (err)
> + netdev_err(dev->netdev, "getting device id failure: %d\n", err);
> +
> + else if (device_id)
> + *device_id = args[0];
> +
> + return err;
> +}
> +
> +/*
> + * update current time ref with received timestamp
> + */
> +static int pcan_usb_update_ts(struct pcan_usb_msg_context *mc)
> +{
> + u16 tmp16;
> +
> + if ((mc->ptr+2) > mc->end)
> + return -EINVAL;
> +
> + memcpy(&tmp16, mc->ptr, 2);
> +
> + mc->ts16 = le16_to_cpu(tmp16);
> +
> + if (mc->rec_idx > 0)
> + peak_usb_update_ts_now(&mc->pdev->time_ref, mc->ts16);
> + else
> + peak_usb_set_ts_now(&mc->pdev->time_ref, mc->ts16);
> +
> + return 0;
> +}
> +
> +/*
> + * decode received timestamp
> + */
> +static int pcan_usb_decode_ts(struct pcan_usb_msg_context *mc, u8 first_packet)
> +{
> + /* only 1st packet supplies a word timestamp */
> + if (first_packet) {
> + u16 tmp16;
> +
> + if ((mc->ptr+2) > mc->end)
Spaces around "+"
> + return -EINVAL;
> +
> + memcpy(&tmp16, mc->ptr, 2);
> + mc->ptr += 2;
> +
> + mc->ts16 = le16_to_cpu(tmp16);
> + mc->prev_ts8 = mc->ts16 & 0x00ff;
> + } else {
> + u8 ts8;
> +
> + if ((mc->ptr+1) > mc->end)
Ditto
> + return -EINVAL;
> +
> + ts8 = *mc->ptr++;
> +
> + if (ts8 < mc->prev_ts8)
> + mc->ts16 += 0x100;
> +
> + mc->ts16 &= 0xff00;
> + mc->ts16 |= ts8;
> + mc->prev_ts8 = ts8;
> + }
> +
> + return 0;
> +}
> +
> +/*
> + * decode non-data usb message
> + */
> +static int pcan_usb_decode_status(struct pcan_usb_msg_context *mc,
> + u8 status_len)
> +{
> + u8 rec_len = (status_len & PCAN_USB_STATUSLEN_DLC);
> + struct sk_buff *skb;
> + struct can_frame *cf;
> + struct timeval tv;
> + u8 f, n;
> +
> + /* check whether function and number can be read */
> + if ((mc->ptr + 2) > mc->end)
> + return -EINVAL;
> +
> + f = mc->ptr[0];
> + n = mc->ptr[1];
> + mc->ptr += 2;
> +
> + if (status_len & PCAN_USB_STATUSLEN_TIMESTAMP) {
> + int err = pcan_usb_decode_ts(mc, !mc->rec_idx);
Add empty line .
> + if (err)
> + return err;
> + }
> +
> + switch (f) {
> + case PCAN_USB_REC_ERROR:
> + /* no status flag => ignore record */
> + if (!n)
> + break;
> +
> + /* ignore this error until 1st ts received */
> + if (n == PCAN_USB_ERROR_QOVR)
> + if (!mc->pdev->time_ref.tick_count)
> + break;
> +
> + /* allocate an skb to store the error frame */
> + skb = alloc_can_err_skb(mc->netdev, &cf);
> + if (!skb)
> + return -ENOMEM;
> +
> + if (n & (PCAN_USB_ERROR_RXQOVR | PCAN_USB_ERROR_QOVR)) {
> + cf->can_id |= CAN_ERR_CRTL;
> + cf->data[1] |= CAN_ERR_CRTL_RX_OVERFLOW;
> + mc->netdev->stats.rx_over_errors++;
> + mc->netdev->stats.rx_errors++;
> + }
> + if (n & PCAN_USB_ERROR_BUS_OFF) {
> + cf->can_id |= CAN_ERR_BUSOFF;
> + can_bus_off(mc->netdev);
> + }
> + if (n & PCAN_USB_ERROR_BUS_HEAVY) {
> + cf->can_id |= CAN_ERR_CRTL;
> + cf->data[1] |= CAN_ERR_CRTL_RX_PASSIVE;
As you don't know the direction. Please add "| CAN_ERR_CRTL_TX_PASSIVE"
> + mc->pdev->dev.can.can_stats.error_passive++;
> + }
> + if (n & PCAN_USB_ERROR_BUS_LIGHT) {
> + cf->can_id |= CAN_ERR_CRTL;
> + cf->data[1] |= CAN_ERR_CRTL_RX_WARNING;
> + mc->pdev->dev.can.can_stats.error_warning++;
Similar here.
> + }
> +
> + if (cf->can_id != CAN_ERR_FLAG) {
> + if (status_len & PCAN_USB_STATUSLEN_TIMESTAMP) {
> + peak_usb_get_ts_tv(&mc->pdev->time_ref,
> + mc->ts16, &tv);
> + skb->tstamp = timeval_to_ktime(tv);
> + }
> + netif_rx(skb);
> + mc->netdev->stats.rx_packets++;
What about rx_bytes?
> + } else {
> + kfree_skb(skb);
> + }
> +
> + break;
> +
> + case PCAN_USB_REC_ANALOG:
> + /* analog values (ignored) */
> + rec_len = 2;
> + break;
> +
> + case PCAN_USB_REC_BUSLOAD:
> + /* bus load (ignored) */
> + rec_len = 1;
> + break;
> +
> + case PCAN_USB_REC_TS:
> + /* only timestamp */
> + if (pcan_usb_update_ts(mc))
> + return -EINVAL;
> + break;
> +
> + case PCAN_USB_REC_BUSEVT:
> + /* error frame/bus event */
> + if (n & PCAN_USB_ERROR_TXQFULL)
> + netdev_info(mc->netdev, "device Tx queue full)\n");
Can this happen frequently? netdev_dbg() or ratelimiting?
> + break;
> +
> + case PCAN_USB_REC_EXT:
> + /* future... */
> + break;
Please remove if it's not really needed!
> + default:
> + netdev_err(mc->netdev, "unexpected function %u\n", f);
> + break;
> + }
> +
> + if ((mc->ptr + rec_len) > mc->end)
> + return -EINVAL;
> +
> + mc->ptr += rec_len;
> +
> + return 0;
> +}
> +
> +/*
> + * decode data usb message
> + */
> +static int pcan_usb_decode_data(struct pcan_usb_msg_context *mc, u8 status_len)
> +{
> + u8 rec_len = (status_len & PCAN_USB_STATUSLEN_DLC);
"()" not needed.
> + struct sk_buff *skb;
> + struct can_frame *cf;
> + struct timeval tv;
> +
> + skb = alloc_can_skb(mc->netdev, &cf);
> + if (!skb)
> + return -ENOMEM;
> +
> + if (status_len & PCAN_USB_STATUSLEN_EXT_ID) {
> + u32 tmp32;
> +
> + if ((mc->ptr + 4) > mc->end)
> + goto decode_failed;
> +
> + memcpy(&tmp32, mc->ptr, 4);
> + mc->ptr += 4;
> +
> + cf->can_id = le32_to_cpu(tmp32 >> 3) | CAN_EFF_FLAG;
> + } else {
> + u16 tmp16;
> +
> + if ((mc->ptr + 2) > mc->end)
> + goto decode_failed;
> +
> + memcpy(&tmp16, mc->ptr, 2);
> + mc->ptr += 2;
> +
> + cf->can_id = le16_to_cpu(tmp16 >> 5);
> + }
> +
> + cf->can_dlc = get_can_dlc(rec_len);
> +
> + /* first data packet timestamp is a word */
> + if (pcan_usb_decode_ts(mc, !mc->rec_data_idx))
> + goto decode_failed;
> +
> + /* read data */
> + memset(cf->data, 0x0, sizeof(cf->data));
> + if (status_len & PCAN_USB_STATUSLEN_RTR) {
> + cf->can_id |= CAN_RTR_FLAG;
> + } else {
> + if ((mc->ptr + rec_len) > mc->end)
> + goto decode_failed;
> +
> + memcpy(cf->data, mc->ptr, rec_len);
> + mc->ptr += rec_len;
> + }
> +
> + /* convert timestamp into kernel time */
> + peak_usb_get_ts_tv(&mc->pdev->time_ref, mc->ts16, &tv);
> + skb->tstamp = timeval_to_ktime(tv);
> +
> + /* push the skb */
> + netif_rx(skb);
> +
> + /* update statistics */
> + mc->netdev->stats.rx_packets++;
> + mc->netdev->stats.rx_bytes += cf->can_dlc;
> +
> + return 0;
> +
> +decode_failed:
> + kfree_skb(skb);
> + return -EINVAL;
> +}
> +
> +/*
> + * process incoming message
> + */
> +static int pcan_usb_decode_msg(struct peak_usb_device *dev,
> + u8 *ibuf, u32 lbuf)
> +{
> + struct pcan_usb_msg_context mc = {
> + .rec_cnt = ibuf[1],
> + .ptr = ibuf + PCAN_USB_MSG_HEADER_LEN,
> + .end = ibuf + lbuf,
> + .netdev = dev->netdev,
> + .pdev = (struct pcan_usb *)dev,
Is the cast really necessary?
> + };
> + int err;
> +
> + for (err = 0; mc.rec_idx < mc.rec_cnt && !err; mc.rec_idx++) {
> + u8 sl = *mc.ptr++;
> +
> + /* handle status and error frames here */
> + if (sl & PCAN_USB_STATUSLEN_INTERNAL) {
> + err = pcan_usb_decode_status(&mc, sl);
> +
Remove empty line.
> + /* handle normal can frames here */
> + } else {
> + err = pcan_usb_decode_data(&mc, sl);
> + mc.rec_data_idx++;
> + }
> + }
> +
> + return err;
> +}
> +
> +/*
> + * process any incoming buffer
> + */
> +static int pcan_usb_decode_buf(struct peak_usb_device *dev, struct urb *urb)
> +{
> + int err = 0;
> +
> + if (urb->actual_length > PCAN_USB_MSG_HEADER_LEN) {
> + err = pcan_usb_decode_msg(dev, urb->transfer_buffer,
> + urb->actual_length);
> +
> + } else if (urb->actual_length > 0) {
> + netdev_err(dev->netdev, "usb message length error (%u)\n",
> + urb->actual_length);
> + err = -EINVAL;
> + }
> +
> + return err;
> +}
> +
> +/*
> + * process outgoing packet
> + */
> +static int pcan_usb_encode_msg(struct peak_usb_device *dev,
> + struct sk_buff *skb, u8 *obuf, size_t *size)
> +{
> + struct net_device *netdev = dev->netdev;
> + struct net_device_stats *stats = &netdev->stats;
> + struct can_frame *cf = (struct can_frame *)skb->data;
> + u8 *pc;
> +
> + obuf[0] = 2;
> + obuf[1] = 1;
> +
> + pc = obuf + PCAN_USB_MSG_HEADER_LEN;
> +
> + /* status/len byte */
> + *pc = cf->can_dlc;
> + if (cf->can_id & CAN_RTR_FLAG)
> + *pc |= PCAN_USB_STATUSLEN_RTR;
> +
> + /* can id */
> + if (cf->can_id & CAN_EFF_FLAG) {
> + __le32 tmp32 = cpu_to_le32(cf->can_id & CAN_ERR_MASK);
Empty line.
> + tmp32 <<= 3;
> + *pc |= PCAN_USB_STATUSLEN_EXT_ID;
> + memcpy(++pc, &tmp32, 4);
> + pc += 4;
> + } else {
> + __le16 tmp16 = cpu_to_le32(cf->can_id & CAN_ERR_MASK);
Ditto.
> + tmp16 <<= 5;
> + memcpy(++pc, &tmp16, 2);
> + pc += 2;
> + }
> +
> + /* can data */
> + if (!(cf->can_id & CAN_RTR_FLAG)) {
> + memcpy(pc, cf->data, cf->can_dlc);
> + pc += cf->can_dlc;
> + }
> +
> + obuf[(*size)-1] = (u8)(stats->tx_packets & 0xff);
> +
> + return 0;
> +}
> +
> +/*
> + * start interface
> + */
> +static int pcan_usb_start(struct peak_usb_device *dev)
> +{
> + struct pcan_usb *pdev = (struct pcan_usb *)dev;
> + int err;
> +
> + /* number of bits used in timestamps read from adapter struct */
> + peak_usb_init_time_ref(&pdev->time_ref, &pcan_usb);
> +
> + /* if revision greater than 3, can put silent mode on/off */
> + if (dev->device_rev > 3) {
> + err = pcan_usb_set_silent(dev,
> + (dev->can.ctrlmode & CAN_CTRLMODE_LISTENONLY));
"()" not needed!
> + if (err)
> + goto start_failed;
> + }
> +
> + err = pcan_usb_set_ext_vcc(dev, 0);
> + if (err)
> + goto start_failed;
> +
> + return 0;
> +
> +start_failed:
> + return err;
This label is not really useful.
> +}
> +
> +static int pcan_usb_init(struct peak_usb_device *dev)
> +{
> + u32 serial_number;
> + int err;
> +
> + err = pcan_usb_get_serial(dev, &serial_number);
> + if (!err)
> + netdev_info(dev->netdev, "serial %08X\n", serial_number);
> +
> + return err;
> +}
> +
> +/*
> + * probe function for new PCAN-USB usb interface
> + */
> +static int pcan_usb_probe(struct usb_interface *intf)
> +{
> + struct usb_host_interface *if_desc;
> + int i;
> +
> + if_desc = intf->altsetting;
> +
> + /* check interface endpoint addresses */
> + for (i = 0; i < if_desc->desc.bNumEndpoints; i++) {
> + struct usb_endpoint_descriptor *ep = &if_desc->endpoint[i].desc;
> +
> + switch (ep->bEndpointAddress) {
> + case PCAN_USB_EP_CMDOUT:
> + case PCAN_USB_EP_CMDIN:
> + case PCAN_USB_EP_MSGOUT:
> + case PCAN_USB_EP_MSGIN:
> + break;
> + default:
> + return -ENODEV;
> + }
> + }
> +
> + return 0;
> +}
> +
> +/*
> + * describe the PCAN-USB adapter
> + */
> +struct peak_usb_adapter pcan_usb = {
> + .name = "PCAN-USB",
> + .device_id = PCAN_USB_PRODUCT_ID,
> + .ctrl_count = 1,
> + .clock = {
> + .freq = PCAN_USB_CRYSTAL_HZ/2,
Spaces around "/"
> + },
> + .bittiming_const = {
> + .name = "pcan_usb",
> + .tseg1_min = 1,
> + .tseg1_max = 16,
> + .tseg2_min = 1,
> + .tseg2_max = 8,
> + .sjw_max = 4,
> + .brp_min = 1,
> + .brp_max = 64,
> + .brp_inc = 1,
> + },
> +
> + /* size of device private data */
> + .sizeof_dev_private = sizeof(struct pcan_usb),
> +
> + /* timestamps usage */
> + .ts_used_bits = 16,
> + .ts_period = 24575, /* calibration period in ts. */
> + .us_per_ts_scale = PCAN_USB_TS_US_PER_TICK, /* us=(ts*scale) */
> + .us_per_ts_shift = PCAN_USB_TS_DIV_SHIFTER, /* >> shift */
> +
> + /* give here commands/messages in/out endpoints */
> + .ep_msg_in = PCAN_USB_EP_MSGIN,
> + .ep_msg_out = {PCAN_USB_EP_MSGOUT},
> + /* size of rx/tx usb buffers */
> + .rx_buffer_size = PCAN_USB_RX_BUFFER_SIZE,
> + .tx_buffer_size = PCAN_USB_TX_BUFFER_SIZE,
> +
> + /* device callbacks */
> + .intf_probe = pcan_usb_probe,
> + .dev_init = pcan_usb_init,
> + .dev_set_bus = pcan_usb_write_mode,
> + .dev_set_bittiming = pcan_usb_set_bittiming,
> + .dev_get_device_id = pcan_usb_get_device_id,
> + .dev_decode_buf = pcan_usb_decode_buf,
> + .dev_encode_msg = pcan_usb_encode_msg,
> + .dev_start = pcan_usb_start,
> +};
Wolfgang.
prev parent reply other threads:[~2012-01-10 10:41 UTC|newest]
Thread overview: 5+ messages / expand[flat|nested] mbox.gz Atom feed top
2011-12-22 13:13 [PATCH] Add support for PEAK System PCAN-USB adapter Stephane Grosjean
2011-12-23 19:38 ` Sebastian Haas
2011-12-26 11:08 ` Grosjean Stephane
2011-12-26 14:21 ` Sebastian Haas
2012-01-10 10:41 ` Wolfgang Grandegger [this message]
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=4F0C15E9.1000704@grandegger.com \
--to=wg@grandegger.com \
--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).