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