提交 9fb434bc 编写于 作者: D David S. Miller

Merge tag 'linux-can-next-for-5.13-20210413' of...

Merge tag 'linux-can-next-for-5.13-20210413' of git://git.kernel.org/pub/scm/linux/kernel/git/mkl/linux-can-next

Marc Kleine-Budde says:

====================
pull-request: can-next 2021-04-13

this is a pull request of 14 patches for net-next/master.

The first patch is by Yoshihiro Shimoda and updates the DT bindings
for the rcar_can driver.

Vincent Mailhol contributes 3 patches that add support for several
ETAS USB CAN adapters.

The final 10 patches are by me and clean up the peak_usb CAN driver.
====================
Signed-off-by: NDavid S. Miller <davem@davemloft.net>
......@@ -19,7 +19,8 @@ Required properties:
"renesas,can-r8a7793" if CAN controller is a part of R8A7793 SoC.
"renesas,can-r8a7794" if CAN controller is a part of R8A7794 SoC.
"renesas,can-r8a7795" if CAN controller is a part of R8A7795 SoC.
"renesas,can-r8a7796" if CAN controller is a part of R8A7796 SoC.
"renesas,can-r8a7796" if CAN controller is a part of R8A77960 SoC.
"renesas,can-r8a77961" if CAN controller is a part of R8A77961 SoC.
"renesas,can-r8a77965" if CAN controller is a part of R8A77965 SoC.
"renesas,can-r8a77990" if CAN controller is a part of R8A77990 SoC.
"renesas,can-r8a77995" if CAN controller is a part of R8A77995 SoC.
......@@ -40,7 +41,7 @@ Required properties:
- pinctrl-names: must be "default".
Required properties for R8A774A1, R8A774B1, R8A774C0, R8A774E1, R8A7795,
R8A7796, R8A77965, R8A77990, and R8A77995:
R8A77960, R8A77961, R8A77965, R8A77990, and R8A77995:
For the denoted SoCs, "clkp2" can be CANFD clock. This is a div6 clock and can
be used by both CAN and CAN FD controller at the same time. It needs to be
scaled to maximum frequency if any of these controllers use it. This is done
......
......@@ -20,6 +20,16 @@ config CAN_ESD_USB2
This driver supports the CAN-USB/2 interface
from esd electronic system design gmbh (http://www.esd.eu).
config CAN_ETAS_ES58X
tristate "ETAS ES58X CAN/USB interfaces"
select CRC16
help
This driver supports the ES581.4, ES582.1 and ES584.1 interfaces
from ETAS GmbH (https://www.etas.com/en/products/es58x.php).
To compile this driver as a module, choose M here: the module
will be called etas_es58x.
config CAN_GS_USB
tristate "Geschwister Schneider UG interfaces"
help
......
......@@ -6,6 +6,7 @@
obj-$(CONFIG_CAN_8DEV_USB) += usb_8dev.o
obj-$(CONFIG_CAN_EMS_USB) += ems_usb.o
obj-$(CONFIG_CAN_ESD_USB2) += esd_usb2.o
obj-$(CONFIG_CAN_ETAS_ES58X) += etas_es58x/
obj-$(CONFIG_CAN_GS_USB) += gs_usb.o
obj-$(CONFIG_CAN_KVASER_USB) += kvaser_usb/
obj-$(CONFIG_CAN_MCBA_USB) += mcba_usb.o
......
# SPDX-License-Identifier: GPL-2.0
obj-$(CONFIG_CAN_ETAS_ES58X) += etas_es58x.o
etas_es58x-y = es58x_core.o es581_4.o es58x_fd.o
// SPDX-License-Identifier: GPL-2.0
/* Driver for ETAS GmbH ES58X USB CAN(-FD) Bus Interfaces.
*
* File es581_4.c: Adds support to ETAS ES581.4.
*
* Copyright (c) 2019 Robert Bosch Engineering and Business Solutions. All rights reserved.
* Copyright (c) 2020 ETAS K.K.. All rights reserved.
* Copyright (c) 2020, 2021 Vincent Mailhol <mailhol.vincent@wanadoo.fr>
*/
#include <linux/kernel.h>
#include <asm/unaligned.h>
#include "es58x_core.h"
#include "es581_4.h"
/**
* es581_4_sizeof_rx_tx_msg() - Calculate the actual length of the
* structure of a rx or tx message.
* @msg: message of variable length, must have a dlc field.
*
* Even if RTR frames have actually no payload, the ES58X devices
* still expect it. Must be a macro in order to accept several types
* (struct es581_4_tx_can_msg and struct es581_4_rx_can_msg) as an
* input.
*
* Return: length of the message.
*/
#define es581_4_sizeof_rx_tx_msg(msg) \
offsetof(typeof(msg), data[can_cc_dlc2len((msg).dlc)])
static u16 es581_4_get_msg_len(const union es58x_urb_cmd *urb_cmd)
{
return get_unaligned_le16(&urb_cmd->es581_4_urb_cmd.msg_len);
}
static int es581_4_echo_msg(struct es58x_device *es58x_dev,
const struct es581_4_urb_cmd *es581_4_urb_cmd)
{
struct net_device *netdev;
const struct es581_4_bulk_echo_msg *bulk_echo_msg;
const struct es581_4_echo_msg *echo_msg;
u64 *tstamps = es58x_dev->timestamps;
u16 msg_len;
u32 first_packet_idx, packet_idx;
unsigned int dropped = 0;
int i, num_element, ret;
bulk_echo_msg = &es581_4_urb_cmd->bulk_echo_msg;
msg_len = get_unaligned_le16(&es581_4_urb_cmd->msg_len) -
sizeof(bulk_echo_msg->channel_no);
num_element = es58x_msg_num_element(es58x_dev->dev,
bulk_echo_msg->echo_msg, msg_len);
if (num_element <= 0)
return num_element;
ret = es58x_get_netdev(es58x_dev, bulk_echo_msg->channel_no,
ES581_4_CHANNEL_IDX_OFFSET, &netdev);
if (ret)
return ret;
echo_msg = &bulk_echo_msg->echo_msg[0];
first_packet_idx = get_unaligned_le32(&echo_msg->packet_idx);
packet_idx = first_packet_idx;
for (i = 0; i < num_element; i++) {
u32 tmp_idx;
echo_msg = &bulk_echo_msg->echo_msg[i];
tmp_idx = get_unaligned_le32(&echo_msg->packet_idx);
if (tmp_idx == packet_idx - 1) {
if (net_ratelimit())
netdev_warn(netdev,
"Received echo packet idx %u twice\n",
packet_idx - 1);
dropped++;
continue;
}
if (tmp_idx != packet_idx) {
netdev_err(netdev, "Echo packet idx jumped from %u to %u\n",
packet_idx - 1, echo_msg->packet_idx);
return -EBADMSG;
}
tstamps[i] = get_unaligned_le64(&echo_msg->timestamp);
packet_idx++;
}
netdev->stats.tx_dropped += dropped;
return es58x_can_get_echo_skb(netdev, first_packet_idx,
tstamps, num_element - dropped);
}
static int es581_4_rx_can_msg(struct es58x_device *es58x_dev,
const struct es581_4_urb_cmd *es581_4_urb_cmd,
u16 msg_len)
{
const struct device *dev = es58x_dev->dev;
struct net_device *netdev;
int pkts, num_element, channel_no, ret;
num_element = es58x_msg_num_element(dev, es581_4_urb_cmd->rx_can_msg,
msg_len);
if (num_element <= 0)
return num_element;
channel_no = es581_4_urb_cmd->rx_can_msg[0].channel_no;
ret = es58x_get_netdev(es58x_dev, channel_no,
ES581_4_CHANNEL_IDX_OFFSET, &netdev);
if (ret)
return ret;
if (!netif_running(netdev)) {
if (net_ratelimit())
netdev_info(netdev,
"%s: %s is down, dropping %d rx packets\n",
__func__, netdev->name, num_element);
netdev->stats.rx_dropped += num_element;
return 0;
}
for (pkts = 0; pkts < num_element; pkts++) {
const struct es581_4_rx_can_msg *rx_can_msg =
&es581_4_urb_cmd->rx_can_msg[pkts];
u64 tstamp = get_unaligned_le64(&rx_can_msg->timestamp);
canid_t can_id = get_unaligned_le32(&rx_can_msg->can_id);
if (channel_no != rx_can_msg->channel_no)
return -EBADMSG;
ret = es58x_rx_can_msg(netdev, tstamp, rx_can_msg->data,
can_id, rx_can_msg->flags,
rx_can_msg->dlc);
if (ret)
break;
}
return ret;
}
static int es581_4_rx_err_msg(struct es58x_device *es58x_dev,
const struct es581_4_rx_err_msg *rx_err_msg)
{
struct net_device *netdev;
enum es58x_err error = get_unaligned_le32(&rx_err_msg->error);
int ret;
ret = es58x_get_netdev(es58x_dev, rx_err_msg->channel_no,
ES581_4_CHANNEL_IDX_OFFSET, &netdev);
if (ret)
return ret;
return es58x_rx_err_msg(netdev, error, 0,
get_unaligned_le64(&rx_err_msg->timestamp));
}
static int es581_4_rx_event_msg(struct es58x_device *es58x_dev,
const struct es581_4_rx_event_msg *rx_event_msg)
{
struct net_device *netdev;
enum es58x_event event = get_unaligned_le32(&rx_event_msg->event);
int ret;
ret = es58x_get_netdev(es58x_dev, rx_event_msg->channel_no,
ES581_4_CHANNEL_IDX_OFFSET, &netdev);
if (ret)
return ret;
return es58x_rx_err_msg(netdev, 0, event,
get_unaligned_le64(&rx_event_msg->timestamp));
}
static int es581_4_rx_cmd_ret_u32(struct es58x_device *es58x_dev,
const struct es581_4_urb_cmd *es581_4_urb_cmd,
enum es58x_ret_type ret_type)
{
struct net_device *netdev;
const struct es581_4_rx_cmd_ret *rx_cmd_ret;
u16 msg_len = get_unaligned_le16(&es581_4_urb_cmd->msg_len);
int ret;
ret = es58x_check_msg_len(es58x_dev->dev,
es581_4_urb_cmd->rx_cmd_ret, msg_len);
if (ret)
return ret;
rx_cmd_ret = &es581_4_urb_cmd->rx_cmd_ret;
ret = es58x_get_netdev(es58x_dev, rx_cmd_ret->channel_no,
ES581_4_CHANNEL_IDX_OFFSET, &netdev);
if (ret)
return ret;
return es58x_rx_cmd_ret_u32(netdev, ret_type,
get_unaligned_le32(&rx_cmd_ret->rx_cmd_ret_le32));
}
static int es581_4_tx_ack_msg(struct es58x_device *es58x_dev,
const struct es581_4_urb_cmd *es581_4_urb_cmd)
{
struct net_device *netdev;
const struct es581_4_tx_ack_msg *tx_ack_msg;
u16 msg_len = get_unaligned_le16(&es581_4_urb_cmd->msg_len);
int ret;
tx_ack_msg = &es581_4_urb_cmd->tx_ack_msg;
ret = es58x_check_msg_len(es58x_dev->dev, *tx_ack_msg, msg_len);
if (ret)
return ret;
if (tx_ack_msg->rx_cmd_ret_u8 != ES58X_RET_U8_OK)
return es58x_rx_cmd_ret_u8(es58x_dev->dev,
ES58X_RET_TYPE_TX_MSG,
tx_ack_msg->rx_cmd_ret_u8);
ret = es58x_get_netdev(es58x_dev, tx_ack_msg->channel_no,
ES581_4_CHANNEL_IDX_OFFSET, &netdev);
if (ret)
return ret;
return es58x_tx_ack_msg(netdev,
get_unaligned_le16(&tx_ack_msg->tx_free_entries),
ES58X_RET_U32_OK);
}
static int es581_4_dispatch_rx_cmd(struct es58x_device *es58x_dev,
const struct es581_4_urb_cmd *es581_4_urb_cmd)
{
const struct device *dev = es58x_dev->dev;
u16 msg_len = get_unaligned_le16(&es581_4_urb_cmd->msg_len);
enum es581_4_rx_type rx_type = es581_4_urb_cmd->rx_can_msg[0].rx_type;
int ret = 0;
switch (rx_type) {
case ES581_4_RX_TYPE_MESSAGE:
return es581_4_rx_can_msg(es58x_dev, es581_4_urb_cmd, msg_len);
case ES581_4_RX_TYPE_ERROR:
ret = es58x_check_msg_len(dev, es581_4_urb_cmd->rx_err_msg,
msg_len);
if (ret < 0)
return ret;
return es581_4_rx_err_msg(es58x_dev,
&es581_4_urb_cmd->rx_err_msg);
case ES581_4_RX_TYPE_EVENT:
ret = es58x_check_msg_len(dev, es581_4_urb_cmd->rx_event_msg,
msg_len);
if (ret < 0)
return ret;
return es581_4_rx_event_msg(es58x_dev,
&es581_4_urb_cmd->rx_event_msg);
default:
dev_err(dev, "%s: Unknown rx_type 0x%02X\n", __func__, rx_type);
return -EBADRQC;
}
}
static int es581_4_handle_urb_cmd(struct es58x_device *es58x_dev,
const union es58x_urb_cmd *urb_cmd)
{
const struct es581_4_urb_cmd *es581_4_urb_cmd;
struct device *dev = es58x_dev->dev;
u16 msg_len = es581_4_get_msg_len(urb_cmd);
int ret;
es581_4_urb_cmd = &urb_cmd->es581_4_urb_cmd;
if (es581_4_urb_cmd->cmd_type != ES581_4_CAN_COMMAND_TYPE) {
dev_err(dev, "%s: Unknown command type (0x%02X)\n",
__func__, es581_4_urb_cmd->cmd_type);
return -EBADRQC;
}
switch ((enum es581_4_cmd_id)es581_4_urb_cmd->cmd_id) {
case ES581_4_CMD_ID_SET_BITTIMING:
return es581_4_rx_cmd_ret_u32(es58x_dev, es581_4_urb_cmd,
ES58X_RET_TYPE_SET_BITTIMING);
case ES581_4_CMD_ID_ENABLE_CHANNEL:
return es581_4_rx_cmd_ret_u32(es58x_dev, es581_4_urb_cmd,
ES58X_RET_TYPE_ENABLE_CHANNEL);
case ES581_4_CMD_ID_TX_MSG:
return es581_4_tx_ack_msg(es58x_dev, es581_4_urb_cmd);
case ES581_4_CMD_ID_RX_MSG:
return es581_4_dispatch_rx_cmd(es58x_dev, es581_4_urb_cmd);
case ES581_4_CMD_ID_RESET_RX:
ret = es581_4_rx_cmd_ret_u32(es58x_dev, es581_4_urb_cmd,
ES58X_RET_TYPE_RESET_RX);
return ret;
case ES581_4_CMD_ID_RESET_TX:
ret = es581_4_rx_cmd_ret_u32(es58x_dev, es581_4_urb_cmd,
ES58X_RET_TYPE_RESET_TX);
return ret;
case ES581_4_CMD_ID_DISABLE_CHANNEL:
return es581_4_rx_cmd_ret_u32(es58x_dev, es581_4_urb_cmd,
ES58X_RET_TYPE_DISABLE_CHANNEL);
case ES581_4_CMD_ID_TIMESTAMP:
ret = es58x_check_msg_len(dev, es581_4_urb_cmd->timestamp,
msg_len);
if (ret < 0)
return ret;
es58x_rx_timestamp(es58x_dev,
get_unaligned_le64(&es581_4_urb_cmd->timestamp));
return 0;
case ES581_4_CMD_ID_ECHO:
return es581_4_echo_msg(es58x_dev, es581_4_urb_cmd);
case ES581_4_CMD_ID_DEVICE_ERR:
ret = es58x_check_msg_len(dev, es581_4_urb_cmd->rx_cmd_ret_u8,
msg_len);
if (ret)
return ret;
return es58x_rx_cmd_ret_u8(dev, ES58X_RET_TYPE_DEVICE_ERR,
es581_4_urb_cmd->rx_cmd_ret_u8);
default:
dev_warn(dev, "%s: Unexpected command ID: 0x%02X\n",
__func__, es581_4_urb_cmd->cmd_id);
return -EBADRQC;
}
}
static void es581_4_fill_urb_header(union es58x_urb_cmd *urb_cmd, u8 cmd_type,
u8 cmd_id, u8 channel_idx, u16 msg_len)
{
struct es581_4_urb_cmd *es581_4_urb_cmd = &urb_cmd->es581_4_urb_cmd;
es581_4_urb_cmd->SOF = cpu_to_le16(es581_4_param.tx_start_of_frame);
es581_4_urb_cmd->cmd_type = cmd_type;
es581_4_urb_cmd->cmd_id = cmd_id;
es581_4_urb_cmd->msg_len = cpu_to_le16(msg_len);
}
static int es581_4_tx_can_msg(struct es58x_priv *priv,
const struct sk_buff *skb)
{
struct es58x_device *es58x_dev = priv->es58x_dev;
union es58x_urb_cmd *urb_cmd = priv->tx_urb->transfer_buffer;
struct es581_4_urb_cmd *es581_4_urb_cmd = &urb_cmd->es581_4_urb_cmd;
struct can_frame *cf = (struct can_frame *)skb->data;
struct es581_4_tx_can_msg *tx_can_msg;
u16 msg_len;
int ret;
if (can_is_canfd_skb(skb))
return -EMSGSIZE;
if (priv->tx_can_msg_cnt == 0) {
msg_len = 1; /* struct es581_4_bulk_tx_can_msg:num_can_msg */
es581_4_fill_urb_header(urb_cmd, ES581_4_CAN_COMMAND_TYPE,
ES581_4_CMD_ID_TX_MSG,
priv->channel_idx, msg_len);
es581_4_urb_cmd->bulk_tx_can_msg.num_can_msg = 0;
} else {
msg_len = es581_4_get_msg_len(urb_cmd);
}
ret = es58x_check_msg_max_len(es58x_dev->dev,
es581_4_urb_cmd->bulk_tx_can_msg,
msg_len + sizeof(*tx_can_msg));
if (ret)
return ret;
/* Fill message contents. */
tx_can_msg = (struct es581_4_tx_can_msg *)
&es581_4_urb_cmd->bulk_tx_can_msg.tx_can_msg_buf[msg_len - 1];
put_unaligned_le32(es58x_get_raw_can_id(cf), &tx_can_msg->can_id);
put_unaligned_le32(priv->tx_head, &tx_can_msg->packet_idx);
put_unaligned_le16((u16)es58x_get_flags(skb), &tx_can_msg->flags);
tx_can_msg->channel_no = priv->channel_idx + ES581_4_CHANNEL_IDX_OFFSET;
tx_can_msg->dlc = can_get_cc_dlc(cf, priv->can.ctrlmode);
memcpy(tx_can_msg->data, cf->data, cf->len);
/* Calculate new sizes. */
es581_4_urb_cmd->bulk_tx_can_msg.num_can_msg++;
msg_len += es581_4_sizeof_rx_tx_msg(*tx_can_msg);
priv->tx_urb->transfer_buffer_length = es58x_get_urb_cmd_len(es58x_dev,
msg_len);
es581_4_urb_cmd->msg_len = cpu_to_le16(msg_len);
return 0;
}
static int es581_4_set_bittiming(struct es58x_priv *priv)
{
struct es581_4_tx_conf_msg tx_conf_msg = { 0 };
struct can_bittiming *bt = &priv->can.bittiming;
tx_conf_msg.bitrate = cpu_to_le32(bt->bitrate);
/* bt->sample_point is in tenth of percent. Convert it to percent. */
tx_conf_msg.sample_point = cpu_to_le32(bt->sample_point / 10U);
tx_conf_msg.samples_per_bit = cpu_to_le32(ES58X_SAMPLES_PER_BIT_ONE);
tx_conf_msg.bit_time = cpu_to_le32(can_bit_time(bt));
tx_conf_msg.sjw = cpu_to_le32(bt->sjw);
tx_conf_msg.sync_edge = cpu_to_le32(ES58X_SYNC_EDGE_SINGLE);
tx_conf_msg.physical_layer =
cpu_to_le32(ES58X_PHYSICAL_LAYER_HIGH_SPEED);
tx_conf_msg.echo_mode = cpu_to_le32(ES58X_ECHO_ON);
tx_conf_msg.channel_no = priv->channel_idx + ES581_4_CHANNEL_IDX_OFFSET;
return es58x_send_msg(priv->es58x_dev, ES581_4_CAN_COMMAND_TYPE,
ES581_4_CMD_ID_SET_BITTIMING, &tx_conf_msg,
sizeof(tx_conf_msg), priv->channel_idx);
}
static int es581_4_enable_channel(struct es58x_priv *priv)
{
int ret;
u8 msg = priv->channel_idx + ES581_4_CHANNEL_IDX_OFFSET;
ret = es581_4_set_bittiming(priv);
if (ret)
return ret;
return es58x_send_msg(priv->es58x_dev, ES581_4_CAN_COMMAND_TYPE,
ES581_4_CMD_ID_ENABLE_CHANNEL, &msg, sizeof(msg),
priv->channel_idx);
}
static int es581_4_disable_channel(struct es58x_priv *priv)
{
u8 msg = priv->channel_idx + ES581_4_CHANNEL_IDX_OFFSET;
return es58x_send_msg(priv->es58x_dev, ES581_4_CAN_COMMAND_TYPE,
ES581_4_CMD_ID_DISABLE_CHANNEL, &msg, sizeof(msg),
priv->channel_idx);
}
static int es581_4_reset_device(struct es58x_device *es58x_dev)
{
return es58x_send_msg(es58x_dev, ES581_4_CAN_COMMAND_TYPE,
ES581_4_CMD_ID_RESET_DEVICE,
ES58X_EMPTY_MSG, 0, ES58X_CHANNEL_IDX_NA);
}
static int es581_4_get_timestamp(struct es58x_device *es58x_dev)
{
return es58x_send_msg(es58x_dev, ES581_4_CAN_COMMAND_TYPE,
ES581_4_CMD_ID_TIMESTAMP,
ES58X_EMPTY_MSG, 0, ES58X_CHANNEL_IDX_NA);
}
/* Nominal bittiming constants for ES581.4 as specified in the
* microcontroller datasheet: "Stellaris(R) LM3S5B91 Microcontroller"
* table 17-4 "CAN Protocol Ranges" from Texas Instruments.
*/
static const struct can_bittiming_const es581_4_bittiming_const = {
.name = "ES581.4",
.tseg1_min = 1,
.tseg1_max = 8,
.tseg2_min = 1,
.tseg2_max = 8,
.sjw_max = 4,
.brp_min = 1,
.brp_max = 128,
.brp_inc = 1
};
const struct es58x_parameters es581_4_param = {
.bittiming_const = &es581_4_bittiming_const,
.data_bittiming_const = NULL,
.tdc_const = NULL,
.bitrate_max = 1 * CAN_MBPS,
.clock = {.freq = 50 * CAN_MHZ},
.ctrlmode_supported = CAN_CTRLMODE_CC_LEN8_DLC,
.tx_start_of_frame = 0xAFAF,
.rx_start_of_frame = 0xFAFA,
.tx_urb_cmd_max_len = ES581_4_TX_URB_CMD_MAX_LEN,
.rx_urb_cmd_max_len = ES581_4_RX_URB_CMD_MAX_LEN,
/* Size of internal device TX queue is 330.
*
* However, we witnessed some ES58X_ERR_PROT_CRC errors from
* the device and thus, echo_skb_max was lowered to the
* empirical value of 75 which seems stable and then rounded
* down to become a power of two.
*
* Root cause of those ES58X_ERR_PROT_CRC errors is still
* unclear.
*/
.fifo_mask = 63, /* echo_skb_max = 64 */
.dql_min_limit = CAN_FRAME_LEN_MAX * 50, /* Empirical value. */
.tx_bulk_max = ES581_4_TX_BULK_MAX,
.urb_cmd_header_len = ES581_4_URB_CMD_HEADER_LEN,
.rx_urb_max = ES58X_RX_URBS_MAX,
.tx_urb_max = ES58X_TX_URBS_MAX
};
const struct es58x_operators es581_4_ops = {
.get_msg_len = es581_4_get_msg_len,
.handle_urb_cmd = es581_4_handle_urb_cmd,
.fill_urb_header = es581_4_fill_urb_header,
.tx_can_msg = es581_4_tx_can_msg,
.enable_channel = es581_4_enable_channel,
.disable_channel = es581_4_disable_channel,
.reset_device = es581_4_reset_device,
.get_timestamp = es581_4_get_timestamp
};
/* SPDX-License-Identifier: GPL-2.0 */
/* Driver for ETAS GmbH ES58X USB CAN(-FD) Bus Interfaces.
*
* File es581_4.h: Definitions and declarations specific to ETAS
* ES581.4.
*
* Copyright (c) 2019 Robert Bosch Engineering and Business Solutions. All rights reserved.
* Copyright (c) 2020 ETAS K.K.. All rights reserved.
* Copyright (c) 2020, 2021 Vincent Mailhol <mailhol.vincent@wanadoo.fr>
*/
#ifndef __ES581_4_H__
#define __ES581_4_H__
#include <linux/types.h>
#define ES581_4_NUM_CAN_CH 2
#define ES581_4_CHANNEL_IDX_OFFSET 1
#define ES581_4_TX_BULK_MAX 25
#define ES581_4_RX_BULK_MAX 30
#define ES581_4_ECHO_BULK_MAX 30
enum es581_4_cmd_type {
ES581_4_CAN_COMMAND_TYPE = 0x45
};
enum es581_4_cmd_id {
ES581_4_CMD_ID_OPEN_CHANNEL = 0x01,
ES581_4_CMD_ID_CLOSE_CHANNEL = 0x02,
ES581_4_CMD_ID_SET_BITTIMING = 0x03,
ES581_4_CMD_ID_ENABLE_CHANNEL = 0x04,
ES581_4_CMD_ID_TX_MSG = 0x05,
ES581_4_CMD_ID_RX_MSG = 0x06,
ES581_4_CMD_ID_RESET_RX = 0x0A,
ES581_4_CMD_ID_RESET_TX = 0x0B,
ES581_4_CMD_ID_DISABLE_CHANNEL = 0x0C,
ES581_4_CMD_ID_TIMESTAMP = 0x0E,
ES581_4_CMD_ID_RESET_DEVICE = 0x28,
ES581_4_CMD_ID_ECHO = 0x71,
ES581_4_CMD_ID_DEVICE_ERR = 0x72
};
enum es581_4_rx_type {
ES581_4_RX_TYPE_MESSAGE = 1,
ES581_4_RX_TYPE_ERROR = 3,
ES581_4_RX_TYPE_EVENT = 4
};
/**
* struct es581_4_tx_conf_msg - Channel configuration.
* @bitrate: Bitrate.
* @sample_point: Sample point is in percent [0..100].
* @samples_per_bit: type enum es58x_samples_per_bit.
* @bit_time: Number of time quanta in one bit.
* @sjw: Synchronization Jump Width.
* @sync_edge: type enum es58x_sync_edge.
* @physical_layer: type enum es58x_physical_layer.
* @echo_mode: type enum es58x_echo_mode.
* @channel_no: Channel number, starting from 1. Not to be confused
* with channed_idx of the ES58X FD which starts from 0.
*/
struct es581_4_tx_conf_msg {
__le32 bitrate;
__le32 sample_point;
__le32 samples_per_bit;
__le32 bit_time;
__le32 sjw;
__le32 sync_edge;
__le32 physical_layer;
__le32 echo_mode;
u8 channel_no;
} __packed;
struct es581_4_tx_can_msg {
__le32 can_id;
__le32 packet_idx;
__le16 flags;
u8 channel_no;
u8 dlc;
u8 data[CAN_MAX_DLEN];
} __packed;
/* The ES581.4 allows bulk transfer. */
struct es581_4_bulk_tx_can_msg {
u8 num_can_msg;
/* Using type "u8[]" instead of "struct es581_4_tx_can_msg[]"
* for tx_msg_buf because each member has a flexible size.
*/
u8 tx_can_msg_buf[ES581_4_TX_BULK_MAX *
sizeof(struct es581_4_tx_can_msg)];
} __packed;
struct es581_4_echo_msg {
__le64 timestamp;
__le32 packet_idx;
} __packed;
struct es581_4_bulk_echo_msg {
u8 channel_no;
struct es581_4_echo_msg echo_msg[ES581_4_ECHO_BULK_MAX];
} __packed;
/* Normal Rx CAN Message */
struct es581_4_rx_can_msg {
__le64 timestamp;
u8 rx_type; /* type enum es581_4_rx_type */
u8 flags; /* type enum es58x_flag */
u8 channel_no;
u8 dlc;
__le32 can_id;
u8 data[CAN_MAX_DLEN];
} __packed;
struct es581_4_rx_err_msg {
__le64 timestamp;
__le16 rx_type; /* type enum es581_4_rx_type */
__le16 flags; /* type enum es58x_flag */
u8 channel_no;
u8 __padding[2];
u8 dlc;
__le32 tag; /* Related to the CAN filtering. Unused in this module */
__le32 can_id;
__le32 error; /* type enum es58x_error */
__le32 destination; /* Unused in this module */
} __packed;
struct es581_4_rx_event_msg {
__le64 timestamp;
__le16 rx_type; /* type enum es581_4_rx_type */
u8 channel_no;
u8 __padding;
__le32 tag; /* Related to the CAN filtering. Unused in this module */
__le32 event; /* type enum es58x_event */
__le32 destination; /* Unused in this module */
} __packed;
struct es581_4_tx_ack_msg {
__le16 tx_free_entries; /* Number of remaining free entries in the device TX queue */
u8 channel_no;
u8 rx_cmd_ret_u8; /* type enum es58x_cmd_ret_code_u8 */
} __packed;
struct es581_4_rx_cmd_ret {
__le32 rx_cmd_ret_le32;
u8 channel_no;
u8 __padding[3];
} __packed;
/**
* struct es581_4_urb_cmd - Commands received from or sent to the
* ES581.4 device.
* @SOF: Start of Frame.
* @cmd_type: Command Type (type: enum es581_4_cmd_type). The CRC
* calculation starts at this position.
* @cmd_id: Command ID (type: enum es581_4_cmd_id).
* @msg_len: Length of the message, excluding CRC (i.e. length of the
* union).
* @tx_conf_msg: Channel configuration.
* @bulk_tx_can_msg: Tx messages.
* @rx_can_msg: Array of Rx messages.
* @bulk_echo_msg: Tx message being looped back.
* @rx_err_msg: Error message.
* @rx_event_msg: Event message.
* @tx_ack_msg: Tx acknowledgment message.
* @rx_cmd_ret: Command return code.
* @timestamp: Timestamp reply.
* @rx_cmd_ret_u8: Rx 8 bits return code (type: enum
* es58x_cmd_ret_code_u8).
* @raw_msg: Message raw payload.
* @reserved_for_crc16_do_not_use: The structure ends with a
* CRC16. Because the structures in above union are of variable
* lengths, we can not predict the offset of the CRC in
* advance. Use functions es58x_get_crc() and es58x_set_crc() to
* manipulate it.
*/
struct es581_4_urb_cmd {
__le16 SOF;
u8 cmd_type;
u8 cmd_id;
__le16 msg_len;
union {
struct es581_4_tx_conf_msg tx_conf_msg;
struct es581_4_bulk_tx_can_msg bulk_tx_can_msg;
struct es581_4_rx_can_msg rx_can_msg[ES581_4_RX_BULK_MAX];
struct es581_4_bulk_echo_msg bulk_echo_msg;
struct es581_4_rx_err_msg rx_err_msg;
struct es581_4_rx_event_msg rx_event_msg;
struct es581_4_tx_ack_msg tx_ack_msg;
struct es581_4_rx_cmd_ret rx_cmd_ret;
__le64 timestamp;
u8 rx_cmd_ret_u8;
u8 raw_msg[0];
} __packed;
__le16 reserved_for_crc16_do_not_use;
} __packed;
#define ES581_4_URB_CMD_HEADER_LEN (offsetof(struct es581_4_urb_cmd, raw_msg))
#define ES581_4_TX_URB_CMD_MAX_LEN \
ES58X_SIZEOF_URB_CMD(struct es581_4_urb_cmd, bulk_tx_can_msg)
#define ES581_4_RX_URB_CMD_MAX_LEN \
ES58X_SIZEOF_URB_CMD(struct es581_4_urb_cmd, rx_can_msg)
#endif /* __ES581_4_H__ */
此差异已折叠。
此差异已折叠。
// SPDX-License-Identifier: GPL-2.0
/* Driver for ETAS GmbH ES58X USB CAN(-FD) Bus Interfaces.
*
* File es58x_fd.c: Adds support to ETAS ES582.1 and ES584.1 (naming
* convention: we use the term "ES58X FD" when referring to those two
* variants together).
*
* Copyright (c) 2019 Robert Bosch Engineering and Business Solutions. All rights reserved.
* Copyright (c) 2020 ETAS K.K.. All rights reserved.
* Copyright (c) 2020, 2021 Vincent Mailhol <mailhol.vincent@wanadoo.fr>
*/
#include <linux/kernel.h>
#include <asm/unaligned.h>
#include "es58x_core.h"
#include "es58x_fd.h"
/**
* es58x_fd_sizeof_rx_tx_msg() - Calculate the actual length of the
* structure of a rx or tx message.
* @msg: message of variable length, must have a dlc and a len fields.
*
* Even if RTR frames have actually no payload, the ES58X devices
* still expect it. Must be a macro in order to accept several types
* (struct es58x_fd_tx_can_msg and struct es58x_fd_rx_can_msg) as an
* input.
*
* Return: length of the message.
*/
#define es58x_fd_sizeof_rx_tx_msg(msg) \
({ \
typeof(msg) __msg = (msg); \
size_t __msg_len; \
\
if (__msg.flags & ES58X_FLAG_FD_DATA) \
__msg_len = canfd_sanitize_len(__msg.len); \
else \
__msg_len = can_cc_dlc2len(__msg.dlc); \
\
offsetof(typeof(__msg), data[__msg_len]); \
})
static enum es58x_fd_cmd_type es58x_fd_cmd_type(struct net_device *netdev)
{
u32 ctrlmode = es58x_priv(netdev)->can.ctrlmode;
if (ctrlmode & (CAN_CTRLMODE_FD | CAN_CTRLMODE_FD_NON_ISO))
return ES58X_FD_CMD_TYPE_CANFD;
else
return ES58X_FD_CMD_TYPE_CAN;
}
static u16 es58x_fd_get_msg_len(const union es58x_urb_cmd *urb_cmd)
{
return get_unaligned_le16(&urb_cmd->es58x_fd_urb_cmd.msg_len);
}
static int es58x_fd_echo_msg(struct net_device *netdev,
const struct es58x_fd_urb_cmd *es58x_fd_urb_cmd)
{
struct es58x_priv *priv = es58x_priv(netdev);
const struct es58x_fd_echo_msg *echo_msg;
struct es58x_device *es58x_dev = priv->es58x_dev;
u64 *tstamps = es58x_dev->timestamps;
u16 msg_len = get_unaligned_le16(&es58x_fd_urb_cmd->msg_len);
int i, num_element;
u32 rcv_packet_idx;
const u32 mask = GENMASK(31, sizeof(echo_msg->packet_idx) * 8);
num_element = es58x_msg_num_element(es58x_dev->dev,
es58x_fd_urb_cmd->echo_msg,
msg_len);
if (num_element < 0)
return num_element;
echo_msg = es58x_fd_urb_cmd->echo_msg;
rcv_packet_idx = (priv->tx_tail & mask) | echo_msg[0].packet_idx;
for (i = 0; i < num_element; i++) {
if ((u8)rcv_packet_idx != echo_msg[i].packet_idx) {
netdev_err(netdev, "Packet idx jumped from %u to %u\n",
(u8)rcv_packet_idx - 1,
echo_msg[i].packet_idx);
return -EBADMSG;
}
tstamps[i] = get_unaligned_le64(&echo_msg[i].timestamp);
rcv_packet_idx++;
}
return es58x_can_get_echo_skb(netdev, priv->tx_tail, tstamps, num_element);
}
static int es58x_fd_rx_can_msg(struct net_device *netdev,
const struct es58x_fd_urb_cmd *es58x_fd_urb_cmd)
{
struct es58x_device *es58x_dev = es58x_priv(netdev)->es58x_dev;
const u8 *rx_can_msg_buf = es58x_fd_urb_cmd->rx_can_msg_buf;
u16 rx_can_msg_buf_len = get_unaligned_le16(&es58x_fd_urb_cmd->msg_len);
int pkts, ret;
ret = es58x_check_msg_max_len(es58x_dev->dev,
es58x_fd_urb_cmd->rx_can_msg_buf,
rx_can_msg_buf_len);
if (ret)
return ret;
for (pkts = 0; rx_can_msg_buf_len > 0; pkts++) {
const struct es58x_fd_rx_can_msg *rx_can_msg =
(const struct es58x_fd_rx_can_msg *)rx_can_msg_buf;
bool is_can_fd = !!(rx_can_msg->flags & ES58X_FLAG_FD_DATA);
/* rx_can_msg_len is the length of the rx_can_msg
* buffer. Not to be confused with rx_can_msg->len
* which is the length of the CAN payload
* rx_can_msg->data.
*/
u16 rx_can_msg_len = es58x_fd_sizeof_rx_tx_msg(*rx_can_msg);
if (rx_can_msg_len > rx_can_msg_buf_len) {
netdev_err(netdev,
"%s: Expected a rx_can_msg of size %d but only %d bytes are left in rx_can_msg_buf\n",
__func__,
rx_can_msg_len, rx_can_msg_buf_len);
return -EMSGSIZE;
}
if (rx_can_msg->len > CANFD_MAX_DLEN) {
netdev_err(netdev,
"%s: Data length is %d but maximum should be %d\n",
__func__, rx_can_msg->len, CANFD_MAX_DLEN);
return -EMSGSIZE;
}
if (netif_running(netdev)) {
u64 tstamp = get_unaligned_le64(&rx_can_msg->timestamp);
canid_t can_id = get_unaligned_le32(&rx_can_msg->can_id);
u8 dlc;
if (is_can_fd)
dlc = can_fd_len2dlc(rx_can_msg->len);
else
dlc = rx_can_msg->dlc;
ret = es58x_rx_can_msg(netdev, tstamp, rx_can_msg->data,
can_id, rx_can_msg->flags, dlc);
if (ret)
break;
}
rx_can_msg_buf_len -= rx_can_msg_len;
rx_can_msg_buf += rx_can_msg_len;
}
if (!netif_running(netdev)) {
if (net_ratelimit())
netdev_info(netdev,
"%s: %s is down, dropping %d rx packets\n",
__func__, netdev->name, pkts);
netdev->stats.rx_dropped += pkts;
}
return ret;
}
static int es58x_fd_rx_event_msg(struct net_device *netdev,
const struct es58x_fd_urb_cmd *es58x_fd_urb_cmd)
{
struct es58x_device *es58x_dev = es58x_priv(netdev)->es58x_dev;
u16 msg_len = get_unaligned_le16(&es58x_fd_urb_cmd->msg_len);
const struct es58x_fd_rx_event_msg *rx_event_msg;
int ret;
ret = es58x_check_msg_len(es58x_dev->dev, *rx_event_msg, msg_len);
if (ret)
return ret;
rx_event_msg = &es58x_fd_urb_cmd->rx_event_msg;
return es58x_rx_err_msg(netdev, rx_event_msg->error_code,
rx_event_msg->event_code,
get_unaligned_le64(&rx_event_msg->timestamp));
}
static int es58x_fd_rx_cmd_ret_u32(struct net_device *netdev,
const struct es58x_fd_urb_cmd *es58x_fd_urb_cmd,
enum es58x_ret_type cmd_ret_type)
{
struct es58x_device *es58x_dev = es58x_priv(netdev)->es58x_dev;
u16 msg_len = get_unaligned_le16(&es58x_fd_urb_cmd->msg_len);
int ret;
ret = es58x_check_msg_len(es58x_dev->dev,
es58x_fd_urb_cmd->rx_cmd_ret_le32, msg_len);
if (ret)
return ret;
return es58x_rx_cmd_ret_u32(netdev, cmd_ret_type,
get_unaligned_le32(&es58x_fd_urb_cmd->rx_cmd_ret_le32));
}
static int es58x_fd_tx_ack_msg(struct net_device *netdev,
const struct es58x_fd_urb_cmd *es58x_fd_urb_cmd)
{
struct es58x_device *es58x_dev = es58x_priv(netdev)->es58x_dev;
const struct es58x_fd_tx_ack_msg *tx_ack_msg;
u16 msg_len = get_unaligned_le16(&es58x_fd_urb_cmd->msg_len);
int ret;
tx_ack_msg = &es58x_fd_urb_cmd->tx_ack_msg;
ret = es58x_check_msg_len(es58x_dev->dev, *tx_ack_msg, msg_len);
if (ret)
return ret;
return es58x_tx_ack_msg(netdev,
get_unaligned_le16(&tx_ack_msg->tx_free_entries),
get_unaligned_le32(&tx_ack_msg->rx_cmd_ret_le32));
}
static int es58x_fd_can_cmd_id(struct es58x_device *es58x_dev,
const struct es58x_fd_urb_cmd *es58x_fd_urb_cmd)
{
struct net_device *netdev;
int ret;
ret = es58x_get_netdev(es58x_dev, es58x_fd_urb_cmd->channel_idx,
ES58X_FD_CHANNEL_IDX_OFFSET, &netdev);
if (ret)
return ret;
switch ((enum es58x_fd_can_cmd_id)es58x_fd_urb_cmd->cmd_id) {
case ES58X_FD_CAN_CMD_ID_ENABLE_CHANNEL:
return es58x_fd_rx_cmd_ret_u32(netdev, es58x_fd_urb_cmd,
ES58X_RET_TYPE_ENABLE_CHANNEL);
case ES58X_FD_CAN_CMD_ID_DISABLE_CHANNEL:
return es58x_fd_rx_cmd_ret_u32(netdev, es58x_fd_urb_cmd,
ES58X_RET_TYPE_DISABLE_CHANNEL);
case ES58X_FD_CAN_CMD_ID_TX_MSG:
return es58x_fd_tx_ack_msg(netdev, es58x_fd_urb_cmd);
case ES58X_FD_CAN_CMD_ID_ECHO_MSG:
return es58x_fd_echo_msg(netdev, es58x_fd_urb_cmd);
case ES58X_FD_CAN_CMD_ID_RX_MSG:
return es58x_fd_rx_can_msg(netdev, es58x_fd_urb_cmd);
case ES58X_FD_CAN_CMD_ID_RESET_RX:
return es58x_fd_rx_cmd_ret_u32(netdev, es58x_fd_urb_cmd,
ES58X_RET_TYPE_RESET_RX);
case ES58X_FD_CAN_CMD_ID_RESET_TX:
return es58x_fd_rx_cmd_ret_u32(netdev, es58x_fd_urb_cmd,
ES58X_RET_TYPE_RESET_TX);
case ES58X_FD_CAN_CMD_ID_ERROR_OR_EVENT_MSG:
return es58x_fd_rx_event_msg(netdev, es58x_fd_urb_cmd);
default:
return -EBADRQC;
}
}
static int es58x_fd_device_cmd_id(struct es58x_device *es58x_dev,
const struct es58x_fd_urb_cmd *es58x_fd_urb_cmd)
{
u16 msg_len = get_unaligned_le16(&es58x_fd_urb_cmd->msg_len);
int ret;
switch ((enum es58x_fd_dev_cmd_id)es58x_fd_urb_cmd->cmd_id) {
case ES58X_FD_DEV_CMD_ID_TIMESTAMP:
ret = es58x_check_msg_len(es58x_dev->dev,
es58x_fd_urb_cmd->timestamp, msg_len);
if (ret)
return ret;
es58x_rx_timestamp(es58x_dev,
get_unaligned_le64(&es58x_fd_urb_cmd->timestamp));
return 0;
default:
return -EBADRQC;
}
}
static int es58x_fd_handle_urb_cmd(struct es58x_device *es58x_dev,
const union es58x_urb_cmd *urb_cmd)
{
const struct es58x_fd_urb_cmd *es58x_fd_urb_cmd;
int ret;
es58x_fd_urb_cmd = &urb_cmd->es58x_fd_urb_cmd;
switch ((enum es58x_fd_cmd_type)es58x_fd_urb_cmd->cmd_type) {
case ES58X_FD_CMD_TYPE_CAN:
case ES58X_FD_CMD_TYPE_CANFD:
ret = es58x_fd_can_cmd_id(es58x_dev, es58x_fd_urb_cmd);
break;
case ES58X_FD_CMD_TYPE_DEVICE:
ret = es58x_fd_device_cmd_id(es58x_dev, es58x_fd_urb_cmd);
break;
default:
ret = -EBADRQC;
break;
}
if (ret == -EBADRQC)
dev_err(es58x_dev->dev,
"%s: Unknown command type (0x%02X) and command ID (0x%02X) combination\n",
__func__, es58x_fd_urb_cmd->cmd_type,
es58x_fd_urb_cmd->cmd_id);
return ret;
}
static void es58x_fd_fill_urb_header(union es58x_urb_cmd *urb_cmd, u8 cmd_type,
u8 cmd_id, u8 channel_idx, u16 msg_len)
{
struct es58x_fd_urb_cmd *es58x_fd_urb_cmd = &urb_cmd->es58x_fd_urb_cmd;
es58x_fd_urb_cmd->SOF = cpu_to_le16(es58x_fd_param.tx_start_of_frame);
es58x_fd_urb_cmd->cmd_type = cmd_type;
es58x_fd_urb_cmd->cmd_id = cmd_id;
es58x_fd_urb_cmd->channel_idx = channel_idx;
es58x_fd_urb_cmd->msg_len = cpu_to_le16(msg_len);
}
static int es58x_fd_tx_can_msg(struct es58x_priv *priv,
const struct sk_buff *skb)
{
struct es58x_device *es58x_dev = priv->es58x_dev;
union es58x_urb_cmd *urb_cmd = priv->tx_urb->transfer_buffer;
struct es58x_fd_urb_cmd *es58x_fd_urb_cmd = &urb_cmd->es58x_fd_urb_cmd;
struct can_frame *cf = (struct can_frame *)skb->data;
struct es58x_fd_tx_can_msg *tx_can_msg;
bool is_fd = can_is_canfd_skb(skb);
u16 msg_len;
int ret;
if (priv->tx_can_msg_cnt == 0) {
msg_len = 0;
es58x_fd_fill_urb_header(urb_cmd,
is_fd ? ES58X_FD_CMD_TYPE_CANFD
: ES58X_FD_CMD_TYPE_CAN,
ES58X_FD_CAN_CMD_ID_TX_MSG_NO_ACK,
priv->channel_idx, msg_len);
} else {
msg_len = es58x_fd_get_msg_len(urb_cmd);
}
ret = es58x_check_msg_max_len(es58x_dev->dev,
es58x_fd_urb_cmd->tx_can_msg_buf,
msg_len + sizeof(*tx_can_msg));
if (ret)
return ret;
/* Fill message contents. */
tx_can_msg = (struct es58x_fd_tx_can_msg *)
&es58x_fd_urb_cmd->tx_can_msg_buf[msg_len];
tx_can_msg->packet_idx = (u8)priv->tx_head;
put_unaligned_le32(es58x_get_raw_can_id(cf), &tx_can_msg->can_id);
tx_can_msg->flags = (u8)es58x_get_flags(skb);
if (is_fd)
tx_can_msg->len = cf->len;
else
tx_can_msg->dlc = can_get_cc_dlc(cf, priv->can.ctrlmode);
memcpy(tx_can_msg->data, cf->data, cf->len);
/* Calculate new sizes */
msg_len += es58x_fd_sizeof_rx_tx_msg(*tx_can_msg);
priv->tx_urb->transfer_buffer_length = es58x_get_urb_cmd_len(es58x_dev,
msg_len);
put_unaligned_le16(msg_len, &es58x_fd_urb_cmd->msg_len);
return 0;
}
static void es58x_fd_convert_bittiming(struct es58x_fd_bittiming *es58x_fd_bt,
struct can_bittiming *bt)
{
/* The actual value set in the hardware registers is one less
* than the functional value.
*/
const int offset = 1;
es58x_fd_bt->bitrate = cpu_to_le32(bt->bitrate);
es58x_fd_bt->tseg1 =
cpu_to_le16(bt->prop_seg + bt->phase_seg1 - offset);
es58x_fd_bt->tseg2 = cpu_to_le16(bt->phase_seg2 - offset);
es58x_fd_bt->brp = cpu_to_le16(bt->brp - offset);
es58x_fd_bt->sjw = cpu_to_le16(bt->sjw - offset);
}
static int es58x_fd_enable_channel(struct es58x_priv *priv)
{
struct es58x_device *es58x_dev = priv->es58x_dev;
struct net_device *netdev = es58x_dev->netdev[priv->channel_idx];
struct es58x_fd_tx_conf_msg tx_conf_msg = { 0 };
u32 ctrlmode;
size_t conf_len = 0;
es58x_fd_convert_bittiming(&tx_conf_msg.nominal_bittiming,
&priv->can.bittiming);
ctrlmode = priv->can.ctrlmode;
if (ctrlmode & CAN_CTRLMODE_3_SAMPLES)
tx_conf_msg.samples_per_bit = ES58X_SAMPLES_PER_BIT_THREE;
else
tx_conf_msg.samples_per_bit = ES58X_SAMPLES_PER_BIT_ONE;
tx_conf_msg.sync_edge = ES58X_SYNC_EDGE_SINGLE;
tx_conf_msg.physical_layer = ES58X_PHYSICAL_LAYER_HIGH_SPEED;
tx_conf_msg.echo_mode = ES58X_ECHO_ON;
if (ctrlmode & CAN_CTRLMODE_LISTENONLY)
tx_conf_msg.ctrlmode |= ES58X_FD_CTRLMODE_PASSIVE;
else
tx_conf_msg.ctrlmode |= ES58X_FD_CTRLMODE_ACTIVE;
if (ctrlmode & CAN_CTRLMODE_FD_NON_ISO) {
tx_conf_msg.ctrlmode |= ES58X_FD_CTRLMODE_FD_NON_ISO;
tx_conf_msg.canfd_enabled = 1;
} else if (ctrlmode & CAN_CTRLMODE_FD) {
tx_conf_msg.ctrlmode |= ES58X_FD_CTRLMODE_FD;
tx_conf_msg.canfd_enabled = 1;
}
if (tx_conf_msg.canfd_enabled) {
es58x_fd_convert_bittiming(&tx_conf_msg.data_bittiming,
&priv->can.data_bittiming);
if (priv->can.tdc.tdco) {
tx_conf_msg.tdc_enabled = 1;
tx_conf_msg.tdco = cpu_to_le16(priv->can.tdc.tdco);
tx_conf_msg.tdcf = cpu_to_le16(priv->can.tdc.tdcf);
}
conf_len = ES58X_FD_CANFD_CONF_LEN;
} else {
conf_len = ES58X_FD_CAN_CONF_LEN;
}
return es58x_send_msg(es58x_dev, es58x_fd_cmd_type(netdev),
ES58X_FD_CAN_CMD_ID_ENABLE_CHANNEL,
&tx_conf_msg, conf_len, priv->channel_idx);
}
static int es58x_fd_disable_channel(struct es58x_priv *priv)
{
/* The type (ES58X_FD_CMD_TYPE_CAN or ES58X_FD_CMD_TYPE_CANFD) does
* not matter here.
*/
return es58x_send_msg(priv->es58x_dev, ES58X_FD_CMD_TYPE_CAN,
ES58X_FD_CAN_CMD_ID_DISABLE_CHANNEL,
ES58X_EMPTY_MSG, 0, priv->channel_idx);
}
static int es58x_fd_get_timestamp(struct es58x_device *es58x_dev)
{
return es58x_send_msg(es58x_dev, ES58X_FD_CMD_TYPE_DEVICE,
ES58X_FD_DEV_CMD_ID_TIMESTAMP, ES58X_EMPTY_MSG,
0, ES58X_CHANNEL_IDX_NA);
}
/* Nominal bittiming constants for ES582.1 and ES584.1 as specified in
* the microcontroller datasheet: "SAM E701/S70/V70/V71 Family"
* section 49.6.8 "MCAN Nominal Bit Timing and Prescaler Register"
* from Microchip.
*
* The values from the specification are the hardware register
* values. To convert them to the functional values, all ranges were
* incremented by 1 (e.g. range [0..n-1] changed to [1..n]).
*/
static const struct can_bittiming_const es58x_fd_nom_bittiming_const = {
.name = "ES582.1/ES584.1",
.tseg1_min = 2,
.tseg1_max = 256,
.tseg2_min = 2,
.tseg2_max = 128,
.sjw_max = 128,
.brp_min = 1,
.brp_max = 512,
.brp_inc = 1
};
/* Data bittiming constants for ES582.1 and ES584.1 as specified in
* the microcontroller datasheet: "SAM E701/S70/V70/V71 Family"
* section 49.6.4 "MCAN Data Bit Timing and Prescaler Register" from
* Microchip.
*/
static const struct can_bittiming_const es58x_fd_data_bittiming_const = {
.name = "ES582.1/ES584.1",
.tseg1_min = 2,
.tseg1_max = 32,
.tseg2_min = 1,
.tseg2_max = 16,
.sjw_max = 8,
.brp_min = 1,
.brp_max = 32,
.brp_inc = 1
};
/* Transmission Delay Compensation constants for ES582.1 and ES584.1
* as specified in the microcontroller datasheet: "SAM
* E701/S70/V70/V71 Family" section 49.6.15 "MCAN Transmitter Delay
* Compensation Register" from Microchip.
*/
static const struct can_tdc_const es58x_tdc_const = {
.tdcv_max = 0, /* Manual mode not supported. */
.tdco_max = 127,
.tdcf_max = 127
};
const struct es58x_parameters es58x_fd_param = {
.bittiming_const = &es58x_fd_nom_bittiming_const,
.data_bittiming_const = &es58x_fd_data_bittiming_const,
.tdc_const = &es58x_tdc_const,
/* The devices use NXP TJA1044G transievers which guarantee
* the timing for data rates up to 5 Mbps. Bitrates up to 8
* Mbps work in an optimal environment but are not recommended
* for production environment.
*/
.bitrate_max = 8 * CAN_MBPS,
.clock = {.freq = 80 * CAN_MHZ},
.ctrlmode_supported = CAN_CTRLMODE_LOOPBACK | CAN_CTRLMODE_LISTENONLY |
CAN_CTRLMODE_3_SAMPLES | CAN_CTRLMODE_FD | CAN_CTRLMODE_FD_NON_ISO |
CAN_CTRLMODE_CC_LEN8_DLC,
.tx_start_of_frame = 0xCEFA, /* FACE in little endian */
.rx_start_of_frame = 0xFECA, /* CAFE in little endian */
.tx_urb_cmd_max_len = ES58X_FD_TX_URB_CMD_MAX_LEN,
.rx_urb_cmd_max_len = ES58X_FD_RX_URB_CMD_MAX_LEN,
/* Size of internal device TX queue is 500.
*
* However, when reaching value around 278, the device's busy
* LED turns on and thus maximum value of 500 is never reached
* in practice. Also, when this value is too high, some error
* on the echo_msg were witnessed when the device is
* recovering from bus off.
*
* For above reasons, a value that would prevent the device
* from becoming busy was chosen. In practice, BQL would
* prevent the value from even getting closer to below
* maximum, so no impact on performance was measured.
*/
.fifo_mask = 255, /* echo_skb_max = 256 */
.dql_min_limit = CAN_FRAME_LEN_MAX * 15, /* Empirical value. */
.tx_bulk_max = ES58X_FD_TX_BULK_MAX,
.urb_cmd_header_len = ES58X_FD_URB_CMD_HEADER_LEN,
.rx_urb_max = ES58X_RX_URBS_MAX,
.tx_urb_max = ES58X_TX_URBS_MAX
};
const struct es58x_operators es58x_fd_ops = {
.get_msg_len = es58x_fd_get_msg_len,
.handle_urb_cmd = es58x_fd_handle_urb_cmd,
.fill_urb_header = es58x_fd_fill_urb_header,
.tx_can_msg = es58x_fd_tx_can_msg,
.enable_channel = es58x_fd_enable_channel,
.disable_channel = es58x_fd_disable_channel,
.reset_device = NULL, /* Not implemented in the device firmware. */
.get_timestamp = es58x_fd_get_timestamp
};
/* SPDX-License-Identifier: GPL-2.0 */
/* Driver for ETAS GmbH ES58X USB CAN(-FD) Bus Interfaces.
*
* File es58x_fd.h: Definitions and declarations specific to ETAS
* ES582.1 and ES584.1 (naming convention: we use the term "ES58X FD"
* when referring to those two variants together).
*
* Copyright (c) 2019 Robert Bosch Engineering and Business Solutions. All rights reserved.
* Copyright (c) 2020 ETAS K.K.. All rights reserved.
* Copyright (c) 2020, 2021 Vincent Mailhol <mailhol.vincent@wanadoo.fr>
*/
#ifndef __ES58X_FD_H__
#define __ES58X_FD_H__
#include <linux/types.h>
#define ES582_1_NUM_CAN_CH 2
#define ES584_1_NUM_CAN_CH 1
#define ES58X_FD_NUM_CAN_CH 2
#define ES58X_FD_CHANNEL_IDX_OFFSET 0
#define ES58X_FD_TX_BULK_MAX 100
#define ES58X_FD_RX_BULK_MAX 100
#define ES58X_FD_ECHO_BULK_MAX 100
enum es58x_fd_cmd_type {
ES58X_FD_CMD_TYPE_CAN = 0x03,
ES58X_FD_CMD_TYPE_CANFD = 0x04,
ES58X_FD_CMD_TYPE_DEVICE = 0xFF
};
/* Command IDs for ES58X_FD_CMD_TYPE_{CAN,CANFD}. */
enum es58x_fd_can_cmd_id {
ES58X_FD_CAN_CMD_ID_ENABLE_CHANNEL = 0x01,
ES58X_FD_CAN_CMD_ID_DISABLE_CHANNEL = 0x02,
ES58X_FD_CAN_CMD_ID_TX_MSG = 0x05,
ES58X_FD_CAN_CMD_ID_ECHO_MSG = 0x07,
ES58X_FD_CAN_CMD_ID_RX_MSG = 0x10,
ES58X_FD_CAN_CMD_ID_ERROR_OR_EVENT_MSG = 0x11,
ES58X_FD_CAN_CMD_ID_RESET_RX = 0x20,
ES58X_FD_CAN_CMD_ID_RESET_TX = 0x21,
ES58X_FD_CAN_CMD_ID_TX_MSG_NO_ACK = 0x55
};
/* Command IDs for ES58X_FD_CMD_TYPE_DEVICE. */
enum es58x_fd_dev_cmd_id {
ES58X_FD_DEV_CMD_ID_GETTIMETICKS = 0x01,
ES58X_FD_DEV_CMD_ID_TIMESTAMP = 0x02
};
/**
* enum es58x_fd_ctrlmode - Controller mode.
* @ES58X_FD_CTRLMODE_ACTIVE: send and receive messages.
* @ES58X_FD_CTRLMODE_PASSIVE: only receive messages (monitor). Do not
* send anything, not even the acknowledgment bit.
* @ES58X_FD_CTRLMODE_FD: CAN FD according to ISO11898-1.
* @ES58X_FD_CTRLMODE_FD_NON_ISO: follow Bosch CAN FD Specification
* V1.0
* @ES58X_FD_CTRLMODE_DISABLE_PROTOCOL_EXCEPTION_HANDLING: How to
* behave when CAN FD reserved bit is monitored as
* dominant. (c.f. ISO 11898-1:2015, section 10.4.2.4 "Control
* field", paragraph "r0 bit"). 0 (not disable = enable): send
* error frame. 1 (disable): goes into bus integration mode
* (c.f. below).
* @ES58X_FD_CTRLMODE_EDGE_FILTER_DURING_BUS_INTEGRATION: 0: Edge
* filtering is disabled. 1: Edge filtering is enabled. Two
* consecutive dominant bits required to detect an edge for hard
* synchronization.
*/
enum es58x_fd_ctrlmode {
ES58X_FD_CTRLMODE_ACTIVE = 0,
ES58X_FD_CTRLMODE_PASSIVE = BIT(0),
ES58X_FD_CTRLMODE_FD = BIT(4),
ES58X_FD_CTRLMODE_FD_NON_ISO = BIT(5),
ES58X_FD_CTRLMODE_DISABLE_PROTOCOL_EXCEPTION_HANDLING = BIT(6),
ES58X_FD_CTRLMODE_EDGE_FILTER_DURING_BUS_INTEGRATION = BIT(7)
};
struct es58x_fd_bittiming {
__le32 bitrate;
__le16 tseg1; /* range: [tseg1_min-1..tseg1_max-1] */
__le16 tseg2; /* range: [tseg2_min-1..tseg2_max-1] */
__le16 brp; /* range: [brp_min-1..brp_max-1] */
__le16 sjw; /* range: [0..sjw_max-1] */
} __packed;
/**
* struct es58x_fd_tx_conf_msg - Channel configuration.
* @nominal_bittiming: Nominal bittiming.
* @samples_per_bit: type enum es58x_samples_per_bit.
* @sync_edge: type enum es58x_sync_edge.
* @physical_layer: type enum es58x_physical_layer.
* @echo_mode: type enum es58x_echo_mode.
* @ctrlmode: type enum es58x_fd_ctrlmode.
* @canfd_enabled: boolean (0: Classical CAN, 1: CAN and/or CANFD).
* @data_bittiming: Bittiming for flexible data-rate transmission.
* @tdc_enabled: Transmitter Delay Compensation switch (0: disabled,
* 1: enabled). On very high bitrates, the delay between when the
* bit is sent and received on the CANTX and CANRX pins of the
* transceiver start to be significant enough for errors to occur
* and thus need to be compensated.
* @tdco: Transmitter Delay Compensation Offset. Offset value, in time
* quanta, defining the delay between the start of the bit
* reception on the CANRX pin of the transceiver and the SSP
* (Secondary Sample Point). Valid values: 0 to 127.
* @tdcf: Transmitter Delay Compensation Filter window. Defines the
* minimum value for the SSP position, in time quanta. The
* feature is enabled when TDCF is configured to a value greater
* than TDCO. Valid values: 0 to 127.
*
* Please refer to the microcontroller datasheet: "SAM
* E701/S70/V70/V71 Family" section 49 "Controller Area Network
* (MCAN)" for additional information.
*/
struct es58x_fd_tx_conf_msg {
struct es58x_fd_bittiming nominal_bittiming;
u8 samples_per_bit;
u8 sync_edge;
u8 physical_layer;
u8 echo_mode;
u8 ctrlmode;
u8 canfd_enabled;
struct es58x_fd_bittiming data_bittiming;
u8 tdc_enabled;
__le16 tdco;
__le16 tdcf;
} __packed;
#define ES58X_FD_CAN_CONF_LEN \
(offsetof(struct es58x_fd_tx_conf_msg, canfd_enabled))
#define ES58X_FD_CANFD_CONF_LEN (sizeof(struct es58x_fd_tx_conf_msg))
struct es58x_fd_tx_can_msg {
u8 packet_idx;
__le32 can_id;
u8 flags;
union {
u8 dlc; /* Only if cmd_id is ES58X_FD_CMD_TYPE_CAN */
u8 len; /* Only if cmd_id is ES58X_FD_CMD_TYPE_CANFD */
} __packed;
u8 data[CANFD_MAX_DLEN];
} __packed;
#define ES58X_FD_CAN_TX_LEN \
(offsetof(struct es58x_fd_tx_can_msg, data[CAN_MAX_DLEN]))
#define ES58X_FD_CANFD_TX_LEN (sizeof(struct es58x_fd_tx_can_msg))
struct es58x_fd_rx_can_msg {
__le64 timestamp;
__le32 can_id;
u8 flags;
union {
u8 dlc; /* Only if cmd_id is ES58X_FD_CMD_TYPE_CAN */
u8 len; /* Only if cmd_id is ES58X_FD_CMD_TYPE_CANFD */
} __packed;
u8 data[CANFD_MAX_DLEN];
} __packed;
#define ES58X_FD_CAN_RX_LEN \
(offsetof(struct es58x_fd_rx_can_msg, data[CAN_MAX_DLEN]))
#define ES58X_FD_CANFD_RX_LEN (sizeof(struct es58x_fd_rx_can_msg))
struct es58x_fd_echo_msg {
__le64 timestamp;
u8 packet_idx;
} __packed;
struct es58x_fd_rx_event_msg {
__le64 timestamp;
__le32 can_id;
u8 flags; /* type enum es58x_flag */
u8 error_type; /* 0: event, 1: error */
u8 error_code;
u8 event_code;
} __packed;
struct es58x_fd_tx_ack_msg {
__le32 rx_cmd_ret_le32; /* type enum es58x_cmd_ret_code_u32 */
__le16 tx_free_entries; /* Number of remaining free entries in the device TX queue */
} __packed;
/**
* struct es58x_fd_urb_cmd - Commands received from or sent to the
* ES58X FD device.
* @SOF: Start of Frame.
* @cmd_type: Command Type (type: enum es58x_fd_cmd_type). The CRC
* calculation starts at this position.
* @cmd_id: Command ID (type: enum es58x_fd_cmd_id).
* @channel_idx: Channel index starting at 0.
* @msg_len: Length of the message, excluding CRC (i.e. length of the
* union).
* @tx_conf_msg: Channel configuration.
* @tx_can_msg_buf: Concatenation of Tx messages. Type is "u8[]"
* instead of "struct es58x_fd_tx_msg[]" because the structure
* has a flexible size.
* @rx_can_msg_buf: Concatenation Rx messages. Type is "u8[]" instead
* of "struct es58x_fd_rx_msg[]" because the structure has a
* flexible size.
* @echo_msg: Array of echo messages (e.g. Tx messages being looped
* back).
* @rx_event_msg: Error or event message.
* @tx_ack_msg: Tx acknowledgment message.
* @timestamp: Timestamp reply.
* @rx_cmd_ret_le32: Rx 32 bits return code (type: enum
* es58x_cmd_ret_code_u32).
* @raw_msg: Message raw payload.
* @reserved_for_crc16_do_not_use: The structure ends with a
* CRC16. Because the structures in above union are of variable
* lengths, we can not predict the offset of the CRC in
* advance. Use functions es58x_get_crc() and es58x_set_crc() to
* manipulate it.
*/
struct es58x_fd_urb_cmd {
__le16 SOF;
u8 cmd_type;
u8 cmd_id;
u8 channel_idx;
__le16 msg_len;
union {
struct es58x_fd_tx_conf_msg tx_conf_msg;
u8 tx_can_msg_buf[ES58X_FD_TX_BULK_MAX * ES58X_FD_CANFD_TX_LEN];
u8 rx_can_msg_buf[ES58X_FD_RX_BULK_MAX * ES58X_FD_CANFD_RX_LEN];
struct es58x_fd_echo_msg echo_msg[ES58X_FD_ECHO_BULK_MAX];
struct es58x_fd_rx_event_msg rx_event_msg;
struct es58x_fd_tx_ack_msg tx_ack_msg;
__le64 timestamp;
__le32 rx_cmd_ret_le32;
u8 raw_msg[0];
} __packed;
__le16 reserved_for_crc16_do_not_use;
} __packed;
#define ES58X_FD_URB_CMD_HEADER_LEN (offsetof(struct es58x_fd_urb_cmd, raw_msg))
#define ES58X_FD_TX_URB_CMD_MAX_LEN \
ES58X_SIZEOF_URB_CMD(struct es58x_fd_urb_cmd, tx_can_msg_buf)
#define ES58X_FD_RX_URB_CMD_MAX_LEN \
ES58X_SIZEOF_URB_CMD(struct es58x_fd_urb_cmd, rx_can_msg_buf)
#endif /* __ES58X_FD_H__ */
......@@ -365,16 +365,11 @@ static int pcan_usb_get_serial(struct peak_usb_device *dev, u32 *serial_number)
int err;
err = pcan_usb_wait_rsp(dev, PCAN_USB_CMD_SN, PCAN_USB_GET, args);
if (err) {
netdev_err(dev->netdev, "getting serial failure: %d\n", err);
} else if (serial_number) {
__le32 tmp32;
memcpy(&tmp32, args, 4);
*serial_number = le32_to_cpu(tmp32);
}
if (err)
return err;
*serial_number = le32_to_cpup((__le32 *)args);
return err;
return 0;
}
/*
......@@ -388,8 +383,8 @@ static int pcan_usb_get_device_id(struct peak_usb_device *dev, u32 *device_id)
err = pcan_usb_wait_rsp(dev, PCAN_USB_CMD_DEVID, PCAN_USB_GET, args);
if (err)
netdev_err(dev->netdev, "getting device id failure: %d\n", err);
else if (device_id)
*device_id = args[0];
*device_id = args[0];
return err;
}
......@@ -399,14 +394,10 @@ static int pcan_usb_get_device_id(struct peak_usb_device *dev, u32 *device_id)
*/
static int pcan_usb_update_ts(struct pcan_usb_msg_context *mc)
{
__le16 tmp16;
if ((mc->ptr+2) > mc->end)
if ((mc->ptr + 2) > mc->end)
return -EINVAL;
memcpy(&tmp16, mc->ptr, 2);
mc->ts16 = le16_to_cpu(tmp16);
mc->ts16 = get_unaligned_le16(mc->ptr);
if (mc->rec_idx > 0)
peak_usb_update_ts_now(&mc->pdev->time_ref, mc->ts16);
......@@ -423,16 +414,13 @@ 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) {
__le16 tmp16;
if ((mc->ptr + 2) > mc->end)
return -EINVAL;
memcpy(&tmp16, mc->ptr, 2);
mc->ptr += 2;
mc->ts16 = le16_to_cpu(tmp16);
mc->ts16 = get_unaligned_le16(mc->ptr);
mc->prev_ts8 = mc->ts16 & 0x00ff;
mc->ptr += 2;
} else {
u8 ts8;
......@@ -722,25 +710,17 @@ static int pcan_usb_decode_data(struct pcan_usb_msg_context *mc, u8 status_len)
return -ENOMEM;
if (status_len & PCAN_USB_STATUSLEN_EXT_ID) {
__le32 tmp32;
if ((mc->ptr + 4) > mc->end)
goto decode_failed;
memcpy(&tmp32, mc->ptr, 4);
cf->can_id = get_unaligned_le32(mc->ptr) >> 3 | CAN_EFF_FLAG;
mc->ptr += 4;
cf->can_id = (le32_to_cpu(tmp32) >> 3) | CAN_EFF_FLAG;
} else {
__le16 tmp16;
if ((mc->ptr + 2) > mc->end)
goto decode_failed;
memcpy(&tmp16, mc->ptr, 2);
cf->can_id = get_unaligned_le16(mc->ptr) >> 5;
mc->ptr += 2;
cf->can_id = le16_to_cpu(tmp16) >> 5;
}
can_frame_set_cc_len(cf, rec_len, mc->pdev->dev.can.ctrlmode);
......@@ -854,15 +834,15 @@ static int pcan_usb_encode_msg(struct peak_usb_device *dev, struct sk_buff *skb,
/* can id */
if (cf->can_id & CAN_EFF_FLAG) {
__le32 tmp32 = cpu_to_le32((cf->can_id & CAN_ERR_MASK) << 3);
*pc |= PCAN_USB_STATUSLEN_EXT_ID;
memcpy(++pc, &tmp32, 4);
pc++;
put_unaligned_le32((cf->can_id & CAN_ERR_MASK) << 3, pc);
pc += 4;
} else {
__le16 tmp16 = cpu_to_le16((cf->can_id & CAN_ERR_MASK) << 5);
pc++;
memcpy(++pc, &tmp16, 2);
put_unaligned_le16((cf->can_id & CAN_ERR_MASK) << 5, pc);
pc += 2;
}
......@@ -1039,7 +1019,7 @@ const struct peak_usb_adapter pcan_usb = {
CAN_CTRLMODE_BERR_REPORTING |
CAN_CTRLMODE_CC_LEN8_DLC,
.clock = {
.freq = PCAN_USB_CRYSTAL_HZ / 2 ,
.freq = PCAN_USB_CRYSTAL_HZ / 2,
},
.bittiming_const = &pcan_usb_const,
......@@ -1050,7 +1030,6 @@ const struct peak_usb_adapter 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 */
......
......@@ -27,28 +27,32 @@ MODULE_DESCRIPTION("CAN driver for PEAK-System USB adapters");
MODULE_LICENSE("GPL v2");
/* Table of devices that work with this driver */
static struct usb_device_id peak_usb_table[] = {
{USB_DEVICE(PCAN_USB_VENDOR_ID, PCAN_USB_PRODUCT_ID)},
{USB_DEVICE(PCAN_USB_VENDOR_ID, PCAN_USBPRO_PRODUCT_ID)},
{USB_DEVICE(PCAN_USB_VENDOR_ID, PCAN_USBFD_PRODUCT_ID)},
{USB_DEVICE(PCAN_USB_VENDOR_ID, PCAN_USBPROFD_PRODUCT_ID)},
{USB_DEVICE(PCAN_USB_VENDOR_ID, PCAN_USBCHIP_PRODUCT_ID)},
{USB_DEVICE(PCAN_USB_VENDOR_ID, PCAN_USBX6_PRODUCT_ID)},
{} /* Terminating entry */
static const struct usb_device_id peak_usb_table[] = {
{
USB_DEVICE(PCAN_USB_VENDOR_ID, PCAN_USB_PRODUCT_ID),
.driver_info = (kernel_ulong_t)&pcan_usb,
}, {
USB_DEVICE(PCAN_USB_VENDOR_ID, PCAN_USBPRO_PRODUCT_ID),
.driver_info = (kernel_ulong_t)&pcan_usb_pro,
}, {
USB_DEVICE(PCAN_USB_VENDOR_ID, PCAN_USBFD_PRODUCT_ID),
.driver_info = (kernel_ulong_t)&pcan_usb_fd,
}, {
USB_DEVICE(PCAN_USB_VENDOR_ID, PCAN_USBPROFD_PRODUCT_ID),
.driver_info = (kernel_ulong_t)&pcan_usb_pro_fd,
}, {
USB_DEVICE(PCAN_USB_VENDOR_ID, PCAN_USBCHIP_PRODUCT_ID),
.driver_info = (kernel_ulong_t)&pcan_usb_chip,
}, {
USB_DEVICE(PCAN_USB_VENDOR_ID, PCAN_USBX6_PRODUCT_ID),
.driver_info = (kernel_ulong_t)&pcan_usb_x6,
}, {
/* Terminating entry */
}
};
MODULE_DEVICE_TABLE(usb, peak_usb_table);
/* List of supported PCAN-USB adapters (NULL terminated list) */
static const struct peak_usb_adapter *const peak_usb_adapters_list[] = {
&pcan_usb,
&pcan_usb_pro,
&pcan_usb_fd,
&pcan_usb_pro_fd,
&pcan_usb_chip,
&pcan_usb_x6,
};
/*
* dump memory
*/
......@@ -624,6 +628,7 @@ static int peak_usb_ndo_stop(struct net_device *netdev)
/* can set bus off now */
if (dev->adapter->dev_set_bus) {
int err = dev->adapter->dev_set_bus(dev, 0);
if (err)
return err;
}
......@@ -927,24 +932,11 @@ static void peak_usb_disconnect(struct usb_interface *intf)
static int peak_usb_probe(struct usb_interface *intf,
const struct usb_device_id *id)
{
struct usb_device *usb_dev = interface_to_usbdev(intf);
const u16 usb_id_product = le16_to_cpu(usb_dev->descriptor.idProduct);
const struct peak_usb_adapter *peak_usb_adapter = NULL;
const struct peak_usb_adapter *peak_usb_adapter;
int i, err = -ENOMEM;
/* get corresponding PCAN-USB adapter */
for (i = 0; i < ARRAY_SIZE(peak_usb_adapters_list); i++)
if (peak_usb_adapters_list[i]->device_id == usb_id_product) {
peak_usb_adapter = peak_usb_adapters_list[i];
break;
}
if (!peak_usb_adapter) {
/* should never come except device_id bad usage in this file */
pr_err("%s: didn't find device id. 0x%x in devices list\n",
PCAN_USB_DRIVER_NAME, usb_id_product);
return -ENODEV;
}
peak_usb_adapter = (const struct peak_usb_adapter *)id->driver_info;
/* got corresponding adapter: check if it handles current interface */
if (peak_usb_adapter->intf_probe) {
......
......@@ -31,7 +31,7 @@
/* usb adapters maximum channels per usb interface */
#define PCAN_USB_MAX_CHANNEL 2
/* maximum length of the usb commands sent to/received from the devices */
/* maximum length of the usb commands sent to/received from the devices */
#define PCAN_USB_MAX_CMD_LEN 32
struct peak_usb_device;
......@@ -73,7 +73,6 @@ struct peak_usb_adapter {
u8 ep_msg_in;
u8 ep_msg_out[PCAN_USB_MAX_CHANNEL];
u8 ts_used_bits;
u32 ts_period;
u8 us_per_ts_shift;
u32 us_per_ts_scale;
......@@ -114,8 +113,6 @@ struct peak_usb_device {
unsigned int ctrl_idx;
u32 state;
struct sk_buff *echo_skb[PCAN_USB_MAX_TX_URBS];
struct usb_device *udev;
struct net_device *netdev;
......@@ -132,8 +129,6 @@ struct peak_usb_device {
u8 ep_msg_in;
u8 ep_msg_out;
u16 bus_load;
struct peak_usb_device *prev_siblings;
struct peak_usb_device *next_siblings;
};
......
......@@ -1081,7 +1081,6 @@ const struct peak_usb_adapter pcan_usb_fd = {
/* timestamps usage */
.ts_used_bits = 32,
.ts_period = 1000000, /* calibration period in ts. */
.us_per_ts_scale = 1, /* us = (ts * scale) >> shift */
.us_per_ts_shift = 0,
......@@ -1156,7 +1155,6 @@ const struct peak_usb_adapter pcan_usb_chip = {
/* timestamps usage */
.ts_used_bits = 32,
.ts_period = 1000000, /* calibration period in ts. */
.us_per_ts_scale = 1, /* us = (ts * scale) >> shift */
.us_per_ts_shift = 0,
......@@ -1231,7 +1229,6 @@ const struct peak_usb_adapter pcan_usb_pro_fd = {
/* timestamps usage */
.ts_used_bits = 32,
.ts_period = 1000000, /* calibration period in ts. */
.us_per_ts_scale = 1, /* us = (ts * scale) >> shift */
.us_per_ts_shift = 0,
......@@ -1306,7 +1303,6 @@ const struct peak_usb_adapter pcan_usb_x6 = {
/* timestamps usage */
.ts_used_bits = 32,
.ts_period = 1000000, /* calibration period in ts. */
.us_per_ts_scale = 1, /* us = (ts * scale) >> shift */
.us_per_ts_shift = 0,
......
......@@ -290,7 +290,7 @@ static int pcan_usb_pro_wait_rsp(struct peak_usb_device *dev,
pr->data_type);
/* check if channel in response corresponds too */
else if ((req_channel != 0xff) && \
else if ((req_channel != 0xff) &&
(pr->bus_act.channel != req_channel))
netdev_err(dev->netdev,
"got rsp %xh but on chan%u: ignored\n",
......@@ -439,8 +439,7 @@ static int pcan_usb_pro_get_device_id(struct peak_usb_device *dev,
return err;
pdn = (struct pcan_usb_pro_devid *)pc;
if (device_id)
*device_id = le32_to_cpu(pdn->serial_num);
*device_id = le32_to_cpu(pdn->serial_num);
return err;
}
......@@ -1058,7 +1057,6 @@ const struct peak_usb_adapter pcan_usb_pro = {
/* timestamps usage */
.ts_used_bits = 32,
.ts_period = 1000000, /* calibration period in ts. */
.us_per_ts_scale = 1, /* us = (ts * scale) >> shift */
.us_per_ts_shift = 0,
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册