// SPDX-License-Identifier: GPL-2.0 
 | 
/* Parts of this driver are based on the following: 
 | 
 *  - Kvaser linux mhydra driver (version 5.24) 
 | 
 *  - CAN driver for esd CAN-USB/2 
 | 
 * 
 | 
 * Copyright (C) 2018 KVASER AB, Sweden. All rights reserved. 
 | 
 * Copyright (C) 2010 Matthias Fuchs <matthias.fuchs@esd.eu>, esd gmbh 
 | 
 * 
 | 
 * Known issues: 
 | 
 *  - Transition from CAN_STATE_ERROR_WARNING to CAN_STATE_ERROR_ACTIVE is only 
 | 
 *    reported after a call to do_get_berr_counter(), since firmware does not 
 | 
 *    distinguish between ERROR_WARNING and ERROR_ACTIVE. 
 | 
 *  - Hardware timestamps are not set for CAN Tx frames. 
 | 
 */ 
 | 
  
 | 
#include <linux/completion.h> 
 | 
#include <linux/device.h> 
 | 
#include <linux/gfp.h> 
 | 
#include <linux/jiffies.h> 
 | 
#include <linux/kernel.h> 
 | 
#include <linux/netdevice.h> 
 | 
#include <linux/spinlock.h> 
 | 
#include <linux/string.h> 
 | 
#include <linux/types.h> 
 | 
#include <linux/usb.h> 
 | 
  
 | 
#include <linux/can.h> 
 | 
#include <linux/can/dev.h> 
 | 
#include <linux/can/error.h> 
 | 
#include <linux/can/netlink.h> 
 | 
  
 | 
#include "kvaser_usb.h" 
 | 
  
 | 
/* Forward declarations */ 
 | 
static const struct kvaser_usb_dev_cfg kvaser_usb_hydra_dev_cfg_kcan; 
 | 
static const struct kvaser_usb_dev_cfg kvaser_usb_hydra_dev_cfg_flexc; 
 | 
  
 | 
#define KVASER_USB_HYDRA_BULK_EP_IN_ADDR    0x82 
 | 
#define KVASER_USB_HYDRA_BULK_EP_OUT_ADDR    0x02 
 | 
  
 | 
#define KVASER_USB_HYDRA_MAX_TRANSID        0xff 
 | 
#define KVASER_USB_HYDRA_MIN_TRANSID        0x01 
 | 
  
 | 
/* Minihydra command IDs */ 
 | 
#define CMD_SET_BUSPARAMS_REQ            16 
 | 
#define CMD_GET_CHIP_STATE_REQ            19 
 | 
#define CMD_CHIP_STATE_EVENT            20 
 | 
#define CMD_SET_DRIVERMODE_REQ            21 
 | 
#define CMD_START_CHIP_REQ            26 
 | 
#define CMD_START_CHIP_RESP            27 
 | 
#define CMD_STOP_CHIP_REQ            28 
 | 
#define CMD_STOP_CHIP_RESP            29 
 | 
#define CMD_TX_CAN_MESSAGE            33 
 | 
#define CMD_GET_CARD_INFO_REQ            34 
 | 
#define CMD_GET_CARD_INFO_RESP            35 
 | 
#define CMD_GET_SOFTWARE_INFO_REQ        38 
 | 
#define CMD_GET_SOFTWARE_INFO_RESP        39 
 | 
#define CMD_ERROR_EVENT                45 
 | 
#define CMD_FLUSH_QUEUE                48 
 | 
#define CMD_TX_ACKNOWLEDGE            50 
 | 
#define CMD_FLUSH_QUEUE_RESP            66 
 | 
#define CMD_SET_BUSPARAMS_FD_REQ        69 
 | 
#define CMD_SET_BUSPARAMS_FD_RESP        70 
 | 
#define CMD_SET_BUSPARAMS_RESP            85 
 | 
#define CMD_GET_CAPABILITIES_REQ        95 
 | 
#define CMD_GET_CAPABILITIES_RESP        96 
 | 
#define CMD_RX_MESSAGE                106 
 | 
#define CMD_MAP_CHANNEL_REQ            200 
 | 
#define CMD_MAP_CHANNEL_RESP            201 
 | 
#define CMD_GET_SOFTWARE_DETAILS_REQ        202 
 | 
#define CMD_GET_SOFTWARE_DETAILS_RESP        203 
 | 
#define CMD_EXTENDED                255 
 | 
  
 | 
/* Minihydra extended command IDs */ 
 | 
#define CMD_TX_CAN_MESSAGE_FD            224 
 | 
#define CMD_TX_ACKNOWLEDGE_FD            225 
 | 
#define CMD_RX_MESSAGE_FD            226 
 | 
  
 | 
/* Hydra commands are handled by different threads in firmware. 
 | 
 * The threads are denoted hydra entity (HE). Each HE got a unique 6-bit 
 | 
 * address. The address is used in hydra commands to get/set source and 
 | 
 * destination HE. There are two predefined HE addresses, the remaining 
 | 
 * addresses are different between devices and firmware versions. Hence, we need 
 | 
 * to enumerate the addresses (see kvaser_usb_hydra_map_channel()). 
 | 
 */ 
 | 
  
 | 
/* Well-known HE addresses */ 
 | 
#define KVASER_USB_HYDRA_HE_ADDRESS_ROUTER    0x00 
 | 
#define KVASER_USB_HYDRA_HE_ADDRESS_ILLEGAL    0x3e 
 | 
  
 | 
#define KVASER_USB_HYDRA_TRANSID_CANHE        0x40 
 | 
#define KVASER_USB_HYDRA_TRANSID_SYSDBG        0x61 
 | 
  
 | 
struct kvaser_cmd_map_ch_req { 
 | 
    char name[16]; 
 | 
    u8 channel; 
 | 
    u8 reserved[11]; 
 | 
} __packed; 
 | 
  
 | 
struct kvaser_cmd_map_ch_res { 
 | 
    u8 he_addr; 
 | 
    u8 channel; 
 | 
    u8 reserved[26]; 
 | 
} __packed; 
 | 
  
 | 
struct kvaser_cmd_card_info { 
 | 
    __le32 serial_number; 
 | 
    __le32 clock_res; 
 | 
    __le32 mfg_date; 
 | 
    __le32 ean[2]; 
 | 
    u8 hw_version; 
 | 
    u8 usb_mode; 
 | 
    u8 hw_type; 
 | 
    u8 reserved0; 
 | 
    u8 nchannels; 
 | 
    u8 reserved1[3]; 
 | 
} __packed; 
 | 
  
 | 
struct kvaser_cmd_sw_info { 
 | 
    u8 reserved0[8]; 
 | 
    __le16 max_outstanding_tx; 
 | 
    u8 reserved1[18]; 
 | 
} __packed; 
 | 
  
 | 
struct kvaser_cmd_sw_detail_req { 
 | 
    u8 use_ext_cmd; 
 | 
    u8 reserved[27]; 
 | 
} __packed; 
 | 
  
 | 
/* Software detail flags */ 
 | 
#define KVASER_USB_HYDRA_SW_FLAG_FW_BETA    BIT(2) 
 | 
#define KVASER_USB_HYDRA_SW_FLAG_FW_BAD        BIT(4) 
 | 
#define KVASER_USB_HYDRA_SW_FLAG_FREQ_80M    BIT(5) 
 | 
#define KVASER_USB_HYDRA_SW_FLAG_EXT_CMD    BIT(9) 
 | 
#define KVASER_USB_HYDRA_SW_FLAG_CANFD        BIT(10) 
 | 
#define KVASER_USB_HYDRA_SW_FLAG_NONISO        BIT(11) 
 | 
#define KVASER_USB_HYDRA_SW_FLAG_EXT_CAP    BIT(12) 
 | 
struct kvaser_cmd_sw_detail_res { 
 | 
    __le32 sw_flags; 
 | 
    __le32 sw_version; 
 | 
    __le32 sw_name; 
 | 
    __le32 ean[2]; 
 | 
    __le32 max_bitrate; 
 | 
    u8 reserved[4]; 
 | 
} __packed; 
 | 
  
 | 
/* Sub commands for cap_req and cap_res */ 
 | 
#define KVASER_USB_HYDRA_CAP_CMD_LISTEN_MODE    0x02 
 | 
#define KVASER_USB_HYDRA_CAP_CMD_ERR_REPORT    0x05 
 | 
#define KVASER_USB_HYDRA_CAP_CMD_ONE_SHOT    0x06 
 | 
struct kvaser_cmd_cap_req { 
 | 
    __le16 cap_cmd; 
 | 
    u8 reserved[26]; 
 | 
} __packed; 
 | 
  
 | 
/* Status codes for cap_res */ 
 | 
#define KVASER_USB_HYDRA_CAP_STAT_OK        0x00 
 | 
#define KVASER_USB_HYDRA_CAP_STAT_NOT_IMPL    0x01 
 | 
#define KVASER_USB_HYDRA_CAP_STAT_UNAVAIL    0x02 
 | 
struct kvaser_cmd_cap_res { 
 | 
    __le16 cap_cmd; 
 | 
    __le16 status; 
 | 
    __le32 mask; 
 | 
    __le32 value; 
 | 
    u8 reserved[16]; 
 | 
} __packed; 
 | 
  
 | 
/* CMD_ERROR_EVENT error codes */ 
 | 
#define KVASER_USB_HYDRA_ERROR_EVENT_CAN    0x01 
 | 
#define KVASER_USB_HYDRA_ERROR_EVENT_PARAM    0x09 
 | 
struct kvaser_cmd_error_event { 
 | 
    __le16 timestamp[3]; 
 | 
    u8 reserved; 
 | 
    u8 error_code; 
 | 
    __le16 info1; 
 | 
    __le16 info2; 
 | 
} __packed; 
 | 
  
 | 
/* Chip state status flags. Used for chip_state_event and err_frame_data. */ 
 | 
#define KVASER_USB_HYDRA_BUS_ERR_ACT        0x00 
 | 
#define KVASER_USB_HYDRA_BUS_ERR_PASS        BIT(5) 
 | 
#define KVASER_USB_HYDRA_BUS_BUS_OFF        BIT(6) 
 | 
struct kvaser_cmd_chip_state_event { 
 | 
    __le16 timestamp[3]; 
 | 
    u8 tx_err_counter; 
 | 
    u8 rx_err_counter; 
 | 
    u8 bus_status; 
 | 
    u8 reserved[19]; 
 | 
} __packed; 
 | 
  
 | 
/* Busparam modes */ 
 | 
#define KVASER_USB_HYDRA_BUS_MODE_CAN        0x00 
 | 
#define KVASER_USB_HYDRA_BUS_MODE_CANFD_ISO    0x01 
 | 
#define KVASER_USB_HYDRA_BUS_MODE_NONISO    0x02 
 | 
struct kvaser_cmd_set_busparams { 
 | 
    __le32 bitrate; 
 | 
    u8 tseg1; 
 | 
    u8 tseg2; 
 | 
    u8 sjw; 
 | 
    u8 nsamples; 
 | 
    u8 reserved0[4]; 
 | 
    __le32 bitrate_d; 
 | 
    u8 tseg1_d; 
 | 
    u8 tseg2_d; 
 | 
    u8 sjw_d; 
 | 
    u8 nsamples_d; 
 | 
    u8 canfd_mode; 
 | 
    u8 reserved1[7]; 
 | 
} __packed; 
 | 
  
 | 
/* Ctrl modes */ 
 | 
#define KVASER_USB_HYDRA_CTRLMODE_NORMAL    0x01 
 | 
#define KVASER_USB_HYDRA_CTRLMODE_LISTEN    0x02 
 | 
struct kvaser_cmd_set_ctrlmode { 
 | 
    u8 mode; 
 | 
    u8 reserved[27]; 
 | 
} __packed; 
 | 
  
 | 
struct kvaser_err_frame_data { 
 | 
    u8 bus_status; 
 | 
    u8 reserved0; 
 | 
    u8 tx_err_counter; 
 | 
    u8 rx_err_counter; 
 | 
    u8 reserved1[4]; 
 | 
} __packed; 
 | 
  
 | 
struct kvaser_cmd_rx_can { 
 | 
    u8 cmd_len; 
 | 
    u8 cmd_no; 
 | 
    u8 channel; 
 | 
    u8 flags; 
 | 
    __le16 timestamp[3]; 
 | 
    u8 dlc; 
 | 
    u8 padding; 
 | 
    __le32 id; 
 | 
    union { 
 | 
        u8 data[8]; 
 | 
        struct kvaser_err_frame_data err_frame_data; 
 | 
    }; 
 | 
} __packed; 
 | 
  
 | 
/* Extended CAN ID flag. Used in rx_can and tx_can */ 
 | 
#define KVASER_USB_HYDRA_EXTENDED_FRAME_ID    BIT(31) 
 | 
