17259124eSJimmy Assarsson // SPDX-License-Identifier: GPL-2.0
27259124eSJimmy Assarsson /* Parts of this driver are based on the following:
37259124eSJimmy Assarsson * - Kvaser linux leaf driver (version 4.78)
47259124eSJimmy Assarsson * - CAN driver for esd CAN-USB/2
57259124eSJimmy Assarsson * - Kvaser linux usbcanII driver (version 5.3)
67259124eSJimmy Assarsson *
77259124eSJimmy Assarsson * Copyright (C) 2002-2018 KVASER AB, Sweden. All rights reserved.
87259124eSJimmy Assarsson * Copyright (C) 2010 Matthias Fuchs <matthias.fuchs@esd.eu>, esd gmbh
97259124eSJimmy Assarsson * Copyright (C) 2012 Olivier Sobrie <olivier@sobrie.be>
107259124eSJimmy Assarsson * Copyright (C) 2015 Valeo S.A.
117259124eSJimmy Assarsson */
127259124eSJimmy Assarsson
13478248f1SJimmy Assarsson #include <linux/bitfield.h>
147259124eSJimmy Assarsson #include <linux/completion.h>
157259124eSJimmy Assarsson #include <linux/device.h>
167259124eSJimmy Assarsson #include <linux/gfp.h>
177259124eSJimmy Assarsson #include <linux/jiffies.h>
187259124eSJimmy Assarsson #include <linux/kernel.h>
197259124eSJimmy Assarsson #include <linux/netdevice.h>
207259124eSJimmy Assarsson #include <linux/spinlock.h>
217259124eSJimmy Assarsson #include <linux/string.h>
227259124eSJimmy Assarsson #include <linux/types.h>
23b8f91799SJimmy Assarsson #include <linux/units.h>
247259124eSJimmy Assarsson #include <linux/usb.h>
258d21f592SAnssi Hannula #include <linux/workqueue.h>
267259124eSJimmy Assarsson
277259124eSJimmy Assarsson #include <linux/can.h>
287259124eSJimmy Assarsson #include <linux/can/dev.h>
297259124eSJimmy Assarsson #include <linux/can/error.h>
307259124eSJimmy Assarsson #include <linux/can/netlink.h>
317259124eSJimmy Assarsson
327259124eSJimmy Assarsson #include "kvaser_usb.h"
337259124eSJimmy Assarsson
347259124eSJimmy Assarsson #define MAX_USBCAN_NET_DEVICES 2
357259124eSJimmy Assarsson
367259124eSJimmy Assarsson /* Command header size */
377259124eSJimmy Assarsson #define CMD_HEADER_LEN 2
387259124eSJimmy Assarsson
397259124eSJimmy Assarsson /* Kvaser CAN message flags */
407259124eSJimmy Assarsson #define MSG_FLAG_ERROR_FRAME BIT(0)
417259124eSJimmy Assarsson #define MSG_FLAG_OVERRUN BIT(1)
427259124eSJimmy Assarsson #define MSG_FLAG_NERR BIT(2)
437259124eSJimmy Assarsson #define MSG_FLAG_WAKEUP BIT(3)
447259124eSJimmy Assarsson #define MSG_FLAG_REMOTE_FRAME BIT(4)
457259124eSJimmy Assarsson #define MSG_FLAG_RESERVED BIT(5)
467259124eSJimmy Assarsson #define MSG_FLAG_TX_ACK BIT(6)
477259124eSJimmy Assarsson #define MSG_FLAG_TX_REQUEST BIT(7)
487259124eSJimmy Assarsson
497259124eSJimmy Assarsson /* CAN states (M16C CxSTRH register) */
507259124eSJimmy Assarsson #define M16C_STATE_BUS_RESET BIT(0)
517259124eSJimmy Assarsson #define M16C_STATE_BUS_ERROR BIT(4)
527259124eSJimmy Assarsson #define M16C_STATE_BUS_PASSIVE BIT(5)
537259124eSJimmy Assarsson #define M16C_STATE_BUS_OFF BIT(6)
547259124eSJimmy Assarsson
557259124eSJimmy Assarsson /* Leaf/usbcan command ids */
567259124eSJimmy Assarsson #define CMD_RX_STD_MESSAGE 12
577259124eSJimmy Assarsson #define CMD_TX_STD_MESSAGE 13
587259124eSJimmy Assarsson #define CMD_RX_EXT_MESSAGE 14
597259124eSJimmy Assarsson #define CMD_TX_EXT_MESSAGE 15
607259124eSJimmy Assarsson #define CMD_SET_BUS_PARAMS 16
6139d3df6bSJimmy Assarsson #define CMD_GET_BUS_PARAMS 17
6239d3df6bSJimmy Assarsson #define CMD_GET_BUS_PARAMS_REPLY 18
638d21f592SAnssi Hannula #define CMD_GET_CHIP_STATE 19
647259124eSJimmy Assarsson #define CMD_CHIP_STATE_EVENT 20
657259124eSJimmy Assarsson #define CMD_SET_CTRL_MODE 21
667259124eSJimmy Assarsson #define CMD_RESET_CHIP 24
677259124eSJimmy Assarsson #define CMD_START_CHIP 26
687259124eSJimmy Assarsson #define CMD_START_CHIP_REPLY 27
697259124eSJimmy Assarsson #define CMD_STOP_CHIP 28
707259124eSJimmy Assarsson #define CMD_STOP_CHIP_REPLY 29
717259124eSJimmy Assarsson
727259124eSJimmy Assarsson #define CMD_USBCAN_CLOCK_OVERFLOW_EVENT 33
737259124eSJimmy Assarsson
747259124eSJimmy Assarsson #define CMD_GET_CARD_INFO 34
757259124eSJimmy Assarsson #define CMD_GET_CARD_INFO_REPLY 35
767259124eSJimmy Assarsson #define CMD_GET_SOFTWARE_INFO 38
777259124eSJimmy Assarsson #define CMD_GET_SOFTWARE_INFO_REPLY 39
78b24cb2d1SJimmy Assarsson #define CMD_ERROR_EVENT 45
797259124eSJimmy Assarsson #define CMD_FLUSH_QUEUE 48
807259124eSJimmy Assarsson #define CMD_TX_ACKNOWLEDGE 50
817259124eSJimmy Assarsson #define CMD_CAN_ERROR_EVENT 51
827259124eSJimmy Assarsson #define CMD_FLUSH_QUEUE_REPLY 68
8335364f5bSJimmy Assarsson #define CMD_GET_CAPABILITIES_REQ 95
8435364f5bSJimmy Assarsson #define CMD_GET_CAPABILITIES_RESP 96
85478248f1SJimmy Assarsson #define CMD_LED_ACTION_REQ 101
86478248f1SJimmy Assarsson #define CMD_LED_ACTION_RESP 102
877259124eSJimmy Assarsson
887259124eSJimmy Assarsson #define CMD_LEAF_LOG_MESSAGE 106
897259124eSJimmy Assarsson
90fb12797aSJimmy Assarsson /* Leaf frequency options */
91fb12797aSJimmy Assarsson #define KVASER_USB_LEAF_SWOPTION_FREQ_MASK 0x60
92fb12797aSJimmy Assarsson #define KVASER_USB_LEAF_SWOPTION_FREQ_16_MHZ_CLK 0
93fb12797aSJimmy Assarsson #define KVASER_USB_LEAF_SWOPTION_FREQ_32_MHZ_CLK BIT(5)
94fb12797aSJimmy Assarsson #define KVASER_USB_LEAF_SWOPTION_FREQ_24_MHZ_CLK BIT(6)
95fb12797aSJimmy Assarsson
9635364f5bSJimmy Assarsson #define KVASER_USB_LEAF_SWOPTION_EXT_CAP BIT(12)
9735364f5bSJimmy Assarsson
987259124eSJimmy Assarsson /* error factors */
997259124eSJimmy Assarsson #define M16C_EF_ACKE BIT(0)
1007259124eSJimmy Assarsson #define M16C_EF_CRCE BIT(1)
1017259124eSJimmy Assarsson #define M16C_EF_FORME BIT(2)
1027259124eSJimmy Assarsson #define M16C_EF_STFE BIT(3)
1037259124eSJimmy Assarsson #define M16C_EF_BITE0 BIT(4)
1047259124eSJimmy Assarsson #define M16C_EF_BITE1 BIT(5)
1057259124eSJimmy Assarsson #define M16C_EF_RCVE BIT(6)
1067259124eSJimmy Assarsson #define M16C_EF_TRE BIT(7)
1077259124eSJimmy Assarsson
1087259124eSJimmy Assarsson /* Only Leaf-based devices can report M16C error factors,
1097259124eSJimmy Assarsson * thus define our own error status flags for USBCANII
1107259124eSJimmy Assarsson */
1117259124eSJimmy Assarsson #define USBCAN_ERROR_STATE_NONE 0
1127259124eSJimmy Assarsson #define USBCAN_ERROR_STATE_TX_ERROR BIT(0)
1137259124eSJimmy Assarsson #define USBCAN_ERROR_STATE_RX_ERROR BIT(1)
1147259124eSJimmy Assarsson #define USBCAN_ERROR_STATE_BUSERROR BIT(2)
1157259124eSJimmy Assarsson
1167259124eSJimmy Assarsson /* ctrl modes */
1177259124eSJimmy Assarsson #define KVASER_CTRL_MODE_NORMAL 1
1187259124eSJimmy Assarsson #define KVASER_CTRL_MODE_SILENT 2
1197259124eSJimmy Assarsson #define KVASER_CTRL_MODE_SELFRECEPTION 3
1207259124eSJimmy Assarsson #define KVASER_CTRL_MODE_OFF 4
1217259124eSJimmy Assarsson
1227259124eSJimmy Assarsson /* Extended CAN identifier flag */
1237259124eSJimmy Assarsson #define KVASER_EXTENDED_FRAME BIT(31)
1247259124eSJimmy Assarsson
125c644c969SJimmy Assarsson /* USBCanII timestamp */
126c644c969SJimmy Assarsson #define KVASER_USB_USBCAN_CLK_OVERFLOW_MASK GENMASK(31, 16)
1270aa639d3SJimmy Assarsson #define KVASER_USB_USBCAN_TIMESTAMP_FACTOR 10
128c644c969SJimmy Assarsson
1297259124eSJimmy Assarsson struct kvaser_cmd_simple {
1307259124eSJimmy Assarsson u8 tid;
1317259124eSJimmy Assarsson u8 channel;
1327259124eSJimmy Assarsson } __packed;
1337259124eSJimmy Assarsson
1347259124eSJimmy Assarsson struct kvaser_cmd_cardinfo {
1357259124eSJimmy Assarsson u8 tid;
1367259124eSJimmy Assarsson u8 nchannels;
1377259124eSJimmy Assarsson __le32 serial_number;
1381f6ed42cSJimmy Assarsson __le32 padding0;
1397259124eSJimmy Assarsson __le32 clock_resolution;
1407259124eSJimmy Assarsson __le32 mfgdate;
141*0020f2baSJimmy Assarsson __le32 ean[2];
1427259124eSJimmy Assarsson u8 hw_revision;
1437259124eSJimmy Assarsson union {
1447259124eSJimmy Assarsson struct {
1457259124eSJimmy Assarsson u8 usb_hs_mode;
1467259124eSJimmy Assarsson } __packed leaf1;
1477259124eSJimmy Assarsson struct {
1487259124eSJimmy Assarsson u8 padding;
1497259124eSJimmy Assarsson } __packed usbcan1;
1507259124eSJimmy Assarsson } __packed;
1511f6ed42cSJimmy Assarsson __le16 padding1;
1527259124eSJimmy Assarsson } __packed;
1537259124eSJimmy Assarsson
1547259124eSJimmy Assarsson struct leaf_cmd_softinfo {
1557259124eSJimmy Assarsson u8 tid;
1567259124eSJimmy Assarsson u8 padding0;
1577259124eSJimmy Assarsson __le32 sw_options;
1587259124eSJimmy Assarsson __le32 fw_version;
1597259124eSJimmy Assarsson __le16 max_outstanding_tx;
1607259124eSJimmy Assarsson __le16 padding1[9];
1617259124eSJimmy Assarsson } __packed;
1627259124eSJimmy Assarsson
1637259124eSJimmy Assarsson struct usbcan_cmd_softinfo {
1647259124eSJimmy Assarsson u8 tid;
1657259124eSJimmy Assarsson u8 fw_name[5];
1667259124eSJimmy Assarsson __le16 max_outstanding_tx;
1677259124eSJimmy Assarsson u8 padding[6];
1687259124eSJimmy Assarsson __le32 fw_version;
1697259124eSJimmy Assarsson __le16 checksum;
1707259124eSJimmy Assarsson __le16 sw_options;
1717259124eSJimmy Assarsson } __packed;
1727259124eSJimmy Assarsson
1737259124eSJimmy Assarsson struct kvaser_cmd_busparams {
1747259124eSJimmy Assarsson u8 tid;
1757259124eSJimmy Assarsson u8 channel;
17600e57861SJimmy Assarsson struct kvaser_usb_busparams busparams;
1777259124eSJimmy Assarsson } __packed;
1787259124eSJimmy Assarsson
179478248f1SJimmy Assarsson /* The device has one LED per CAN channel
180478248f1SJimmy Assarsson * The LSB of action field controls the state:
181478248f1SJimmy Assarsson * 0 = ON
182478248f1SJimmy Assarsson * 1 = OFF
183478248f1SJimmy Assarsson * The remaining bits of action field is the LED index
184478248f1SJimmy Assarsson */
185478248f1SJimmy Assarsson #define KVASER_USB_LEAF_LED_IDX_MASK GENMASK(31, 1)
186478248f1SJimmy Assarsson #define KVASER_USB_LEAF_LED_YELLOW_CH0_IDX 2
187478248f1SJimmy Assarsson struct kvaser_cmd_led_action_req {
188478248f1SJimmy Assarsson u8 tid;
189478248f1SJimmy Assarsson u8 action;
190478248f1SJimmy Assarsson __le16 duration_ms;
191478248f1SJimmy Assarsson u8 padding[24];
192478248f1SJimmy Assarsson } __packed;
193478248f1SJimmy Assarsson
1947259124eSJimmy Assarsson struct kvaser_cmd_tx_can {
1957259124eSJimmy Assarsson u8 channel;
1967259124eSJimmy Assarsson u8 tid;
1977259124eSJimmy Assarsson u8 data[14];
1987259124eSJimmy Assarsson union {
1997259124eSJimmy Assarsson struct {
2007259124eSJimmy Assarsson u8 padding;
2017259124eSJimmy Assarsson u8 flags;
2027259124eSJimmy Assarsson } __packed leaf;
2037259124eSJimmy Assarsson struct {
2047259124eSJimmy Assarsson u8 flags;
2057259124eSJimmy Assarsson u8 padding;
2067259124eSJimmy Assarsson } __packed usbcan;
2077259124eSJimmy Assarsson } __packed;
2087259124eSJimmy Assarsson } __packed;
2097259124eSJimmy Assarsson
2107259124eSJimmy Assarsson struct kvaser_cmd_rx_can_header {
2117259124eSJimmy Assarsson u8 channel;
2127259124eSJimmy Assarsson u8 flag;
2137259124eSJimmy Assarsson } __packed;
2147259124eSJimmy Assarsson
2157259124eSJimmy Assarsson struct leaf_cmd_rx_can {
2167259124eSJimmy Assarsson u8 channel;
2177259124eSJimmy Assarsson u8 flag;
2187259124eSJimmy Assarsson
2197259124eSJimmy Assarsson __le16 time[3];
2207259124eSJimmy Assarsson u8 data[14];
2217259124eSJimmy Assarsson } __packed;
2227259124eSJimmy Assarsson
2237259124eSJimmy Assarsson struct usbcan_cmd_rx_can {
2247259124eSJimmy Assarsson u8 channel;
2257259124eSJimmy Assarsson u8 flag;
2267259124eSJimmy Assarsson
2277259124eSJimmy Assarsson u8 data[14];
2287259124eSJimmy Assarsson __le16 time;
2297259124eSJimmy Assarsson } __packed;
2307259124eSJimmy Assarsson
2317259124eSJimmy Assarsson struct leaf_cmd_chip_state_event {
2327259124eSJimmy Assarsson u8 tid;
2337259124eSJimmy Assarsson u8 channel;
2347259124eSJimmy Assarsson
2357259124eSJimmy Assarsson __le16 time[3];
2367259124eSJimmy Assarsson u8 tx_errors_count;
2377259124eSJimmy Assarsson u8 rx_errors_count;
2387259124eSJimmy Assarsson
2397259124eSJimmy Assarsson u8 status;
2407259124eSJimmy Assarsson u8 padding[3];
2417259124eSJimmy Assarsson } __packed;
2427259124eSJimmy Assarsson
2437259124eSJimmy Assarsson struct usbcan_cmd_chip_state_event {
2447259124eSJimmy Assarsson u8 tid;
2457259124eSJimmy Assarsson u8 channel;
2467259124eSJimmy Assarsson
2477259124eSJimmy Assarsson u8 tx_errors_count;
2487259124eSJimmy Assarsson u8 rx_errors_count;
2497259124eSJimmy Assarsson __le16 time;
2507259124eSJimmy Assarsson
2517259124eSJimmy Assarsson u8 status;
2527259124eSJimmy Assarsson u8 padding[3];
2537259124eSJimmy Assarsson } __packed;
2547259124eSJimmy Assarsson
2557259124eSJimmy Assarsson struct kvaser_cmd_tx_acknowledge_header {
2567259124eSJimmy Assarsson u8 channel;
2577259124eSJimmy Assarsson u8 tid;
2587259124eSJimmy Assarsson } __packed;
2597259124eSJimmy Assarsson
2608e789594SJimmy Assarsson struct leaf_cmd_tx_acknowledge {
2618e789594SJimmy Assarsson u8 channel;
2628e789594SJimmy Assarsson u8 tid;
2638e789594SJimmy Assarsson __le16 time[3];
2648e789594SJimmy Assarsson u8 padding[2];
2658e789594SJimmy Assarsson } __packed;
2668e789594SJimmy Assarsson
267a7cfb220SJimmy Assarsson struct usbcan_cmd_tx_acknowledge {
268a7cfb220SJimmy Assarsson u8 channel;
269a7cfb220SJimmy Assarsson u8 tid;
270a7cfb220SJimmy Assarsson __le16 time;
271a7cfb220SJimmy Assarsson u8 padding[2];
272a7cfb220SJimmy Assarsson } __packed;
273a7cfb220SJimmy Assarsson
2747ea56128SJimmy Assarsson struct leaf_cmd_can_error_event {
2757259124eSJimmy Assarsson u8 tid;
2767259124eSJimmy Assarsson u8 flags;
2777259124eSJimmy Assarsson __le16 time[3];
2787259124eSJimmy Assarsson u8 channel;
2797259124eSJimmy Assarsson u8 padding;
2807259124eSJimmy Assarsson u8 tx_errors_count;
2817259124eSJimmy Assarsson u8 rx_errors_count;
2827259124eSJimmy Assarsson u8 status;
2837259124eSJimmy Assarsson u8 error_factor;
2847259124eSJimmy Assarsson } __packed;
2857259124eSJimmy Assarsson
2867ea56128SJimmy Assarsson struct usbcan_cmd_can_error_event {
2877259124eSJimmy Assarsson u8 tid;
2887259124eSJimmy Assarsson u8 padding;
2897259124eSJimmy Assarsson u8 tx_errors_count_ch0;
2907259124eSJimmy Assarsson u8 rx_errors_count_ch0;
2917259124eSJimmy Assarsson u8 tx_errors_count_ch1;
2927259124eSJimmy Assarsson u8 rx_errors_count_ch1;
2937259124eSJimmy Assarsson u8 status_ch0;
2947259124eSJimmy Assarsson u8 status_ch1;
2957259124eSJimmy Assarsson __le16 time;
2967259124eSJimmy Assarsson } __packed;
2977259124eSJimmy Assarsson
298b24cb2d1SJimmy Assarsson /* CMD_ERROR_EVENT error codes */
299b24cb2d1SJimmy Assarsson #define KVASER_USB_LEAF_ERROR_EVENT_TX_QUEUE_FULL 0x8
300b24cb2d1SJimmy Assarsson #define KVASER_USB_LEAF_ERROR_EVENT_PARAM 0x9
301b24cb2d1SJimmy Assarsson
302b24cb2d1SJimmy Assarsson struct leaf_cmd_error_event {
303b24cb2d1SJimmy Assarsson u8 tid;
304b24cb2d1SJimmy Assarsson u8 error_code;
305b24cb2d1SJimmy Assarsson __le16 timestamp[3];
306b24cb2d1SJimmy Assarsson __le16 padding;
307b24cb2d1SJimmy Assarsson __le16 info1;
308b24cb2d1SJimmy Assarsson __le16 info2;
309b24cb2d1SJimmy Assarsson } __packed;
310b24cb2d1SJimmy Assarsson
311b24cb2d1SJimmy Assarsson struct usbcan_cmd_error_event {
312b24cb2d1SJimmy Assarsson u8 tid;
313b24cb2d1SJimmy Assarsson u8 error_code;
314b24cb2d1SJimmy Assarsson __le16 info1;
315b24cb2d1SJimmy Assarsson __le16 info2;
316b24cb2d1SJimmy Assarsson __le16 timestamp;
317b24cb2d1SJimmy Assarsson __le16 padding;
318b24cb2d1SJimmy Assarsson } __packed;
319b24cb2d1SJimmy Assarsson
320a7cfb220SJimmy Assarsson struct usbcan_cmd_clk_overflow_event {
321a7cfb220SJimmy Assarsson u8 tid;
322a7cfb220SJimmy Assarsson u8 padding;
323a7cfb220SJimmy Assarsson __le32 time;
324a7cfb220SJimmy Assarsson } __packed;
325a7cfb220SJimmy Assarsson
3267259124eSJimmy Assarsson struct kvaser_cmd_ctrl_mode {
3277259124eSJimmy Assarsson u8 tid;
3287259124eSJimmy Assarsson u8 channel;
3297259124eSJimmy Assarsson u8 ctrl_mode;
3307259124eSJimmy Assarsson u8 padding[3];
3317259124eSJimmy Assarsson } __packed;
3327259124eSJimmy Assarsson
3337259124eSJimmy Assarsson struct kvaser_cmd_flush_queue {
3347259124eSJimmy Assarsson u8 tid;
3357259124eSJimmy Assarsson u8 channel;
3367259124eSJimmy Assarsson u8 flags;
3377259124eSJimmy Assarsson u8 padding[3];
3387259124eSJimmy Assarsson } __packed;
3397259124eSJimmy Assarsson
3407259124eSJimmy Assarsson struct leaf_cmd_log_message {
3417259124eSJimmy Assarsson u8 channel;
3427259124eSJimmy Assarsson u8 flags;
3437259124eSJimmy Assarsson __le16 time[3];
3447259124eSJimmy Assarsson u8 dlc;
3457259124eSJimmy Assarsson u8 time_offset;
3467259124eSJimmy Assarsson __le32 id;
3477259124eSJimmy Assarsson u8 data[8];
3487259124eSJimmy Assarsson } __packed;
3497259124eSJimmy Assarsson
35035364f5bSJimmy Assarsson /* Sub commands for cap_req and cap_res */
35135364f5bSJimmy Assarsson #define KVASER_USB_LEAF_CAP_CMD_LISTEN_MODE 0x02
35235364f5bSJimmy Assarsson #define KVASER_USB_LEAF_CAP_CMD_ERR_REPORT 0x05
35335364f5bSJimmy Assarsson struct kvaser_cmd_cap_req {
35435364f5bSJimmy Assarsson __le16 padding0;
35535364f5bSJimmy Assarsson __le16 cap_cmd;
35635364f5bSJimmy Assarsson __le16 padding1;
35735364f5bSJimmy Assarsson __le16 channel;
35835364f5bSJimmy Assarsson } __packed;
35935364f5bSJimmy Assarsson
36035364f5bSJimmy Assarsson /* Status codes for cap_res */
36135364f5bSJimmy Assarsson #define KVASER_USB_LEAF_CAP_STAT_OK 0x00
36235364f5bSJimmy Assarsson #define KVASER_USB_LEAF_CAP_STAT_NOT_IMPL 0x01
36335364f5bSJimmy Assarsson #define KVASER_USB_LEAF_CAP_STAT_UNAVAIL 0x02
36435364f5bSJimmy Assarsson struct kvaser_cmd_cap_res {
36535364f5bSJimmy Assarsson __le16 padding;
36635364f5bSJimmy Assarsson __le16 cap_cmd;
36735364f5bSJimmy Assarsson __le16 status;
36835364f5bSJimmy Assarsson __le32 mask;
36935364f5bSJimmy Assarsson __le32 value;
37035364f5bSJimmy Assarsson } __packed;
37135364f5bSJimmy Assarsson
3727259124eSJimmy Assarsson struct kvaser_cmd {
3737259124eSJimmy Assarsson u8 len;
3747259124eSJimmy Assarsson u8 id;
3757259124eSJimmy Assarsson union {
3767259124eSJimmy Assarsson struct kvaser_cmd_simple simple;
3777259124eSJimmy Assarsson struct kvaser_cmd_cardinfo cardinfo;
3787259124eSJimmy Assarsson struct kvaser_cmd_busparams busparams;
3797259124eSJimmy Assarsson
380478248f1SJimmy Assarsson struct kvaser_cmd_led_action_req led_action_req;
381478248f1SJimmy Assarsson
3827259124eSJimmy Assarsson struct kvaser_cmd_rx_can_header rx_can_header;
3837259124eSJimmy Assarsson struct kvaser_cmd_tx_acknowledge_header tx_acknowledge_header;
3847259124eSJimmy Assarsson
3857259124eSJimmy Assarsson union {
3867259124eSJimmy Assarsson struct leaf_cmd_softinfo softinfo;
3877259124eSJimmy Assarsson struct leaf_cmd_rx_can rx_can;
3887259124eSJimmy Assarsson struct leaf_cmd_chip_state_event chip_state_event;
3897ea56128SJimmy Assarsson struct leaf_cmd_can_error_event can_error_event;
3907259124eSJimmy Assarsson struct leaf_cmd_log_message log_message;
391b24cb2d1SJimmy Assarsson struct leaf_cmd_error_event error_event;
39235364f5bSJimmy Assarsson struct kvaser_cmd_cap_req cap_req;
39335364f5bSJimmy Assarsson struct kvaser_cmd_cap_res cap_res;
3948e789594SJimmy Assarsson struct leaf_cmd_tx_acknowledge tx_ack;
3957259124eSJimmy Assarsson } __packed leaf;
3967259124eSJimmy Assarsson
3977259124eSJimmy Assarsson union {
3987259124eSJimmy Assarsson struct usbcan_cmd_softinfo softinfo;
3997259124eSJimmy Assarsson struct usbcan_cmd_rx_can rx_can;
4007259124eSJimmy Assarsson struct usbcan_cmd_chip_state_event chip_state_event;
4017ea56128SJimmy Assarsson struct usbcan_cmd_can_error_event can_error_event;
402b24cb2d1SJimmy Assarsson struct usbcan_cmd_error_event error_event;
403a7cfb220SJimmy Assarsson struct usbcan_cmd_tx_acknowledge tx_ack;
404a7cfb220SJimmy Assarsson struct usbcan_cmd_clk_overflow_event clk_overflow_event;
4057259124eSJimmy Assarsson } __packed usbcan;
4067259124eSJimmy Assarsson
4077259124eSJimmy Assarsson struct kvaser_cmd_tx_can tx_can;
4087259124eSJimmy Assarsson struct kvaser_cmd_ctrl_mode ctrl_mode;
4097259124eSJimmy Assarsson struct kvaser_cmd_flush_queue flush_queue;
4107259124eSJimmy Assarsson } u;
4117259124eSJimmy Assarsson } __packed;
4127259124eSJimmy Assarsson
4131499ecaeSAnssi Hannula #define CMD_SIZE_ANY 0xff
4141499ecaeSAnssi Hannula #define kvaser_fsize(field) sizeof_field(struct kvaser_cmd, field)
4151499ecaeSAnssi Hannula
4161499ecaeSAnssi Hannula static const u8 kvaser_usb_leaf_cmd_sizes_leaf[] = {
4171499ecaeSAnssi Hannula [CMD_START_CHIP_REPLY] = kvaser_fsize(u.simple),
4181499ecaeSAnssi Hannula [CMD_STOP_CHIP_REPLY] = kvaser_fsize(u.simple),
4191499ecaeSAnssi Hannula [CMD_GET_CARD_INFO_REPLY] = kvaser_fsize(u.cardinfo),
4208e789594SJimmy Assarsson [CMD_TX_ACKNOWLEDGE] = kvaser_fsize(u.leaf.tx_ack),
4211499ecaeSAnssi Hannula [CMD_GET_SOFTWARE_INFO_REPLY] = kvaser_fsize(u.leaf.softinfo),
4221499ecaeSAnssi Hannula [CMD_RX_STD_MESSAGE] = kvaser_fsize(u.leaf.rx_can),
4231499ecaeSAnssi Hannula [CMD_RX_EXT_MESSAGE] = kvaser_fsize(u.leaf.rx_can),
4241499ecaeSAnssi Hannula [CMD_LEAF_LOG_MESSAGE] = kvaser_fsize(u.leaf.log_message),
4251499ecaeSAnssi Hannula [CMD_CHIP_STATE_EVENT] = kvaser_fsize(u.leaf.chip_state_event),
4267ea56128SJimmy Assarsson [CMD_CAN_ERROR_EVENT] = kvaser_fsize(u.leaf.can_error_event),
42735364f5bSJimmy Assarsson [CMD_GET_CAPABILITIES_RESP] = kvaser_fsize(u.leaf.cap_res),
42839d3df6bSJimmy Assarsson [CMD_GET_BUS_PARAMS_REPLY] = kvaser_fsize(u.busparams),
429b24cb2d1SJimmy Assarsson [CMD_ERROR_EVENT] = kvaser_fsize(u.leaf.error_event),
4301499ecaeSAnssi Hannula /* ignored events: */
4311499ecaeSAnssi Hannula [CMD_FLUSH_QUEUE_REPLY] = CMD_SIZE_ANY,
432478248f1SJimmy Assarsson [CMD_LED_ACTION_RESP] = CMD_SIZE_ANY,
4331499ecaeSAnssi Hannula };
4341499ecaeSAnssi Hannula
4351499ecaeSAnssi Hannula static const u8 kvaser_usb_leaf_cmd_sizes_usbcan[] = {
4361499ecaeSAnssi Hannula [CMD_START_CHIP_REPLY] = kvaser_fsize(u.simple),
4371499ecaeSAnssi Hannula [CMD_STOP_CHIP_REPLY] = kvaser_fsize(u.simple),
4381499ecaeSAnssi Hannula [CMD_GET_CARD_INFO_REPLY] = kvaser_fsize(u.cardinfo),
439a7cfb220SJimmy Assarsson [CMD_TX_ACKNOWLEDGE] = kvaser_fsize(u.usbcan.tx_ack),
4401499ecaeSAnssi Hannula [CMD_GET_SOFTWARE_INFO_REPLY] = kvaser_fsize(u.usbcan.softinfo),
4411499ecaeSAnssi Hannula [CMD_RX_STD_MESSAGE] = kvaser_fsize(u.usbcan.rx_can),
4421499ecaeSAnssi Hannula [CMD_RX_EXT_MESSAGE] = kvaser_fsize(u.usbcan.rx_can),
4431499ecaeSAnssi Hannula [CMD_CHIP_STATE_EVENT] = kvaser_fsize(u.usbcan.chip_state_event),
4447ea56128SJimmy Assarsson [CMD_CAN_ERROR_EVENT] = kvaser_fsize(u.usbcan.can_error_event),
445b24cb2d1SJimmy Assarsson [CMD_ERROR_EVENT] = kvaser_fsize(u.usbcan.error_event),
446a7cfb220SJimmy Assarsson [CMD_USBCAN_CLOCK_OVERFLOW_EVENT] = kvaser_fsize(u.usbcan.clk_overflow_event),
447478248f1SJimmy Assarsson /* ignored events: */
448478248f1SJimmy Assarsson [CMD_LED_ACTION_RESP] = CMD_SIZE_ANY,
4491499ecaeSAnssi Hannula };
4501499ecaeSAnssi Hannula
4517259124eSJimmy Assarsson /* Summary of a kvaser error event, for a unified Leaf/Usbcan error
4527259124eSJimmy Assarsson * handling. Some discrepancies between the two families exist:
4537259124eSJimmy Assarsson *
4547259124eSJimmy Assarsson * - USBCAN firmware does not report M16C "error factors"
4557259124eSJimmy Assarsson * - USBCAN controllers has difficulties reporting if the raised error
4567259124eSJimmy Assarsson * event is for ch0 or ch1. They leave such arbitration to the OS
4577259124eSJimmy Assarsson * driver by letting it compare error counters with previous values
4587259124eSJimmy Assarsson * and decide the error event's channel. Thus for USBCAN, the channel
4597259124eSJimmy Assarsson * field is only advisory.
4607259124eSJimmy Assarsson */
4617259124eSJimmy Assarsson struct kvaser_usb_err_summary {
4627259124eSJimmy Assarsson u8 channel, status, txerr, rxerr;
4637259124eSJimmy Assarsson union {
4647259124eSJimmy Assarsson struct {
4657259124eSJimmy Assarsson u8 error_factor;
4667259124eSJimmy Assarsson } leaf;
4677259124eSJimmy Assarsson struct {
4687259124eSJimmy Assarsson u8 other_ch_status;
4697259124eSJimmy Assarsson u8 error_state;
4707259124eSJimmy Assarsson } usbcan;
4717259124eSJimmy Assarsson };
4727259124eSJimmy Assarsson };
4737259124eSJimmy Assarsson
4748d21f592SAnssi Hannula struct kvaser_usb_net_leaf_priv {
4758d21f592SAnssi Hannula struct kvaser_usb_net_priv *net;
4768d21f592SAnssi Hannula
4778d21f592SAnssi Hannula struct delayed_work chip_state_req_work;
478abb86709SAnssi Hannula
479abb86709SAnssi Hannula /* started but not reported as bus-on yet */
480abb86709SAnssi Hannula bool joining_bus;
4818d21f592SAnssi Hannula };
4828d21f592SAnssi Hannula
483b3b6df2cSJimmy Assarsson static const struct can_bittiming_const kvaser_usb_leaf_m16c_bittiming_const = {
484b3b6df2cSJimmy Assarsson .name = "kvaser_usb_ucii",
485b3b6df2cSJimmy Assarsson .tseg1_min = 4,
486b3b6df2cSJimmy Assarsson .tseg1_max = 16,
487b3b6df2cSJimmy Assarsson .tseg2_min = 2,
488b3b6df2cSJimmy Assarsson .tseg2_max = 8,
489b3b6df2cSJimmy Assarsson .sjw_max = 4,
490b3b6df2cSJimmy Assarsson .brp_min = 1,
491b3b6df2cSJimmy Assarsson .brp_max = 16,
492b3b6df2cSJimmy Assarsson .brp_inc = 1,
493fb12797aSJimmy Assarsson };
494fb12797aSJimmy Assarsson
495b3b6df2cSJimmy Assarsson static const struct can_bittiming_const kvaser_usb_leaf_m32c_bittiming_const = {
496b3b6df2cSJimmy Assarsson .name = "kvaser_usb_leaf",
497b3b6df2cSJimmy Assarsson .tseg1_min = 3,
498b3b6df2cSJimmy Assarsson .tseg1_max = 16,
499b3b6df2cSJimmy Assarsson .tseg2_min = 2,
500b3b6df2cSJimmy Assarsson .tseg2_max = 8,
501b3b6df2cSJimmy Assarsson .sjw_max = 4,
502b3b6df2cSJimmy Assarsson .brp_min = 2,
503b3b6df2cSJimmy Assarsson .brp_max = 128,
504b3b6df2cSJimmy Assarsson .brp_inc = 2,
505b3b6df2cSJimmy Assarsson };
506b3b6df2cSJimmy Assarsson
507b3b6df2cSJimmy Assarsson static const struct kvaser_usb_dev_cfg kvaser_usb_leaf_usbcan_dev_cfg = {
508fb12797aSJimmy Assarsson .clock = {
509b8f91799SJimmy Assarsson .freq = 8 * MEGA /* Hz */,
510fb12797aSJimmy Assarsson },
511fb12797aSJimmy Assarsson .timestamp_freq = 1,
512b3b6df2cSJimmy Assarsson .bittiming_const = &kvaser_usb_leaf_m16c_bittiming_const,
513fb12797aSJimmy Assarsson };
514fb12797aSJimmy Assarsson
5159e1cd0d2SJimmy Assarsson static const struct kvaser_usb_dev_cfg kvaser_usb_leaf_m32c_dev_cfg_16mhz = {
516fb12797aSJimmy Assarsson .clock = {
517b8f91799SJimmy Assarsson .freq = 16 * MEGA /* Hz */,
518fb12797aSJimmy Assarsson },
5199e1cd0d2SJimmy Assarsson .timestamp_freq = 16,
5209e1cd0d2SJimmy Assarsson .bittiming_const = &kvaser_usb_leaf_m32c_bittiming_const,
5219e1cd0d2SJimmy Assarsson };
5229e1cd0d2SJimmy Assarsson
5239e1cd0d2SJimmy Assarsson static const struct kvaser_usb_dev_cfg kvaser_usb_leaf_m32c_dev_cfg_24mhz = {
5249e1cd0d2SJimmy Assarsson .clock = {
5259e1cd0d2SJimmy Assarsson .freq = 16 * MEGA /* Hz */,
5269e1cd0d2SJimmy Assarsson },
5279e1cd0d2SJimmy Assarsson .timestamp_freq = 24,
5289e1cd0d2SJimmy Assarsson .bittiming_const = &kvaser_usb_leaf_m32c_bittiming_const,
5299e1cd0d2SJimmy Assarsson };
5309e1cd0d2SJimmy Assarsson
5319e1cd0d2SJimmy Assarsson static const struct kvaser_usb_dev_cfg kvaser_usb_leaf_m32c_dev_cfg_32mhz = {
5329e1cd0d2SJimmy Assarsson .clock = {
5339e1cd0d2SJimmy Assarsson .freq = 16 * MEGA /* Hz */,
5349e1cd0d2SJimmy Assarsson },
5359e1cd0d2SJimmy Assarsson .timestamp_freq = 32,
536b3b6df2cSJimmy Assarsson .bittiming_const = &kvaser_usb_leaf_m32c_bittiming_const,
537fb12797aSJimmy Assarsson };
538fb12797aSJimmy Assarsson
539b3b6df2cSJimmy Assarsson static const struct kvaser_usb_dev_cfg kvaser_usb_leaf_imx_dev_cfg_16mhz = {
540b3b6df2cSJimmy Assarsson .clock = {
541b3b6df2cSJimmy Assarsson .freq = 16 * MEGA /* Hz */,
542b3b6df2cSJimmy Assarsson },
543dcc8c203SJimmy Assarsson .timestamp_freq = 16,
544b3b6df2cSJimmy Assarsson .bittiming_const = &kvaser_usb_flexc_bittiming_const,
545b3b6df2cSJimmy Assarsson };
546b3b6df2cSJimmy Assarsson
547b3b6df2cSJimmy Assarsson static const struct kvaser_usb_dev_cfg kvaser_usb_leaf_imx_dev_cfg_24mhz = {
548fb12797aSJimmy Assarsson .clock = {
549b8f91799SJimmy Assarsson .freq = 24 * MEGA /* Hz */,
550fb12797aSJimmy Assarsson },
551dcc8c203SJimmy Assarsson .timestamp_freq = 24,
552b3b6df2cSJimmy Assarsson .bittiming_const = &kvaser_usb_flexc_bittiming_const,
553fb12797aSJimmy Assarsson };
554fb12797aSJimmy Assarsson
555b3b6df2cSJimmy Assarsson static const struct kvaser_usb_dev_cfg kvaser_usb_leaf_imx_dev_cfg_32mhz = {
556fb12797aSJimmy Assarsson .clock = {
557b8f91799SJimmy Assarsson .freq = 32 * MEGA /* Hz */,
558fb12797aSJimmy Assarsson },
559dcc8c203SJimmy Assarsson .timestamp_freq = 32,
560b3b6df2cSJimmy Assarsson .bittiming_const = &kvaser_usb_flexc_bittiming_const,
561fb12797aSJimmy Assarsson };
562fb12797aSJimmy Assarsson
kvaser_usb_usbcan_timestamp_to_ktime(const struct kvaser_usb * dev,__le16 timestamp)5630aa639d3SJimmy Assarsson static inline ktime_t kvaser_usb_usbcan_timestamp_to_ktime(const struct kvaser_usb *dev,
5640aa639d3SJimmy Assarsson __le16 timestamp)
5650aa639d3SJimmy Assarsson {
5660aa639d3SJimmy Assarsson u64 ticks = le16_to_cpu(timestamp) |
5670aa639d3SJimmy Assarsson dev->card_data.usbcan_timestamp_msb;
5680aa639d3SJimmy Assarsson
5690aa639d3SJimmy Assarsson return kvaser_usb_ticks_to_ktime(dev->cfg, ticks * KVASER_USB_USBCAN_TIMESTAMP_FACTOR);
5700aa639d3SJimmy Assarsson }
5710aa639d3SJimmy Assarsson
kvaser_usb_leaf_verify_size(const struct kvaser_usb * dev,const struct kvaser_cmd * cmd)5721499ecaeSAnssi Hannula static int kvaser_usb_leaf_verify_size(const struct kvaser_usb *dev,
5731499ecaeSAnssi Hannula const struct kvaser_cmd *cmd)
5741499ecaeSAnssi Hannula {
5751499ecaeSAnssi Hannula /* buffer size >= cmd->len ensured by caller */
5761499ecaeSAnssi Hannula u8 min_size = 0;
5771499ecaeSAnssi Hannula
5781499ecaeSAnssi Hannula switch (dev->driver_info->family) {
5791499ecaeSAnssi Hannula case KVASER_LEAF:
5801499ecaeSAnssi Hannula if (cmd->id < ARRAY_SIZE(kvaser_usb_leaf_cmd_sizes_leaf))
5811499ecaeSAnssi Hannula min_size = kvaser_usb_leaf_cmd_sizes_leaf[cmd->id];
5821499ecaeSAnssi Hannula break;
5831499ecaeSAnssi Hannula case KVASER_USBCAN:
5841499ecaeSAnssi Hannula if (cmd->id < ARRAY_SIZE(kvaser_usb_leaf_cmd_sizes_usbcan))
5851499ecaeSAnssi Hannula min_size = kvaser_usb_leaf_cmd_sizes_usbcan[cmd->id];
5861499ecaeSAnssi Hannula break;
5871499ecaeSAnssi Hannula }
5881499ecaeSAnssi Hannula
5891499ecaeSAnssi Hannula if (min_size == CMD_SIZE_ANY)
5901499ecaeSAnssi Hannula return 0;
5911499ecaeSAnssi Hannula
5921499ecaeSAnssi Hannula if (min_size) {
5931499ecaeSAnssi Hannula min_size += CMD_HEADER_LEN;
5941499ecaeSAnssi Hannula if (cmd->len >= min_size)
5951499ecaeSAnssi Hannula return 0;
5961499ecaeSAnssi Hannula
5971499ecaeSAnssi Hannula dev_err_ratelimited(&dev->intf->dev,
5981499ecaeSAnssi Hannula "Received command %u too short (size %u, needed %u)",
5991499ecaeSAnssi Hannula cmd->id, cmd->len, min_size);
6001499ecaeSAnssi Hannula return -EIO;
6011499ecaeSAnssi Hannula }
6021499ecaeSAnssi Hannula
6031499ecaeSAnssi Hannula dev_warn_ratelimited(&dev->intf->dev,
6041499ecaeSAnssi Hannula "Unhandled command (%d, size %d)\n",
6051499ecaeSAnssi Hannula cmd->id, cmd->len);
6061499ecaeSAnssi Hannula return -EINVAL;
6071499ecaeSAnssi Hannula }
6081499ecaeSAnssi Hannula
6097259124eSJimmy Assarsson static void *
kvaser_usb_leaf_frame_to_cmd(const struct kvaser_usb_net_priv * priv,const struct sk_buff * skb,int * cmd_len,u16 transid)6107259124eSJimmy Assarsson kvaser_usb_leaf_frame_to_cmd(const struct kvaser_usb_net_priv *priv,
611cc4b08c3SVincent Mailhol const struct sk_buff *skb, int *cmd_len,
612cc4b08c3SVincent Mailhol u16 transid)
6137259124eSJimmy Assarsson {
6147259124eSJimmy Assarsson struct kvaser_usb *dev = priv->dev;
6157259124eSJimmy Assarsson struct kvaser_cmd *cmd;
6167259124eSJimmy Assarsson u8 *cmd_tx_can_flags = NULL; /* GCC */
6177259124eSJimmy Assarsson struct can_frame *cf = (struct can_frame *)skb->data;
6187259124eSJimmy Assarsson
6197259124eSJimmy Assarsson cmd = kmalloc(sizeof(*cmd), GFP_ATOMIC);
6207259124eSJimmy Assarsson if (cmd) {
6217259124eSJimmy Assarsson cmd->u.tx_can.tid = transid & 0xff;
6227259124eSJimmy Assarsson cmd->len = *cmd_len = CMD_HEADER_LEN +
6237259124eSJimmy Assarsson sizeof(struct kvaser_cmd_tx_can);
6247259124eSJimmy Assarsson cmd->u.tx_can.channel = priv->channel;
6257259124eSJimmy Assarsson
62649f274c7SJimmy Assarsson switch (dev->driver_info->family) {
6277259124eSJimmy Assarsson case KVASER_LEAF:
6287259124eSJimmy Assarsson cmd_tx_can_flags = &cmd->u.tx_can.leaf.flags;
6297259124eSJimmy Assarsson break;
6307259124eSJimmy Assarsson case KVASER_USBCAN:
6317259124eSJimmy Assarsson cmd_tx_can_flags = &cmd->u.tx_can.usbcan.flags;
6327259124eSJimmy Assarsson break;
6337259124eSJimmy Assarsson }
6347259124eSJimmy Assarsson
6357259124eSJimmy Assarsson *cmd_tx_can_flags = 0;
6367259124eSJimmy Assarsson
6377259124eSJimmy Assarsson if (cf->can_id & CAN_EFF_FLAG) {
6387259124eSJimmy Assarsson cmd->id = CMD_TX_EXT_MESSAGE;
6397259124eSJimmy Assarsson cmd->u.tx_can.data[0] = (cf->can_id >> 24) & 0x1f;
6407259124eSJimmy Assarsson cmd->u.tx_can.data[1] = (cf->can_id >> 18) & 0x3f;
6417259124eSJimmy Assarsson cmd->u.tx_can.data[2] = (cf->can_id >> 14) & 0x0f;
6427259124eSJimmy Assarsson cmd->u.tx_can.data[3] = (cf->can_id >> 6) & 0xff;
6437259124eSJimmy Assarsson cmd->u.tx_can.data[4] = cf->can_id & 0x3f;
6447259124eSJimmy Assarsson } else {
6457259124eSJimmy Assarsson cmd->id = CMD_TX_STD_MESSAGE;
6467259124eSJimmy Assarsson cmd->u.tx_can.data[0] = (cf->can_id >> 6) & 0x1f;
6477259124eSJimmy Assarsson cmd->u.tx_can.data[1] = cf->can_id & 0x3f;
6487259124eSJimmy Assarsson }
6497259124eSJimmy Assarsson
650843b8464SCarsten Schmidt cmd->u.tx_can.data[5] = can_get_cc_dlc(cf, priv->can.ctrlmode);
651c7b74967SOliver Hartkopp memcpy(&cmd->u.tx_can.data[6], cf->data, cf->len);
6527259124eSJimmy Assarsson
6537259124eSJimmy Assarsson if (cf->can_id & CAN_RTR_FLAG)
6547259124eSJimmy Assarsson *cmd_tx_can_flags |= MSG_FLAG_REMOTE_FRAME;
6557259124eSJimmy Assarsson }
6567259124eSJimmy Assarsson return cmd;
6577259124eSJimmy Assarsson }
6587259124eSJimmy Assarsson
kvaser_usb_leaf_wait_cmd(const struct kvaser_usb * dev,u8 id,struct kvaser_cmd * cmd)6597259124eSJimmy Assarsson static int kvaser_usb_leaf_wait_cmd(const struct kvaser_usb *dev, u8 id,
6607259124eSJimmy Assarsson struct kvaser_cmd *cmd)
6617259124eSJimmy Assarsson {
6627259124eSJimmy Assarsson struct kvaser_cmd *tmp;
6637259124eSJimmy Assarsson void *buf;
6647259124eSJimmy Assarsson int actual_len;
6657259124eSJimmy Assarsson int err;
6667259124eSJimmy Assarsson int pos;
6677259124eSJimmy Assarsson unsigned long to = jiffies + msecs_to_jiffies(KVASER_USB_TIMEOUT);
6687259124eSJimmy Assarsson
6697259124eSJimmy Assarsson buf = kzalloc(KVASER_USB_RX_BUFFER_SIZE, GFP_KERNEL);
6707259124eSJimmy Assarsson if (!buf)
6717259124eSJimmy Assarsson return -ENOMEM;
6727259124eSJimmy Assarsson
6737259124eSJimmy Assarsson do {
6747259124eSJimmy Assarsson err = kvaser_usb_recv_cmd(dev, buf, KVASER_USB_RX_BUFFER_SIZE,
6757259124eSJimmy Assarsson &actual_len);
6767259124eSJimmy Assarsson if (err < 0)
6777259124eSJimmy Assarsson goto end;
6787259124eSJimmy Assarsson
6797259124eSJimmy Assarsson pos = 0;
6807259124eSJimmy Assarsson while (pos <= actual_len - CMD_HEADER_LEN) {
6817259124eSJimmy Assarsson tmp = buf + pos;
6827259124eSJimmy Assarsson
6837259124eSJimmy Assarsson /* Handle commands crossing the USB endpoint max packet
6847259124eSJimmy Assarsson * size boundary. Check kvaser_usb_read_bulk_callback()
6857259124eSJimmy Assarsson * for further details.
6867259124eSJimmy Assarsson */
6877259124eSJimmy Assarsson if (tmp->len == 0) {
6887259124eSJimmy Assarsson pos = round_up(pos,
6897259124eSJimmy Assarsson le16_to_cpu
6907259124eSJimmy Assarsson (dev->bulk_in->wMaxPacketSize));
6917259124eSJimmy Assarsson continue;
6927259124eSJimmy Assarsson }
6937259124eSJimmy Assarsson
6947259124eSJimmy Assarsson if (pos + tmp->len > actual_len) {
6957259124eSJimmy Assarsson dev_err_ratelimited(&dev->intf->dev,
6967259124eSJimmy Assarsson "Format error\n");
6977259124eSJimmy Assarsson break;
6987259124eSJimmy Assarsson }
6997259124eSJimmy Assarsson
7007259124eSJimmy Assarsson if (tmp->id == id) {
7017259124eSJimmy Assarsson memcpy(cmd, tmp, tmp->len);
7027259124eSJimmy Assarsson goto end;
7037259124eSJimmy Assarsson }
7047259124eSJimmy Assarsson
7057259124eSJimmy Assarsson pos += tmp->len;
7067259124eSJimmy Assarsson }
7077259124eSJimmy Assarsson } while (time_before(jiffies, to));
7087259124eSJimmy Assarsson
7097259124eSJimmy Assarsson err = -EINVAL;
7107259124eSJimmy Assarsson
7117259124eSJimmy Assarsson end:
7127259124eSJimmy Assarsson kfree(buf);
7137259124eSJimmy Assarsson
7141499ecaeSAnssi Hannula if (err == 0)
7151499ecaeSAnssi Hannula err = kvaser_usb_leaf_verify_size(dev, cmd);
7161499ecaeSAnssi Hannula
7177259124eSJimmy Assarsson return err;
7187259124eSJimmy Assarsson }
7197259124eSJimmy Assarsson
kvaser_usb_leaf_send_simple_cmd(const struct kvaser_usb * dev,u8 cmd_id,int channel)7207259124eSJimmy Assarsson static int kvaser_usb_leaf_send_simple_cmd(const struct kvaser_usb *dev,
7217259124eSJimmy Assarsson u8 cmd_id, int channel)
7227259124eSJimmy Assarsson {
7237259124eSJimmy Assarsson struct kvaser_cmd *cmd;
7247259124eSJimmy Assarsson int rc;
7257259124eSJimmy Assarsson
7267259124eSJimmy Assarsson cmd = kmalloc(sizeof(*cmd), GFP_KERNEL);
7277259124eSJimmy Assarsson if (!cmd)
7287259124eSJimmy Assarsson return -ENOMEM;
7297259124eSJimmy Assarsson
7307259124eSJimmy Assarsson cmd->id = cmd_id;
7317259124eSJimmy Assarsson cmd->len = CMD_HEADER_LEN + sizeof(struct kvaser_cmd_simple);
7327259124eSJimmy Assarsson cmd->u.simple.channel = channel;
7337259124eSJimmy Assarsson cmd->u.simple.tid = 0xff;
7347259124eSJimmy Assarsson
7357259124eSJimmy Assarsson rc = kvaser_usb_send_cmd(dev, cmd, cmd->len);
7367259124eSJimmy Assarsson
7377259124eSJimmy Assarsson kfree(cmd);
7387259124eSJimmy Assarsson return rc;
7397259124eSJimmy Assarsson }
7407259124eSJimmy Assarsson
kvaser_usb_leaf_get_software_info_leaf(struct kvaser_usb * dev,const struct leaf_cmd_softinfo * softinfo)741fb12797aSJimmy Assarsson static void kvaser_usb_leaf_get_software_info_leaf(struct kvaser_usb *dev,
742fb12797aSJimmy Assarsson const struct leaf_cmd_softinfo *softinfo)
743fb12797aSJimmy Assarsson {
744280eba33SJimmy Assarsson u32 fw_version;
745fb12797aSJimmy Assarsson u32 sw_options = le32_to_cpu(softinfo->sw_options);
746fb12797aSJimmy Assarsson
747280eba33SJimmy Assarsson fw_version = le32_to_cpu(softinfo->fw_version);
748280eba33SJimmy Assarsson dev->fw_version.major = FIELD_GET(KVASER_USB_SW_VERSION_MAJOR_MASK, fw_version);
749280eba33SJimmy Assarsson dev->fw_version.minor = FIELD_GET(KVASER_USB_SW_VERSION_MINOR_MASK, fw_version);
750280eba33SJimmy Assarsson dev->fw_version.build = FIELD_GET(KVASER_USB_SW_VERSION_BUILD_MASK, fw_version);
751fb12797aSJimmy Assarsson dev->max_tx_urbs = le16_to_cpu(softinfo->max_outstanding_tx);
752fb12797aSJimmy Assarsson
75335364f5bSJimmy Assarsson if (sw_options & KVASER_USB_LEAF_SWOPTION_EXT_CAP)
75435364f5bSJimmy Assarsson dev->card_data.capabilities |= KVASER_USB_CAP_EXT_CAP;
75535364f5bSJimmy Assarsson
756e6c80e60SJimmy Assarsson if (dev->driver_info->quirks & KVASER_USB_QUIRK_IGNORE_CLK_FREQ) {
757e6c80e60SJimmy Assarsson /* Firmware expects bittiming parameters calculated for 16MHz
758e6c80e60SJimmy Assarsson * clock, regardless of the actual clock
7599e1cd0d2SJimmy Assarsson * Though, the reported freq is used for timestamps
760e6c80e60SJimmy Assarsson */
7619e1cd0d2SJimmy Assarsson switch (sw_options & KVASER_USB_LEAF_SWOPTION_FREQ_MASK) {
7629e1cd0d2SJimmy Assarsson case KVASER_USB_LEAF_SWOPTION_FREQ_16_MHZ_CLK:
7639e1cd0d2SJimmy Assarsson dev->cfg = &kvaser_usb_leaf_m32c_dev_cfg_16mhz;
7649e1cd0d2SJimmy Assarsson break;
7659e1cd0d2SJimmy Assarsson case KVASER_USB_LEAF_SWOPTION_FREQ_24_MHZ_CLK:
7669e1cd0d2SJimmy Assarsson dev->cfg = &kvaser_usb_leaf_m32c_dev_cfg_24mhz;
7679e1cd0d2SJimmy Assarsson break;
7689e1cd0d2SJimmy Assarsson case KVASER_USB_LEAF_SWOPTION_FREQ_32_MHZ_CLK:
7699e1cd0d2SJimmy Assarsson dev->cfg = &kvaser_usb_leaf_m32c_dev_cfg_32mhz;
7709e1cd0d2SJimmy Assarsson break;
7719e1cd0d2SJimmy Assarsson }
772e6c80e60SJimmy Assarsson } else {
773fb12797aSJimmy Assarsson switch (sw_options & KVASER_USB_LEAF_SWOPTION_FREQ_MASK) {
774fb12797aSJimmy Assarsson case KVASER_USB_LEAF_SWOPTION_FREQ_16_MHZ_CLK:
775b3b6df2cSJimmy Assarsson dev->cfg = &kvaser_usb_leaf_imx_dev_cfg_16mhz;
776fb12797aSJimmy Assarsson break;
777fb12797aSJimmy Assarsson case KVASER_USB_LEAF_SWOPTION_FREQ_24_MHZ_CLK:
778b3b6df2cSJimmy Assarsson dev->cfg = &kvaser_usb_leaf_imx_dev_cfg_24mhz;
779fb12797aSJimmy Assarsson break;
780fb12797aSJimmy Assarsson case KVASER_USB_LEAF_SWOPTION_FREQ_32_MHZ_CLK:
781b3b6df2cSJimmy Assarsson dev->cfg = &kvaser_usb_leaf_imx_dev_cfg_32mhz;
782fb12797aSJimmy Assarsson break;
783fb12797aSJimmy Assarsson }
784fb12797aSJimmy Assarsson }
785e6c80e60SJimmy Assarsson }
786fb12797aSJimmy Assarsson
kvaser_usb_leaf_get_software_info_inner(struct kvaser_usb * dev)7877259124eSJimmy Assarsson static int kvaser_usb_leaf_get_software_info_inner(struct kvaser_usb *dev)
7887259124eSJimmy Assarsson {
7897259124eSJimmy Assarsson struct kvaser_cmd cmd;
7907259124eSJimmy Assarsson int err;
791280eba33SJimmy Assarsson u32 fw_version;
7927259124eSJimmy Assarsson
7937259124eSJimmy Assarsson err = kvaser_usb_leaf_send_simple_cmd(dev, CMD_GET_SOFTWARE_INFO, 0);
7947259124eSJimmy Assarsson if (err)
7957259124eSJimmy Assarsson return err;
7967259124eSJimmy Assarsson
7977259124eSJimmy Assarsson err = kvaser_usb_leaf_wait_cmd(dev, CMD_GET_SOFTWARE_INFO_REPLY, &cmd);
7987259124eSJimmy Assarsson if (err)
7997259124eSJimmy Assarsson return err;
8007259124eSJimmy Assarsson
80149f274c7SJimmy Assarsson switch (dev->driver_info->family) {
8027259124eSJimmy Assarsson case KVASER_LEAF:
803fb12797aSJimmy Assarsson kvaser_usb_leaf_get_software_info_leaf(dev, &cmd.u.leaf.softinfo);
8047259124eSJimmy Assarsson break;
8057259124eSJimmy Assarsson case KVASER_USBCAN:
806280eba33SJimmy Assarsson fw_version = le32_to_cpu(cmd.u.usbcan.softinfo.fw_version);
807280eba33SJimmy Assarsson dev->fw_version.major = FIELD_GET(KVASER_USB_SW_VERSION_MAJOR_MASK,
808280eba33SJimmy Assarsson fw_version);
809280eba33SJimmy Assarsson dev->fw_version.minor = FIELD_GET(KVASER_USB_SW_VERSION_MINOR_MASK,
810280eba33SJimmy Assarsson fw_version);
811280eba33SJimmy Assarsson dev->fw_version.build = FIELD_GET(KVASER_USB_SW_VERSION_BUILD_MASK,
812280eba33SJimmy Assarsson fw_version);
8137259124eSJimmy Assarsson dev->max_tx_urbs =
8147259124eSJimmy Assarsson le16_to_cpu(cmd.u.usbcan.softinfo.max_outstanding_tx);
815b3b6df2cSJimmy Assarsson dev->cfg = &kvaser_usb_leaf_usbcan_dev_cfg;
8167259124eSJimmy Assarsson break;
8177259124eSJimmy Assarsson }
8187259124eSJimmy Assarsson
8197259124eSJimmy Assarsson return 0;
8207259124eSJimmy Assarsson }
8217259124eSJimmy Assarsson
kvaser_usb_leaf_get_software_info(struct kvaser_usb * dev)8227259124eSJimmy Assarsson static int kvaser_usb_leaf_get_software_info(struct kvaser_usb *dev)
8237259124eSJimmy Assarsson {
8247259124eSJimmy Assarsson int err;
8257259124eSJimmy Assarsson int retry = 3;
8267259124eSJimmy Assarsson
8277259124eSJimmy Assarsson /* On some x86 laptops, plugging a Kvaser device again after
8287259124eSJimmy Assarsson * an unplug makes the firmware always ignore the very first
8297259124eSJimmy Assarsson * command. For such a case, provide some room for retries
8307259124eSJimmy Assarsson * instead of completely exiting the driver.
8317259124eSJimmy Assarsson */
8327259124eSJimmy Assarsson do {
8337259124eSJimmy Assarsson err = kvaser_usb_leaf_get_software_info_inner(dev);
8347259124eSJimmy Assarsson } while (--retry && err == -ETIMEDOUT);
8357259124eSJimmy Assarsson
8367259124eSJimmy Assarsson return err;
8377259124eSJimmy Assarsson }
8387259124eSJimmy Assarsson
kvaser_usb_leaf_get_card_info(struct kvaser_usb * dev)8397259124eSJimmy Assarsson static int kvaser_usb_leaf_get_card_info(struct kvaser_usb *dev)
8407259124eSJimmy Assarsson {
8417259124eSJimmy Assarsson struct kvaser_cmd cmd;
8427259124eSJimmy Assarsson int err;
8437259124eSJimmy Assarsson
8447259124eSJimmy Assarsson err = kvaser_usb_leaf_send_simple_cmd(dev, CMD_GET_CARD_INFO, 0);
8457259124eSJimmy Assarsson if (err)
8467259124eSJimmy Assarsson return err;
8477259124eSJimmy Assarsson
8487259124eSJimmy Assarsson err = kvaser_usb_leaf_wait_cmd(dev, CMD_GET_CARD_INFO_REPLY, &cmd);
8497259124eSJimmy Assarsson if (err)
8507259124eSJimmy Assarsson return err;
8517259124eSJimmy Assarsson
8527259124eSJimmy Assarsson dev->nchannels = cmd.u.cardinfo.nchannels;
8537259124eSJimmy Assarsson if (dev->nchannels > KVASER_USB_MAX_NET_DEVICES ||
85449f274c7SJimmy Assarsson (dev->driver_info->family == KVASER_USBCAN &&
8557259124eSJimmy Assarsson dev->nchannels > MAX_USBCAN_NET_DEVICES))
8567259124eSJimmy Assarsson return -EINVAL;
857*0020f2baSJimmy Assarsson dev->ean[1] = le32_to_cpu(cmd.u.cardinfo.ean[1]);
858*0020f2baSJimmy Assarsson dev->ean[0] = le32_to_cpu(cmd.u.cardinfo.ean[0]);
859*0020f2baSJimmy Assarsson dev->serial_number = le32_to_cpu(cmd.u.cardinfo.serial_number);
860*0020f2baSJimmy Assarsson dev->hw_revision = cmd.u.cardinfo.hw_revision;
8617259124eSJimmy Assarsson
8627259124eSJimmy Assarsson return 0;
8637259124eSJimmy Assarsson }
8647259124eSJimmy Assarsson
kvaser_usb_leaf_get_single_capability(struct kvaser_usb * dev,u16 cap_cmd_req,u16 * status)86535364f5bSJimmy Assarsson static int kvaser_usb_leaf_get_single_capability(struct kvaser_usb *dev,
86635364f5bSJimmy Assarsson u16 cap_cmd_req, u16 *status)
86735364f5bSJimmy Assarsson {
86835364f5bSJimmy Assarsson struct kvaser_usb_dev_card_data *card_data = &dev->card_data;
86935364f5bSJimmy Assarsson struct kvaser_cmd *cmd;
87035364f5bSJimmy Assarsson u32 value = 0;
87135364f5bSJimmy Assarsson u32 mask = 0;
87235364f5bSJimmy Assarsson u16 cap_cmd_res;
87335364f5bSJimmy Assarsson int err;
87435364f5bSJimmy Assarsson int i;
87535364f5bSJimmy Assarsson
87635364f5bSJimmy Assarsson cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
87735364f5bSJimmy Assarsson if (!cmd)
87835364f5bSJimmy Assarsson return -ENOMEM;
87935364f5bSJimmy Assarsson
88035364f5bSJimmy Assarsson cmd->id = CMD_GET_CAPABILITIES_REQ;
88135364f5bSJimmy Assarsson cmd->u.leaf.cap_req.cap_cmd = cpu_to_le16(cap_cmd_req);
88235364f5bSJimmy Assarsson cmd->len = CMD_HEADER_LEN + sizeof(struct kvaser_cmd_cap_req);
88335364f5bSJimmy Assarsson
88435364f5bSJimmy Assarsson err = kvaser_usb_send_cmd(dev, cmd, cmd->len);
88535364f5bSJimmy Assarsson if (err)
88635364f5bSJimmy Assarsson goto end;
88735364f5bSJimmy Assarsson
88835364f5bSJimmy Assarsson err = kvaser_usb_leaf_wait_cmd(dev, CMD_GET_CAPABILITIES_RESP, cmd);
88935364f5bSJimmy Assarsson if (err)
89035364f5bSJimmy Assarsson goto end;
89135364f5bSJimmy Assarsson
89235364f5bSJimmy Assarsson *status = le16_to_cpu(cmd->u.leaf.cap_res.status);
89335364f5bSJimmy Assarsson
89435364f5bSJimmy Assarsson if (*status != KVASER_USB_LEAF_CAP_STAT_OK)
89535364f5bSJimmy Assarsson goto end;
89635364f5bSJimmy Assarsson
89735364f5bSJimmy Assarsson cap_cmd_res = le16_to_cpu(cmd->u.leaf.cap_res.cap_cmd);
89835364f5bSJimmy Assarsson switch (cap_cmd_res) {
89935364f5bSJimmy Assarsson case KVASER_USB_LEAF_CAP_CMD_LISTEN_MODE:
90035364f5bSJimmy Assarsson case KVASER_USB_LEAF_CAP_CMD_ERR_REPORT:
90135364f5bSJimmy Assarsson value = le32_to_cpu(cmd->u.leaf.cap_res.value);
90235364f5bSJimmy Assarsson mask = le32_to_cpu(cmd->u.leaf.cap_res.mask);
90335364f5bSJimmy Assarsson break;
90435364f5bSJimmy Assarsson default:
90535364f5bSJimmy Assarsson dev_warn(&dev->intf->dev, "Unknown capability command %u\n",
90635364f5bSJimmy Assarsson cap_cmd_res);
90735364f5bSJimmy Assarsson break;
90835364f5bSJimmy Assarsson }
90935364f5bSJimmy Assarsson
91035364f5bSJimmy Assarsson for (i = 0; i < dev->nchannels; i++) {
91135364f5bSJimmy Assarsson if (BIT(i) & (value & mask)) {
91235364f5bSJimmy Assarsson switch (cap_cmd_res) {
91335364f5bSJimmy Assarsson case KVASER_USB_LEAF_CAP_CMD_LISTEN_MODE:
91435364f5bSJimmy Assarsson card_data->ctrlmode_supported |=
91535364f5bSJimmy Assarsson CAN_CTRLMODE_LISTENONLY;
91635364f5bSJimmy Assarsson break;
91735364f5bSJimmy Assarsson case KVASER_USB_LEAF_CAP_CMD_ERR_REPORT:
91835364f5bSJimmy Assarsson card_data->capabilities |=
91935364f5bSJimmy Assarsson KVASER_USB_CAP_BERR_CAP;
92035364f5bSJimmy Assarsson break;
92135364f5bSJimmy Assarsson }
92235364f5bSJimmy Assarsson }
92335364f5bSJimmy Assarsson }
92435364f5bSJimmy Assarsson
92535364f5bSJimmy Assarsson end:
92635364f5bSJimmy Assarsson kfree(cmd);
92735364f5bSJimmy Assarsson
92835364f5bSJimmy Assarsson return err;
92935364f5bSJimmy Assarsson }
93035364f5bSJimmy Assarsson
kvaser_usb_leaf_get_capabilities_leaf(struct kvaser_usb * dev)93135364f5bSJimmy Assarsson static int kvaser_usb_leaf_get_capabilities_leaf(struct kvaser_usb *dev)
93235364f5bSJimmy Assarsson {
93335364f5bSJimmy Assarsson int err;
93435364f5bSJimmy Assarsson u16 status;
93535364f5bSJimmy Assarsson
93635364f5bSJimmy Assarsson if (!(dev->card_data.capabilities & KVASER_USB_CAP_EXT_CAP)) {
93735364f5bSJimmy Assarsson dev_info(&dev->intf->dev,
93835364f5bSJimmy Assarsson "No extended capability support. Upgrade device firmware.\n");
93935364f5bSJimmy Assarsson return 0;
94035364f5bSJimmy Assarsson }
94135364f5bSJimmy Assarsson
94235364f5bSJimmy Assarsson err = kvaser_usb_leaf_get_single_capability(dev,
94335364f5bSJimmy Assarsson KVASER_USB_LEAF_CAP_CMD_LISTEN_MODE,
94435364f5bSJimmy Assarsson &status);
94535364f5bSJimmy Assarsson if (err)
94635364f5bSJimmy Assarsson return err;
94735364f5bSJimmy Assarsson if (status)
94835364f5bSJimmy Assarsson dev_info(&dev->intf->dev,
94935364f5bSJimmy Assarsson "KVASER_USB_LEAF_CAP_CMD_LISTEN_MODE failed %u\n",
95035364f5bSJimmy Assarsson status);
95135364f5bSJimmy Assarsson
95235364f5bSJimmy Assarsson err = kvaser_usb_leaf_get_single_capability(dev,
95335364f5bSJimmy Assarsson KVASER_USB_LEAF_CAP_CMD_ERR_REPORT,
95435364f5bSJimmy Assarsson &status);
95535364f5bSJimmy Assarsson if (err)
95635364f5bSJimmy Assarsson return err;
95735364f5bSJimmy Assarsson if (status)
95835364f5bSJimmy Assarsson dev_info(&dev->intf->dev,
95935364f5bSJimmy Assarsson "KVASER_USB_LEAF_CAP_CMD_ERR_REPORT failed %u\n",
96035364f5bSJimmy Assarsson status);
96135364f5bSJimmy Assarsson
96235364f5bSJimmy Assarsson return 0;
96335364f5bSJimmy Assarsson }
96435364f5bSJimmy Assarsson
kvaser_usb_leaf_set_led(struct kvaser_usb_net_priv * priv,enum kvaser_usb_led_state state,u16 duration_ms)965478248f1SJimmy Assarsson static int kvaser_usb_leaf_set_led(struct kvaser_usb_net_priv *priv,
966478248f1SJimmy Assarsson enum kvaser_usb_led_state state,
967478248f1SJimmy Assarsson u16 duration_ms)
968478248f1SJimmy Assarsson {
969478248f1SJimmy Assarsson struct kvaser_usb *dev = priv->dev;
970478248f1SJimmy Assarsson struct kvaser_cmd *cmd;
971478248f1SJimmy Assarsson int ret;
972478248f1SJimmy Assarsson
973478248f1SJimmy Assarsson cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
974478248f1SJimmy Assarsson if (!cmd)
975478248f1SJimmy Assarsson return -ENOMEM;
976478248f1SJimmy Assarsson
977478248f1SJimmy Assarsson cmd->id = CMD_LED_ACTION_REQ;
978478248f1SJimmy Assarsson cmd->len = CMD_HEADER_LEN + sizeof(struct kvaser_cmd_led_action_req);
979478248f1SJimmy Assarsson cmd->u.led_action_req.tid = 0xff;
980478248f1SJimmy Assarsson
981478248f1SJimmy Assarsson cmd->u.led_action_req.duration_ms = cpu_to_le16(duration_ms);
982478248f1SJimmy Assarsson cmd->u.led_action_req.action = state |
983478248f1SJimmy Assarsson FIELD_PREP(KVASER_USB_LEAF_LED_IDX_MASK,
984478248f1SJimmy Assarsson KVASER_USB_LEAF_LED_YELLOW_CH0_IDX +
985478248f1SJimmy Assarsson priv->channel);
986478248f1SJimmy Assarsson
987478248f1SJimmy Assarsson ret = kvaser_usb_send_cmd(dev, cmd, cmd->len);
988478248f1SJimmy Assarsson kfree(cmd);
989478248f1SJimmy Assarsson
990478248f1SJimmy Assarsson return ret;
991478248f1SJimmy Assarsson }
992478248f1SJimmy Assarsson
kvaser_usb_leaf_get_capabilities(struct kvaser_usb * dev)99335364f5bSJimmy Assarsson static int kvaser_usb_leaf_get_capabilities(struct kvaser_usb *dev)
99435364f5bSJimmy Assarsson {
99535364f5bSJimmy Assarsson int err = 0;
99635364f5bSJimmy Assarsson
99735364f5bSJimmy Assarsson if (dev->driver_info->family == KVASER_LEAF)
99835364f5bSJimmy Assarsson err = kvaser_usb_leaf_get_capabilities_leaf(dev);
99935364f5bSJimmy Assarsson
100035364f5bSJimmy Assarsson return err;
100135364f5bSJimmy Assarsson }
100235364f5bSJimmy Assarsson
kvaser_usb_leaf_tx_acknowledge(const struct kvaser_usb * dev,const struct kvaser_cmd * cmd)10037259124eSJimmy Assarsson static void kvaser_usb_leaf_tx_acknowledge(const struct kvaser_usb *dev,
10047259124eSJimmy Assarsson const struct kvaser_cmd *cmd)
10057259124eSJimmy Assarsson {
10067259124eSJimmy Assarsson struct net_device_stats *stats;
10077259124eSJimmy Assarsson struct kvaser_usb_tx_urb_context *context;
10087259124eSJimmy Assarsson struct kvaser_usb_net_priv *priv;
10097259124eSJimmy Assarsson unsigned long flags;
10107259124eSJimmy Assarsson u8 channel, tid;
10118a52e5a0SJimmy Assarsson struct sk_buff *skb;
10128a52e5a0SJimmy Assarsson ktime_t hwtstamp = 0;
10137259124eSJimmy Assarsson
10147259124eSJimmy Assarsson channel = cmd->u.tx_acknowledge_header.channel;
10157259124eSJimmy Assarsson tid = cmd->u.tx_acknowledge_header.tid;
10167259124eSJimmy Assarsson
10177259124eSJimmy Assarsson if (channel >= dev->nchannels) {
10187259124eSJimmy Assarsson dev_err(&dev->intf->dev,
10197259124eSJimmy Assarsson "Invalid channel number (%d)\n", channel);
10207259124eSJimmy Assarsson return;
10217259124eSJimmy Assarsson }
10227259124eSJimmy Assarsson
10237259124eSJimmy Assarsson priv = dev->nets[channel];
10247259124eSJimmy Assarsson
10257259124eSJimmy Assarsson if (!netif_device_present(priv->netdev))
10267259124eSJimmy Assarsson return;
10277259124eSJimmy Assarsson
10287259124eSJimmy Assarsson stats = &priv->netdev->stats;
10297259124eSJimmy Assarsson
10307259124eSJimmy Assarsson context = &priv->tx_contexts[tid % dev->max_tx_urbs];
10317259124eSJimmy Assarsson
10327259124eSJimmy Assarsson /* Sometimes the state change doesn't come after a bus-off event */
103390904d32SAnssi Hannula if (priv->can.restart_ms && priv->can.state == CAN_STATE_BUS_OFF) {
10347f382375SJimmy Assarsson struct sk_buff *err_skb;
10357259124eSJimmy Assarsson struct can_frame *cf;
10367259124eSJimmy Assarsson
10377f382375SJimmy Assarsson err_skb = alloc_can_err_skb(priv->netdev, &cf);
10387f382375SJimmy Assarsson if (err_skb) {
10397259124eSJimmy Assarsson cf->can_id |= CAN_ERR_RESTARTED;
10407259124eSJimmy Assarsson
10417f382375SJimmy Assarsson netif_rx(err_skb);
10427259124eSJimmy Assarsson } else {
10437259124eSJimmy Assarsson netdev_err(priv->netdev,
10447259124eSJimmy Assarsson "No memory left for err_skb\n");
10457259124eSJimmy Assarsson }
10467259124eSJimmy Assarsson
10477259124eSJimmy Assarsson priv->can.can_stats.restarts++;
10487259124eSJimmy Assarsson netif_carrier_on(priv->netdev);
10497259124eSJimmy Assarsson
10507259124eSJimmy Assarsson priv->can.state = CAN_STATE_ERROR_ACTIVE;
10517259124eSJimmy Assarsson }
10528a52e5a0SJimmy Assarsson switch (dev->driver_info->family) {
10538a52e5a0SJimmy Assarsson case KVASER_LEAF:
10548a52e5a0SJimmy Assarsson hwtstamp = kvaser_usb_timestamp48_to_ktime(dev->cfg, cmd->u.leaf.tx_ack.time);
10558a52e5a0SJimmy Assarsson break;
10568a52e5a0SJimmy Assarsson case KVASER_USBCAN:
10570aa639d3SJimmy Assarsson hwtstamp = kvaser_usb_usbcan_timestamp_to_ktime(dev, cmd->u.usbcan.tx_ack.time);
10588a52e5a0SJimmy Assarsson break;
10598a52e5a0SJimmy Assarsson }
10607259124eSJimmy Assarsson
10617259124eSJimmy Assarsson spin_lock_irqsave(&priv->tx_contexts_lock, flags);
10627259124eSJimmy Assarsson
10638a52e5a0SJimmy Assarsson skb = priv->can.echo_skb[context->echo_index];
10648a52e5a0SJimmy Assarsson if (skb)
10658a52e5a0SJimmy Assarsson skb_hwtstamps(skb)->hwtstamp = hwtstamp;
1066cc4b08c3SVincent Mailhol stats->tx_packets++;
1067cc4b08c3SVincent Mailhol stats->tx_bytes += can_get_echo_skb(priv->netdev,
1068cc4b08c3SVincent Mailhol context->echo_index, NULL);
10697259124eSJimmy Assarsson context->echo_index = dev->max_tx_urbs;
10707259124eSJimmy Assarsson --priv->active_tx_contexts;
10717259124eSJimmy Assarsson netif_wake_queue(priv->netdev);
10727259124eSJimmy Assarsson
10737259124eSJimmy Assarsson spin_unlock_irqrestore(&priv->tx_contexts_lock, flags);
10747259124eSJimmy Assarsson }
10757259124eSJimmy Assarsson
kvaser_usb_leaf_simple_cmd_async(struct kvaser_usb_net_priv * priv,u8 cmd_id)10767259124eSJimmy Assarsson static int kvaser_usb_leaf_simple_cmd_async(struct kvaser_usb_net_priv *priv,
10777259124eSJimmy Assarsson u8 cmd_id)
10787259124eSJimmy Assarsson {
10797259124eSJimmy Assarsson struct kvaser_cmd *cmd;
10807259124eSJimmy Assarsson int err;
10817259124eSJimmy Assarsson
1082da2311a6SXiaolong Huang cmd = kzalloc(sizeof(*cmd), GFP_ATOMIC);
10837259124eSJimmy Assarsson if (!cmd)
10847259124eSJimmy Assarsson return -ENOMEM;
10857259124eSJimmy Assarsson
10867259124eSJimmy Assarsson cmd->len = CMD_HEADER_LEN + sizeof(struct kvaser_cmd_simple);
10877259124eSJimmy Assarsson cmd->id = cmd_id;
10887259124eSJimmy Assarsson cmd->u.simple.channel = priv->channel;
10897259124eSJimmy Assarsson
10907259124eSJimmy Assarsson err = kvaser_usb_send_cmd_async(priv, cmd, cmd->len);
10917259124eSJimmy Assarsson if (err)
10927259124eSJimmy Assarsson kfree(cmd);
10937259124eSJimmy Assarsson
10947259124eSJimmy Assarsson return err;
10957259124eSJimmy Assarsson }
10967259124eSJimmy Assarsson
kvaser_usb_leaf_chip_state_req_work(struct work_struct * work)10978d21f592SAnssi Hannula static void kvaser_usb_leaf_chip_state_req_work(struct work_struct *work)
10988d21f592SAnssi Hannula {
10998d21f592SAnssi Hannula struct kvaser_usb_net_leaf_priv *leaf =
11008d21f592SAnssi Hannula container_of(work, struct kvaser_usb_net_leaf_priv,
11018d21f592SAnssi Hannula chip_state_req_work.work);
11028d21f592SAnssi Hannula struct kvaser_usb_net_priv *priv = leaf->net;
11038d21f592SAnssi Hannula
11048d21f592SAnssi Hannula kvaser_usb_leaf_simple_cmd_async(priv, CMD_GET_CHIP_STATE);
11058d21f592SAnssi Hannula }
11068d21f592SAnssi Hannula
11077259124eSJimmy Assarsson static void
kvaser_usb_leaf_rx_error_update_can_state(struct kvaser_usb_net_priv * priv,const struct kvaser_usb_err_summary * es,struct can_frame * cf)11087259124eSJimmy Assarsson kvaser_usb_leaf_rx_error_update_can_state(struct kvaser_usb_net_priv *priv,
11097259124eSJimmy Assarsson const struct kvaser_usb_err_summary *es,
11107259124eSJimmy Assarsson struct can_frame *cf)
11117259124eSJimmy Assarsson {
1112abb86709SAnssi Hannula struct kvaser_usb_net_leaf_priv *leaf = priv->sub_priv;
11137259124eSJimmy Assarsson struct kvaser_usb *dev = priv->dev;
11147259124eSJimmy Assarsson struct net_device_stats *stats = &priv->netdev->stats;
11157259124eSJimmy Assarsson enum can_state cur_state, new_state, tx_state, rx_state;
11167259124eSJimmy Assarsson
11177259124eSJimmy Assarsson netdev_dbg(priv->netdev, "Error status: 0x%02x\n", es->status);
11187259124eSJimmy Assarsson
11197259124eSJimmy Assarsson new_state = priv->can.state;
11207259124eSJimmy Assarsson cur_state = priv->can.state;
11217259124eSJimmy Assarsson
11227259124eSJimmy Assarsson if (es->status & (M16C_STATE_BUS_OFF | M16C_STATE_BUS_RESET)) {
11237259124eSJimmy Assarsson new_state = CAN_STATE_BUS_OFF;
11247259124eSJimmy Assarsson } else if (es->status & M16C_STATE_BUS_PASSIVE) {
11257259124eSJimmy Assarsson new_state = CAN_STATE_ERROR_PASSIVE;
1126df1b7af2SAnssi Hannula } else if ((es->status & M16C_STATE_BUS_ERROR) &&
1127df1b7af2SAnssi Hannula cur_state >= CAN_STATE_BUS_OFF) {
11287259124eSJimmy Assarsson /* Guard against spurious error events after a busoff */
1129df1b7af2SAnssi Hannula } else if (es->txerr >= 128 || es->rxerr >= 128) {
11307259124eSJimmy Assarsson new_state = CAN_STATE_ERROR_PASSIVE;
1131df1b7af2SAnssi Hannula } else if (es->txerr >= 96 || es->rxerr >= 96) {
11327259124eSJimmy Assarsson new_state = CAN_STATE_ERROR_WARNING;
1133df1b7af2SAnssi Hannula } else {
11347259124eSJimmy Assarsson new_state = CAN_STATE_ERROR_ACTIVE;
11357259124eSJimmy Assarsson }
11367259124eSJimmy Assarsson
1137abb86709SAnssi Hannula /* 0bfd:0124 FW 4.18.778 was observed to send the initial
1138abb86709SAnssi Hannula * CMD_CHIP_STATE_EVENT after CMD_START_CHIP with M16C_STATE_BUS_OFF
1139abb86709SAnssi Hannula * bit set if the channel was bus-off when it was last stopped (even
1140abb86709SAnssi Hannula * across chip resets). This bit will clear shortly afterwards, without
1141abb86709SAnssi Hannula * triggering a second unsolicited chip state event.
1142abb86709SAnssi Hannula * Ignore this initial bus-off.
1143abb86709SAnssi Hannula */
1144abb86709SAnssi Hannula if (leaf->joining_bus) {
1145abb86709SAnssi Hannula if (new_state == CAN_STATE_BUS_OFF) {
1146abb86709SAnssi Hannula netdev_dbg(priv->netdev, "ignoring bus-off during startup");
1147abb86709SAnssi Hannula new_state = cur_state;
1148abb86709SAnssi Hannula } else {
1149abb86709SAnssi Hannula leaf->joining_bus = false;
1150abb86709SAnssi Hannula }
1151abb86709SAnssi Hannula }
1152abb86709SAnssi Hannula
11537259124eSJimmy Assarsson if (new_state != cur_state) {
11547259124eSJimmy Assarsson tx_state = (es->txerr >= es->rxerr) ? new_state : 0;
11557259124eSJimmy Assarsson rx_state = (es->txerr <= es->rxerr) ? new_state : 0;
11567259124eSJimmy Assarsson
11577259124eSJimmy Assarsson can_change_state(priv->netdev, cf, tx_state, rx_state);
11587259124eSJimmy Assarsson }
11597259124eSJimmy Assarsson
11607259124eSJimmy Assarsson if (priv->can.restart_ms &&
116190904d32SAnssi Hannula cur_state == CAN_STATE_BUS_OFF &&
11627259124eSJimmy Assarsson new_state < CAN_STATE_BUS_OFF)
11637259124eSJimmy Assarsson priv->can.can_stats.restarts++;
11647259124eSJimmy Assarsson
116549f274c7SJimmy Assarsson switch (dev->driver_info->family) {
11667259124eSJimmy Assarsson case KVASER_LEAF:
11677259124eSJimmy Assarsson if (es->leaf.error_factor) {
11687259124eSJimmy Assarsson priv->can.can_stats.bus_error++;
11697259124eSJimmy Assarsson stats->rx_errors++;
11707259124eSJimmy Assarsson }
11717259124eSJimmy Assarsson break;
11727259124eSJimmy Assarsson case KVASER_USBCAN:
11737259124eSJimmy Assarsson if (es->usbcan.error_state & USBCAN_ERROR_STATE_TX_ERROR)
11747259124eSJimmy Assarsson stats->tx_errors++;
11757259124eSJimmy Assarsson if (es->usbcan.error_state & USBCAN_ERROR_STATE_RX_ERROR)
11767259124eSJimmy Assarsson stats->rx_errors++;
11777259124eSJimmy Assarsson if (es->usbcan.error_state & USBCAN_ERROR_STATE_BUSERROR)
11787259124eSJimmy Assarsson priv->can.can_stats.bus_error++;
11797259124eSJimmy Assarsson break;
11807259124eSJimmy Assarsson }
11817259124eSJimmy Assarsson
11827259124eSJimmy Assarsson priv->bec.txerr = es->txerr;
11837259124eSJimmy Assarsson priv->bec.rxerr = es->rxerr;
11847259124eSJimmy Assarsson }
11857259124eSJimmy Assarsson
kvaser_usb_leaf_rx_error(const struct kvaser_usb * dev,const struct kvaser_usb_err_summary * es)11867259124eSJimmy Assarsson static void kvaser_usb_leaf_rx_error(const struct kvaser_usb *dev,
11877259124eSJimmy Assarsson const struct kvaser_usb_err_summary *es)
11887259124eSJimmy Assarsson {
11890dfa617cSJimmy Assarsson struct can_frame *cf = NULL;
11900dfa617cSJimmy Assarsson struct sk_buff *skb = NULL;
11917259124eSJimmy Assarsson struct net_device_stats *stats;
11927259124eSJimmy Assarsson struct kvaser_usb_net_priv *priv;
11938d21f592SAnssi Hannula struct kvaser_usb_net_leaf_priv *leaf;
11947259124eSJimmy Assarsson enum can_state old_state, new_state;
11957259124eSJimmy Assarsson
11967259124eSJimmy Assarsson if (es->channel >= dev->nchannels) {
11977259124eSJimmy Assarsson dev_err(&dev->intf->dev,
11987259124eSJimmy Assarsson "Invalid channel number (%d)\n", es->channel);
11997259124eSJimmy Assarsson return;
12007259124eSJimmy Assarsson }
12017259124eSJimmy Assarsson
12027259124eSJimmy Assarsson priv = dev->nets[es->channel];
12038d21f592SAnssi Hannula leaf = priv->sub_priv;
12047259124eSJimmy Assarsson stats = &priv->netdev->stats;
12057259124eSJimmy Assarsson
1206a11249acSAnssi Hannula /* Ignore e.g. state change to bus-off reported just after stopping */
1207a11249acSAnssi Hannula if (!netif_running(priv->netdev))
1208a11249acSAnssi Hannula return;
1209a11249acSAnssi Hannula
12107259124eSJimmy Assarsson old_state = priv->can.state;
12110dfa617cSJimmy Assarsson if (priv->can.ctrlmode & CAN_CTRLMODE_BERR_REPORTING)
12123749637bSJimmy Assarsson skb = alloc_can_err_skb(priv->netdev, &cf);
12133749637bSJimmy Assarsson kvaser_usb_leaf_rx_error_update_can_state(priv, es, cf);
12147259124eSJimmy Assarsson new_state = priv->can.state;
12157259124eSJimmy Assarsson
12168d21f592SAnssi Hannula /* If there are errors, request status updates periodically as we do
12178d21f592SAnssi Hannula * not get automatic notifications of improved state.
1218abb86709SAnssi Hannula * Also request updates if we saw a stale BUS_OFF during startup
1219abb86709SAnssi Hannula * (joining_bus).
12208d21f592SAnssi Hannula */
12218d21f592SAnssi Hannula if (new_state < CAN_STATE_BUS_OFF &&
1222abb86709SAnssi Hannula (es->rxerr || es->txerr || new_state == CAN_STATE_ERROR_PASSIVE ||
1223abb86709SAnssi Hannula leaf->joining_bus))
12248d21f592SAnssi Hannula schedule_delayed_work(&leaf->chip_state_req_work,
12258d21f592SAnssi Hannula msecs_to_jiffies(500));
12268d21f592SAnssi Hannula
12277259124eSJimmy Assarsson if (new_state != old_state) {
12287259124eSJimmy Assarsson if (es->status &
12297259124eSJimmy Assarsson (M16C_STATE_BUS_OFF | M16C_STATE_BUS_RESET)) {
12307259124eSJimmy Assarsson if (!priv->can.restart_ms)
12317259124eSJimmy Assarsson kvaser_usb_leaf_simple_cmd_async(priv,
12327259124eSJimmy Assarsson CMD_STOP_CHIP);
12337259124eSJimmy Assarsson netif_carrier_off(priv->netdev);
12347259124eSJimmy Assarsson }
12357259124eSJimmy Assarsson
12367259124eSJimmy Assarsson if (priv->can.restart_ms &&
123790904d32SAnssi Hannula old_state == CAN_STATE_BUS_OFF &&
12387259124eSJimmy Assarsson new_state < CAN_STATE_BUS_OFF) {
12393749637bSJimmy Assarsson if (cf)
12407259124eSJimmy Assarsson cf->can_id |= CAN_ERR_RESTARTED;
12417259124eSJimmy Assarsson netif_carrier_on(priv->netdev);
12427259124eSJimmy Assarsson }
12437259124eSJimmy Assarsson }
12447259124eSJimmy Assarsson
12453749637bSJimmy Assarsson if (!skb) {
12460dfa617cSJimmy Assarsson if (priv->can.ctrlmode & CAN_CTRLMODE_BERR_REPORTING) {
12473749637bSJimmy Assarsson stats->rx_dropped++;
12483749637bSJimmy Assarsson netdev_warn(priv->netdev, "No memory left for err_skb\n");
12490dfa617cSJimmy Assarsson }
12503749637bSJimmy Assarsson return;
12513749637bSJimmy Assarsson }
12523749637bSJimmy Assarsson
125349f274c7SJimmy Assarsson switch (dev->driver_info->family) {
12547259124eSJimmy Assarsson case KVASER_LEAF:
12557259124eSJimmy Assarsson if (es->leaf.error_factor) {
12567259124eSJimmy Assarsson cf->can_id |= CAN_ERR_BUSERROR | CAN_ERR_PROT;
12577259124eSJimmy Assarsson
12587259124eSJimmy Assarsson if (es->leaf.error_factor & M16C_EF_ACKE)
12597259124eSJimmy Assarsson cf->data[3] = CAN_ERR_PROT_LOC_ACK;
12607259124eSJimmy Assarsson if (es->leaf.error_factor & M16C_EF_CRCE)
12617259124eSJimmy Assarsson cf->data[3] = CAN_ERR_PROT_LOC_CRC_SEQ;
12627259124eSJimmy Assarsson if (es->leaf.error_factor & M16C_EF_FORME)
12637259124eSJimmy Assarsson cf->data[2] |= CAN_ERR_PROT_FORM;
12647259124eSJimmy Assarsson if (es->leaf.error_factor & M16C_EF_STFE)
12657259124eSJimmy Assarsson cf->data[2] |= CAN_ERR_PROT_STUFF;
12667259124eSJimmy Assarsson if (es->leaf.error_factor & M16C_EF_BITE0)
12677259124eSJimmy Assarsson cf->data[2] |= CAN_ERR_PROT_BIT0;
12687259124eSJimmy Assarsson if (es->leaf.error_factor & M16C_EF_BITE1)
12697259124eSJimmy Assarsson cf->data[2] |= CAN_ERR_PROT_BIT1;
12707259124eSJimmy Assarsson if (es->leaf.error_factor & M16C_EF_TRE)
12717259124eSJimmy Assarsson cf->data[2] |= CAN_ERR_PROT_TX;
12727259124eSJimmy Assarsson }
12737259124eSJimmy Assarsson break;
12747259124eSJimmy Assarsson case KVASER_USBCAN:
12757259124eSJimmy Assarsson if (es->usbcan.error_state & USBCAN_ERROR_STATE_BUSERROR)
12767259124eSJimmy Assarsson cf->can_id |= CAN_ERR_BUSERROR;
12777259124eSJimmy Assarsson break;
12787259124eSJimmy Assarsson }
12797259124eSJimmy Assarsson
1280a5773208SVincent Mailhol if (new_state != CAN_STATE_BUS_OFF) {
12813e5c291cSVincent Mailhol cf->can_id |= CAN_ERR_CNT;
12827259124eSJimmy Assarsson cf->data[6] = es->txerr;
12837259124eSJimmy Assarsson cf->data[7] = es->rxerr;
1284a5773208SVincent Mailhol }
12857259124eSJimmy Assarsson
12867259124eSJimmy Assarsson netif_rx(skb);
12877259124eSJimmy Assarsson }
12887259124eSJimmy Assarsson
12897259124eSJimmy Assarsson /* For USBCAN, report error to userspace if the channels's errors counter
12907259124eSJimmy Assarsson * has changed, or we're the only channel seeing a bus error state.
12917259124eSJimmy Assarsson */
12927259124eSJimmy Assarsson static void
kvaser_usb_leaf_usbcan_conditionally_rx_error(const struct kvaser_usb * dev,struct kvaser_usb_err_summary * es)12937259124eSJimmy Assarsson kvaser_usb_leaf_usbcan_conditionally_rx_error(const struct kvaser_usb *dev,
12947259124eSJimmy Assarsson struct kvaser_usb_err_summary *es)
12957259124eSJimmy Assarsson {
12967259124eSJimmy Assarsson struct kvaser_usb_net_priv *priv;
12977259124eSJimmy Assarsson unsigned int channel;
12987259124eSJimmy Assarsson bool report_error;
12997259124eSJimmy Assarsson
13007259124eSJimmy Assarsson channel = es->channel;
13017259124eSJimmy Assarsson if (channel >= dev->nchannels) {
13027259124eSJimmy Assarsson dev_err(&dev->intf->dev,
13037259124eSJimmy Assarsson "Invalid channel number (%d)\n", channel);
13047259124eSJimmy Assarsson return;
13057259124eSJimmy Assarsson }
13067259124eSJimmy Assarsson
13077259124eSJimmy Assarsson priv = dev->nets[channel];
13087259124eSJimmy Assarsson report_error = false;
13097259124eSJimmy Assarsson
13107259124eSJimmy Assarsson if (es->txerr != priv->bec.txerr) {
13117259124eSJimmy Assarsson es->usbcan.error_state |= USBCAN_ERROR_STATE_TX_ERROR;
13127259124eSJimmy Assarsson report_error = true;
13137259124eSJimmy Assarsson }
13147259124eSJimmy Assarsson if (es->rxerr != priv->bec.rxerr) {
13157259124eSJimmy Assarsson es->usbcan.error_state |= USBCAN_ERROR_STATE_RX_ERROR;
13167259124eSJimmy Assarsson report_error = true;
13177259124eSJimmy Assarsson }
13187259124eSJimmy Assarsson if ((es->status & M16C_STATE_BUS_ERROR) &&
13197259124eSJimmy Assarsson !(es->usbcan.other_ch_status & M16C_STATE_BUS_ERROR)) {
13207259124eSJimmy Assarsson es->usbcan.error_state |= USBCAN_ERROR_STATE_BUSERROR;
13217259124eSJimmy Assarsson report_error = true;
13227259124eSJimmy Assarsson }
13237259124eSJimmy Assarsson
13247259124eSJimmy Assarsson if (report_error)
13257259124eSJimmy Assarsson kvaser_usb_leaf_rx_error(dev, es);
13267259124eSJimmy Assarsson }
13277259124eSJimmy Assarsson
kvaser_usb_leaf_usbcan_rx_error(const struct kvaser_usb * dev,const struct kvaser_cmd * cmd)13287259124eSJimmy Assarsson static void kvaser_usb_leaf_usbcan_rx_error(const struct kvaser_usb *dev,
13297259124eSJimmy Assarsson const struct kvaser_cmd *cmd)
13307259124eSJimmy Assarsson {
13317259124eSJimmy Assarsson struct kvaser_usb_err_summary es = { };
13327259124eSJimmy Assarsson
13337259124eSJimmy Assarsson switch (cmd->id) {
13347259124eSJimmy Assarsson /* Sometimes errors are sent as unsolicited chip state events */
13357259124eSJimmy Assarsson case CMD_CHIP_STATE_EVENT:
13367259124eSJimmy Assarsson es.channel = cmd->u.usbcan.chip_state_event.channel;
13377259124eSJimmy Assarsson es.status = cmd->u.usbcan.chip_state_event.status;
13387259124eSJimmy Assarsson es.txerr = cmd->u.usbcan.chip_state_event.tx_errors_count;
13397259124eSJimmy Assarsson es.rxerr = cmd->u.usbcan.chip_state_event.rx_errors_count;
13407259124eSJimmy Assarsson kvaser_usb_leaf_usbcan_conditionally_rx_error(dev, &es);
13417259124eSJimmy Assarsson break;
13427259124eSJimmy Assarsson
13437259124eSJimmy Assarsson case CMD_CAN_ERROR_EVENT:
13447259124eSJimmy Assarsson es.channel = 0;
13457ea56128SJimmy Assarsson es.status = cmd->u.usbcan.can_error_event.status_ch0;
13467ea56128SJimmy Assarsson es.txerr = cmd->u.usbcan.can_error_event.tx_errors_count_ch0;
13477ea56128SJimmy Assarsson es.rxerr = cmd->u.usbcan.can_error_event.rx_errors_count_ch0;
13487259124eSJimmy Assarsson es.usbcan.other_ch_status =
13497ea56128SJimmy Assarsson cmd->u.usbcan.can_error_event.status_ch1;
13507259124eSJimmy Assarsson kvaser_usb_leaf_usbcan_conditionally_rx_error(dev, &es);
13517259124eSJimmy Assarsson
13527259124eSJimmy Assarsson /* The USBCAN firmware supports up to 2 channels.
13537259124eSJimmy Assarsson * Now that ch0 was checked, check if ch1 has any errors.
13547259124eSJimmy Assarsson */
13557259124eSJimmy Assarsson if (dev->nchannels == MAX_USBCAN_NET_DEVICES) {
13567259124eSJimmy Assarsson es.channel = 1;
13577ea56128SJimmy Assarsson es.status = cmd->u.usbcan.can_error_event.status_ch1;
13587259124eSJimmy Assarsson es.txerr =
13597ea56128SJimmy Assarsson cmd->u.usbcan.can_error_event.tx_errors_count_ch1;
13607259124eSJimmy Assarsson es.rxerr =
13617ea56128SJimmy Assarsson cmd->u.usbcan.can_error_event.rx_errors_count_ch1;
13627259124eSJimmy Assarsson es.usbcan.other_ch_status =
13637ea56128SJimmy Assarsson cmd->u.usbcan.can_error_event.status_ch0;
13647259124eSJimmy Assarsson kvaser_usb_leaf_usbcan_conditionally_rx_error(dev, &es);
13657259124eSJimmy Assarsson }
13667259124eSJimmy Assarsson break;
13677259124eSJimmy Assarsson
13687259124eSJimmy Assarsson default:
13697259124eSJimmy Assarsson dev_err(&dev->intf->dev, "Invalid cmd id (%d)\n", cmd->id);
13707259124eSJimmy Assarsson }
13717259124eSJimmy Assarsson }
13727259124eSJimmy Assarsson
kvaser_usb_leaf_leaf_rx_error(const struct kvaser_usb * dev,const struct kvaser_cmd * cmd)13737259124eSJimmy Assarsson static void kvaser_usb_leaf_leaf_rx_error(const struct kvaser_usb *dev,
13747259124eSJimmy Assarsson const struct kvaser_cmd *cmd)
13757259124eSJimmy Assarsson {
13767259124eSJimmy Assarsson struct kvaser_usb_err_summary es = { };
13777259124eSJimmy Assarsson
13787259124eSJimmy Assarsson switch (cmd->id) {
13797259124eSJimmy Assarsson case CMD_CAN_ERROR_EVENT:
13807ea56128SJimmy Assarsson es.channel = cmd->u.leaf.can_error_event.channel;
13817ea56128SJimmy Assarsson es.status = cmd->u.leaf.can_error_event.status;
13827ea56128SJimmy Assarsson es.txerr = cmd->u.leaf.can_error_event.tx_errors_count;
13837ea56128SJimmy Assarsson es.rxerr = cmd->u.leaf.can_error_event.rx_errors_count;
13847ea56128SJimmy Assarsson es.leaf.error_factor = cmd->u.leaf.can_error_event.error_factor;
13857259124eSJimmy Assarsson break;
13867259124eSJimmy Assarsson case CMD_LEAF_LOG_MESSAGE:
13877259124eSJimmy Assarsson es.channel = cmd->u.leaf.log_message.channel;
13887259124eSJimmy Assarsson es.status = cmd->u.leaf.log_message.data[0];
13897259124eSJimmy Assarsson es.txerr = cmd->u.leaf.log_message.data[2];
13907259124eSJimmy Assarsson es.rxerr = cmd->u.leaf.log_message.data[3];
13917259124eSJimmy Assarsson es.leaf.error_factor = cmd->u.leaf.log_message.data[1];
13927259124eSJimmy Assarsson break;
13937259124eSJimmy Assarsson case CMD_CHIP_STATE_EVENT:
13947259124eSJimmy Assarsson es.channel = cmd->u.leaf.chip_state_event.channel;
13957259124eSJimmy Assarsson es.status = cmd->u.leaf.chip_state_event.status;
13967259124eSJimmy Assarsson es.txerr = cmd->u.leaf.chip_state_event.tx_errors_count;
13977259124eSJimmy Assarsson es.rxerr = cmd->u.leaf.chip_state_event.rx_errors_count;
13987259124eSJimmy Assarsson es.leaf.error_factor = 0;
13997259124eSJimmy Assarsson break;
14007259124eSJimmy Assarsson default:
14017259124eSJimmy Assarsson dev_err(&dev->intf->dev, "Invalid cmd id (%d)\n", cmd->id);
14027259124eSJimmy Assarsson return;
14037259124eSJimmy Assarsson }
14047259124eSJimmy Assarsson
14057259124eSJimmy Assarsson kvaser_usb_leaf_rx_error(dev, &es);
14067259124eSJimmy Assarsson }
14077259124eSJimmy Assarsson
kvaser_usb_leaf_rx_can_err(const struct kvaser_usb_net_priv * priv,const struct kvaser_cmd * cmd)14087259124eSJimmy Assarsson static void kvaser_usb_leaf_rx_can_err(const struct kvaser_usb_net_priv *priv,
14097259124eSJimmy Assarsson const struct kvaser_cmd *cmd)
14107259124eSJimmy Assarsson {
14117259124eSJimmy Assarsson if (cmd->u.rx_can_header.flag & (MSG_FLAG_ERROR_FRAME |
14127259124eSJimmy Assarsson MSG_FLAG_NERR)) {
14137259124eSJimmy Assarsson struct net_device_stats *stats = &priv->netdev->stats;
14147259124eSJimmy Assarsson
14157259124eSJimmy Assarsson netdev_err(priv->netdev, "Unknown error (flags: 0x%02x)\n",
14167259124eSJimmy Assarsson cmd->u.rx_can_header.flag);
14177259124eSJimmy Assarsson
14187259124eSJimmy Assarsson stats->rx_errors++;
14197259124eSJimmy Assarsson return;
14207259124eSJimmy Assarsson }
14217259124eSJimmy Assarsson
14227259124eSJimmy Assarsson if (cmd->u.rx_can_header.flag & MSG_FLAG_OVERRUN)
14237259124eSJimmy Assarsson kvaser_usb_can_rx_over_error(priv->netdev);
14247259124eSJimmy Assarsson }
14257259124eSJimmy Assarsson
kvaser_usb_leaf_rx_can_msg(const struct kvaser_usb * dev,const struct kvaser_cmd * cmd)14267259124eSJimmy Assarsson static void kvaser_usb_leaf_rx_can_msg(const struct kvaser_usb *dev,
14277259124eSJimmy Assarsson const struct kvaser_cmd *cmd)
14287259124eSJimmy Assarsson {
14297259124eSJimmy Assarsson struct kvaser_usb_net_priv *priv;
14307259124eSJimmy Assarsson struct can_frame *cf;
14317259124eSJimmy Assarsson struct sk_buff *skb;
14327259124eSJimmy Assarsson struct net_device_stats *stats;
14337259124eSJimmy Assarsson u8 channel = cmd->u.rx_can_header.channel;
14347259124eSJimmy Assarsson const u8 *rx_data = NULL; /* GCC */
14358a52e5a0SJimmy Assarsson ktime_t hwtstamp = 0;
14367259124eSJimmy Assarsson
14377259124eSJimmy Assarsson if (channel >= dev->nchannels) {
14387259124eSJimmy Assarsson dev_err(&dev->intf->dev,
14397259124eSJimmy Assarsson "Invalid channel number (%d)\n", channel);
14407259124eSJimmy Assarsson return;
14417259124eSJimmy Assarsson }
14427259124eSJimmy Assarsson
14437259124eSJimmy Assarsson priv = dev->nets[channel];
14447259124eSJimmy Assarsson stats = &priv->netdev->stats;
14457259124eSJimmy Assarsson
14467259124eSJimmy Assarsson if ((cmd->u.rx_can_header.flag & MSG_FLAG_ERROR_FRAME) &&
144749f274c7SJimmy Assarsson (dev->driver_info->family == KVASER_LEAF &&
14487259124eSJimmy Assarsson cmd->id == CMD_LEAF_LOG_MESSAGE)) {
14497259124eSJimmy Assarsson kvaser_usb_leaf_leaf_rx_error(dev, cmd);
14507259124eSJimmy Assarsson return;
14517259124eSJimmy Assarsson } else if (cmd->u.rx_can_header.flag & (MSG_FLAG_ERROR_FRAME |
14527259124eSJimmy Assarsson MSG_FLAG_NERR |
14537259124eSJimmy Assarsson MSG_FLAG_OVERRUN)) {
14547259124eSJimmy Assarsson kvaser_usb_leaf_rx_can_err(priv, cmd);
14557259124eSJimmy Assarsson return;
14567259124eSJimmy Assarsson } else if (cmd->u.rx_can_header.flag & ~MSG_FLAG_REMOTE_FRAME) {
14577259124eSJimmy Assarsson netdev_warn(priv->netdev,
14587259124eSJimmy Assarsson "Unhandled frame (flags: 0x%02x)\n",
14597259124eSJimmy Assarsson cmd->u.rx_can_header.flag);
14607259124eSJimmy Assarsson return;
14617259124eSJimmy Assarsson }
14627259124eSJimmy Assarsson
146349f274c7SJimmy Assarsson switch (dev->driver_info->family) {
14647259124eSJimmy Assarsson case KVASER_LEAF:
14657259124eSJimmy Assarsson rx_data = cmd->u.leaf.rx_can.data;
14668a52e5a0SJimmy Assarsson hwtstamp = kvaser_usb_timestamp48_to_ktime(dev->cfg, cmd->u.leaf.rx_can.time);
14677259124eSJimmy Assarsson break;
14687259124eSJimmy Assarsson case KVASER_USBCAN:
14697259124eSJimmy Assarsson rx_data = cmd->u.usbcan.rx_can.data;
14700aa639d3SJimmy Assarsson hwtstamp = kvaser_usb_usbcan_timestamp_to_ktime(dev, cmd->u.usbcan.rx_can.time);
14717259124eSJimmy Assarsson break;
14727259124eSJimmy Assarsson }
14737259124eSJimmy Assarsson
14747259124eSJimmy Assarsson skb = alloc_can_skb(priv->netdev, &cf);
14757259124eSJimmy Assarsson if (!skb) {
14767259124eSJimmy Assarsson stats->rx_dropped++;
14777259124eSJimmy Assarsson return;
14787259124eSJimmy Assarsson }
14797259124eSJimmy Assarsson
148049f274c7SJimmy Assarsson if (dev->driver_info->family == KVASER_LEAF && cmd->id ==
14817259124eSJimmy Assarsson CMD_LEAF_LOG_MESSAGE) {
14827259124eSJimmy Assarsson cf->can_id = le32_to_cpu(cmd->u.leaf.log_message.id);
14837259124eSJimmy Assarsson if (cf->can_id & KVASER_EXTENDED_FRAME)
14847259124eSJimmy Assarsson cf->can_id &= CAN_EFF_MASK | CAN_EFF_FLAG;
14857259124eSJimmy Assarsson else
14867259124eSJimmy Assarsson cf->can_id &= CAN_SFF_MASK;
14877259124eSJimmy Assarsson
1488843b8464SCarsten Schmidt can_frame_set_cc_len(cf, cmd->u.leaf.log_message.dlc & 0xF, priv->can.ctrlmode);
14897259124eSJimmy Assarsson
14907259124eSJimmy Assarsson if (cmd->u.leaf.log_message.flags & MSG_FLAG_REMOTE_FRAME)
14917259124eSJimmy Assarsson cf->can_id |= CAN_RTR_FLAG;
14927259124eSJimmy Assarsson else
14937259124eSJimmy Assarsson memcpy(cf->data, &cmd->u.leaf.log_message.data,
1494c7b74967SOliver Hartkopp cf->len);
14957259124eSJimmy Assarsson } else {
14967259124eSJimmy Assarsson cf->can_id = ((rx_data[0] & 0x1f) << 6) | (rx_data[1] & 0x3f);
14977259124eSJimmy Assarsson
14987259124eSJimmy Assarsson if (cmd->id == CMD_RX_EXT_MESSAGE) {
14997259124eSJimmy Assarsson cf->can_id <<= 18;
15007259124eSJimmy Assarsson cf->can_id |= ((rx_data[2] & 0x0f) << 14) |
15017259124eSJimmy Assarsson ((rx_data[3] & 0xff) << 6) |
15027259124eSJimmy Assarsson (rx_data[4] & 0x3f);
15037259124eSJimmy Assarsson cf->can_id |= CAN_EFF_FLAG;
15047259124eSJimmy Assarsson }
15057259124eSJimmy Assarsson
1506843b8464SCarsten Schmidt can_frame_set_cc_len(cf, rx_data[5] & 0xF, priv->can.ctrlmode);
15077259124eSJimmy Assarsson
15087259124eSJimmy Assarsson if (cmd->u.rx_can_header.flag & MSG_FLAG_REMOTE_FRAME)
15097259124eSJimmy Assarsson cf->can_id |= CAN_RTR_FLAG;
15107259124eSJimmy Assarsson else
1511c7b74967SOliver Hartkopp memcpy(cf->data, &rx_data[6], cf->len);
15127259124eSJimmy Assarsson }
15137259124eSJimmy Assarsson
15148a52e5a0SJimmy Assarsson skb_hwtstamps(skb)->hwtstamp = hwtstamp;
15157259124eSJimmy Assarsson stats->rx_packets++;
15168e674ca7SVincent Mailhol if (!(cf->can_id & CAN_RTR_FLAG))
1517c7b74967SOliver Hartkopp stats->rx_bytes += cf->len;
15187259124eSJimmy Assarsson netif_rx(skb);
15197259124eSJimmy Assarsson }
15207259124eSJimmy Assarsson
kvaser_usb_leaf_error_event_parameter(const struct kvaser_usb * dev,const struct kvaser_cmd * cmd)1521b24cb2d1SJimmy Assarsson static void kvaser_usb_leaf_error_event_parameter(const struct kvaser_usb *dev,
1522b24cb2d1SJimmy Assarsson const struct kvaser_cmd *cmd)
1523b24cb2d1SJimmy Assarsson {
1524b24cb2d1SJimmy Assarsson u16 info1 = 0;
1525b24cb2d1SJimmy Assarsson
1526b24cb2d1SJimmy Assarsson switch (dev->driver_info->family) {
1527b24cb2d1SJimmy Assarsson case KVASER_LEAF:
1528b24cb2d1SJimmy Assarsson info1 = le16_to_cpu(cmd->u.leaf.error_event.info1);
1529b24cb2d1SJimmy Assarsson break;
1530b24cb2d1SJimmy Assarsson case KVASER_USBCAN:
1531b24cb2d1SJimmy Assarsson info1 = le16_to_cpu(cmd->u.usbcan.error_event.info1);
1532b24cb2d1SJimmy Assarsson break;
1533b24cb2d1SJimmy Assarsson }
1534b24cb2d1SJimmy Assarsson
1535b24cb2d1SJimmy Assarsson /* info1 will contain the offending cmd_no */
1536b24cb2d1SJimmy Assarsson switch (info1) {
1537b24cb2d1SJimmy Assarsson case CMD_SET_CTRL_MODE:
1538b24cb2d1SJimmy Assarsson dev_warn(&dev->intf->dev,
1539b24cb2d1SJimmy Assarsson "CMD_SET_CTRL_MODE error in parameter\n");
1540b24cb2d1SJimmy Assarsson break;
1541b24cb2d1SJimmy Assarsson
1542b24cb2d1SJimmy Assarsson case CMD_SET_BUS_PARAMS:
1543b24cb2d1SJimmy Assarsson dev_warn(&dev->intf->dev,
1544b24cb2d1SJimmy Assarsson "CMD_SET_BUS_PARAMS error in parameter\n");
1545b24cb2d1SJimmy Assarsson break;
1546b24cb2d1SJimmy Assarsson
1547b24cb2d1SJimmy Assarsson default:
1548b24cb2d1SJimmy Assarsson dev_warn(&dev->intf->dev,
1549b24cb2d1SJimmy Assarsson "Unhandled parameter error event cmd_no (%u)\n",
1550b24cb2d1SJimmy Assarsson info1);
1551b24cb2d1SJimmy Assarsson break;
1552b24cb2d1SJimmy Assarsson }
1553b24cb2d1SJimmy Assarsson }
1554b24cb2d1SJimmy Assarsson
kvaser_usb_leaf_error_event(const struct kvaser_usb * dev,const struct kvaser_cmd * cmd)1555b24cb2d1SJimmy Assarsson static void kvaser_usb_leaf_error_event(const struct kvaser_usb *dev,
1556b24cb2d1SJimmy Assarsson const struct kvaser_cmd *cmd)
1557b24cb2d1SJimmy Assarsson {
1558b24cb2d1SJimmy Assarsson u8 error_code = 0;
1559b24cb2d1SJimmy Assarsson
1560b24cb2d1SJimmy Assarsson switch (dev->driver_info->family) {
1561b24cb2d1SJimmy Assarsson case KVASER_LEAF:
1562b24cb2d1SJimmy Assarsson error_code = cmd->u.leaf.error_event.error_code;
1563b24cb2d1SJimmy Assarsson break;
1564b24cb2d1SJimmy Assarsson case KVASER_USBCAN:
1565b24cb2d1SJimmy Assarsson error_code = cmd->u.usbcan.error_event.error_code;
1566b24cb2d1SJimmy Assarsson break;
1567b24cb2d1SJimmy Assarsson }
1568b24cb2d1SJimmy Assarsson
1569b24cb2d1SJimmy Assarsson switch (error_code) {
1570b24cb2d1SJimmy Assarsson case KVASER_USB_LEAF_ERROR_EVENT_TX_QUEUE_FULL:
1571b24cb2d1SJimmy Assarsson /* Received additional CAN message, when firmware TX queue is
1572b24cb2d1SJimmy Assarsson * already full. Something is wrong with the driver.
1573b24cb2d1SJimmy Assarsson * This should never happen!
1574b24cb2d1SJimmy Assarsson */
1575b24cb2d1SJimmy Assarsson dev_err(&dev->intf->dev,
1576b24cb2d1SJimmy Assarsson "Received error event TX_QUEUE_FULL\n");
1577b24cb2d1SJimmy Assarsson break;
1578b24cb2d1SJimmy Assarsson case KVASER_USB_LEAF_ERROR_EVENT_PARAM:
1579b24cb2d1SJimmy Assarsson kvaser_usb_leaf_error_event_parameter(dev, cmd);
1580b24cb2d1SJimmy Assarsson break;
1581b24cb2d1SJimmy Assarsson
1582b24cb2d1SJimmy Assarsson default:
1583b24cb2d1SJimmy Assarsson dev_warn(&dev->intf->dev,
1584b24cb2d1SJimmy Assarsson "Unhandled error event (%d)\n", error_code);
1585b24cb2d1SJimmy Assarsson break;
1586b24cb2d1SJimmy Assarsson }
1587b24cb2d1SJimmy Assarsson }
1588b24cb2d1SJimmy Assarsson
kvaser_usb_leaf_start_chip_reply(const struct kvaser_usb * dev,const struct kvaser_cmd * cmd)15897259124eSJimmy Assarsson static void kvaser_usb_leaf_start_chip_reply(const struct kvaser_usb *dev,
15907259124eSJimmy Assarsson const struct kvaser_cmd *cmd)
15917259124eSJimmy Assarsson {
15927259124eSJimmy Assarsson struct kvaser_usb_net_priv *priv;
15937259124eSJimmy Assarsson u8 channel = cmd->u.simple.channel;
15947259124eSJimmy Assarsson
15957259124eSJimmy Assarsson if (channel >= dev->nchannels) {
15967259124eSJimmy Assarsson dev_err(&dev->intf->dev,
15977259124eSJimmy Assarsson "Invalid channel number (%d)\n", channel);
15987259124eSJimmy Assarsson return;
15997259124eSJimmy Assarsson }
16007259124eSJimmy Assarsson
16017259124eSJimmy Assarsson priv = dev->nets[channel];
16027259124eSJimmy Assarsson
16037259124eSJimmy Assarsson if (completion_done(&priv->start_comp) &&
16047259124eSJimmy Assarsson netif_queue_stopped(priv->netdev)) {
16057259124eSJimmy Assarsson netif_wake_queue(priv->netdev);
16067259124eSJimmy Assarsson } else {
16077259124eSJimmy Assarsson netif_start_queue(priv->netdev);
16087259124eSJimmy Assarsson complete(&priv->start_comp);
16097259124eSJimmy Assarsson }
16107259124eSJimmy Assarsson }
16117259124eSJimmy Assarsson
kvaser_usb_leaf_stop_chip_reply(const struct kvaser_usb * dev,const struct kvaser_cmd * cmd)16127259124eSJimmy Assarsson static void kvaser_usb_leaf_stop_chip_reply(const struct kvaser_usb *dev,
16137259124eSJimmy Assarsson const struct kvaser_cmd *cmd)
16147259124eSJimmy Assarsson {
16157259124eSJimmy Assarsson struct kvaser_usb_net_priv *priv;
16167259124eSJimmy Assarsson u8 channel = cmd->u.simple.channel;
16177259124eSJimmy Assarsson
16187259124eSJimmy Assarsson if (channel >= dev->nchannels) {
16197259124eSJimmy Assarsson dev_err(&dev->intf->dev,
16207259124eSJimmy Assarsson "Invalid channel number (%d)\n", channel);
16217259124eSJimmy Assarsson return;
16227259124eSJimmy Assarsson }
16237259124eSJimmy Assarsson
16247259124eSJimmy Assarsson priv = dev->nets[channel];
16257259124eSJimmy Assarsson
16267259124eSJimmy Assarsson complete(&priv->stop_comp);
16277259124eSJimmy Assarsson }
16287259124eSJimmy Assarsson
kvaser_usb_leaf_get_busparams_reply(const struct kvaser_usb * dev,const struct kvaser_cmd * cmd)162939d3df6bSJimmy Assarsson static void kvaser_usb_leaf_get_busparams_reply(const struct kvaser_usb *dev,
163039d3df6bSJimmy Assarsson const struct kvaser_cmd *cmd)
163139d3df6bSJimmy Assarsson {
163239d3df6bSJimmy Assarsson struct kvaser_usb_net_priv *priv;
163339d3df6bSJimmy Assarsson u8 channel = cmd->u.busparams.channel;
163439d3df6bSJimmy Assarsson
163539d3df6bSJimmy Assarsson if (channel >= dev->nchannels) {
163639d3df6bSJimmy Assarsson dev_err(&dev->intf->dev,
163739d3df6bSJimmy Assarsson "Invalid channel number (%d)\n", channel);
163839d3df6bSJimmy Assarsson return;
163939d3df6bSJimmy Assarsson }
164039d3df6bSJimmy Assarsson
164139d3df6bSJimmy Assarsson priv = dev->nets[channel];
164239d3df6bSJimmy Assarsson memcpy(&priv->busparams_nominal, &cmd->u.busparams.busparams,
164339d3df6bSJimmy Assarsson sizeof(priv->busparams_nominal));
164439d3df6bSJimmy Assarsson
164539d3df6bSJimmy Assarsson complete(&priv->get_busparams_comp);
164639d3df6bSJimmy Assarsson }
164739d3df6bSJimmy Assarsson
kvaser_usb_leaf_handle_command(struct kvaser_usb * dev,const struct kvaser_cmd * cmd)1648c644c969SJimmy Assarsson static void kvaser_usb_leaf_handle_command(struct kvaser_usb *dev,
16497259124eSJimmy Assarsson const struct kvaser_cmd *cmd)
16507259124eSJimmy Assarsson {
16511499ecaeSAnssi Hannula if (kvaser_usb_leaf_verify_size(dev, cmd) < 0)
16521499ecaeSAnssi Hannula return;
16531499ecaeSAnssi Hannula
16547259124eSJimmy Assarsson switch (cmd->id) {
16557259124eSJimmy Assarsson case CMD_START_CHIP_REPLY:
16567259124eSJimmy Assarsson kvaser_usb_leaf_start_chip_reply(dev, cmd);
16577259124eSJimmy Assarsson break;
16587259124eSJimmy Assarsson
16597259124eSJimmy Assarsson case CMD_STOP_CHIP_REPLY:
16607259124eSJimmy Assarsson kvaser_usb_leaf_stop_chip_reply(dev, cmd);
16617259124eSJimmy Assarsson break;
16627259124eSJimmy Assarsson
16637259124eSJimmy Assarsson case CMD_RX_STD_MESSAGE:
16647259124eSJimmy Assarsson case CMD_RX_EXT_MESSAGE:
16657259124eSJimmy Assarsson kvaser_usb_leaf_rx_can_msg(dev, cmd);
16667259124eSJimmy Assarsson break;
16677259124eSJimmy Assarsson
16687259124eSJimmy Assarsson case CMD_LEAF_LOG_MESSAGE:
166949f274c7SJimmy Assarsson if (dev->driver_info->family != KVASER_LEAF)
16707259124eSJimmy Assarsson goto warn;
16717259124eSJimmy Assarsson kvaser_usb_leaf_rx_can_msg(dev, cmd);
16727259124eSJimmy Assarsson break;
16737259124eSJimmy Assarsson
16747259124eSJimmy Assarsson case CMD_CHIP_STATE_EVENT:
16757259124eSJimmy Assarsson case CMD_CAN_ERROR_EVENT:
167649f274c7SJimmy Assarsson if (dev->driver_info->family == KVASER_LEAF)
16777259124eSJimmy Assarsson kvaser_usb_leaf_leaf_rx_error(dev, cmd);
16787259124eSJimmy Assarsson else
16797259124eSJimmy Assarsson kvaser_usb_leaf_usbcan_rx_error(dev, cmd);
16807259124eSJimmy Assarsson break;
16817259124eSJimmy Assarsson
16827259124eSJimmy Assarsson case CMD_TX_ACKNOWLEDGE:
16837259124eSJimmy Assarsson kvaser_usb_leaf_tx_acknowledge(dev, cmd);
16847259124eSJimmy Assarsson break;
16857259124eSJimmy Assarsson
1686b24cb2d1SJimmy Assarsson case CMD_ERROR_EVENT:
1687b24cb2d1SJimmy Assarsson kvaser_usb_leaf_error_event(dev, cmd);
1688b24cb2d1SJimmy Assarsson break;
1689b24cb2d1SJimmy Assarsson
169039d3df6bSJimmy Assarsson case CMD_GET_BUS_PARAMS_REPLY:
169139d3df6bSJimmy Assarsson kvaser_usb_leaf_get_busparams_reply(dev, cmd);
169239d3df6bSJimmy Assarsson break;
169339d3df6bSJimmy Assarsson
16947259124eSJimmy Assarsson case CMD_USBCAN_CLOCK_OVERFLOW_EVENT:
169549f274c7SJimmy Assarsson if (dev->driver_info->family != KVASER_USBCAN)
16967259124eSJimmy Assarsson goto warn;
1697c644c969SJimmy Assarsson dev->card_data.usbcan_timestamp_msb =
1698c644c969SJimmy Assarsson le32_to_cpu(cmd->u.usbcan.clk_overflow_event.time) &
1699c644c969SJimmy Assarsson KVASER_USB_USBCAN_CLK_OVERFLOW_MASK;
17007259124eSJimmy Assarsson break;
17017259124eSJimmy Assarsson
1702c644c969SJimmy Assarsson /* Ignored commands */
17037259124eSJimmy Assarsson case CMD_FLUSH_QUEUE_REPLY:
170449f274c7SJimmy Assarsson if (dev->driver_info->family != KVASER_LEAF)
17057259124eSJimmy Assarsson goto warn;
17067259124eSJimmy Assarsson break;
1707478248f1SJimmy Assarsson case CMD_LED_ACTION_RESP:
1708478248f1SJimmy Assarsson break;
17097259124eSJimmy Assarsson
17107259124eSJimmy Assarsson default:
17117259124eSJimmy Assarsson warn: dev_warn(&dev->intf->dev, "Unhandled command (%d)\n", cmd->id);
17127259124eSJimmy Assarsson break;
17137259124eSJimmy Assarsson }
17147259124eSJimmy Assarsson }
17157259124eSJimmy Assarsson
kvaser_usb_leaf_read_bulk_callback(struct kvaser_usb * dev,void * buf,int len)17167259124eSJimmy Assarsson static void kvaser_usb_leaf_read_bulk_callback(struct kvaser_usb *dev,
17177259124eSJimmy Assarsson void *buf, int len)
17187259124eSJimmy Assarsson {
17197259124eSJimmy Assarsson struct kvaser_cmd *cmd;
17207259124eSJimmy Assarsson int pos = 0;
17217259124eSJimmy Assarsson
17227259124eSJimmy Assarsson while (pos <= len - CMD_HEADER_LEN) {
17237259124eSJimmy Assarsson cmd = buf + pos;
17247259124eSJimmy Assarsson
17257259124eSJimmy Assarsson /* The Kvaser firmware can only read and write commands that
17267259124eSJimmy Assarsson * does not cross the USB's endpoint wMaxPacketSize boundary.
17277259124eSJimmy Assarsson * If a follow-up command crosses such boundary, firmware puts
17287259124eSJimmy Assarsson * a placeholder zero-length command in its place then aligns
17297259124eSJimmy Assarsson * the real command to the next max packet size.
17307259124eSJimmy Assarsson *
17317259124eSJimmy Assarsson * Handle such cases or we're going to miss a significant
17327259124eSJimmy Assarsson * number of events in case of a heavy rx load on the bus.
17337259124eSJimmy Assarsson */
17347259124eSJimmy Assarsson if (cmd->len == 0) {
17357259124eSJimmy Assarsson pos = round_up(pos, le16_to_cpu
17367259124eSJimmy Assarsson (dev->bulk_in->wMaxPacketSize));
17377259124eSJimmy Assarsson continue;
17387259124eSJimmy Assarsson }
17397259124eSJimmy Assarsson
17407259124eSJimmy Assarsson if (pos + cmd->len > len) {
17417259124eSJimmy Assarsson dev_err_ratelimited(&dev->intf->dev, "Format error\n");
17427259124eSJimmy Assarsson break;
17437259124eSJimmy Assarsson }
17447259124eSJimmy Assarsson
17457259124eSJimmy Assarsson kvaser_usb_leaf_handle_command(dev, cmd);
17467259124eSJimmy Assarsson pos += cmd->len;
17477259124eSJimmy Assarsson }
17487259124eSJimmy Assarsson }
17497259124eSJimmy Assarsson
kvaser_usb_leaf_set_opt_mode(const struct kvaser_usb_net_priv * priv)17507259124eSJimmy Assarsson static int kvaser_usb_leaf_set_opt_mode(const struct kvaser_usb_net_priv *priv)
17517259124eSJimmy Assarsson {
17527259124eSJimmy Assarsson struct kvaser_cmd *cmd;
17537259124eSJimmy Assarsson int rc;
17547259124eSJimmy Assarsson
1755da2311a6SXiaolong Huang cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
17567259124eSJimmy Assarsson if (!cmd)
17577259124eSJimmy Assarsson return -ENOMEM;
17587259124eSJimmy Assarsson
17597259124eSJimmy Assarsson cmd->id = CMD_SET_CTRL_MODE;
17607259124eSJimmy Assarsson cmd->len = CMD_HEADER_LEN + sizeof(struct kvaser_cmd_ctrl_mode);
17617259124eSJimmy Assarsson cmd->u.ctrl_mode.tid = 0xff;
17627259124eSJimmy Assarsson cmd->u.ctrl_mode.channel = priv->channel;
17637259124eSJimmy Assarsson
17647259124eSJimmy Assarsson if (priv->can.ctrlmode & CAN_CTRLMODE_LISTENONLY)
17657259124eSJimmy Assarsson cmd->u.ctrl_mode.ctrl_mode = KVASER_CTRL_MODE_SILENT;
17667259124eSJimmy Assarsson else
17677259124eSJimmy Assarsson cmd->u.ctrl_mode.ctrl_mode = KVASER_CTRL_MODE_NORMAL;
17687259124eSJimmy Assarsson
17697259124eSJimmy Assarsson rc = kvaser_usb_send_cmd(priv->dev, cmd, cmd->len);
17707259124eSJimmy Assarsson
17717259124eSJimmy Assarsson kfree(cmd);
17727259124eSJimmy Assarsson return rc;
17737259124eSJimmy Assarsson }
17747259124eSJimmy Assarsson
kvaser_usb_leaf_start_chip(struct kvaser_usb_net_priv * priv)17757259124eSJimmy Assarsson static int kvaser_usb_leaf_start_chip(struct kvaser_usb_net_priv *priv)
17767259124eSJimmy Assarsson {
1777abb86709SAnssi Hannula struct kvaser_usb_net_leaf_priv *leaf = priv->sub_priv;
17787259124eSJimmy Assarsson int err;
17797259124eSJimmy Assarsson
1780abb86709SAnssi Hannula leaf->joining_bus = true;
1781abb86709SAnssi Hannula
17822871edb3SAnssi Hannula reinit_completion(&priv->start_comp);
17837259124eSJimmy Assarsson
17847259124eSJimmy Assarsson err = kvaser_usb_leaf_send_simple_cmd(priv->dev, CMD_START_CHIP,
17857259124eSJimmy Assarsson priv->channel);
17867259124eSJimmy Assarsson if (err)
17877259124eSJimmy Assarsson return err;
17887259124eSJimmy Assarsson
17897259124eSJimmy Assarsson if (!wait_for_completion_timeout(&priv->start_comp,
17907259124eSJimmy Assarsson msecs_to_jiffies(KVASER_USB_TIMEOUT)))
17917259124eSJimmy Assarsson return -ETIMEDOUT;
17927259124eSJimmy Assarsson
17937259124eSJimmy Assarsson return 0;
17947259124eSJimmy Assarsson }
17957259124eSJimmy Assarsson
kvaser_usb_leaf_stop_chip(struct kvaser_usb_net_priv * priv)17967259124eSJimmy Assarsson static int kvaser_usb_leaf_stop_chip(struct kvaser_usb_net_priv *priv)
17977259124eSJimmy Assarsson {
17988d21f592SAnssi Hannula struct kvaser_usb_net_leaf_priv *leaf = priv->sub_priv;
17997259124eSJimmy Assarsson int err;
18007259124eSJimmy Assarsson
18012871edb3SAnssi Hannula reinit_completion(&priv->stop_comp);
18027259124eSJimmy Assarsson
18038d21f592SAnssi Hannula cancel_delayed_work(&leaf->chip_state_req_work);
18048d21f592SAnssi Hannula
18057259124eSJimmy Assarsson err = kvaser_usb_leaf_send_simple_cmd(priv->dev, CMD_STOP_CHIP,
18067259124eSJimmy Assarsson priv->channel);
18077259124eSJimmy Assarsson if (err)
18087259124eSJimmy Assarsson return err;
18097259124eSJimmy Assarsson
18107259124eSJimmy Assarsson if (!wait_for_completion_timeout(&priv->stop_comp,
18117259124eSJimmy Assarsson msecs_to_jiffies(KVASER_USB_TIMEOUT)))
18127259124eSJimmy Assarsson return -ETIMEDOUT;
18137259124eSJimmy Assarsson
18147259124eSJimmy Assarsson return 0;
18157259124eSJimmy Assarsson }
18167259124eSJimmy Assarsson
kvaser_usb_leaf_reset_chip(struct kvaser_usb * dev,int channel)18177259124eSJimmy Assarsson static int kvaser_usb_leaf_reset_chip(struct kvaser_usb *dev, int channel)
18187259124eSJimmy Assarsson {
18197259124eSJimmy Assarsson return kvaser_usb_leaf_send_simple_cmd(dev, CMD_RESET_CHIP, channel);
18207259124eSJimmy Assarsson }
18217259124eSJimmy Assarsson
kvaser_usb_leaf_flush_queue(struct kvaser_usb_net_priv * priv)18227259124eSJimmy Assarsson static int kvaser_usb_leaf_flush_queue(struct kvaser_usb_net_priv *priv)
18237259124eSJimmy Assarsson {
18247259124eSJimmy Assarsson struct kvaser_cmd *cmd;
18257259124eSJimmy Assarsson int rc;
18267259124eSJimmy Assarsson
1827da2311a6SXiaolong Huang cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
18287259124eSJimmy Assarsson if (!cmd)
18297259124eSJimmy Assarsson return -ENOMEM;
18307259124eSJimmy Assarsson
18317259124eSJimmy Assarsson cmd->id = CMD_FLUSH_QUEUE;
18327259124eSJimmy Assarsson cmd->len = CMD_HEADER_LEN + sizeof(struct kvaser_cmd_flush_queue);
18337259124eSJimmy Assarsson cmd->u.flush_queue.channel = priv->channel;
18347259124eSJimmy Assarsson cmd->u.flush_queue.flags = 0x00;
18357259124eSJimmy Assarsson
18367259124eSJimmy Assarsson rc = kvaser_usb_send_cmd(priv->dev, cmd, cmd->len);
18377259124eSJimmy Assarsson
18387259124eSJimmy Assarsson kfree(cmd);
18397259124eSJimmy Assarsson return rc;
18407259124eSJimmy Assarsson }
18417259124eSJimmy Assarsson
kvaser_usb_leaf_init_card(struct kvaser_usb * dev)18427259124eSJimmy Assarsson static int kvaser_usb_leaf_init_card(struct kvaser_usb *dev)
18437259124eSJimmy Assarsson {
18447259124eSJimmy Assarsson struct kvaser_usb_dev_card_data *card_data = &dev->card_data;
18457259124eSJimmy Assarsson
18467259124eSJimmy Assarsson card_data->ctrlmode_supported |= CAN_CTRLMODE_3_SAMPLES;
18477259124eSJimmy Assarsson
18487259124eSJimmy Assarsson return 0;
18497259124eSJimmy Assarsson }
18507259124eSJimmy Assarsson
kvaser_usb_leaf_init_channel(struct kvaser_usb_net_priv * priv)18518d21f592SAnssi Hannula static int kvaser_usb_leaf_init_channel(struct kvaser_usb_net_priv *priv)
18528d21f592SAnssi Hannula {
18538d21f592SAnssi Hannula struct kvaser_usb_net_leaf_priv *leaf;
18548d21f592SAnssi Hannula
18558d21f592SAnssi Hannula leaf = devm_kzalloc(&priv->dev->intf->dev, sizeof(*leaf), GFP_KERNEL);
18568d21f592SAnssi Hannula if (!leaf)
18578d21f592SAnssi Hannula return -ENOMEM;
18588d21f592SAnssi Hannula
18598d21f592SAnssi Hannula leaf->net = priv;
18608d21f592SAnssi Hannula INIT_DELAYED_WORK(&leaf->chip_state_req_work,
18618d21f592SAnssi Hannula kvaser_usb_leaf_chip_state_req_work);
18628d21f592SAnssi Hannula
18638d21f592SAnssi Hannula priv->sub_priv = leaf;
18648d21f592SAnssi Hannula
18658d21f592SAnssi Hannula return 0;
18668d21f592SAnssi Hannula }
18678d21f592SAnssi Hannula
kvaser_usb_leaf_remove_channel(struct kvaser_usb_net_priv * priv)18688d21f592SAnssi Hannula static void kvaser_usb_leaf_remove_channel(struct kvaser_usb_net_priv *priv)
18698d21f592SAnssi Hannula {
18708d21f592SAnssi Hannula struct kvaser_usb_net_leaf_priv *leaf = priv->sub_priv;
18718d21f592SAnssi Hannula
18728d21f592SAnssi Hannula if (leaf)
18738d21f592SAnssi Hannula cancel_delayed_work_sync(&leaf->chip_state_req_work);
18748d21f592SAnssi Hannula }
18758d21f592SAnssi Hannula
kvaser_usb_leaf_set_bittiming(const struct net_device * netdev,const struct kvaser_usb_busparams * busparams)187639d3df6bSJimmy Assarsson static int kvaser_usb_leaf_set_bittiming(const struct net_device *netdev,
187739d3df6bSJimmy Assarsson const struct kvaser_usb_busparams *busparams)
18787259124eSJimmy Assarsson {
18797259124eSJimmy Assarsson struct kvaser_usb_net_priv *priv = netdev_priv(netdev);
18807259124eSJimmy Assarsson struct kvaser_usb *dev = priv->dev;
18817259124eSJimmy Assarsson struct kvaser_cmd *cmd;
18827259124eSJimmy Assarsson int rc;
18837259124eSJimmy Assarsson
18847259124eSJimmy Assarsson cmd = kmalloc(sizeof(*cmd), GFP_KERNEL);
18857259124eSJimmy Assarsson if (!cmd)
18867259124eSJimmy Assarsson return -ENOMEM;
18877259124eSJimmy Assarsson
18887259124eSJimmy Assarsson cmd->id = CMD_SET_BUS_PARAMS;
18897259124eSJimmy Assarsson cmd->len = CMD_HEADER_LEN + sizeof(struct kvaser_cmd_busparams);
18907259124eSJimmy Assarsson cmd->u.busparams.channel = priv->channel;
18917259124eSJimmy Assarsson cmd->u.busparams.tid = 0xff;
189239d3df6bSJimmy Assarsson memcpy(&cmd->u.busparams.busparams, busparams,
189339d3df6bSJimmy Assarsson sizeof(cmd->u.busparams.busparams));
18947259124eSJimmy Assarsson
18957259124eSJimmy Assarsson rc = kvaser_usb_send_cmd(dev, cmd, cmd->len);
18967259124eSJimmy Assarsson
18977259124eSJimmy Assarsson kfree(cmd);
18987259124eSJimmy Assarsson return rc;
18997259124eSJimmy Assarsson }
19007259124eSJimmy Assarsson
kvaser_usb_leaf_get_busparams(struct kvaser_usb_net_priv * priv)190139d3df6bSJimmy Assarsson static int kvaser_usb_leaf_get_busparams(struct kvaser_usb_net_priv *priv)
190239d3df6bSJimmy Assarsson {
190339d3df6bSJimmy Assarsson int err;
190439d3df6bSJimmy Assarsson
190539d3df6bSJimmy Assarsson if (priv->dev->driver_info->family == KVASER_USBCAN)
190639d3df6bSJimmy Assarsson return -EOPNOTSUPP;
190739d3df6bSJimmy Assarsson
190839d3df6bSJimmy Assarsson reinit_completion(&priv->get_busparams_comp);
190939d3df6bSJimmy Assarsson
191039d3df6bSJimmy Assarsson err = kvaser_usb_leaf_send_simple_cmd(priv->dev, CMD_GET_BUS_PARAMS,
191139d3df6bSJimmy Assarsson priv->channel);
191239d3df6bSJimmy Assarsson if (err)
191339d3df6bSJimmy Assarsson return err;
191439d3df6bSJimmy Assarsson
191539d3df6bSJimmy Assarsson if (!wait_for_completion_timeout(&priv->get_busparams_comp,
191639d3df6bSJimmy Assarsson msecs_to_jiffies(KVASER_USB_TIMEOUT)))
191739d3df6bSJimmy Assarsson return -ETIMEDOUT;
191839d3df6bSJimmy Assarsson
191939d3df6bSJimmy Assarsson return 0;
192039d3df6bSJimmy Assarsson }
192139d3df6bSJimmy Assarsson
kvaser_usb_leaf_set_mode(struct net_device * netdev,enum can_mode mode)19227259124eSJimmy Assarsson static int kvaser_usb_leaf_set_mode(struct net_device *netdev,
19237259124eSJimmy Assarsson enum can_mode mode)
19247259124eSJimmy Assarsson {
19257259124eSJimmy Assarsson struct kvaser_usb_net_priv *priv = netdev_priv(netdev);
1926abb86709SAnssi Hannula struct kvaser_usb_net_leaf_priv *leaf = priv->sub_priv;
19277259124eSJimmy Assarsson int err;
19287259124eSJimmy Assarsson
19297259124eSJimmy Assarsson switch (mode) {
19307259124eSJimmy Assarsson case CAN_MODE_START:
1931455561fbSAnssi Hannula kvaser_usb_unlink_tx_urbs(priv);
1932455561fbSAnssi Hannula
1933abb86709SAnssi Hannula leaf->joining_bus = true;
1934abb86709SAnssi Hannula
19357259124eSJimmy Assarsson err = kvaser_usb_leaf_simple_cmd_async(priv, CMD_START_CHIP);
19367259124eSJimmy Assarsson if (err)
19377259124eSJimmy Assarsson return err;
19380be1a655SAnssi Hannula
19390be1a655SAnssi Hannula priv->can.state = CAN_STATE_ERROR_ACTIVE;
19407259124eSJimmy Assarsson break;
19417259124eSJimmy Assarsson default:
19427259124eSJimmy Assarsson return -EOPNOTSUPP;
19437259124eSJimmy Assarsson }
19447259124eSJimmy Assarsson
19457259124eSJimmy Assarsson return 0;
19467259124eSJimmy Assarsson }
19477259124eSJimmy Assarsson
kvaser_usb_leaf_get_berr_counter(const struct net_device * netdev,struct can_berr_counter * bec)19487259124eSJimmy Assarsson static int kvaser_usb_leaf_get_berr_counter(const struct net_device *netdev,
19497259124eSJimmy Assarsson struct can_berr_counter *bec)
19507259124eSJimmy Assarsson {
19517259124eSJimmy Assarsson struct kvaser_usb_net_priv *priv = netdev_priv(netdev);
19527259124eSJimmy Assarsson
19537259124eSJimmy Assarsson *bec = priv->bec;
19547259124eSJimmy Assarsson
19557259124eSJimmy Assarsson return 0;
19567259124eSJimmy Assarsson }
19577259124eSJimmy Assarsson
kvaser_usb_leaf_setup_endpoints(struct kvaser_usb * dev)19587259124eSJimmy Assarsson static int kvaser_usb_leaf_setup_endpoints(struct kvaser_usb *dev)
19597259124eSJimmy Assarsson {
19607259124eSJimmy Assarsson const struct usb_host_interface *iface_desc;
19617259124eSJimmy Assarsson struct usb_endpoint_descriptor *endpoint;
19627259124eSJimmy Assarsson int i;
19637259124eSJimmy Assarsson
19645660493cSJohan Hovold iface_desc = dev->intf->cur_altsetting;
19657259124eSJimmy Assarsson
19667259124eSJimmy Assarsson for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) {
19677259124eSJimmy Assarsson endpoint = &iface_desc->endpoint[i].desc;
19687259124eSJimmy Assarsson
19697259124eSJimmy Assarsson if (!dev->bulk_in && usb_endpoint_is_bulk_in(endpoint))
19707259124eSJimmy Assarsson dev->bulk_in = endpoint;
19717259124eSJimmy Assarsson
19727259124eSJimmy Assarsson if (!dev->bulk_out && usb_endpoint_is_bulk_out(endpoint))
19737259124eSJimmy Assarsson dev->bulk_out = endpoint;
19747259124eSJimmy Assarsson
19757259124eSJimmy Assarsson /* use first bulk endpoint for in and out */
19767259124eSJimmy Assarsson if (dev->bulk_in && dev->bulk_out)
19777259124eSJimmy Assarsson return 0;
19787259124eSJimmy Assarsson }
19797259124eSJimmy Assarsson
19807259124eSJimmy Assarsson return -ENODEV;
19817259124eSJimmy Assarsson }
19827259124eSJimmy Assarsson
19837259124eSJimmy Assarsson const struct kvaser_usb_dev_ops kvaser_usb_leaf_dev_ops = {
19847259124eSJimmy Assarsson .dev_set_mode = kvaser_usb_leaf_set_mode,
19857259124eSJimmy Assarsson .dev_set_bittiming = kvaser_usb_leaf_set_bittiming,
198639d3df6bSJimmy Assarsson .dev_get_busparams = kvaser_usb_leaf_get_busparams,
1987aec5fb22SJimmy Assarsson .dev_set_data_bittiming = NULL,
198839d3df6bSJimmy Assarsson .dev_get_data_busparams = NULL,
19897259124eSJimmy Assarsson .dev_get_berr_counter = kvaser_usb_leaf_get_berr_counter,
19907259124eSJimmy Assarsson .dev_setup_endpoints = kvaser_usb_leaf_setup_endpoints,
19917259124eSJimmy Assarsson .dev_init_card = kvaser_usb_leaf_init_card,
19928d21f592SAnssi Hannula .dev_init_channel = kvaser_usb_leaf_init_channel,
19938d21f592SAnssi Hannula .dev_remove_channel = kvaser_usb_leaf_remove_channel,
19947259124eSJimmy Assarsson .dev_get_software_info = kvaser_usb_leaf_get_software_info,
1995aec5fb22SJimmy Assarsson .dev_get_software_details = NULL,
19967259124eSJimmy Assarsson .dev_get_card_info = kvaser_usb_leaf_get_card_info,
199735364f5bSJimmy Assarsson .dev_get_capabilities = kvaser_usb_leaf_get_capabilities,
1998478248f1SJimmy Assarsson .dev_set_led = kvaser_usb_leaf_set_led,
19997259124eSJimmy Assarsson .dev_set_opt_mode = kvaser_usb_leaf_set_opt_mode,
20007259124eSJimmy Assarsson .dev_start_chip = kvaser_usb_leaf_start_chip,
20017259124eSJimmy Assarsson .dev_stop_chip = kvaser_usb_leaf_stop_chip,
20027259124eSJimmy Assarsson .dev_reset_chip = kvaser_usb_leaf_reset_chip,
20037259124eSJimmy Assarsson .dev_flush_queue = kvaser_usb_leaf_flush_queue,
20047259124eSJimmy Assarsson .dev_read_bulk_callback = kvaser_usb_leaf_read_bulk_callback,
20057259124eSJimmy Assarsson .dev_frame_to_cmd = kvaser_usb_leaf_frame_to_cmd,
20067259124eSJimmy Assarsson };
2007