566 lines · c
1// SPDX-License-Identifier: GPL-2.02 3/* Driver for ETAS GmbH ES58X USB CAN(-FD) Bus Interfaces.4 *5 * File es58x_fd.c: Adds support to ETAS ES582.1 and ES584.1 (naming6 * convention: we use the term "ES58X FD" when referring to those two7 * variants together).8 *9 * Copyright (c) 2019 Robert Bosch Engineering and Business Solutions. All rights reserved.10 * Copyright (c) 2020 ETAS K.K.. All rights reserved.11 * Copyright (c) 2020-2022 Vincent Mailhol <mailhol.vincent@wanadoo.fr>12 */13 14#include <linux/unaligned.h>15#include <linux/kernel.h>16#include <linux/units.h>17 18#include "es58x_core.h"19#include "es58x_fd.h"20 21/**22 * es58x_fd_sizeof_rx_tx_msg() - Calculate the actual length of the23 * structure of a rx or tx message.24 * @msg: message of variable length, must have a dlc and a len fields.25 *26 * Even if RTR frames have actually no payload, the ES58X devices27 * still expect it. Must be a macro in order to accept several types28 * (struct es58x_fd_tx_can_msg and struct es58x_fd_rx_can_msg) as an29 * input.30 *31 * Return: length of the message.32 */33#define es58x_fd_sizeof_rx_tx_msg(msg) \34({ \35 typeof(msg) __msg = (msg); \36 size_t __msg_len; \37 \38 if (__msg.flags & ES58X_FLAG_FD_DATA) \39 __msg_len = canfd_sanitize_len(__msg.len); \40 else \41 __msg_len = can_cc_dlc2len(__msg.dlc); \42 \43 offsetof(typeof(__msg), data[__msg_len]); \44})45 46static enum es58x_fd_cmd_type es58x_fd_cmd_type(struct net_device *netdev)47{48 u32 ctrlmode = es58x_priv(netdev)->can.ctrlmode;49 50 if (ctrlmode & (CAN_CTRLMODE_FD | CAN_CTRLMODE_FD_NON_ISO))51 return ES58X_FD_CMD_TYPE_CANFD;52 else53 return ES58X_FD_CMD_TYPE_CAN;54}55 56static u16 es58x_fd_get_msg_len(const union es58x_urb_cmd *urb_cmd)57{58 return get_unaligned_le16(&urb_cmd->es58x_fd_urb_cmd.msg_len);59}60 61static int es58x_fd_echo_msg(struct net_device *netdev,62 const struct es58x_fd_urb_cmd *es58x_fd_urb_cmd)63{64 struct es58x_priv *priv = es58x_priv(netdev);65 const struct es58x_fd_echo_msg *echo_msg;66 struct es58x_device *es58x_dev = priv->es58x_dev;67 u64 *tstamps = es58x_dev->timestamps;68 u16 msg_len = get_unaligned_le16(&es58x_fd_urb_cmd->msg_len);69 int i, num_element;70 u32 rcv_packet_idx;71 72 const u32 mask = GENMASK(BITS_PER_TYPE(mask) - 1,73 BITS_PER_TYPE(echo_msg->packet_idx));74 75 num_element = es58x_msg_num_element(es58x_dev->dev,76 es58x_fd_urb_cmd->echo_msg,77 msg_len);78 if (num_element < 0)79 return num_element;80 echo_msg = es58x_fd_urb_cmd->echo_msg;81 82 rcv_packet_idx = (priv->tx_tail & mask) | echo_msg[0].packet_idx;83 for (i = 0; i < num_element; i++) {84 if ((u8)rcv_packet_idx != echo_msg[i].packet_idx) {85 netdev_err(netdev, "Packet idx jumped from %u to %u\n",86 (u8)rcv_packet_idx - 1,87 echo_msg[i].packet_idx);88 return -EBADMSG;89 }90 91 tstamps[i] = get_unaligned_le64(&echo_msg[i].timestamp);92 rcv_packet_idx++;93 }94 95 return es58x_can_get_echo_skb(netdev, priv->tx_tail, tstamps, num_element);96}97 98static int es58x_fd_rx_can_msg(struct net_device *netdev,99 const struct es58x_fd_urb_cmd *es58x_fd_urb_cmd)100{101 struct es58x_device *es58x_dev = es58x_priv(netdev)->es58x_dev;102 const u8 *rx_can_msg_buf = es58x_fd_urb_cmd->rx_can_msg_buf;103 u16 rx_can_msg_buf_len = get_unaligned_le16(&es58x_fd_urb_cmd->msg_len);104 int pkts, ret;105 106 ret = es58x_check_msg_max_len(es58x_dev->dev,107 es58x_fd_urb_cmd->rx_can_msg_buf,108 rx_can_msg_buf_len);109 if (ret)110 return ret;111 112 for (pkts = 0; rx_can_msg_buf_len > 0; pkts++) {113 const struct es58x_fd_rx_can_msg *rx_can_msg =114 (const struct es58x_fd_rx_can_msg *)rx_can_msg_buf;115 bool is_can_fd = !!(rx_can_msg->flags & ES58X_FLAG_FD_DATA);116 /* rx_can_msg_len is the length of the rx_can_msg117 * buffer. Not to be confused with rx_can_msg->len118 * which is the length of the CAN payload119 * rx_can_msg->data.120 */121 u16 rx_can_msg_len = es58x_fd_sizeof_rx_tx_msg(*rx_can_msg);122 123 if (rx_can_msg_len > rx_can_msg_buf_len) {124 netdev_err(netdev,125 "%s: Expected a rx_can_msg of size %d but only %d bytes are left in rx_can_msg_buf\n",126 __func__,127 rx_can_msg_len, rx_can_msg_buf_len);128 return -EMSGSIZE;129 }130 if (rx_can_msg->len > CANFD_MAX_DLEN) {131 netdev_err(netdev,132 "%s: Data length is %d but maximum should be %d\n",133 __func__, rx_can_msg->len, CANFD_MAX_DLEN);134 return -EMSGSIZE;135 }136 137 if (netif_running(netdev)) {138 u64 tstamp = get_unaligned_le64(&rx_can_msg->timestamp);139 canid_t can_id = get_unaligned_le32(&rx_can_msg->can_id);140 u8 dlc;141 142 if (is_can_fd)143 dlc = can_fd_len2dlc(rx_can_msg->len);144 else145 dlc = rx_can_msg->dlc;146 147 ret = es58x_rx_can_msg(netdev, tstamp, rx_can_msg->data,148 can_id, rx_can_msg->flags, dlc);149 if (ret)150 break;151 }152 153 rx_can_msg_buf_len -= rx_can_msg_len;154 rx_can_msg_buf += rx_can_msg_len;155 }156 157 if (!netif_running(netdev)) {158 if (net_ratelimit())159 netdev_info(netdev,160 "%s: %s is down, dropping %d rx packets\n",161 __func__, netdev->name, pkts);162 netdev->stats.rx_dropped += pkts;163 }164 165 return ret;166}167 168static int es58x_fd_rx_event_msg(struct net_device *netdev,169 const struct es58x_fd_urb_cmd *es58x_fd_urb_cmd)170{171 struct es58x_device *es58x_dev = es58x_priv(netdev)->es58x_dev;172 u16 msg_len = get_unaligned_le16(&es58x_fd_urb_cmd->msg_len);173 const struct es58x_fd_rx_event_msg *rx_event_msg;174 int ret;175 176 rx_event_msg = &es58x_fd_urb_cmd->rx_event_msg;177 ret = es58x_check_msg_len(es58x_dev->dev, *rx_event_msg, msg_len);178 if (ret)179 return ret;180 181 return es58x_rx_err_msg(netdev, rx_event_msg->error_code,182 rx_event_msg->event_code,183 get_unaligned_le64(&rx_event_msg->timestamp));184}185 186static int es58x_fd_rx_cmd_ret_u32(struct net_device *netdev,187 const struct es58x_fd_urb_cmd *es58x_fd_urb_cmd,188 enum es58x_ret_type cmd_ret_type)189{190 struct es58x_device *es58x_dev = es58x_priv(netdev)->es58x_dev;191 u16 msg_len = get_unaligned_le16(&es58x_fd_urb_cmd->msg_len);192 int ret;193 194 ret = es58x_check_msg_len(es58x_dev->dev,195 es58x_fd_urb_cmd->rx_cmd_ret_le32, msg_len);196 if (ret)197 return ret;198 199 return es58x_rx_cmd_ret_u32(netdev, cmd_ret_type,200 get_unaligned_le32(&es58x_fd_urb_cmd->rx_cmd_ret_le32));201}202 203static int es58x_fd_tx_ack_msg(struct net_device *netdev,204 const struct es58x_fd_urb_cmd *es58x_fd_urb_cmd)205{206 struct es58x_device *es58x_dev = es58x_priv(netdev)->es58x_dev;207 const struct es58x_fd_tx_ack_msg *tx_ack_msg;208 u16 msg_len = get_unaligned_le16(&es58x_fd_urb_cmd->msg_len);209 int ret;210 211 tx_ack_msg = &es58x_fd_urb_cmd->tx_ack_msg;212 ret = es58x_check_msg_len(es58x_dev->dev, *tx_ack_msg, msg_len);213 if (ret)214 return ret;215 216 return es58x_tx_ack_msg(netdev,217 get_unaligned_le16(&tx_ack_msg->tx_free_entries),218 get_unaligned_le32(&tx_ack_msg->rx_cmd_ret_le32));219}220 221static int es58x_fd_can_cmd_id(struct es58x_device *es58x_dev,222 const struct es58x_fd_urb_cmd *es58x_fd_urb_cmd)223{224 struct net_device *netdev;225 int ret;226 227 ret = es58x_get_netdev(es58x_dev, es58x_fd_urb_cmd->channel_idx,228 ES58X_FD_CHANNEL_IDX_OFFSET, &netdev);229 if (ret)230 return ret;231 232 switch ((enum es58x_fd_can_cmd_id)es58x_fd_urb_cmd->cmd_id) {233 case ES58X_FD_CAN_CMD_ID_ENABLE_CHANNEL:234 return es58x_fd_rx_cmd_ret_u32(netdev, es58x_fd_urb_cmd,235 ES58X_RET_TYPE_ENABLE_CHANNEL);236 237 case ES58X_FD_CAN_CMD_ID_DISABLE_CHANNEL:238 return es58x_fd_rx_cmd_ret_u32(netdev, es58x_fd_urb_cmd,239 ES58X_RET_TYPE_DISABLE_CHANNEL);240 241 case ES58X_FD_CAN_CMD_ID_TX_MSG:242 return es58x_fd_tx_ack_msg(netdev, es58x_fd_urb_cmd);243 244 case ES58X_FD_CAN_CMD_ID_ECHO_MSG:245 return es58x_fd_echo_msg(netdev, es58x_fd_urb_cmd);246 247 case ES58X_FD_CAN_CMD_ID_RX_MSG:248 return es58x_fd_rx_can_msg(netdev, es58x_fd_urb_cmd);249 250 case ES58X_FD_CAN_CMD_ID_RESET_RX:251 return es58x_fd_rx_cmd_ret_u32(netdev, es58x_fd_urb_cmd,252 ES58X_RET_TYPE_RESET_RX);253 254 case ES58X_FD_CAN_CMD_ID_RESET_TX:255 return es58x_fd_rx_cmd_ret_u32(netdev, es58x_fd_urb_cmd,256 ES58X_RET_TYPE_RESET_TX);257 258 case ES58X_FD_CAN_CMD_ID_ERROR_OR_EVENT_MSG:259 return es58x_fd_rx_event_msg(netdev, es58x_fd_urb_cmd);260 261 default:262 return -EBADRQC;263 }264}265 266static int es58x_fd_device_cmd_id(struct es58x_device *es58x_dev,267 const struct es58x_fd_urb_cmd *es58x_fd_urb_cmd)268{269 u16 msg_len = get_unaligned_le16(&es58x_fd_urb_cmd->msg_len);270 int ret;271 272 switch ((enum es58x_fd_dev_cmd_id)es58x_fd_urb_cmd->cmd_id) {273 case ES58X_FD_DEV_CMD_ID_TIMESTAMP:274 ret = es58x_check_msg_len(es58x_dev->dev,275 es58x_fd_urb_cmd->timestamp, msg_len);276 if (ret)277 return ret;278 es58x_rx_timestamp(es58x_dev,279 get_unaligned_le64(&es58x_fd_urb_cmd->timestamp));280 return 0;281 282 default:283 return -EBADRQC;284 }285}286 287static int es58x_fd_handle_urb_cmd(struct es58x_device *es58x_dev,288 const union es58x_urb_cmd *urb_cmd)289{290 const struct es58x_fd_urb_cmd *es58x_fd_urb_cmd;291 int ret;292 293 es58x_fd_urb_cmd = &urb_cmd->es58x_fd_urb_cmd;294 295 switch ((enum es58x_fd_cmd_type)es58x_fd_urb_cmd->cmd_type) {296 case ES58X_FD_CMD_TYPE_CAN:297 case ES58X_FD_CMD_TYPE_CANFD:298 ret = es58x_fd_can_cmd_id(es58x_dev, es58x_fd_urb_cmd);299 break;300 301 case ES58X_FD_CMD_TYPE_DEVICE:302 ret = es58x_fd_device_cmd_id(es58x_dev, es58x_fd_urb_cmd);303 break;304 305 default:306 ret = -EBADRQC;307 break;308 }309 310 if (ret == -EBADRQC)311 dev_err(es58x_dev->dev,312 "%s: Unknown command type (0x%02X) and command ID (0x%02X) combination\n",313 __func__, es58x_fd_urb_cmd->cmd_type,314 es58x_fd_urb_cmd->cmd_id);315 316 return ret;317}318 319static void es58x_fd_fill_urb_header(union es58x_urb_cmd *urb_cmd, u8 cmd_type,320 u8 cmd_id, u8 channel_idx, u16 msg_len)321{322 struct es58x_fd_urb_cmd *es58x_fd_urb_cmd = &urb_cmd->es58x_fd_urb_cmd;323 324 es58x_fd_urb_cmd->SOF = cpu_to_le16(es58x_fd_param.tx_start_of_frame);325 es58x_fd_urb_cmd->cmd_type = cmd_type;326 es58x_fd_urb_cmd->cmd_id = cmd_id;327 es58x_fd_urb_cmd->channel_idx = channel_idx;328 es58x_fd_urb_cmd->msg_len = cpu_to_le16(msg_len);329}330 331static int es58x_fd_tx_can_msg(struct es58x_priv *priv,332 const struct sk_buff *skb)333{334 struct es58x_device *es58x_dev = priv->es58x_dev;335 union es58x_urb_cmd *urb_cmd = priv->tx_urb->transfer_buffer;336 struct es58x_fd_urb_cmd *es58x_fd_urb_cmd = &urb_cmd->es58x_fd_urb_cmd;337 struct can_frame *cf = (struct can_frame *)skb->data;338 struct es58x_fd_tx_can_msg *tx_can_msg;339 bool is_fd = can_is_canfd_skb(skb);340 u16 msg_len;341 int ret;342 343 if (priv->tx_can_msg_cnt == 0) {344 msg_len = 0;345 es58x_fd_fill_urb_header(urb_cmd,346 is_fd ? ES58X_FD_CMD_TYPE_CANFD347 : ES58X_FD_CMD_TYPE_CAN,348 ES58X_FD_CAN_CMD_ID_TX_MSG_NO_ACK,349 priv->channel_idx, msg_len);350 } else {351 msg_len = es58x_fd_get_msg_len(urb_cmd);352 }353 354 ret = es58x_check_msg_max_len(es58x_dev->dev,355 es58x_fd_urb_cmd->tx_can_msg_buf,356 msg_len + sizeof(*tx_can_msg));357 if (ret)358 return ret;359 360 /* Fill message contents. */361 tx_can_msg = (typeof(tx_can_msg))&es58x_fd_urb_cmd->raw_msg[msg_len];362 tx_can_msg->packet_idx = (u8)priv->tx_head;363 put_unaligned_le32(es58x_get_raw_can_id(cf), &tx_can_msg->can_id);364 tx_can_msg->flags = (u8)es58x_get_flags(skb);365 if (is_fd)366 tx_can_msg->len = cf->len;367 else368 tx_can_msg->dlc = can_get_cc_dlc(cf, priv->can.ctrlmode);369 memcpy(tx_can_msg->data, cf->data, cf->len);370 371 /* Calculate new sizes */372 msg_len += es58x_fd_sizeof_rx_tx_msg(*tx_can_msg);373 priv->tx_urb->transfer_buffer_length = es58x_get_urb_cmd_len(es58x_dev,374 msg_len);375 put_unaligned_le16(msg_len, &es58x_fd_urb_cmd->msg_len);376 377 return 0;378}379 380static void es58x_fd_convert_bittiming(struct es58x_fd_bittiming *es58x_fd_bt,381 struct can_bittiming *bt)382{383 /* The actual value set in the hardware registers is one less384 * than the functional value.385 */386 const int offset = 1;387 388 es58x_fd_bt->bitrate = cpu_to_le32(bt->bitrate);389 es58x_fd_bt->tseg1 =390 cpu_to_le16(bt->prop_seg + bt->phase_seg1 - offset);391 es58x_fd_bt->tseg2 = cpu_to_le16(bt->phase_seg2 - offset);392 es58x_fd_bt->brp = cpu_to_le16(bt->brp - offset);393 es58x_fd_bt->sjw = cpu_to_le16(bt->sjw - offset);394}395 396static int es58x_fd_enable_channel(struct es58x_priv *priv)397{398 struct es58x_device *es58x_dev = priv->es58x_dev;399 struct net_device *netdev = es58x_dev->netdev[priv->channel_idx];400 struct es58x_fd_tx_conf_msg tx_conf_msg = { 0 };401 u32 ctrlmode;402 size_t conf_len = 0;403 404 es58x_fd_convert_bittiming(&tx_conf_msg.nominal_bittiming,405 &priv->can.bittiming);406 ctrlmode = priv->can.ctrlmode;407 408 if (ctrlmode & CAN_CTRLMODE_3_SAMPLES)409 tx_conf_msg.samples_per_bit = ES58X_SAMPLES_PER_BIT_THREE;410 else411 tx_conf_msg.samples_per_bit = ES58X_SAMPLES_PER_BIT_ONE;412 tx_conf_msg.sync_edge = ES58X_SYNC_EDGE_SINGLE;413 tx_conf_msg.physical_layer = ES58X_PHYSICAL_LAYER_HIGH_SPEED;414 tx_conf_msg.echo_mode = ES58X_ECHO_ON;415 if (ctrlmode & CAN_CTRLMODE_LISTENONLY)416 tx_conf_msg.ctrlmode |= ES58X_FD_CTRLMODE_PASSIVE;417 else418 tx_conf_msg.ctrlmode |= ES58X_FD_CTRLMODE_ACTIVE;419 420 if (ctrlmode & CAN_CTRLMODE_FD_NON_ISO) {421 tx_conf_msg.ctrlmode |= ES58X_FD_CTRLMODE_FD_NON_ISO;422 tx_conf_msg.canfd_enabled = 1;423 } else if (ctrlmode & CAN_CTRLMODE_FD) {424 tx_conf_msg.ctrlmode |= ES58X_FD_CTRLMODE_FD;425 tx_conf_msg.canfd_enabled = 1;426 }427 428 if (tx_conf_msg.canfd_enabled) {429 es58x_fd_convert_bittiming(&tx_conf_msg.data_bittiming,430 &priv->can.data_bittiming);431 432 if (can_tdc_is_enabled(&priv->can)) {433 tx_conf_msg.tdc_enabled = 1;434 tx_conf_msg.tdco = cpu_to_le16(priv->can.tdc.tdco);435 tx_conf_msg.tdcf = cpu_to_le16(priv->can.tdc.tdcf);436 }437 438 conf_len = ES58X_FD_CANFD_CONF_LEN;439 } else {440 conf_len = ES58X_FD_CAN_CONF_LEN;441 }442 443 return es58x_send_msg(es58x_dev, es58x_fd_cmd_type(netdev),444 ES58X_FD_CAN_CMD_ID_ENABLE_CHANNEL,445 &tx_conf_msg, conf_len, priv->channel_idx);446}447 448static int es58x_fd_disable_channel(struct es58x_priv *priv)449{450 /* The type (ES58X_FD_CMD_TYPE_CAN or ES58X_FD_CMD_TYPE_CANFD) does451 * not matter here.452 */453 return es58x_send_msg(priv->es58x_dev, ES58X_FD_CMD_TYPE_CAN,454 ES58X_FD_CAN_CMD_ID_DISABLE_CHANNEL,455 ES58X_EMPTY_MSG, 0, priv->channel_idx);456}457 458static int es58x_fd_get_timestamp(struct es58x_device *es58x_dev)459{460 return es58x_send_msg(es58x_dev, ES58X_FD_CMD_TYPE_DEVICE,461 ES58X_FD_DEV_CMD_ID_TIMESTAMP, ES58X_EMPTY_MSG,462 0, ES58X_CHANNEL_IDX_NA);463}464 465/* Nominal bittiming constants for ES582.1 and ES584.1 as specified in466 * the microcontroller datasheet: "SAM E70/S70/V70/V71 Family" section467 * 49.6.8 "MCAN Nominal Bit Timing and Prescaler Register" from468 * Microchip.469 *470 * The values from the specification are the hardware register471 * values. To convert them to the functional values, all ranges were472 * incremented by 1 (e.g. range [0..n-1] changed to [1..n]).473 */474static const struct can_bittiming_const es58x_fd_nom_bittiming_const = {475 .name = "ES582.1/ES584.1",476 .tseg1_min = 2,477 .tseg1_max = 256,478 .tseg2_min = 2,479 .tseg2_max = 128,480 .sjw_max = 128,481 .brp_min = 1,482 .brp_max = 512,483 .brp_inc = 1484};485 486/* Data bittiming constants for ES582.1 and ES584.1 as specified in487 * the microcontroller datasheet: "SAM E70/S70/V70/V71 Family" section488 * 49.6.4 "MCAN Data Bit Timing and Prescaler Register" from489 * Microchip.490 */491static const struct can_bittiming_const es58x_fd_data_bittiming_const = {492 .name = "ES582.1/ES584.1",493 .tseg1_min = 2,494 .tseg1_max = 32,495 .tseg2_min = 1,496 .tseg2_max = 16,497 .sjw_max = 8,498 .brp_min = 1,499 .brp_max = 32,500 .brp_inc = 1501};502 503/* Transmission Delay Compensation constants for ES582.1 and ES584.1504 * as specified in the microcontroller datasheet: "SAM E70/S70/V70/V71505 * Family" section 49.6.15 "MCAN Transmitter Delay Compensation506 * Register" from Microchip.507 */508static const struct can_tdc_const es58x_tdc_const = {509 .tdcv_min = 0,510 .tdcv_max = 0, /* Manual mode not supported. */511 .tdco_min = 0,512 .tdco_max = 127,513 .tdcf_min = 0,514 .tdcf_max = 127515};516 517const struct es58x_parameters es58x_fd_param = {518 .bittiming_const = &es58x_fd_nom_bittiming_const,519 .data_bittiming_const = &es58x_fd_data_bittiming_const,520 .tdc_const = &es58x_tdc_const,521 /* The devices use NXP TJA1044G transievers which guarantee522 * the timing for data rates up to 5 Mbps. Bitrates up to 8523 * Mbps work in an optimal environment but are not recommended524 * for production environment.525 */526 .bitrate_max = 8 * MEGA /* BPS */,527 .clock = {.freq = 80 * MEGA /* Hz */},528 .ctrlmode_supported = CAN_CTRLMODE_LOOPBACK | CAN_CTRLMODE_LISTENONLY |529 CAN_CTRLMODE_3_SAMPLES | CAN_CTRLMODE_FD | CAN_CTRLMODE_FD_NON_ISO |530 CAN_CTRLMODE_CC_LEN8_DLC | CAN_CTRLMODE_TDC_AUTO,531 .tx_start_of_frame = 0xCEFA, /* FACE in little endian */532 .rx_start_of_frame = 0xFECA, /* CAFE in little endian */533 .tx_urb_cmd_max_len = ES58X_FD_TX_URB_CMD_MAX_LEN,534 .rx_urb_cmd_max_len = ES58X_FD_RX_URB_CMD_MAX_LEN,535 /* Size of internal device TX queue is 500.536 *537 * However, when reaching value around 278, the device's busy538 * LED turns on and thus maximum value of 500 is never reached539 * in practice. Also, when this value is too high, some error540 * on the echo_msg were witnessed when the device is541 * recovering from bus off.542 *543 * For above reasons, a value that would prevent the device544 * from becoming busy was chosen. In practice, BQL would545 * prevent the value from even getting closer to below546 * maximum, so no impact on performance was measured.547 */548 .fifo_mask = 255, /* echo_skb_max = 256 */549 .dql_min_limit = CAN_FRAME_LEN_MAX * 15, /* Empirical value. */550 .tx_bulk_max = ES58X_FD_TX_BULK_MAX,551 .urb_cmd_header_len = ES58X_FD_URB_CMD_HEADER_LEN,552 .rx_urb_max = ES58X_RX_URBS_MAX,553 .tx_urb_max = ES58X_TX_URBS_MAX554};555 556const struct es58x_operators es58x_fd_ops = {557 .get_msg_len = es58x_fd_get_msg_len,558 .handle_urb_cmd = es58x_fd_handle_urb_cmd,559 .fill_urb_header = es58x_fd_fill_urb_header,560 .tx_can_msg = es58x_fd_tx_can_msg,561 .enable_channel = es58x_fd_enable_channel,562 .disable_channel = es58x_fd_disable_channel,563 .reset_device = NULL, /* Not implemented in the device firmware. */564 .get_timestamp = es58x_fd_get_timestamp565};566