struct kvaser_cmd_tx_can { 
 | 
    __le32 id; 
 | 
    u8 data[8]; 
 | 
    u8 dlc; 
 | 
    u8 flags; 
 | 
    __le16 transid; 
 | 
    u8 channel; 
 | 
    u8 reserved[11]; 
 | 
} __packed; 
 | 
  
 | 
struct kvaser_cmd_header { 
 | 
    u8 cmd_no; 
 | 
    /* The destination HE address is stored in 0..5 of he_addr. 
 | 
     * The upper part of source HE address is stored in 6..7 of he_addr, and 
 | 
     * the lower part is stored in 12..15 of transid. 
 | 
     */ 
 | 
    u8 he_addr; 
 | 
    __le16 transid; 
 | 
} __packed; 
 | 
  
 | 
struct kvaser_cmd { 
 | 
    struct kvaser_cmd_header header; 
 | 
    union { 
 | 
        struct kvaser_cmd_map_ch_req map_ch_req; 
 | 
        struct kvaser_cmd_map_ch_res map_ch_res; 
 | 
  
 | 
        struct kvaser_cmd_card_info card_info; 
 | 
        struct kvaser_cmd_sw_info sw_info; 
 | 
        struct kvaser_cmd_sw_detail_req sw_detail_req; 
 | 
        struct kvaser_cmd_sw_detail_res sw_detail_res; 
 | 
  
 | 
        struct kvaser_cmd_cap_req cap_req; 
 | 
        struct kvaser_cmd_cap_res cap_res; 
 | 
  
 | 
        struct kvaser_cmd_error_event error_event; 
 | 
  
 | 
        struct kvaser_cmd_set_busparams set_busparams_req; 
 | 
  
 | 
        struct kvaser_cmd_chip_state_event chip_state_event; 
 | 
  
 | 
        struct kvaser_cmd_set_ctrlmode set_ctrlmode; 
 | 
  
 | 
        struct kvaser_cmd_rx_can rx_can; 
 | 
        struct kvaser_cmd_tx_can tx_can; 
 | 
    } __packed; 
 | 
} __packed; 
 | 
  
 | 
/* CAN frame flags. Used in rx_can, ext_rx_can, tx_can and ext_tx_can */ 
 | 
#define KVASER_USB_HYDRA_CF_FLAG_ERROR_FRAME    BIT(0) 
 | 
#define KVASER_USB_HYDRA_CF_FLAG_OVERRUN    BIT(1) 
 | 
#define KVASER_USB_HYDRA_CF_FLAG_REMOTE_FRAME    BIT(4) 
 | 
#define KVASER_USB_HYDRA_CF_FLAG_EXTENDED_ID    BIT(5) 
 | 
/* CAN frame flags. Used in ext_rx_can and ext_tx_can */ 
 | 
#define KVASER_USB_HYDRA_CF_FLAG_OSM_NACK    BIT(12) 
 | 
#define KVASER_USB_HYDRA_CF_FLAG_ABL        BIT(13) 
 | 
#define KVASER_USB_HYDRA_CF_FLAG_FDF        BIT(16) 
 | 
#define KVASER_USB_HYDRA_CF_FLAG_BRS        BIT(17) 
 | 
#define KVASER_USB_HYDRA_CF_FLAG_ESI        BIT(18) 
 | 
  
 | 
/* KCAN packet header macros. Used in ext_rx_can and ext_tx_can */ 
 | 
#define KVASER_USB_KCAN_DATA_DLC_BITS        4 
 | 
#define KVASER_USB_KCAN_DATA_DLC_SHIFT        8 
 | 
#define KVASER_USB_KCAN_DATA_DLC_MASK \ 
 | 
                GENMASK(KVASER_USB_KCAN_DATA_DLC_BITS - 1 + \ 
 | 
                KVASER_USB_KCAN_DATA_DLC_SHIFT, \ 
 | 
                KVASER_USB_KCAN_DATA_DLC_SHIFT) 
 | 
  
 | 
#define KVASER_USB_KCAN_DATA_BRS        BIT(14) 
 | 
#define KVASER_USB_KCAN_DATA_FDF        BIT(15) 
 | 
#define KVASER_USB_KCAN_DATA_OSM        BIT(16) 
 | 
#define KVASER_USB_KCAN_DATA_AREQ        BIT(31) 
 | 
#define KVASER_USB_KCAN_DATA_SRR        BIT(31) 
 | 
#define KVASER_USB_KCAN_DATA_RTR        BIT(29) 
 | 
#define KVASER_USB_KCAN_DATA_IDE        BIT(30) 
 | 
struct kvaser_cmd_ext_rx_can { 
 | 
    __le32 flags; 
 | 
    __le32 id; 
 | 
    __le32 kcan_id; 
 | 
    __le32 kcan_header; 
 | 
    __le64 timestamp; 
 | 
    union { 
 | 
        u8 kcan_payload[64]; 
 | 
        struct kvaser_err_frame_data err_frame_data; 
 | 
    }; 
 | 
} __packed; 
 | 
  
 | 
struct kvaser_cmd_ext_tx_can { 
 | 
    __le32 flags; 
 | 
    __le32 id; 
 | 
    __le32 kcan_id; 
 | 
    __le32 kcan_header; 
 | 
    u8 databytes; 
 | 
    u8 dlc; 
 | 
    u8 reserved[6]; 
 | 
    u8 kcan_payload[64]; 
 | 
} __packed; 
 | 
  
 | 
struct kvaser_cmd_ext_tx_ack { 
 | 
    __le32 flags; 
 | 
    u8 reserved0[4]; 
 | 
    __le64 timestamp; 
 | 
    u8 reserved1[8]; 
 | 
} __packed; 
 | 
  
 | 
/* struct for extended commands (CMD_EXTENDED) */ 
 | 
struct kvaser_cmd_ext { 
 | 
    struct kvaser_cmd_header header; 
 | 
    __le16 len; 
 | 
    u8 cmd_no_ext; 
 | 
    u8 reserved; 
 | 
  
 | 
    union { 
 | 
        struct kvaser_cmd_ext_rx_can rx_can; 
 | 
        struct kvaser_cmd_ext_tx_can tx_can; 
 | 
        struct kvaser_cmd_ext_tx_ack tx_ack; 
 | 
    } __packed; 
 | 
} __packed; 
 | 
  
 | 
static const struct can_bittiming_const kvaser_usb_hydra_kcan_bittiming_c = { 
 | 
    .name = "kvaser_usb_kcan", 
 | 
    .tseg1_min = 1, 
 | 
    .tseg1_max = 255, 
 | 
    .tseg2_min = 1, 
 | 
    .tseg2_max = 32, 
 | 
    .sjw_max = 16, 
 | 
    .brp_min = 1, 
 | 
    .brp_max = 8192, 
 | 
    .brp_inc = 1, 
 | 
}; 
 | 
  
 | 
const struct can_bittiming_const kvaser_usb_flexc_bittiming_const = { 
 | 
    .name = "kvaser_usb_flex", 
 | 
    .tseg1_min = 4, 
 | 
    .tseg1_max = 16, 
 | 
    .tseg2_min = 2, 
 | 
    .tseg2_max = 8, 
 | 
    .sjw_max = 4, 
 | 
    .brp_min = 1, 
 | 
    .brp_max = 256, 
 | 
    .brp_inc = 1, 
 | 
}; 
 | 
  
 | 
#define KVASER_USB_HYDRA_TRANSID_BITS        12 
 | 
#define KVASER_USB_HYDRA_TRANSID_MASK \ 
 | 
                GENMASK(KVASER_USB_HYDRA_TRANSID_BITS - 1, 0) 
 | 
#define KVASER_USB_HYDRA_HE_ADDR_SRC_MASK    GENMASK(7, 6) 
 | 
#define KVASER_USB_HYDRA_HE_ADDR_DEST_MASK    GENMASK(5, 0) 
 | 
#define KVASER_USB_HYDRA_HE_ADDR_SRC_BITS    2 
 | 
static inline u16 kvaser_usb_hydra_get_cmd_transid(const struct kvaser_cmd *cmd) 
 | 
{ 
 | 
    return le16_to_cpu(cmd->header.transid) & KVASER_USB_HYDRA_TRANSID_MASK; 
 | 
} 
 | 
  
 | 
static inline void kvaser_usb_hydra_set_cmd_transid(struct kvaser_cmd *cmd, 
 | 
                            u16 transid) 
 | 
{ 
 | 
    cmd->header.transid = 
 | 
            cpu_to_le16(transid & KVASER_USB_HYDRA_TRANSID_MASK); 
 | 
} 
 | 
  
 | 
static inline u8 kvaser_usb_hydra_get_cmd_src_he(const struct kvaser_cmd *cmd) 
 | 
{ 
 | 
    return (cmd->header.he_addr & KVASER_USB_HYDRA_HE_ADDR_SRC_MASK) >> 
 | 
        KVASER_USB_HYDRA_HE_ADDR_SRC_BITS | 
 | 
        le16_to_cpu(cmd->header.transid) >> 
 | 
        KVASER_USB_HYDRA_TRANSID_BITS; 
 | 
} 
 | 
  
 | 
static inline void kvaser_usb_hydra_set_cmd_dest_he(struct kvaser_cmd *cmd, 
 | 
                            u8 dest_he) 
 | 
{ 
 | 
    cmd->header.he_addr = 
 | 
        (cmd->header.he_addr & KVASER_USB_HYDRA_HE_ADDR_SRC_MASK) | 
 | 
        (dest_he & KVASER_USB_HYDRA_HE_ADDR_DEST_MASK); 
 | 
} 
 | 
  
 | 
static u8 kvaser_usb_hydra_channel_from_cmd(const struct kvaser_usb *dev, 
 | 
                        const struct kvaser_cmd *cmd) 
 | 
{ 
 | 
    int i; 
 | 
    u8 channel = 0xff; 
 | 
    u8 src_he = kvaser_usb_hydra_get_cmd_src_he(cmd); 
 | 
  
 | 
    for (i = 0; i < KVASER_USB_MAX_NET_DEVICES; i++) { 
 | 
        if (dev->card_data.hydra.channel_to_he[i] == src_he) { 
 | 
            channel = i; 
 | 
            break; 
 | 
        } 
 | 
    } 
 | 
  
 | 
    return channel; 
 | 
} 
 | 
  
 | 
static u16 kvaser_usb_hydra_get_next_transid(struct kvaser_usb *dev) 
 | 
{ 
 | 
    unsigned long flags; 
 | 
    u16 transid; 
 | 
    struct kvaser_usb_dev_card_data_hydra *card_data = 
 | 
                            &dev->card_data.hydra; 
 | 
  
 | 
    spin_lock_irqsave(&card_data->transid_lock, flags); 
 | 
    transid = card_data->transid; 
 | 
    if (transid >= KVASER_USB_HYDRA_MAX_TRANSID) 
 | 
        transid = KVASER_USB_HYDRA_MIN_TRANSID; 
 | 
    else 
 | 
        transid++; 
 | 
    card_data->transid = transid; 
 | 
    spin_unlock_irqrestore(&card_data->transid_lock, flags); 
 | 
  
 | 
    return transid; 
 | 
} 
 | 
  
 | 
static size_t kvaser_usb_hydra_cmd_size(struct kvaser_cmd *cmd) 
 | 
{ 
 | 
    size_t ret; 
 | 
  
 | 
    if (cmd->header.cmd_no == CMD_EXTENDED) 
 | 
        ret = le16_to_cpu(((struct kvaser_cmd_ext *)cmd)->len); 
 | 
    else 
 | 
        ret = sizeof(struct kvaser_cmd); 
 | 
  
 | 
    return ret; 
 | 
} 
 | 
  
 | 
static struct kvaser_usb_net_priv * 
 | 
kvaser_usb_hydra_net_priv_from_cmd(const struct kvaser_usb *dev, 
 | 
                   const struct kvaser_cmd *cmd) 
 | 
{ 
 | 
    struct kvaser_usb_net_priv *priv = NULL; 
 | 
    u8 channel = kvaser_usb_hydra_channel_from_cmd(dev, cmd); 
 | 
  
 | 
    if (channel >= dev->nchannels) 
 | 
        dev_err(&dev->intf->dev, 
 | 
            "Invalid channel number (%d)\n", channel); 
 | 
    else 
 | 
        priv = dev->nets[channel]; 
 | 
  
 | 
    return priv; 
 | 
} 
 | 
  
 | 
static ktime_t 
 | 
kvaser_usb_hydra_ktime_from_rx_cmd(const struct kvaser_usb_dev_cfg *cfg, 
 | 
                   const struct kvaser_cmd *cmd) 
 | 
{ 
 | 
    u64 ticks; 
 | 
  
 | 
    if (cmd->header.cmd_no == CMD_EXTENDED) { 
 | 
        struct kvaser_cmd_ext *cmd_ext = (struct kvaser_cmd_ext *)cmd; 
 | 
  
 | 
        ticks = le64_to_cpu(cmd_ext->rx_can.timestamp); 
 | 
    } else { 
 | 
        ticks = le16_to_cpu(cmd->rx_can.timestamp[0]); 
 | 
        ticks += (u64)(le16_to_cpu(cmd->rx_can.timestamp[1])) << 16; 
 | 
        ticks += (u64)(le16_to_cpu(cmd->rx_can.timestamp[2])) << 32; 
 | 
    } 
 | 
  
 | 
    return ns_to_ktime(div_u64(ticks * 1000, cfg->timestamp_freq)); 
 | 
} 
 | 
  
 | 
static int kvaser_usb_hydra_send_simple_cmd(struct kvaser_usb *dev, 
 | 
                        u8 cmd_no, int channel) 
 | 
{ 
 | 
    struct kvaser_cmd *cmd; 
 | 
    int err; 
 | 
  
 | 
    cmd = kcalloc(1, sizeof(struct kvaser_cmd), GFP_KERNEL); 
 | 
    if (!cmd) 
 | 
        return -ENOMEM; 
 | 
  
 | 
    cmd->header.cmd_no = cmd_no; 
 | 
    if (channel < 0) { 
 | 
        kvaser_usb_hydra_set_cmd_dest_he 
 | 
                (cmd, KVASER_USB_HYDRA_HE_ADDRESS_ILLEGAL); 
 | 
    } else { 
 | 
        if (channel >= KVASER_USB_MAX_NET_DEVICES) { 
 | 
            dev_err(&dev->intf->dev, "channel (%d) out of range.\n", 
 | 
                channel); 
 | 
            err = -EINVAL; 
 | 
            goto end; 
 | 
        } 
 | 
        kvaser_usb_hydra_set_cmd_dest_he 
 | 
            (cmd, dev->card_data.hydra.channel_to_he[channel]); 
 | 
    } 
 | 
    kvaser_usb_hydra_set_cmd_transid 
 | 
                (cmd, kvaser_usb_hydra_get_next_transid(dev)); 
 | 
  
 | 
    err = kvaser_usb_send_cmd(dev, cmd, kvaser_usb_hydra_cmd_size(cmd)); 
 | 
    if (err) 
 | 
        goto end; 
 | 
  
 | 
end: 
 | 
    kfree(cmd); 
 | 
  
 | 
    return err; 
 | 
} 
 | 
  
 | 
static int 
 | 
kvaser_usb_hydra_send_simple_cmd_async(struct kvaser_usb_net_priv *priv, 
 | 
                       u8 cmd_no) 
 | 
{ 
 | 
    struct kvaser_cmd *cmd; 
 | 
    struct kvaser_usb *dev = priv->dev; 
 | 
    int err; 
 | 
  
 | 
    cmd = kcalloc(1, sizeof(struct kvaser_cmd), GFP_ATOMIC); 
 | 
    if (!cmd) 
 | 
        return -ENOMEM; 
 | 
  
 | 
    cmd->header.cmd_no = cmd_no; 
 | 
  
 | 
    kvaser_usb_hydra_set_cmd_dest_he 
 | 
        (cmd, dev->card_data.hydra.channel_to_he[priv->channel]); 
 | 
    kvaser_usb_hydra_set_cmd_transid 
 | 
                (cmd, kvaser_usb_hydra_get_next_transid(dev)); 
 | 
  
 | 
    err = kvaser_usb_send_cmd_async(priv, cmd, 
 | 
                    kvaser_usb_hydra_cmd_size(cmd)); 
 | 
    if (err) 
 | 
        kfree(cmd); 
 | 
  
 | 
    return err; 
 | 
} 
 | 
  
 | 
/* This function is used for synchronously waiting on hydra control commands. 
 | 
 * Note: Compared to kvaser_usb_hydra_read_bulk_callback(), we never need to 
 | 
 *       handle partial hydra commands. Since hydra control commands are always 
 | 
 *       non-extended commands. 
 | 
 */ 
 | 
static int kvaser_usb_hydra_wait_cmd(const struct kvaser_usb *dev, u8 cmd_no, 
 | 
                     struct kvaser_cmd *cmd) 
 | 
{ 
 | 
    void *buf; 
 | 
    int err; 
 | 
    unsigned long timeout = jiffies + msecs_to_jiffies(KVASER_USB_TIMEOUT); 
 | 
  
 | 
    if (cmd->header.cmd_no == CMD_EXTENDED) { 
 | 
        dev_err(&dev->intf->dev, "Wait for CMD_EXTENDED not allowed\n"); 
 | 
        return -EINVAL; 
 | 
    } 
 | 
  
 | 
    buf = kzalloc(KVASER_USB_RX_BUFFER_SIZE, GFP_KERNEL); 
 | 
    if (!buf) 
 | 
        return -ENOMEM; 
 | 
  
 | 
    do { 
 | 
        int actual_len = 0; 
 | 
        int pos = 0; 
 | 
  
 | 
        err = kvaser_usb_recv_cmd(dev, buf, KVASER_USB_RX_BUFFER_SIZE, 
 | 
                      &actual_len); 
 | 
        if (err < 0) 
 | 
            goto end; 
 | 
  
 | 
        while (pos < actual_len) { 
 | 
            struct kvaser_cmd *tmp_cmd; 
 | 
            size_t cmd_len; 
 | 
  
 | 
            tmp_cmd = buf + pos; 
 | 
            cmd_len = kvaser_usb_hydra_cmd_size(tmp_cmd); 
 | 
            if (pos + cmd_len > actual_len) { 
 | 
                dev_err_ratelimited(&dev->intf->dev, 
 | 
                            "Format error\n"); 
 | 
                break; 
 | 
            } 
 | 
  
 | 
            if (tmp_cmd->header.cmd_no == cmd_no) { 
 | 
                memcpy(cmd, tmp_cmd, cmd_len); 
 | 
                goto end; 
 | 
            } 
 | 
            pos += cmd_len; 
 | 
        } 
 | 
    } while (time_before(jiffies, timeout)); 
 | 
  
 | 
    err = -EINVAL; 
 | 
  
 | 
end: 
 | 
    kfree(buf); 
 | 
  
 | 
    return err; 
 | 
} 
 | 
  
 | 
static int kvaser_usb_hydra_map_channel_resp(struct kvaser_usb *dev, 
 | 
                         const struct kvaser_cmd *cmd) 
 | 
{ 
 | 
    u8 he, channel; 
 | 
    u16 transid = kvaser_usb_hydra_get_cmd_transid(cmd); 
 | 
    struct kvaser_usb_dev_card_data_hydra *card_data = 
 | 
                            &dev->card_data.hydra; 
 | 
  
 | 
    if (transid > 0x007f || transid < 0x0040) { 
 | 
        dev_err(&dev->intf->dev, 
 | 
            "CMD_MAP_CHANNEL_RESP, invalid transid: 0x%x\n", 
 | 
            transid); 
 | 
        return -EINVAL; 
 | 
    } 
 | 
  
 | 
    switch (transid) { 
 | 
    case KVASER_USB_HYDRA_TRANSID_CANHE: 
 | 
    case KVASER_USB_HYDRA_TRANSID_CANHE + 1: 
 | 
    case KVASER_USB_HYDRA_TRANSID_CANHE + 2: 
 | 
    case KVASER_USB_HYDRA_TRANSID_CANHE + 3: 
 | 
    case KVASER_USB_HYDRA_TRANSID_CANHE + 4: 
 | 
        channel = transid & 0x000f; 
 | 
        he = cmd->map_ch_res.he_addr; 
 | 
        card_data->channel_to_he[channel] = he; 
 | 
        break; 
 | 
    case KVASER_USB_HYDRA_TRANSID_SYSDBG: 
 | 
        card_data->sysdbg_he = cmd->map_ch_res.he_addr; 
 | 
        break; 
 | 
    default: 
 | 
        dev_warn(&dev->intf->dev, 
 | 
             "Unknown CMD_MAP_CHANNEL_RESP transid=0x%x\n", 
 | 
             transid); 
 | 
        break; 
 | 
    } 
 | 
  
 | 
    return 0; 
 | 
} 
 | 
  
 | 
static int kvaser_usb_hydra_map_channel(struct kvaser_usb *dev, u16 transid, 
 | 
                    u8 channel, const char *name) 
 | 
{ 
 | 
    struct kvaser_cmd *cmd; 
 | 
    int err; 
 | 
  
 | 
    cmd = kcalloc(1, sizeof(struct kvaser_cmd), GFP_KERNEL); 
 | 
    if (!cmd) 
 | 
        return -ENOMEM; 
 | 
  
 | 
    strcpy(cmd->map_ch_req.name, name); 
 | 
    cmd->header.cmd_no = CMD_MAP_CHANNEL_REQ; 
 | 
    kvaser_usb_hydra_set_cmd_dest_he 
 | 
                (cmd, KVASER_USB_HYDRA_HE_ADDRESS_ROUTER); 
 | 
    cmd->map_ch_req.channel = channel; 
 | 
  
 | 
    kvaser_usb_hydra_set_cmd_transid(cmd, transid); 
 | 
  
 | 
    err = kvaser_usb_send_cmd(dev, cmd, kvaser_usb_hydra_cmd_size(cmd)); 
 | 
    if (err) 
 | 
        goto end; 
 | 
  
 | 
    err = kvaser_usb_hydra_wait_cmd(dev, CMD_MAP_CHANNEL_RESP, cmd); 
 | 
    if (err) 
 | 
        goto end; 
 | 
  
 | 
    err = kvaser_usb_hydra_map_channel_resp(dev, cmd); 
 | 
    if (err) 
 | 
        goto end; 
 | 
  
 | 
end: 
 | 
    kfree(cmd); 
 | 
  
 | 
    return err; 
 | 
} 
 | 
  
 | 
static int kvaser_usb_hydra_get_single_capability(struct kvaser_usb *dev, 
 | 
                          u16 cap_cmd_req, u16 *status) 
 | 
{ 
 | 
    struct kvaser_usb_dev_card_data *card_data = &dev->card_data; 
 | 
    struct kvaser_cmd *cmd; 
 | 
    u32 value = 0; 
 | 
    u32 mask = 0; 
 | 
    u16 cap_cmd_res; 
 | 
    int err; 
 | 
    int i; 
 | 
  
 | 
    cmd = kcalloc(1, sizeof(struct kvaser_cmd), GFP_KERNEL); 
 | 
    if (!cmd) 
 | 
        return -ENOMEM; 
 | 
  
 | 
    cmd->header.cmd_no = CMD_GET_CAPABILITIES_REQ; 
 | 
    cmd->cap_req.cap_cmd = cpu_to_le16(cap_cmd_req); 
 | 
  
 | 
    kvaser_usb_hydra_set_cmd_dest_he(cmd, card_data->hydra.sysdbg_he); 
 | 
    kvaser_usb_hydra_set_cmd_transid 
 | 
                (cmd, kvaser_usb_hydra_get_next_transid(dev)); 
 | 
  
 | 
    err = kvaser_usb_send_cmd(dev, cmd, kvaser_usb_hydra_cmd_size(cmd)); 
 | 
    if (err) 
 | 
        goto end; 
 | 
  
 | 
    err = kvaser_usb_hydra_wait_cmd(dev, CMD_GET_CAPABILITIES_RESP, cmd); 
 | 
    if (err) 
 | 
        goto end; 
 | 
  
 | 
    *status = le16_to_cpu(cmd->cap_res.status); 
 | 
  
 | 
    if (*status != KVASER_USB_HYDRA_CAP_STAT_OK) 
 | 
        goto end; 
 | 
  
 | 
    cap_cmd_res = le16_to_cpu(cmd->cap_res.cap_cmd); 
 | 
    switch (cap_cmd_res) { 
 | 
    case KVASER_USB_HYDRA_CAP_CMD_LISTEN_MODE: 
 | 
    case KVASER_USB_HYDRA_CAP_CMD_ERR_REPORT: 
 | 
    case KVASER_USB_HYDRA_CAP_CMD_ONE_SHOT: 
 | 
        value = le32_to_cpu(cmd->cap_res.value); 
 | 
        mask = le32_to_cpu(cmd->cap_res.mask); 
 | 
        break; 
 | 
    default: 
 | 
        dev_warn(&dev->intf->dev, "Unknown capability command %u\n", 
 | 
             cap_cmd_res); 
 | 
        break; 
 | 
    } 
 | 
  
 | 
    for (i = 0; i < dev->nchannels; i++) { 
 | 
        if (BIT(i) & (value & mask)) { 
 | 
            switch (cap_cmd_res) { 
 | 
            case KVASER_USB_HYDRA_CAP_CMD_LISTEN_MODE: 
 | 
                card_data->ctrlmode_supported |= 
 | 
                        CAN_CTRLMODE_LISTENONLY; 
 | 
                break; 
 | 
            case KVASER_USB_HYDRA_CAP_CMD_ERR_REPORT: 
 | 
                card_data->capabilities |= 
 | 
                        KVASER_USB_CAP_BERR_CAP; 
 | 
                break; 
 | 
            case KVASER_USB_HYDRA_CAP_CMD_ONE_SHOT: 
 | 
                card_data->ctrlmode_supported |= 
 | 
                        CAN_CTRLMODE_ONE_SHOT; 
 | 
                break; 
 | 
            } 
 | 
        } 
 | 
    } 
 | 
  
 | 
end: 
 | 
    kfree(cmd); 
 | 
  
 | 
    return err; 
 | 
} 
 | 
  
 | 
static void kvaser_usb_hydra_start_chip_reply(const struct kvaser_usb *dev, 
 | 
                          const struct kvaser_cmd *cmd) 
 | 
{ 
 | 
    struct kvaser_usb_net_priv *priv; 
 | 
  
 | 
    priv = kvaser_usb_hydra_net_priv_from_cmd(dev, cmd); 
 | 
    if (!priv) 
 | 
        return; 
 | 
  
 | 
    if (completion_done(&priv->start_comp) && 
 | 
        netif_queue_stopped(priv->netdev)) { 
 | 
        netif_wake_queue(priv->netdev); 
 | 
    } else { 
 | 
        netif_start_queue(priv->netdev); 
 | 
        complete(&priv->start_comp); 
 | 
    } 
 | 
} 
 | 
  
 | 
static void kvaser_usb_hydra_stop_chip_reply(const struct kvaser_usb *dev, 
 | 
                         const struct kvaser_cmd *cmd) 
 | 
{ 
 | 
    struct kvaser_usb_net_priv *priv; 
 | 
  
 | 
    priv = kvaser_usb_hydra_net_priv_from_cmd(dev, cmd); 
 | 
    if (!priv) 
 | 
        return; 
 | 
  
 | 
    complete(&priv->stop_comp); 
 | 
} 
 | 
  
 | 
static void kvaser_usb_hydra_flush_queue_reply(const struct kvaser_usb *dev, 
 | 
                           const struct kvaser_cmd *cmd) 
 | 
{ 
 | 
    struct kvaser_usb_net_priv *priv; 
 | 
  
 | 
    priv = kvaser_usb_hydra_net_priv_from_cmd(dev, cmd); 
 | 
    if (!priv) 
 | 
        return; 
 | 
  
 | 
    complete(&priv->flush_comp); 
 | 
} 
 | 
  
 | 
static void 
 | 
kvaser_usb_hydra_bus_status_to_can_state(const struct kvaser_usb_net_priv *priv, 
 | 
                     u8 bus_status, 
 | 
                     const struct can_berr_counter *bec, 
 | 
                     enum can_state *new_state) 
 | 
{ 
 | 
    if (bus_status & KVASER_USB_HYDRA_BUS_BUS_OFF) { 
 | 
        *new_state = CAN_STATE_BUS_OFF; 
 | 
    } else if (bus_status & KVASER_USB_HYDRA_BUS_ERR_PASS) { 
 | 
        *new_state = CAN_STATE_ERROR_PASSIVE; 
 | 
    } else if (bus_status == KVASER_USB_HYDRA_BUS_ERR_ACT) { 
 | 
        if (bec->txerr >= 128 || bec->rxerr >= 128) { 
 | 
            netdev_warn(priv->netdev, 
 | 
                    "ERR_ACTIVE but err tx=%u or rx=%u >=128\n", 
 | 
                    bec->txerr, bec->rxerr); 
 | 
            *new_state = CAN_STATE_ERROR_PASSIVE; 
 | 
        } else if (bec->txerr >= 96 || bec->rxerr >= 96) { 
 | 
            *new_state = CAN_STATE_ERROR_WARNING; 
 | 
        } else { 
 | 
            *new_state = CAN_STATE_ERROR_ACTIVE; 
 | 
        } 
 | 
    } 
 | 
} 
 | 
  
 | 
static void kvaser_usb_hydra_update_state(struct kvaser_usb_net_priv *priv, 
 | 
                      u8 bus_status, 
 | 
                      const struct can_berr_counter *bec) 
 | 
{ 
 | 
    struct net_device *netdev = priv->netdev; 
 | 
    struct can_frame *cf; 
 | 
    struct sk_buff *skb; 
 | 
    struct net_device_stats *stats; 
 | 
    enum can_state new_state, old_state; 
 | 
  
 | 
    old_state = priv->can.state; 
 | 
  
 | 
    kvaser_usb_hydra_bus_status_to_can_state(priv, bus_status, bec, 
 | 
                         &new_state); 
 | 
  
 | 
    if (new_state == old_state) 
 | 
        return; 
 | 
  
 | 
    /* Ignore state change if previous state was STOPPED and the new state 
 | 
     * is BUS_OFF. Firmware always report this as BUS_OFF, since firmware 
 | 
     * does not distinguish between BUS_OFF and STOPPED. 
 | 
     */ 
 | 
    if (old_state == CAN_STATE_STOPPED && new_state == CAN_STATE_BUS_OFF) 
 | 
        return; 
 | 
  
 | 
    skb = alloc_can_err_skb(netdev, &cf); 
 | 
    if (skb) { 
 | 
        enum can_state tx_state, rx_state; 
 | 
  
 | 
        tx_state = (bec->txerr >= bec->rxerr) ? 
 | 
                    new_state : CAN_STATE_ERROR_ACTIVE; 
 | 
        rx_state = (bec->txerr <= bec->rxerr) ? 
 | 
                    new_state : CAN_STATE_ERROR_ACTIVE; 
 | 
        can_change_state(netdev, cf, tx_state, rx_state); 
 | 
    } 
 | 
  
 | 
    if (new_state == CAN_STATE_BUS_OFF && old_state < CAN_STATE_BUS_OFF) { 
 | 
        if (!priv->can.restart_ms) 
 | 
            kvaser_usb_hydra_send_simple_cmd_async 
 | 
                        (priv, CMD_STOP_CHIP_REQ); 
 | 
  
 | 
        can_bus_off(netdev); 
 | 
    } 
 | 
  
 | 
    if (!skb) { 
 | 
        netdev_warn(netdev, "No memory left for err_skb\n"); 
 | 
        return; 
 | 
    } 
 | 
  
 | 
    if (priv->can.restart_ms && 
 | 
        old_state >= CAN_STATE_BUS_OFF && 
 | 
        new_state < CAN_STATE_BUS_OFF) 
 | 
        priv->can.can_stats.restarts++; 
 | 
  
 | 
    if (new_state != CAN_STATE_BUS_OFF) { 
 | 
        cf->data[6] = bec->txerr; 
 | 
        cf->data[7] = bec->rxerr; 
 | 
    } 
 | 
  
 | 
    stats = &netdev->stats; 
 | 
    stats->rx_packets++; 
 | 
    stats->rx_bytes += cf->can_dlc; 
 | 
    netif_rx(skb); 
 | 
} 
 | 
  
 | 
static void kvaser_usb_hydra_state_event(const struct kvaser_usb *dev, 
 | 
                     const struct kvaser_cmd *cmd) 
 | 
{ 
 | 
    struct kvaser_usb_net_priv *priv; 
 | 
    struct can_berr_counter bec; 
 | 
    u8 bus_status; 
 | 
  
 | 
    priv = kvaser_usb_hydra_net_priv_from_cmd(dev, cmd); 
 | 
    if (!priv) 
 | 
        return; 
 | 
  
 | 
    bus_status = cmd->chip_state_event.bus_status; 
 | 
    bec.txerr = cmd->chip_state_event.tx_err_counter; 
 | 
    bec.rxerr = cmd->chip_state_event.rx_err_counter; 
 | 
  
 | 
    kvaser_usb_hydra_update_state(priv, bus_status, &bec); 
 | 
    priv->bec.txerr = bec.txerr; 
 | 
    priv->bec.rxerr = bec.rxerr; 
 | 
} 
 | 
  
 | 
static void kvaser_usb_hydra_error_event_parameter(const struct kvaser_usb *dev, 
 | 
                           const struct kvaser_cmd *cmd) 
 | 
{ 
 | 
    /* info1 will contain the offending cmd_no */ 
 | 
    switch (le16_to_cpu(cmd->error_event.info1)) { 
 | 
    case CMD_START_CHIP_REQ: 
 | 
        dev_warn(&dev->intf->dev, 
 | 
             "CMD_START_CHIP_REQ error in parameter\n"); 
 | 
        break; 
 | 
  
 | 
    case CMD_STOP_CHIP_REQ: 
 | 
        dev_warn(&dev->intf->dev, 
 | 
             "CMD_STOP_CHIP_REQ error in parameter\n"); 
 | 
        break; 
 | 
  
 | 
    case CMD_FLUSH_QUEUE: 
 | 
        dev_warn(&dev->intf->dev, 
 | 
             "CMD_FLUSH_QUEUE error in parameter\n"); 
 | 
        break; 
 | 
  
 | 
    case CMD_SET_BUSPARAMS_REQ: 
 | 
        dev_warn(&dev->intf->dev, 
 | 
             "Set bittiming failed. Error in parameter\n"); 
 | 
        break; 
 | 
  
 | 
    case CMD_SET_BUSPARAMS_FD_REQ: 
 | 
        dev_warn(&dev->intf->dev, 
 | 
             "Set data bittiming failed. Error in parameter\n"); 
 | 
        break; 
 | 
  
 | 
    default: 
 | 
        dev_warn(&dev->intf->dev, 
 | 
             "Unhandled parameter error event cmd_no (%u)\n", 
 | 
             le16_to_cpu(cmd->error_event.info1)); 
 | 
        break; 
 | 
    } 
 | 
} 
 | 
  
 | 
static void kvaser_usb_hydra_error_event(const struct kvaser_usb *dev, 
 | 
                     const struct kvaser_cmd *cmd) 
 | 
{ 
 | 
    switch (cmd->error_event.error_code) { 
 | 
    case KVASER_USB_HYDRA_ERROR_EVENT_PARAM: 
 | 
        kvaser_usb_hydra_error_event_parameter(dev, cmd); 
 | 
        break; 
 | 
  
 | 
    case KVASER_USB_HYDRA_ERROR_EVENT_CAN: 
 | 
        /* Wrong channel mapping?! This should never happen! 
 | 
         * info1 will contain the offending cmd_no 
 | 
         */ 
 | 
        dev_err(&dev->intf->dev, 
 | 
            "Received CAN error event for cmd_no (%u)\n", 
 | 
            le16_to_cpu(cmd->error_event.info1)); 
 | 
        break; 
 | 
  
 | 
    default: 
 | 
        dev_warn(&dev->intf->dev, 
 | 
             "Unhandled error event (%d)\n", 
 | 
             cmd->error_event.error_code); 
 | 
        break; 
 | 
    } 
 | 
} 
 | 
  
 | 
static void 
 | 
kvaser_usb_hydra_error_frame(struct kvaser_usb_net_priv *priv, 
 | 
                 const struct kvaser_err_frame_data *err_frame_data, 
 | 
                 ktime_t hwtstamp) 
 | 
{ 
 | 
    struct net_device *netdev = priv->netdev; 
 | 
    struct net_device_stats *stats = &netdev->stats; 
 | 
    struct can_frame *cf; 
 | 
    struct sk_buff *skb; 
 | 
    struct skb_shared_hwtstamps *shhwtstamps; 
 | 
    struct can_berr_counter bec; 
 | 
    enum can_state new_state, old_state; 
 | 
    u8 bus_status; 
 | 
  
 | 
    priv->can.can_stats.bus_error++; 
 | 
    stats->rx_errors++; 
 | 
  
 | 
    bus_status = err_frame_data->bus_status; 
 | 
    bec.txerr = err_frame_data->tx_err_counter; 
 | 
    bec.rxerr = err_frame_data->rx_err_counter; 
 | 
  
 | 
    old_state = priv->can.state; 
 | 
    kvaser_usb_hydra_bus_status_to_can_state(priv, bus_status, &bec, 
 | 
                         &new_state); 
 | 
  
 | 
    skb = alloc_can_err_skb(netdev, &cf); 
 | 
  
 | 
    if (new_state != old_state) { 
 | 
        if (skb) { 
 | 
            enum can_state tx_state, rx_state; 
 | 
  
 | 
            tx_state = (bec.txerr >= bec.rxerr) ? 
 | 
                    new_state : CAN_STATE_ERROR_ACTIVE; 
 | 
            rx_state = (bec.txerr <= bec.rxerr) ? 
 | 
                    new_state : CAN_STATE_ERROR_ACTIVE; 
 | 
  
 | 
            can_change_state(netdev, cf, tx_state, rx_state); 
 | 
  
 | 
            if (priv->can.restart_ms && 
 | 
                old_state >= CAN_STATE_BUS_OFF && 
 | 
                new_state < CAN_STATE_BUS_OFF) 
 | 
                cf->can_id |= CAN_ERR_RESTARTED; 
 | 
        } 
 | 
  
 | 
        if (new_state == CAN_STATE_BUS_OFF) { 
 | 
            if (!priv->can.restart_ms) 
 | 
                kvaser_usb_hydra_send_simple_cmd_async 
 | 
                        (priv, CMD_STOP_CHIP_REQ); 
 | 
  
 | 
            can_bus_off(netdev); 
 | 
        } 
 | 
    } 
 | 
  
 | 
    if (!skb) { 
 | 
        stats->rx_dropped++; 
 | 
        netdev_warn(netdev, "No memory left for err_skb\n"); 
 | 
        return; 
 | 
    } 
 | 
  
 | 
    shhwtstamps = skb_hwtstamps(skb); 
 | 
    shhwtstamps->hwtstamp = hwtstamp; 
 | 
  
 | 
    cf->can_id |= CAN_ERR_BUSERROR; 
 | 
    if (new_state != CAN_STATE_BUS_OFF) { 
 | 
        cf->data[6] = bec.txerr; 
 | 
        cf->data[7] = bec.rxerr; 
 | 
    } 
 | 
  
 | 
    stats->rx_packets++; 
 | 
    stats->rx_bytes += cf->can_dlc; 
 | 
    netif_rx(skb); 
 | 
  
 | 
    priv->bec.txerr = bec.txerr; 
 | 
    priv->bec.rxerr = bec.rxerr; 
 | 
} 
 | 
  
 | 
static void kvaser_usb_hydra_one_shot_fail(struct kvaser_usb_net_priv *priv, 
 | 
                       const struct kvaser_cmd_ext *cmd) 
 | 
{ 
 | 
    struct net_device *netdev = priv->netdev; 
 | 
    struct net_device_stats *stats = &netdev->stats; 
 | 
    struct can_frame *cf; 
 | 
    struct sk_buff *skb; 
 | 
    u32 flags; 
 | 
  
 | 
    skb = alloc_can_err_skb(netdev, &cf); 
 | 
    if (!skb) { 
 | 
        stats->rx_dropped++; 
 | 
        netdev_warn(netdev, "No memory left for err_skb\n"); 
 | 
        return; 
 | 
    } 
 | 
  
 | 
    cf->can_id |= CAN_ERR_BUSERROR; 
 | 
    flags = le32_to_cpu(cmd->tx_ack.flags); 
 | 
  
 | 
    if (flags & KVASER_USB_HYDRA_CF_FLAG_OSM_NACK) 
 | 
        cf->can_id |= CAN_ERR_ACK; 
 | 
    if (flags & KVASER_USB_HYDRA_CF_FLAG_ABL) { 
 | 
        cf->can_id |= CAN_ERR_LOSTARB; 
 | 
        priv->can.can_stats.arbitration_lost++; 
 | 
    } 
 | 
  
 | 
    stats->tx_errors++; 
 | 
    stats->rx_packets++; 
 | 
    stats->rx_bytes += cf->can_dlc; 
 | 
    netif_rx(skb); 
 | 
} 
 | 
  
 | 
static void kvaser_usb_hydra_tx_acknowledge(const struct kvaser_usb *dev, 
 | 
                        const struct kvaser_cmd *cmd) 
 | 
{ 
 | 
    struct kvaser_usb_tx_urb_context *context; 
 | 
    struct kvaser_usb_net_priv *priv; 
 | 
    unsigned long irq_flags; 
 | 
    bool one_shot_fail = false; 
 | 
    u16 transid = kvaser_usb_hydra_get_cmd_transid(cmd); 
 | 
  
 | 
    priv = kvaser_usb_hydra_net_priv_from_cmd(dev, cmd); 
 | 
    if (!priv) 
 | 
        return; 
 | 
  
 | 
    if (!netif_device_present(priv->netdev)) 
 | 
        return; 
 | 
  
 | 
    if (cmd->header.cmd_no == CMD_EXTENDED) { 
 | 
        struct kvaser_cmd_ext *cmd_ext = (struct kvaser_cmd_ext *)cmd; 
 | 
        u32 flags = le32_to_cpu(cmd_ext->tx_ack.flags); 
 | 
  
 | 
        if (flags & (KVASER_USB_HYDRA_CF_FLAG_OSM_NACK | 
 | 
                 KVASER_USB_HYDRA_CF_FLAG_ABL)) { 
 | 
            kvaser_usb_hydra_one_shot_fail(priv, cmd_ext); 
 | 
            one_shot_fail = true; 
 | 
        } 
 | 
    } 
 | 
  
 | 
    context = &priv->tx_contexts[transid % dev->max_tx_urbs]; 
 | 
    if (!one_shot_fail) { 
 | 
        struct net_device_stats *stats = &priv->netdev->stats; 
 | 
  
 | 
        stats->tx_packets++; 
 | 
        stats->tx_bytes += can_dlc2len(context->dlc); 
 | 
    } 
 | 
  
 | 
    spin_lock_irqsave(&priv->tx_contexts_lock, irq_flags); 
 | 
  
 | 
    can_get_echo_skb(priv->netdev, context->echo_index); 
 | 
    context->echo_index = dev->max_tx_urbs; 
 | 
    --priv->active_tx_contexts; 
 | 
    netif_wake_queue(priv->netdev); 
 | 
  
 | 
    spin_unlock_irqrestore(&priv->tx_contexts_lock, irq_flags); 
 | 
} 
 | 
  
 | 
static void kvaser_usb_hydra_rx_msg_std(const struct kvaser_usb *dev, 
 | 
                    const struct kvaser_cmd *cmd) 
 | 
{ 
 | 
    struct kvaser_usb_net_priv *priv = NULL; 
 | 
    struct can_frame *cf; 
 | 
    struct sk_buff *skb; 
 | 
    struct skb_shared_hwtstamps *shhwtstamps; 
 | 
    struct net_device_stats *stats; 
 | 
    u8 flags; 
 | 
    ktime_t hwtstamp; 
 | 
  
 | 
    priv = kvaser_usb_hydra_net_priv_from_cmd(dev, cmd); 
 | 
    if (!priv) 
 | 
        return; 
 | 
  
 | 
    stats = &priv->netdev->stats; 
 | 
  
 | 
    flags = cmd->rx_can.flags; 
 | 
    hwtstamp = kvaser_usb_hydra_ktime_from_rx_cmd(dev->cfg, cmd); 
 | 
  
 | 
    if (flags & KVASER_USB_HYDRA_CF_FLAG_ERROR_FRAME) { 
 | 
        kvaser_usb_hydra_error_frame(priv, &cmd->rx_can.err_frame_data, 
 | 
                         hwtstamp); 
 | 
        return; 
 | 
    } 
 | 
  
 | 
    skb = alloc_can_skb(priv->netdev, &cf); 
 | 
    if (!skb) { 
 | 
        stats->rx_dropped++; 
 | 
        return; 
 | 
    } 
 | 
  
 | 
    shhwtstamps = skb_hwtstamps(skb); 
 | 
    shhwtstamps->hwtstamp = hwtstamp; 
 | 
  
 | 
    cf->can_id = le32_to_cpu(cmd->rx_can.id); 
 | 
  
 | 
    if (cf->can_id &  KVASER_USB_HYDRA_EXTENDED_FRAME_ID) { 
 | 
        cf->can_id &= CAN_EFF_MASK; 
 | 
        cf->can_id |= CAN_EFF_FLAG; 
 | 
    } else { 
 | 
        cf->can_id &= CAN_SFF_MASK; 
 | 
    } 
 | 
  
 | 
    if (flags & KVASER_USB_HYDRA_CF_FLAG_OVERRUN) 
 | 
        kvaser_usb_can_rx_over_error(priv->netdev); 
 | 
  
 | 
    cf->can_dlc = get_can_dlc(cmd->rx_can.dlc); 
 | 
  
 | 
    if (flags & KVASER_USB_HYDRA_CF_FLAG_REMOTE_FRAME) 
 | 
        cf->can_id |= CAN_RTR_FLAG; 
 | 
    else 
 | 
        memcpy(cf->data, cmd->rx_can.data, cf->can_dlc); 
 | 
  
 | 
    stats->rx_packets++; 
 | 
    stats->rx_bytes += cf->can_dlc; 
 | 
    netif_rx(skb); 
 | 
} 
 | 
  
 | 
static void kvaser_usb_hydra_rx_msg_ext(const struct kvaser_usb *dev, 
 | 
                    const struct kvaser_cmd_ext *cmd) 
 | 
{ 
 | 
    struct kvaser_cmd *std_cmd = (struct kvaser_cmd *)cmd; 
 | 
    struct kvaser_usb_net_priv *priv; 
 | 
    struct canfd_frame *cf; 
 | 
    struct sk_buff *skb; 
 | 
    struct skb_shared_hwtstamps *shhwtstamps; 
 | 
    struct net_device_stats *stats; 
 | 
    u32 flags; 
 | 
    u8 dlc; 
 | 
    u32 kcan_header; 
 | 
    ktime_t hwtstamp; 
 | 
  
 | 
    priv = kvaser_usb_hydra_net_priv_from_cmd(dev, std_cmd); 
 | 
    if (!priv) 
 | 
        return; 
 | 
  
 | 
    stats = &priv->netdev->stats; 
 | 
  
 | 
    kcan_header = le32_to_cpu(cmd->rx_can.kcan_header); 
 | 
    dlc = (kcan_header & KVASER_USB_KCAN_DATA_DLC_MASK) >> 
 | 
        KVASER_USB_KCAN_DATA_DLC_SHIFT; 
 | 
  
 | 
    flags = le32_to_cpu(cmd->rx_can.flags); 
 | 
    hwtstamp = kvaser_usb_hydra_ktime_from_rx_cmd(dev->cfg, std_cmd); 
 | 
  
 | 
    if (flags & KVASER_USB_HYDRA_CF_FLAG_ERROR_FRAME) { 
 | 
        kvaser_usb_hydra_error_frame(priv, &cmd->rx_can.err_frame_data, 
 | 
                         hwtstamp); 
 | 
        return; 
 | 
    } 
 | 
  
 | 
    if (flags & KVASER_USB_HYDRA_CF_FLAG_FDF) 
 | 
        skb = alloc_canfd_skb(priv->netdev, &cf); 
 | 
    else 
 | 
        skb = alloc_can_skb(priv->netdev, (struct can_frame **)&cf); 
 | 
  
 | 
    if (!skb) { 
 | 
        stats->rx_dropped++; 
 | 
        return; 
 | 
    } 
 | 
  
 | 
    shhwtstamps = skb_hwtstamps(skb); 
 | 
    shhwtstamps->hwtstamp = hwtstamp; 
 | 
  
 | 
    cf->can_id = le32_to_cpu(cmd->rx_can.id); 
 | 
  
 | 
    if (flags & KVASER_USB_HYDRA_CF_FLAG_EXTENDED_ID) { 
 | 
        cf->can_id &= CAN_EFF_MASK; 
 | 
        cf->can_id |= CAN_EFF_FLAG; 
 | 
    } else { 
 | 
        cf->can_id &= CAN_SFF_MASK; 
 | 
    } 
 | 
  
 | 
    if (flags & KVASER_USB_HYDRA_CF_FLAG_OVERRUN) 
 | 
        kvaser_usb_can_rx_over_error(priv->netdev); 
 | 
  
 | 
    if (flags & KVASER_USB_HYDRA_CF_FLAG_FDF) { 
 | 
        cf->len = can_dlc2len(get_canfd_dlc(dlc)); 
 | 
        if (flags & KVASER_USB_HYDRA_CF_FLAG_BRS) 
 | 
            cf->flags |= CANFD_BRS; 
 | 
        if (flags & KVASER_USB_HYDRA_CF_FLAG_ESI) 
 | 
            cf->flags |= CANFD_ESI; 
 | 
    } else { 
 | 
        cf->len = get_can_dlc(dlc); 
 | 
    } 
 | 
  
 | 
    if (flags & KVASER_USB_HYDRA_CF_FLAG_REMOTE_FRAME) 
 | 
        cf->can_id |= CAN_RTR_FLAG; 
 | 
    else 
 | 
        memcpy(cf->data, cmd->rx_can.kcan_payload, cf->len); 
 | 
  
 | 
    stats->rx_packets++; 
 | 
    stats->rx_bytes += cf->len; 
 | 
    netif_rx(skb); 
 | 
} 
 | 
  
 | 
static void kvaser_usb_hydra_handle_cmd_std(const struct kvaser_usb *dev, 
 | 
                        const struct kvaser_cmd *cmd) 
 | 
{ 
 | 
    switch (cmd->header.cmd_no) { 
 | 
    case CMD_START_CHIP_RESP: 
 | 
        kvaser_usb_hydra_start_chip_reply(dev, cmd); 
 | 
        break; 
 | 
  
 | 
    case CMD_STOP_CHIP_RESP: 
 | 
        kvaser_usb_hydra_stop_chip_reply(dev, cmd); 
 | 
        break; 
 | 
  
 | 
    case CMD_FLUSH_QUEUE_RESP: 
 | 
        kvaser_usb_hydra_flush_queue_reply(dev, cmd); 
 | 
        break; 
 | 
  
 | 
    case CMD_CHIP_STATE_EVENT: 
 | 
        kvaser_usb_hydra_state_event(dev, cmd); 
 | 
        break; 
 | 
  
 | 
    case CMD_ERROR_EVENT: 
 | 
        kvaser_usb_hydra_error_event(dev, cmd); 
 | 
        break; 
 | 
  
 | 
    case CMD_TX_ACKNOWLEDGE: 
 | 
        kvaser_usb_hydra_tx_acknowledge(dev, cmd); 
 | 
        break; 
 | 
  
 | 
    case CMD_RX_MESSAGE: 
 | 
        kvaser_usb_hydra_rx_msg_std(dev, cmd); 
 | 
        break; 
 | 
  
 | 
    /* Ignored commands */ 
 | 
    case CMD_SET_BUSPARAMS_RESP: 
 | 
    case CMD_SET_BUSPARAMS_FD_RESP: 
 | 
        break; 
 | 
  
 | 
    default: 
 | 
        dev_warn(&dev->intf->dev, "Unhandled command (%d)\n", 
 | 
             cmd->header.cmd_no); 
 | 
        break; 
 | 
    } 
 | 
} 
 | 
  
 | 
static void kvaser_usb_hydra_handle_cmd_ext(const struct kvaser_usb *dev, 
 | 
                        const struct kvaser_cmd_ext *cmd) 
 | 
{ 
 | 
    switch (cmd->cmd_no_ext) { 
 | 
    case CMD_TX_ACKNOWLEDGE_FD: 
 | 
        kvaser_usb_hydra_tx_acknowledge(dev, (struct kvaser_cmd *)cmd); 
 | 
        break; 
 | 
  
 | 
    case CMD_RX_MESSAGE_FD: 
 | 
        kvaser_usb_hydra_rx_msg_ext(dev, cmd); 
 | 
        break; 
 | 
  
 | 
    default: 
 | 
        dev_warn(&dev->intf->dev, "Unhandled extended command (%d)\n", 
 | 
             cmd->header.cmd_no); 
 | 
        break; 
 | 
    } 
 | 
} 
 | 
  
 | 
static void kvaser_usb_hydra_handle_cmd(const struct kvaser_usb *dev, 
 | 
                    const struct kvaser_cmd *cmd) 
 | 
{ 
 | 
        if (cmd->header.cmd_no == CMD_EXTENDED) 
 | 
            kvaser_usb_hydra_handle_cmd_ext 
 | 
                    (dev, (struct kvaser_cmd_ext *)cmd); 
 | 
        else 
 | 
            kvaser_usb_hydra_handle_cmd_std(dev, cmd); 
 | 
} 
 | 
  
 | 
static void * 
 | 
kvaser_usb_hydra_frame_to_cmd_ext(const struct kvaser_usb_net_priv *priv, 
 | 
                  const struct sk_buff *skb, int *frame_len, 
 | 
                  int *cmd_len, u16 transid) 
 | 
{ 
 | 
    struct kvaser_usb *dev = priv->dev; 
 | 
    struct kvaser_cmd_ext *cmd; 
 | 
    struct canfd_frame *cf = (struct canfd_frame *)skb->data; 
 | 
    u8 dlc = can_len2dlc(cf->len); 
 | 
    u8 nbr_of_bytes = cf->len; 
 | 
    u32 flags; 
 | 
    u32 id; 
 | 
    u32 kcan_id; 
 | 
    u32 kcan_header; 
 | 
  
 | 
    *frame_len = nbr_of_bytes; 
 | 
  
 | 
    cmd = kcalloc(1, sizeof(struct kvaser_cmd_ext), GFP_ATOMIC); 
 | 
    if (!cmd) 
 | 
        return NULL; 
 | 
  
 | 
    kvaser_usb_hydra_set_cmd_dest_he 
 | 
            ((struct kvaser_cmd *)cmd, 
 | 
             dev->card_data.hydra.channel_to_he[priv->channel]); 
 | 
    kvaser_usb_hydra_set_cmd_transid((struct kvaser_cmd *)cmd, transid); 
 | 
  
 | 
    cmd->header.cmd_no = CMD_EXTENDED; 
 | 
    cmd->cmd_no_ext = CMD_TX_CAN_MESSAGE_FD; 
 | 
  
 | 
    *cmd_len = ALIGN(sizeof(struct kvaser_cmd_ext) - 
 | 
             sizeof(cmd->tx_can.kcan_payload) + nbr_of_bytes, 
 | 
             8); 
 | 
  
 | 
    cmd->len = cpu_to_le16(*cmd_len); 
 | 
  
 | 
    cmd->tx_can.databytes = nbr_of_bytes; 
 | 
    cmd->tx_can.dlc = dlc; 
 | 
  
 | 
    if (cf->can_id & CAN_EFF_FLAG) { 
 | 
        id = cf->can_id & CAN_EFF_MASK; 
 | 
        flags = KVASER_USB_HYDRA_CF_FLAG_EXTENDED_ID; 
 | 
        kcan_id = (cf->can_id & CAN_EFF_MASK) | 
 | 
              KVASER_USB_KCAN_DATA_IDE | KVASER_USB_KCAN_DATA_SRR; 
 | 
    } else { 
 | 
        id = cf->can_id & CAN_SFF_MASK; 
 | 
        flags = 0; 
 | 
        kcan_id = cf->can_id & CAN_SFF_MASK; 
 | 
    } 
 | 
  
 | 
    if (cf->can_id & CAN_ERR_FLAG) 
 | 
        flags |= KVASER_USB_HYDRA_CF_FLAG_ERROR_FRAME; 
 | 
  
 | 
    kcan_header = ((dlc << KVASER_USB_KCAN_DATA_DLC_SHIFT) & 
 | 
                KVASER_USB_KCAN_DATA_DLC_MASK) | 
 | 
            KVASER_USB_KCAN_DATA_AREQ | 
 | 
            (priv->can.ctrlmode & CAN_CTRLMODE_ONE_SHOT ? 
 | 
                KVASER_USB_KCAN_DATA_OSM : 0); 
 | 
  
 | 
    if (can_is_canfd_skb(skb)) { 
 | 
        kcan_header |= KVASER_USB_KCAN_DATA_FDF | 
 | 
                   (cf->flags & CANFD_BRS ? 
 | 
                    KVASER_USB_KCAN_DATA_BRS : 0); 
 | 
    } else { 
 | 
        if (cf->can_id & CAN_RTR_FLAG) { 
 | 
            kcan_id |= KVASER_USB_KCAN_DATA_RTR; 
 | 
            cmd->tx_can.databytes = 0; 
 | 
            flags |= KVASER_USB_HYDRA_CF_FLAG_REMOTE_FRAME; 
 | 
        } 
 | 
    } 
 | 
  
 | 
    cmd->tx_can.kcan_id = cpu_to_le32(kcan_id); 
 | 
    cmd->tx_can.id = cpu_to_le32(id); 
 | 
    cmd->tx_can.flags = cpu_to_le32(flags); 
 | 
    cmd->tx_can.kcan_header = cpu_to_le32(kcan_header); 
 | 
  
 | 
    memcpy(cmd->tx_can.kcan_payload, cf->data, nbr_of_bytes); 
 | 
  
 | 
    return cmd; 
 | 
} 
 | 
  
 | 
static void * 
 | 
kvaser_usb_hydra_frame_to_cmd_std(const struct kvaser_usb_net_priv *priv, 
 | 
                  const struct sk_buff *skb, int *frame_len, 
 | 
                  int *cmd_len, u16 transid) 
 | 
{ 
 | 
    struct kvaser_usb *dev = priv->dev; 
 | 
    struct kvaser_cmd *cmd; 
 | 
    struct can_frame *cf = (struct can_frame *)skb->data; 
 | 
    u32 flags; 
 | 
    u32 id; 
 | 
  
 | 
    *frame_len = cf->can_dlc; 
 | 
  
 | 
    cmd = kcalloc(1, sizeof(struct kvaser_cmd), GFP_ATOMIC); 
 | 
    if (!cmd) 
 | 
        return NULL; 
 | 
  
 | 
    kvaser_usb_hydra_set_cmd_dest_he 
 | 
        (cmd, dev->card_data.hydra.channel_to_he[priv->channel]); 
 | 
    kvaser_usb_hydra_set_cmd_transid(cmd, transid); 
 | 
  
 | 
    cmd->header.cmd_no = CMD_TX_CAN_MESSAGE; 
 | 
  
 | 
    *cmd_len = ALIGN(sizeof(struct kvaser_cmd), 8); 
 | 
  
 | 
    if (cf->can_id & CAN_EFF_FLAG) { 
 | 
        id = (cf->can_id & CAN_EFF_MASK); 
 | 
        id |= KVASER_USB_HYDRA_EXTENDED_FRAME_ID; 
 | 
    } else { 
 | 
        id = cf->can_id & CAN_SFF_MASK; 
 | 
    } 
 | 
  
 | 
    cmd->tx_can.dlc = cf->can_dlc; 
 | 
  
 | 
    flags = (cf->can_id & CAN_EFF_FLAG ? 
 | 
         KVASER_USB_HYDRA_CF_FLAG_EXTENDED_ID : 0); 
 | 
  
 | 
    if (cf->can_id & CAN_RTR_FLAG) 
 | 
        flags |= KVASER_USB_HYDRA_CF_FLAG_REMOTE_FRAME; 
 | 
  
 | 
    flags |= (cf->can_id & CAN_ERR_FLAG ? 
 | 
          KVASER_USB_HYDRA_CF_FLAG_ERROR_FRAME : 0); 
 | 
  
 | 
    cmd->tx_can.id = cpu_to_le32(id); 
 | 
    cmd->tx_can.flags = flags; 
 | 
  
 | 
    memcpy(cmd->tx_can.data, cf->data, *frame_len); 
 | 
  
 | 
    return cmd; 
 | 
} 
 | 
  
 | 
static int kvaser_usb_hydra_set_mode(struct net_device *netdev, 
 | 
                     enum can_mode mode) 
 | 
{ 
 | 
    int err = 0; 
 | 
  
 | 
    switch (mode) { 
 | 
    case CAN_MODE_START: 
 | 
        /* CAN controller automatically recovers from BUS_OFF */ 
 | 
        break; 
 | 
    default: 
 | 
        err = -EOPNOTSUPP; 
 | 
    } 
 | 
  
 | 
    return err; 
 | 
} 
 | 
  
 | 
static int kvaser_usb_hydra_set_bittiming(struct net_device *netdev) 
 | 
{ 
 | 
    struct kvaser_cmd *cmd; 
 | 
    struct kvaser_usb_net_priv *priv = netdev_priv(netdev); 
 | 
    struct can_bittiming *bt = &priv->can.bittiming; 
 | 
    struct kvaser_usb *dev = priv->dev; 
 | 
    int tseg1 = bt->prop_seg + bt->phase_seg1; 
 | 
    int tseg2 = bt->phase_seg2; 
 | 
    int sjw = bt->sjw; 
 | 
    int err; 
 | 
  
 | 
    cmd = kcalloc(1, sizeof(struct kvaser_cmd), GFP_KERNEL); 
 | 
    if (!cmd) 
 | 
        return -ENOMEM; 
 | 
  
 | 
    cmd->header.cmd_no = CMD_SET_BUSPARAMS_REQ; 
 | 
    cmd->set_busparams_req.bitrate = cpu_to_le32(bt->bitrate); 
 | 
    cmd->set_busparams_req.sjw = (u8)sjw; 
 | 
    cmd->set_busparams_req.tseg1 = (u8)tseg1; 
 | 
    cmd->set_busparams_req.tseg2 = (u8)tseg2; 
 | 
    cmd->set_busparams_req.nsamples = 1; 
 | 
  
 | 
    kvaser_usb_hydra_set_cmd_dest_he 
 | 
        (cmd, dev->card_data.hydra.channel_to_he[priv->channel]); 
 | 
    kvaser_usb_hydra_set_cmd_transid 
 | 
                (cmd, kvaser_usb_hydra_get_next_transid(dev)); 
 | 
  
 | 
    err = kvaser_usb_send_cmd(dev, cmd, kvaser_usb_hydra_cmd_size(cmd)); 
 | 
  
 | 
    kfree(cmd); 
 | 
  
 | 
    return err; 
 | 
} 
 | 
  
 | 
static int kvaser_usb_hydra_set_data_bittiming(struct net_device *netdev) 
 | 
{ 
 | 
    struct kvaser_cmd *cmd; 
 | 
    struct kvaser_usb_net_priv *priv = netdev_priv(netdev); 
 | 
    struct can_bittiming *dbt = &priv->can.data_bittiming; 
 | 
    struct kvaser_usb *dev = priv->dev; 
 | 
    int tseg1 = dbt->prop_seg + dbt->phase_seg1; 
 | 
    int tseg2 = dbt->phase_seg2; 
 | 
    int sjw = dbt->sjw; 
 | 
    int err; 
 | 
  
 | 
    cmd = kcalloc(1, sizeof(struct kvaser_cmd), GFP_KERNEL); 
 | 
    if (!cmd) 
 | 
        return -ENOMEM; 
 | 
  
 | 
    cmd->header.cmd_no = CMD_SET_BUSPARAMS_FD_REQ; 
 | 
    cmd->set_busparams_req.bitrate_d = cpu_to_le32(dbt->bitrate); 
 | 
    cmd->set_busparams_req.sjw_d = (u8)sjw; 
 | 
    cmd->set_busparams_req.tseg1_d = (u8)tseg1; 
 | 
    cmd->set_busparams_req.tseg2_d = (u8)tseg2; 
 | 
    cmd->set_busparams_req.nsamples_d = 1; 
 | 
  
 | 
    if (priv->can.ctrlmode & CAN_CTRLMODE_FD) { 
 | 
        if (priv->can.ctrlmode & CAN_CTRLMODE_FD_NON_ISO) 
 | 
            cmd->set_busparams_req.canfd_mode = 
 | 
                    KVASER_USB_HYDRA_BUS_MODE_NONISO; 
 | 
        else 
 | 
            cmd->set_busparams_req.canfd_mode = 
 | 
                    KVASER_USB_HYDRA_BUS_MODE_CANFD_ISO; 
 | 
    } 
 | 
  
 | 
    kvaser_usb_hydra_set_cmd_dest_he 
 | 
        (cmd, dev->card_data.hydra.channel_to_he[priv->channel]); 
 | 
    kvaser_usb_hydra_set_cmd_transid 
 | 
                (cmd, kvaser_usb_hydra_get_next_transid(dev)); 
 | 
  
 | 
    err = kvaser_usb_send_cmd(dev, cmd, kvaser_usb_hydra_cmd_size(cmd)); 
 | 
  
 | 
    kfree(cmd); 
 | 
  
 | 
    return err; 
 | 
} 
 | 
  
 | 
static int kvaser_usb_hydra_get_berr_counter(const struct net_device *netdev, 
 | 
                         struct can_berr_counter *bec) 
 | 
{ 
 | 
    struct kvaser_usb_net_priv *priv = netdev_priv(netdev); 
 | 
    int err; 
 | 
  
 | 
    err = kvaser_usb_hydra_send_simple_cmd(priv->dev, 
 | 
                           CMD_GET_CHIP_STATE_REQ, 
 | 
                           priv->channel); 
 | 
    if (err) 
 | 
        return err; 
 | 
  
 | 
    *bec = priv->bec; 
 | 
  
 | 
    return 0; 
 | 
} 
 | 
  
 | 
static int kvaser_usb_hydra_setup_endpoints(struct kvaser_usb *dev) 
 | 
{ 
 | 
    const struct usb_host_interface *iface_desc; 
 | 
    struct usb_endpoint_descriptor *ep; 
 | 
    int i; 
 | 
  
 | 
    iface_desc = dev->intf->cur_altsetting; 
 | 
  
 | 
    for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) { 
 | 
        ep = &iface_desc->endpoint[i].desc; 
 | 
  
 | 
        if (!dev->bulk_in && usb_endpoint_is_bulk_in(ep) && 
 | 
            ep->bEndpointAddress == KVASER_USB_HYDRA_BULK_EP_IN_ADDR) 
 | 
            dev->bulk_in = ep; 
 | 
  
 | 
        if (!dev->bulk_out && usb_endpoint_is_bulk_out(ep) && 
 | 
            ep->bEndpointAddress == KVASER_USB_HYDRA_BULK_EP_OUT_ADDR) 
 | 
            dev->bulk_out = ep; 
 | 
  
 | 
        if (dev->bulk_in && dev->bulk_out) 
 | 
            return 0; 
 | 
    } 
 | 
  
 | 
    return -ENODEV; 
 | 
} 
 | 
  
 | 
static int kvaser_usb_hydra_init_card(struct kvaser_usb *dev) 
 | 
{ 
 | 
    int err; 
 | 
    unsigned int i; 
 | 
    struct kvaser_usb_dev_card_data_hydra *card_data = 
 | 
                            &dev->card_data.hydra; 
 | 
  
 | 
    card_data->transid = KVASER_USB_HYDRA_MIN_TRANSID; 
 | 
    spin_lock_init(&card_data->transid_lock); 
 | 
  
 | 
    memset(card_data->usb_rx_leftover, 0, KVASER_USB_HYDRA_MAX_CMD_LEN); 
 | 
    card_data->usb_rx_leftover_len = 0; 
 | 
    spin_lock_init(&card_data->usb_rx_leftover_lock); 
 | 
  
 | 
    memset(card_data->channel_to_he, KVASER_USB_HYDRA_HE_ADDRESS_ILLEGAL, 
 | 
           sizeof(card_data->channel_to_he)); 
 | 
    card_data->sysdbg_he = 0; 
 | 
  
 | 
    for (i = 0; i < KVASER_USB_MAX_NET_DEVICES; i++) { 
 | 
        err = kvaser_usb_hydra_map_channel 
 | 
                    (dev, 
 | 
                     (KVASER_USB_HYDRA_TRANSID_CANHE | i), 
 | 
                     i, "CAN"); 
 | 
        if (err) { 
 | 
            dev_err(&dev->intf->dev, 
 | 
                "CMD_MAP_CHANNEL_REQ failed for CAN%u\n", i); 
 | 
            return err; 
 | 
        } 
 | 
    } 
 | 
  
 | 
    err = kvaser_usb_hydra_map_channel(dev, KVASER_USB_HYDRA_TRANSID_SYSDBG, 
 | 
                       0, "SYSDBG"); 
 | 
    if (err) { 
 | 
        dev_err(&dev->intf->dev, 
 | 
            "CMD_MAP_CHANNEL_REQ failed for SYSDBG\n"); 
 | 
        return err; 
 | 
    } 
 | 
  
 | 
    return 0; 
 | 
} 
 | 
  
 | 
static int kvaser_usb_hydra_get_software_info(struct kvaser_usb *dev) 
 | 
{ 
 | 
    struct kvaser_cmd cmd; 
 | 
    int err; 
 | 
  
 | 
    err = kvaser_usb_hydra_send_simple_cmd(dev, CMD_GET_SOFTWARE_INFO_REQ, 
 | 
                           -1); 
 | 
    if (err) 
 | 
        return err; 
 | 
  
 | 
    memset(&cmd, 0, sizeof(struct kvaser_cmd)); 
 | 
    err = kvaser_usb_hydra_wait_cmd(dev, CMD_GET_SOFTWARE_INFO_RESP, &cmd); 
 | 
    if (err) 
 | 
        return err; 
 | 
  
 | 
    dev->max_tx_urbs = min_t(unsigned int, KVASER_USB_MAX_TX_URBS, 
 | 
                 le16_to_cpu(cmd.sw_info.max_outstanding_tx)); 
 | 
  
 | 
    return 0; 
 | 
} 
 | 
  
 | 
static int kvaser_usb_hydra_get_software_details(struct kvaser_usb *dev) 
 | 
{ 
 | 
    struct kvaser_cmd *cmd; 
 | 
    int err; 
 | 
    u32 flags; 
 | 
    struct kvaser_usb_dev_card_data *card_data = &dev->card_data; 
 | 
  
 | 
    cmd = kcalloc(1, sizeof(struct kvaser_cmd), GFP_KERNEL); 
 | 
    if (!cmd) 
 | 
        return -ENOMEM; 
 | 
  
 | 
    cmd->header.cmd_no = CMD_GET_SOFTWARE_DETAILS_REQ; 
 | 
    cmd->sw_detail_req.use_ext_cmd = 1; 
 | 
    kvaser_usb_hydra_set_cmd_dest_he 
 | 
                (cmd, KVASER_USB_HYDRA_HE_ADDRESS_ILLEGAL); 
 | 
  
 | 
    kvaser_usb_hydra_set_cmd_transid 
 | 
                (cmd, kvaser_usb_hydra_get_next_transid(dev)); 
 | 
  
 | 
    err = kvaser_usb_send_cmd(dev, cmd, kvaser_usb_hydra_cmd_size(cmd)); 
 | 
    if (err) 
 | 
        goto end; 
 | 
  
 | 
    err = kvaser_usb_hydra_wait_cmd(dev, CMD_GET_SOFTWARE_DETAILS_RESP, 
 | 
                    cmd); 
 | 
    if (err) 
 | 
        goto end; 
 | 
  
 | 
    dev->fw_version = le32_to_cpu(cmd->sw_detail_res.sw_version); 
 | 
    flags = le32_to_cpu(cmd->sw_detail_res.sw_flags); 
 | 
  
 | 
    if (flags & KVASER_USB_HYDRA_SW_FLAG_FW_BAD) { 
 | 
        dev_err(&dev->intf->dev, 
 | 
            "Bad firmware, device refuse to run!\n"); 
 | 
        err = -EINVAL; 
 | 
        goto end; 
 | 
    } 
 | 
  
 | 
    if (flags & KVASER_USB_HYDRA_SW_FLAG_FW_BETA) 
 | 
        dev_info(&dev->intf->dev, "Beta firmware in use\n"); 
 | 
  
 | 
    if (flags & KVASER_USB_HYDRA_SW_FLAG_EXT_CAP) 
 | 
        card_data->capabilities |= KVASER_USB_CAP_EXT_CAP; 
 | 
  
 | 
    if (flags & KVASER_USB_HYDRA_SW_FLAG_EXT_CMD) 
 | 
        card_data->capabilities |= KVASER_USB_HYDRA_CAP_EXT_CMD; 
 | 
  
 | 
    if (flags & KVASER_USB_HYDRA_SW_FLAG_CANFD) 
 | 
        card_data->ctrlmode_supported |= CAN_CTRLMODE_FD; 
 | 
  
 | 
    if (flags & KVASER_USB_HYDRA_SW_FLAG_NONISO) 
 | 
        card_data->ctrlmode_supported |= CAN_CTRLMODE_FD_NON_ISO; 
 | 
  
 | 
    if (flags &  KVASER_USB_HYDRA_SW_FLAG_FREQ_80M) 
 | 
        dev->cfg = &kvaser_usb_hydra_dev_cfg_kcan; 
 | 
    else 
 | 
        dev->cfg = &kvaser_usb_hydra_dev_cfg_flexc; 
 | 
  
 | 
end: 
 | 
    kfree(cmd); 
 | 
  
 | 
    return err; 
 | 
} 
 | 
  
 | 
static int kvaser_usb_hydra_get_card_info(struct kvaser_usb *dev) 
 | 
{ 
 | 
    struct kvaser_cmd cmd; 
 | 
    int err; 
 | 
  
 | 
    err = kvaser_usb_hydra_send_simple_cmd(dev, CMD_GET_CARD_INFO_REQ, -1); 
 | 
    if (err) 
 | 
        return err; 
 | 
  
 | 
    memset(&cmd, 0, sizeof(struct kvaser_cmd)); 
 | 
    err = kvaser_usb_hydra_wait_cmd(dev, CMD_GET_CARD_INFO_RESP, &cmd); 
 | 
    if (err) 
 | 
        return err; 
 | 
  
 | 
    dev->nchannels = cmd.card_info.nchannels; 
 | 
    if (dev->nchannels > KVASER_USB_MAX_NET_DEVICES) 
 | 
        return -EINVAL; 
 | 
  
 | 
    return 0; 
 | 
} 
 | 
  
 | 
static int kvaser_usb_hydra_get_capabilities(struct kvaser_usb *dev) 
 | 
{ 
 | 
    int err; 
 | 
    u16 status; 
 | 
  
 | 
    if (!(dev->card_data.capabilities & KVASER_USB_CAP_EXT_CAP)) { 
 | 
        dev_info(&dev->intf->dev, 
 | 
             "No extended capability support. Upgrade your device.\n"); 
 | 
        return 0; 
 | 
    } 
 | 
  
 | 
    err = kvaser_usb_hydra_get_single_capability 
 | 
                    (dev, 
 | 
                     KVASER_USB_HYDRA_CAP_CMD_LISTEN_MODE, 
 | 
                     &status); 
 | 
    if (err) 
 | 
        return err; 
 | 
    if (status) 
 | 
        dev_info(&dev->intf->dev, 
 | 
             "KVASER_USB_HYDRA_CAP_CMD_LISTEN_MODE failed %u\n", 
 | 
             status); 
 | 
  
 | 
    err = kvaser_usb_hydra_get_single_capability 
 | 
                    (dev, 
 | 
                     KVASER_USB_HYDRA_CAP_CMD_ERR_REPORT, 
 | 
                     &status); 
 | 
    if (err) 
 | 
        return err; 
 | 
    if (status) 
 | 
        dev_info(&dev->intf->dev, 
 | 
             "KVASER_USB_HYDRA_CAP_CMD_ERR_REPORT failed %u\n", 
 | 
             status); 
 | 
  
 | 
    err = kvaser_usb_hydra_get_single_capability 
 | 
                    (dev, KVASER_USB_HYDRA_CAP_CMD_ONE_SHOT, 
 | 
                     &status); 
 | 
    if (err) 
 | 
        return err; 
 | 
    if (status) 
 | 
        dev_info(&dev->intf->dev, 
 | 
             "KVASER_USB_HYDRA_CAP_CMD_ONE_SHOT failed %u\n", 
 | 
             status); 
 | 
  
 | 
    return 0; 
 | 
} 
 | 
  
 | 
static int kvaser_usb_hydra_set_opt_mode(const struct kvaser_usb_net_priv *priv) 
 | 
{ 
 | 
    struct kvaser_usb *dev = priv->dev; 
 | 
    struct kvaser_cmd *cmd; 
 | 
    int err; 
 | 
  
 | 
    if ((priv->can.ctrlmode & 
 | 
        (CAN_CTRLMODE_FD | CAN_CTRLMODE_FD_NON_ISO)) == 
 | 
        CAN_CTRLMODE_FD_NON_ISO) { 
 | 
        netdev_warn(priv->netdev, 
 | 
                "CTRLMODE_FD shall be on if CTRLMODE_FD_NON_ISO is on\n"); 
 | 
        return -EINVAL; 
 | 
    } 
 | 
  
 | 
    cmd = kcalloc(1, sizeof(struct kvaser_cmd), GFP_KERNEL); 
 | 
    if (!cmd) 
 | 
        return -ENOMEM; 
 | 
  
 | 
    cmd->header.cmd_no = CMD_SET_DRIVERMODE_REQ; 
 | 
    kvaser_usb_hydra_set_cmd_dest_he 
 | 
        (cmd, dev->card_data.hydra.channel_to_he[priv->channel]); 
 | 
    kvaser_usb_hydra_set_cmd_transid 
 | 
                (cmd, kvaser_usb_hydra_get_next_transid(dev)); 
 | 
    if (priv->can.ctrlmode & CAN_CTRLMODE_LISTENONLY) 
 | 
        cmd->set_ctrlmode.mode = KVASER_USB_HYDRA_CTRLMODE_LISTEN; 
 | 
    else 
 | 
        cmd->set_ctrlmode.mode = KVASER_USB_HYDRA_CTRLMODE_NORMAL; 
 | 
  
 | 
    err = kvaser_usb_send_cmd(dev, cmd, kvaser_usb_hydra_cmd_size(cmd)); 
 | 
    kfree(cmd); 
 | 
  
 | 
    return err; 
 | 
} 
 | 
  
 | 
static int kvaser_usb_hydra_start_chip(struct kvaser_usb_net_priv *priv) 
 | 
{ 
 | 
    int err; 
 | 
  
 | 
    reinit_completion(&priv->start_comp); 
 | 
  
 | 
    err = kvaser_usb_hydra_send_simple_cmd(priv->dev, CMD_START_CHIP_REQ, 
 | 
                           priv->channel); 
 | 
    if (err) 
 | 
        return err; 
 | 
  
 | 
    if (!wait_for_completion_timeout(&priv->start_comp, 
 | 
                     msecs_to_jiffies(KVASER_USB_TIMEOUT))) 
 | 
        return -ETIMEDOUT; 
 | 
  
 | 
    return 0; 
 | 
} 
 | 
  
 | 
static int kvaser_usb_hydra_stop_chip(struct kvaser_usb_net_priv *priv) 
 | 
{ 
 | 
    int err; 
 | 
  
 | 
    reinit_completion(&priv->stop_comp); 
 | 
  
 | 
    /* Make sure we do not report invalid BUS_OFF from CMD_CHIP_STATE_EVENT 
 | 
     * see comment in kvaser_usb_hydra_update_state() 
 | 
     */ 
 | 
    priv->can.state = CAN_STATE_STOPPED; 
 | 
  
 | 
    err = kvaser_usb_hydra_send_simple_cmd(priv->dev, CMD_STOP_CHIP_REQ, 
 | 
                           priv->channel); 
 | 
    if (err) 
 | 
        return err; 
 | 
  
 | 
    if (!wait_for_completion_timeout(&priv->stop_comp, 
 | 
                     msecs_to_jiffies(KVASER_USB_TIMEOUT))) 
 | 
        return -ETIMEDOUT; 
 | 
  
 | 
    return 0; 
 | 
} 
 | 
  
 | 
static int kvaser_usb_hydra_flush_queue(struct kvaser_usb_net_priv *priv) 
 | 
{ 
 | 
    int err; 
 | 
  
 | 
    reinit_completion(&priv->flush_comp); 
 | 
  
 | 
    err = kvaser_usb_hydra_send_simple_cmd(priv->dev, CMD_FLUSH_QUEUE, 
 | 
                           priv->channel); 
 | 
    if (err) 
 | 
        return err; 
 | 
  
 | 
    if (!wait_for_completion_timeout(&priv->flush_comp, 
 | 
                     msecs_to_jiffies(KVASER_USB_TIMEOUT))) 
 | 
        return -ETIMEDOUT; 
 | 
  
 | 
    return 0; 
 | 
} 
 | 
  
 | 
/* A single extended hydra command can be transmitted in multiple transfers 
 | 
 * We have to buffer partial hydra commands, and handle them on next callback. 
 | 
 */ 
 | 
static void kvaser_usb_hydra_read_bulk_callback(struct kvaser_usb *dev, 
 | 
                        void *buf, int len) 
 | 
{ 
 | 
    unsigned long irq_flags; 
 | 
    struct kvaser_cmd *cmd; 
 | 
    int pos = 0; 
 | 
    size_t cmd_len; 
 | 
    struct kvaser_usb_dev_card_data_hydra *card_data = 
 | 
                            &dev->card_data.hydra; 
 | 
    int usb_rx_leftover_len; 
 | 
    spinlock_t *usb_rx_leftover_lock = &card_data->usb_rx_leftover_lock; 
 | 
  
 | 
    spin_lock_irqsave(usb_rx_leftover_lock, irq_flags); 
 | 
    usb_rx_leftover_len = card_data->usb_rx_leftover_len; 
 | 
    if (usb_rx_leftover_len) { 
 | 
        int remaining_bytes; 
 | 
  
 | 
        cmd = (struct kvaser_cmd *)card_data->usb_rx_leftover; 
 | 
  
 | 
        cmd_len = kvaser_usb_hydra_cmd_size(cmd); 
 | 
  
 | 
        remaining_bytes = min_t(unsigned int, len, 
 | 
                    cmd_len - usb_rx_leftover_len); 
 | 
        /* Make sure we do not overflow usb_rx_leftover */ 
 | 
        if (remaining_bytes + usb_rx_leftover_len > 
 | 
                        KVASER_USB_HYDRA_MAX_CMD_LEN) { 
 | 
            dev_err(&dev->intf->dev, "Format error\n"); 
 | 
            spin_unlock_irqrestore(usb_rx_leftover_lock, irq_flags); 
 | 
            return; 
 | 
        } 
 | 
  
 | 
        memcpy(card_data->usb_rx_leftover + usb_rx_leftover_len, buf, 
 | 
               remaining_bytes); 
 | 
        pos += remaining_bytes; 
 | 
  
 | 
        if (remaining_bytes + usb_rx_leftover_len == cmd_len) { 
 | 
            kvaser_usb_hydra_handle_cmd(dev, cmd); 
 | 
            usb_rx_leftover_len = 0; 
 | 
        } else { 
 | 
            /* Command still not complete */ 
 | 
            usb_rx_leftover_len += remaining_bytes; 
 | 
        } 
 | 
        card_data->usb_rx_leftover_len = usb_rx_leftover_len; 
 | 
    } 
 | 
    spin_unlock_irqrestore(usb_rx_leftover_lock, irq_flags); 
 | 
  
 | 
    while (pos < len) { 
 | 
        cmd = buf + pos; 
 | 
  
 | 
        cmd_len = kvaser_usb_hydra_cmd_size(cmd); 
 | 
  
 | 
        if (pos + cmd_len > len) { 
 | 
            /* We got first part of a command */ 
 | 
            int leftover_bytes; 
 | 
  
 | 
            leftover_bytes = len - pos; 
 | 
            /* Make sure we do not overflow usb_rx_leftover */ 
 | 
            if (leftover_bytes > KVASER_USB_HYDRA_MAX_CMD_LEN) { 
 | 
                dev_err(&dev->intf->dev, "Format error\n"); 
 | 
                return; 
 | 
            } 
 | 
            spin_lock_irqsave(usb_rx_leftover_lock, irq_flags); 
 | 
            memcpy(card_data->usb_rx_leftover, buf + pos, 
 | 
                   leftover_bytes); 
 | 
            card_data->usb_rx_leftover_len = leftover_bytes; 
 | 
            spin_unlock_irqrestore(usb_rx_leftover_lock, irq_flags); 
 | 
            break; 
 | 
        } 
 | 
  
 | 
        kvaser_usb_hydra_handle_cmd(dev, cmd); 
 | 
        pos += cmd_len; 
 | 
    } 
 | 
} 
 | 
  
 | 
static void * 
 | 
kvaser_usb_hydra_frame_to_cmd(const struct kvaser_usb_net_priv *priv, 
 | 
                  const struct sk_buff *skb, int *frame_len, 
 | 
                  int *cmd_len, u16 transid) 
 | 
{ 
 | 
    void *buf; 
 | 
  
 | 
    if (priv->dev->card_data.capabilities & KVASER_USB_HYDRA_CAP_EXT_CMD) 
 | 
        buf = kvaser_usb_hydra_frame_to_cmd_ext(priv, skb, frame_len, 
 | 
                            cmd_len, transid); 
 | 
    else 
 | 
        buf = kvaser_usb_hydra_frame_to_cmd_std(priv, skb, frame_len, 
 | 
                            cmd_len, transid); 
 | 
  
 | 
    return buf; 
 | 
} 
 | 
  
 | 
const struct kvaser_usb_dev_ops kvaser_usb_hydra_dev_ops = { 
 | 
    .dev_set_mode = kvaser_usb_hydra_set_mode, 
 | 
    .dev_set_bittiming = kvaser_usb_hydra_set_bittiming, 
 | 
    .dev_set_data_bittiming = kvaser_usb_hydra_set_data_bittiming, 
 | 
    .dev_get_berr_counter = kvaser_usb_hydra_get_berr_counter, 
 | 
    .dev_setup_endpoints = kvaser_usb_hydra_setup_endpoints, 
 | 
    .dev_init_card = kvaser_usb_hydra_init_card, 
 | 
    .dev_get_software_info = kvaser_usb_hydra_get_software_info, 
 | 
    .dev_get_software_details = kvaser_usb_hydra_get_software_details, 
 | 
    .dev_get_card_info = kvaser_usb_hydra_get_card_info, 
 | 
    .dev_get_capabilities = kvaser_usb_hydra_get_capabilities, 
 | 
    .dev_set_opt_mode = kvaser_usb_hydra_set_opt_mode, 
 | 
    .dev_start_chip = kvaser_usb_hydra_start_chip, 
 | 
    .dev_stop_chip = kvaser_usb_hydra_stop_chip, 
 | 
    .dev_reset_chip = NULL, 
 | 
    .dev_flush_queue = kvaser_usb_hydra_flush_queue, 
 | 
    .dev_read_bulk_callback = kvaser_usb_hydra_read_bulk_callback, 
 | 
    .dev_frame_to_cmd = kvaser_usb_hydra_frame_to_cmd, 
 | 
}; 
 | 
  
 | 
static const struct kvaser_usb_dev_cfg kvaser_usb_hydra_dev_cfg_kcan = { 
 | 
    .clock = { 
 | 
        .freq = 80000000, 
 | 
    }, 
 | 
    .timestamp_freq = 80, 
 | 
    .bittiming_const = &kvaser_usb_hydra_kcan_bittiming_c, 
 | 
    .data_bittiming_const = &kvaser_usb_hydra_kcan_bittiming_c, 
 | 
}; 
 | 
  
 | 
static const struct kvaser_usb_dev_cfg kvaser_usb_hydra_dev_cfg_flexc = { 
 | 
    .clock = { 
 | 
        .freq = 24000000, 
 | 
    }, 
 | 
    .timestamp_freq = 1, 
 | 
    .bittiming_const = &kvaser_usb_flexc_bittiming_const, 
 | 
}; 
 |