xref: /kernel/linux/linux-6.6/drivers/net/can/usb/ucan.c (revision 62306a36)
162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci
362306a36Sopenharmony_ci/* Driver for Theobroma Systems UCAN devices, Protocol Version 3
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Copyright (C) 2018 Theobroma Systems Design und Consulting GmbH
662306a36Sopenharmony_ci *
762306a36Sopenharmony_ci *
862306a36Sopenharmony_ci * General Description:
962306a36Sopenharmony_ci *
1062306a36Sopenharmony_ci * The USB Device uses three Endpoints:
1162306a36Sopenharmony_ci *
1262306a36Sopenharmony_ci *   CONTROL Endpoint: Is used the setup the device (start, stop,
1362306a36Sopenharmony_ci *   info, configure).
1462306a36Sopenharmony_ci *
1562306a36Sopenharmony_ci *   IN Endpoint: The device sends CAN Frame Messages and Device
1662306a36Sopenharmony_ci *   Information using the IN endpoint.
1762306a36Sopenharmony_ci *
1862306a36Sopenharmony_ci *   OUT Endpoint: The driver sends configuration requests, and CAN
1962306a36Sopenharmony_ci *   Frames on the out endpoint.
2062306a36Sopenharmony_ci *
2162306a36Sopenharmony_ci * Error Handling:
2262306a36Sopenharmony_ci *
2362306a36Sopenharmony_ci *   If error reporting is turned on the device encodes error into CAN
2462306a36Sopenharmony_ci *   error frames (see uapi/linux/can/error.h) and sends it using the
2562306a36Sopenharmony_ci *   IN Endpoint. The driver updates statistics and forward it.
2662306a36Sopenharmony_ci */
2762306a36Sopenharmony_ci
2862306a36Sopenharmony_ci#include <linux/can.h>
2962306a36Sopenharmony_ci#include <linux/can/dev.h>
3062306a36Sopenharmony_ci#include <linux/can/error.h>
3162306a36Sopenharmony_ci#include <linux/ethtool.h>
3262306a36Sopenharmony_ci#include <linux/module.h>
3362306a36Sopenharmony_ci#include <linux/netdevice.h>
3462306a36Sopenharmony_ci#include <linux/signal.h>
3562306a36Sopenharmony_ci#include <linux/skbuff.h>
3662306a36Sopenharmony_ci#include <linux/slab.h>
3762306a36Sopenharmony_ci#include <linux/usb.h>
3862306a36Sopenharmony_ci
3962306a36Sopenharmony_ci#define UCAN_DRIVER_NAME "ucan"
4062306a36Sopenharmony_ci#define UCAN_MAX_RX_URBS 8
4162306a36Sopenharmony_ci/* the CAN controller needs a while to enable/disable the bus */
4262306a36Sopenharmony_ci#define UCAN_USB_CTL_PIPE_TIMEOUT 1000
4362306a36Sopenharmony_ci/* this driver currently supports protocol version 3 only */
4462306a36Sopenharmony_ci#define UCAN_PROTOCOL_VERSION_MIN 3
4562306a36Sopenharmony_ci#define UCAN_PROTOCOL_VERSION_MAX 3
4662306a36Sopenharmony_ci
4762306a36Sopenharmony_ci/* UCAN Message Definitions
4862306a36Sopenharmony_ci * ------------------------
4962306a36Sopenharmony_ci *
5062306a36Sopenharmony_ci *  ucan_message_out_t and ucan_message_in_t define the messages
5162306a36Sopenharmony_ci *  transmitted on the OUT and IN endpoint.
5262306a36Sopenharmony_ci *
5362306a36Sopenharmony_ci *  Multibyte fields are transmitted with little endianness
5462306a36Sopenharmony_ci *
5562306a36Sopenharmony_ci *  INTR Endpoint: a single uint32_t storing the current space in the fifo
5662306a36Sopenharmony_ci *
5762306a36Sopenharmony_ci *  OUT Endpoint: single message of type ucan_message_out_t is
5862306a36Sopenharmony_ci *    transmitted on the out endpoint
5962306a36Sopenharmony_ci *
6062306a36Sopenharmony_ci *  IN Endpoint: multiple messages ucan_message_in_t concateted in
6162306a36Sopenharmony_ci *    the following way:
6262306a36Sopenharmony_ci *
6362306a36Sopenharmony_ci *	m[n].len <=> the length if message n(including the header in bytes)
6462306a36Sopenharmony_ci *	m[n] is is aligned to a 4 byte boundary, hence
6562306a36Sopenharmony_ci *	  offset(m[0])	 := 0;
6662306a36Sopenharmony_ci *	  offset(m[n+1]) := offset(m[n]) + (m[n].len + 3) & 3
6762306a36Sopenharmony_ci *
6862306a36Sopenharmony_ci *	this implies that
6962306a36Sopenharmony_ci *	  offset(m[n]) % 4 <=> 0
7062306a36Sopenharmony_ci */
7162306a36Sopenharmony_ci
7262306a36Sopenharmony_ci/* Device Global Commands */
7362306a36Sopenharmony_cienum {
7462306a36Sopenharmony_ci	UCAN_DEVICE_GET_FW_STRING = 0,
7562306a36Sopenharmony_ci};
7662306a36Sopenharmony_ci
7762306a36Sopenharmony_ci/* UCAN Commands */
7862306a36Sopenharmony_cienum {
7962306a36Sopenharmony_ci	/* start the can transceiver - val defines the operation mode */
8062306a36Sopenharmony_ci	UCAN_COMMAND_START = 0,
8162306a36Sopenharmony_ci	/* cancel pending transmissions and stop the can transceiver */
8262306a36Sopenharmony_ci	UCAN_COMMAND_STOP = 1,
8362306a36Sopenharmony_ci	/* send can transceiver into low-power sleep mode */
8462306a36Sopenharmony_ci	UCAN_COMMAND_SLEEP = 2,
8562306a36Sopenharmony_ci	/* wake up can transceiver from low-power sleep mode */
8662306a36Sopenharmony_ci	UCAN_COMMAND_WAKEUP = 3,
8762306a36Sopenharmony_ci	/* reset the can transceiver */
8862306a36Sopenharmony_ci	UCAN_COMMAND_RESET = 4,
8962306a36Sopenharmony_ci	/* get piece of info from the can transceiver - subcmd defines what
9062306a36Sopenharmony_ci	 * piece
9162306a36Sopenharmony_ci	 */
9262306a36Sopenharmony_ci	UCAN_COMMAND_GET = 5,
9362306a36Sopenharmony_ci	/* clear or disable hardware filter - subcmd defines which of the two */
9462306a36Sopenharmony_ci	UCAN_COMMAND_FILTER = 6,
9562306a36Sopenharmony_ci	/* Setup bittiming */
9662306a36Sopenharmony_ci	UCAN_COMMAND_SET_BITTIMING = 7,
9762306a36Sopenharmony_ci	/* recover from bus-off state */
9862306a36Sopenharmony_ci	UCAN_COMMAND_RESTART = 8,
9962306a36Sopenharmony_ci};
10062306a36Sopenharmony_ci
10162306a36Sopenharmony_ci/* UCAN_COMMAND_START and UCAN_COMMAND_GET_INFO operation modes (bitmap).
10262306a36Sopenharmony_ci * Undefined bits must be set to 0.
10362306a36Sopenharmony_ci */
10462306a36Sopenharmony_cienum {
10562306a36Sopenharmony_ci	UCAN_MODE_LOOPBACK = BIT(0),
10662306a36Sopenharmony_ci	UCAN_MODE_SILENT = BIT(1),
10762306a36Sopenharmony_ci	UCAN_MODE_3_SAMPLES = BIT(2),
10862306a36Sopenharmony_ci	UCAN_MODE_ONE_SHOT = BIT(3),
10962306a36Sopenharmony_ci	UCAN_MODE_BERR_REPORT = BIT(4),
11062306a36Sopenharmony_ci};
11162306a36Sopenharmony_ci
11262306a36Sopenharmony_ci/* UCAN_COMMAND_GET subcommands */
11362306a36Sopenharmony_cienum {
11462306a36Sopenharmony_ci	UCAN_COMMAND_GET_INFO = 0,
11562306a36Sopenharmony_ci	UCAN_COMMAND_GET_PROTOCOL_VERSION = 1,
11662306a36Sopenharmony_ci};
11762306a36Sopenharmony_ci
11862306a36Sopenharmony_ci/* UCAN_COMMAND_FILTER subcommands */
11962306a36Sopenharmony_cienum {
12062306a36Sopenharmony_ci	UCAN_FILTER_CLEAR = 0,
12162306a36Sopenharmony_ci	UCAN_FILTER_DISABLE = 1,
12262306a36Sopenharmony_ci	UCAN_FILTER_ENABLE = 2,
12362306a36Sopenharmony_ci};
12462306a36Sopenharmony_ci
12562306a36Sopenharmony_ci/* OUT endpoint message types */
12662306a36Sopenharmony_cienum {
12762306a36Sopenharmony_ci	UCAN_OUT_TX = 2,     /* transmit a CAN frame */
12862306a36Sopenharmony_ci};
12962306a36Sopenharmony_ci
13062306a36Sopenharmony_ci/* IN endpoint message types */
13162306a36Sopenharmony_cienum {
13262306a36Sopenharmony_ci	UCAN_IN_TX_COMPLETE = 1,  /* CAN frame transmission completed */
13362306a36Sopenharmony_ci	UCAN_IN_RX = 2,           /* CAN frame received */
13462306a36Sopenharmony_ci};
13562306a36Sopenharmony_ci
13662306a36Sopenharmony_cistruct ucan_ctl_cmd_start {
13762306a36Sopenharmony_ci	__le16 mode;         /* OR-ing any of UCAN_MODE_* */
13862306a36Sopenharmony_ci} __packed;
13962306a36Sopenharmony_ci
14062306a36Sopenharmony_cistruct ucan_ctl_cmd_set_bittiming {
14162306a36Sopenharmony_ci	__le32 tq;           /* Time quanta (TQ) in nanoseconds */
14262306a36Sopenharmony_ci	__le16 brp;          /* TQ Prescaler */
14362306a36Sopenharmony_ci	__le16 sample_point; /* Samplepoint on tenth percent */
14462306a36Sopenharmony_ci	u8 prop_seg;         /* Propagation segment in TQs */
14562306a36Sopenharmony_ci	u8 phase_seg1;       /* Phase buffer segment 1 in TQs */
14662306a36Sopenharmony_ci	u8 phase_seg2;       /* Phase buffer segment 2 in TQs */
14762306a36Sopenharmony_ci	u8 sjw;              /* Synchronisation jump width in TQs */
14862306a36Sopenharmony_ci} __packed;
14962306a36Sopenharmony_ci
15062306a36Sopenharmony_cistruct ucan_ctl_cmd_device_info {
15162306a36Sopenharmony_ci	__le32 freq;         /* Clock Frequency for tq generation */
15262306a36Sopenharmony_ci	u8 tx_fifo;          /* Size of the transmission fifo */
15362306a36Sopenharmony_ci	u8 sjw_max;          /* can_bittiming fields... */
15462306a36Sopenharmony_ci	u8 tseg1_min;
15562306a36Sopenharmony_ci	u8 tseg1_max;
15662306a36Sopenharmony_ci	u8 tseg2_min;
15762306a36Sopenharmony_ci	u8 tseg2_max;
15862306a36Sopenharmony_ci	__le16 brp_inc;
15962306a36Sopenharmony_ci	__le32 brp_min;
16062306a36Sopenharmony_ci	__le32 brp_max;      /* ...can_bittiming fields */
16162306a36Sopenharmony_ci	__le16 ctrlmodes;    /* supported control modes */
16262306a36Sopenharmony_ci	__le16 hwfilter;     /* Number of HW filter banks */
16362306a36Sopenharmony_ci	__le16 rxmboxes;     /* Number of receive Mailboxes */
16462306a36Sopenharmony_ci} __packed;
16562306a36Sopenharmony_ci
16662306a36Sopenharmony_cistruct ucan_ctl_cmd_get_protocol_version {
16762306a36Sopenharmony_ci	__le32 version;
16862306a36Sopenharmony_ci} __packed;
16962306a36Sopenharmony_ci
17062306a36Sopenharmony_ciunion ucan_ctl_payload {
17162306a36Sopenharmony_ci	/* Setup Bittiming
17262306a36Sopenharmony_ci	 * bmRequest == UCAN_COMMAND_START
17362306a36Sopenharmony_ci	 */
17462306a36Sopenharmony_ci	struct ucan_ctl_cmd_start cmd_start;
17562306a36Sopenharmony_ci	/* Setup Bittiming
17662306a36Sopenharmony_ci	 * bmRequest == UCAN_COMMAND_SET_BITTIMING
17762306a36Sopenharmony_ci	 */
17862306a36Sopenharmony_ci	struct ucan_ctl_cmd_set_bittiming cmd_set_bittiming;
17962306a36Sopenharmony_ci	/* Get Device Information
18062306a36Sopenharmony_ci	 * bmRequest == UCAN_COMMAND_GET; wValue = UCAN_COMMAND_GET_INFO
18162306a36Sopenharmony_ci	 */
18262306a36Sopenharmony_ci	struct ucan_ctl_cmd_device_info cmd_get_device_info;
18362306a36Sopenharmony_ci	/* Get Protocol Version
18462306a36Sopenharmony_ci	 * bmRequest == UCAN_COMMAND_GET;
18562306a36Sopenharmony_ci	 * wValue = UCAN_COMMAND_GET_PROTOCOL_VERSION
18662306a36Sopenharmony_ci	 */
18762306a36Sopenharmony_ci	struct ucan_ctl_cmd_get_protocol_version cmd_get_protocol_version;
18862306a36Sopenharmony_ci
18962306a36Sopenharmony_ci	u8 raw[128];
19062306a36Sopenharmony_ci} __packed;
19162306a36Sopenharmony_ci
19262306a36Sopenharmony_cienum {
19362306a36Sopenharmony_ci	UCAN_TX_COMPLETE_SUCCESS = BIT(0),
19462306a36Sopenharmony_ci};
19562306a36Sopenharmony_ci
19662306a36Sopenharmony_ci/* Transmission Complete within ucan_message_in */
19762306a36Sopenharmony_cistruct ucan_tx_complete_entry_t {
19862306a36Sopenharmony_ci	u8 echo_index;
19962306a36Sopenharmony_ci	u8 flags;
20062306a36Sopenharmony_ci} __packed __aligned(0x2);
20162306a36Sopenharmony_ci
20262306a36Sopenharmony_ci/* CAN Data message format within ucan_message_in/out */
20362306a36Sopenharmony_cistruct ucan_can_msg {
20462306a36Sopenharmony_ci	/* note DLC is computed by
20562306a36Sopenharmony_ci	 *    msg.len - sizeof (msg.len)
20662306a36Sopenharmony_ci	 *            - sizeof (msg.type)
20762306a36Sopenharmony_ci	 *            - sizeof (msg.can_msg.id)
20862306a36Sopenharmony_ci	 */
20962306a36Sopenharmony_ci	__le32 id;
21062306a36Sopenharmony_ci
21162306a36Sopenharmony_ci	union {
21262306a36Sopenharmony_ci		u8 data[CAN_MAX_DLEN];  /* Data of CAN frames */
21362306a36Sopenharmony_ci		u8 dlc;                 /* RTR dlc */
21462306a36Sopenharmony_ci	};
21562306a36Sopenharmony_ci} __packed;
21662306a36Sopenharmony_ci
21762306a36Sopenharmony_ci/* OUT Endpoint, outbound messages */
21862306a36Sopenharmony_cistruct ucan_message_out {
21962306a36Sopenharmony_ci	__le16 len; /* Length of the content include header */
22062306a36Sopenharmony_ci	u8 type;    /* UCAN_OUT_TX and friends */
22162306a36Sopenharmony_ci	u8 subtype; /* command sub type */
22262306a36Sopenharmony_ci
22362306a36Sopenharmony_ci	union {
22462306a36Sopenharmony_ci		/* Transmit CAN frame
22562306a36Sopenharmony_ci		 * (type == UCAN_TX) && ((msg.can_msg.id & CAN_RTR_FLAG) == 0)
22662306a36Sopenharmony_ci		 * subtype stores the echo id
22762306a36Sopenharmony_ci		 */
22862306a36Sopenharmony_ci		struct ucan_can_msg can_msg;
22962306a36Sopenharmony_ci	} msg;
23062306a36Sopenharmony_ci} __packed __aligned(0x4);
23162306a36Sopenharmony_ci
23262306a36Sopenharmony_ci/* IN Endpoint, inbound messages */
23362306a36Sopenharmony_cistruct ucan_message_in {
23462306a36Sopenharmony_ci	__le16 len; /* Length of the content include header */
23562306a36Sopenharmony_ci	u8 type;    /* UCAN_IN_RX and friends */
23662306a36Sopenharmony_ci	u8 subtype; /* command sub type */
23762306a36Sopenharmony_ci
23862306a36Sopenharmony_ci	union {
23962306a36Sopenharmony_ci		/* CAN Frame received
24062306a36Sopenharmony_ci		 * (type == UCAN_IN_RX)
24162306a36Sopenharmony_ci		 * && ((msg.can_msg.id & CAN_RTR_FLAG) == 0)
24262306a36Sopenharmony_ci		 */
24362306a36Sopenharmony_ci		struct ucan_can_msg can_msg;
24462306a36Sopenharmony_ci
24562306a36Sopenharmony_ci		/* CAN transmission complete
24662306a36Sopenharmony_ci		 * (type == UCAN_IN_TX_COMPLETE)
24762306a36Sopenharmony_ci		 */
24862306a36Sopenharmony_ci		DECLARE_FLEX_ARRAY(struct ucan_tx_complete_entry_t,
24962306a36Sopenharmony_ci				   can_tx_complete_msg);
25062306a36Sopenharmony_ci	} __aligned(0x4) msg;
25162306a36Sopenharmony_ci} __packed __aligned(0x4);
25262306a36Sopenharmony_ci
25362306a36Sopenharmony_ci/* Macros to calculate message lengths */
25462306a36Sopenharmony_ci#define UCAN_OUT_HDR_SIZE offsetof(struct ucan_message_out, msg)
25562306a36Sopenharmony_ci
25662306a36Sopenharmony_ci#define UCAN_IN_HDR_SIZE offsetof(struct ucan_message_in, msg)
25762306a36Sopenharmony_ci#define UCAN_IN_LEN(member) (UCAN_OUT_HDR_SIZE + sizeof(member))
25862306a36Sopenharmony_ci
25962306a36Sopenharmony_cistruct ucan_priv;
26062306a36Sopenharmony_ci
26162306a36Sopenharmony_ci/* Context Information for transmission URBs */
26262306a36Sopenharmony_cistruct ucan_urb_context {
26362306a36Sopenharmony_ci	struct ucan_priv *up;
26462306a36Sopenharmony_ci	bool allocated;
26562306a36Sopenharmony_ci};
26662306a36Sopenharmony_ci
26762306a36Sopenharmony_ci/* Information reported by the USB device */
26862306a36Sopenharmony_cistruct ucan_device_info {
26962306a36Sopenharmony_ci	struct can_bittiming_const bittiming_const;
27062306a36Sopenharmony_ci	u8 tx_fifo;
27162306a36Sopenharmony_ci};
27262306a36Sopenharmony_ci
27362306a36Sopenharmony_ci/* Driver private data */
27462306a36Sopenharmony_cistruct ucan_priv {
27562306a36Sopenharmony_ci	/* must be the first member */
27662306a36Sopenharmony_ci	struct can_priv can;
27762306a36Sopenharmony_ci
27862306a36Sopenharmony_ci	/* linux USB device structures */
27962306a36Sopenharmony_ci	struct usb_device *udev;
28062306a36Sopenharmony_ci	struct net_device *netdev;
28162306a36Sopenharmony_ci
28262306a36Sopenharmony_ci	/* lock for can->echo_skb (used around
28362306a36Sopenharmony_ci	 * can_put/get/free_echo_skb
28462306a36Sopenharmony_ci	 */
28562306a36Sopenharmony_ci	spinlock_t echo_skb_lock;
28662306a36Sopenharmony_ci
28762306a36Sopenharmony_ci	/* usb device information */
28862306a36Sopenharmony_ci	u8 intf_index;
28962306a36Sopenharmony_ci	u8 in_ep_addr;
29062306a36Sopenharmony_ci	u8 out_ep_addr;
29162306a36Sopenharmony_ci	u16 in_ep_size;
29262306a36Sopenharmony_ci
29362306a36Sopenharmony_ci	/* transmission and reception buffers */
29462306a36Sopenharmony_ci	struct usb_anchor rx_urbs;
29562306a36Sopenharmony_ci	struct usb_anchor tx_urbs;
29662306a36Sopenharmony_ci
29762306a36Sopenharmony_ci	union ucan_ctl_payload *ctl_msg_buffer;
29862306a36Sopenharmony_ci	struct ucan_device_info device_info;
29962306a36Sopenharmony_ci
30062306a36Sopenharmony_ci	/* transmission control information and locks */
30162306a36Sopenharmony_ci	spinlock_t context_lock;
30262306a36Sopenharmony_ci	unsigned int available_tx_urbs;
30362306a36Sopenharmony_ci	struct ucan_urb_context *context_array;
30462306a36Sopenharmony_ci};
30562306a36Sopenharmony_ci
30662306a36Sopenharmony_cistatic u8 ucan_can_cc_dlc2len(struct ucan_can_msg *msg, u16 len)
30762306a36Sopenharmony_ci{
30862306a36Sopenharmony_ci	if (le32_to_cpu(msg->id) & CAN_RTR_FLAG)
30962306a36Sopenharmony_ci		return can_cc_dlc2len(msg->dlc);
31062306a36Sopenharmony_ci	else
31162306a36Sopenharmony_ci		return can_cc_dlc2len(len - (UCAN_IN_HDR_SIZE + sizeof(msg->id)));
31262306a36Sopenharmony_ci}
31362306a36Sopenharmony_ci
31462306a36Sopenharmony_cistatic void ucan_release_context_array(struct ucan_priv *up)
31562306a36Sopenharmony_ci{
31662306a36Sopenharmony_ci	if (!up->context_array)
31762306a36Sopenharmony_ci		return;
31862306a36Sopenharmony_ci
31962306a36Sopenharmony_ci	/* lock is not needed because, driver is currently opening or closing */
32062306a36Sopenharmony_ci	up->available_tx_urbs = 0;
32162306a36Sopenharmony_ci
32262306a36Sopenharmony_ci	kfree(up->context_array);
32362306a36Sopenharmony_ci	up->context_array = NULL;
32462306a36Sopenharmony_ci}
32562306a36Sopenharmony_ci
32662306a36Sopenharmony_cistatic int ucan_alloc_context_array(struct ucan_priv *up)
32762306a36Sopenharmony_ci{
32862306a36Sopenharmony_ci	int i;
32962306a36Sopenharmony_ci
33062306a36Sopenharmony_ci	/* release contexts if any */
33162306a36Sopenharmony_ci	ucan_release_context_array(up);
33262306a36Sopenharmony_ci
33362306a36Sopenharmony_ci	up->context_array = kcalloc(up->device_info.tx_fifo,
33462306a36Sopenharmony_ci				    sizeof(*up->context_array),
33562306a36Sopenharmony_ci				    GFP_KERNEL);
33662306a36Sopenharmony_ci	if (!up->context_array) {
33762306a36Sopenharmony_ci		netdev_err(up->netdev,
33862306a36Sopenharmony_ci			   "Not enough memory to allocate tx contexts\n");
33962306a36Sopenharmony_ci		return -ENOMEM;
34062306a36Sopenharmony_ci	}
34162306a36Sopenharmony_ci
34262306a36Sopenharmony_ci	for (i = 0; i < up->device_info.tx_fifo; i++) {
34362306a36Sopenharmony_ci		up->context_array[i].allocated = false;
34462306a36Sopenharmony_ci		up->context_array[i].up = up;
34562306a36Sopenharmony_ci	}
34662306a36Sopenharmony_ci
34762306a36Sopenharmony_ci	/* lock is not needed because, driver is currently opening */
34862306a36Sopenharmony_ci	up->available_tx_urbs = up->device_info.tx_fifo;
34962306a36Sopenharmony_ci
35062306a36Sopenharmony_ci	return 0;
35162306a36Sopenharmony_ci}
35262306a36Sopenharmony_ci
35362306a36Sopenharmony_cistatic struct ucan_urb_context *ucan_alloc_context(struct ucan_priv *up)
35462306a36Sopenharmony_ci{
35562306a36Sopenharmony_ci	int i;
35662306a36Sopenharmony_ci	unsigned long flags;
35762306a36Sopenharmony_ci	struct ucan_urb_context *ret = NULL;
35862306a36Sopenharmony_ci
35962306a36Sopenharmony_ci	if (WARN_ON_ONCE(!up->context_array))
36062306a36Sopenharmony_ci		return NULL;
36162306a36Sopenharmony_ci
36262306a36Sopenharmony_ci	/* execute context operation atomically */
36362306a36Sopenharmony_ci	spin_lock_irqsave(&up->context_lock, flags);
36462306a36Sopenharmony_ci
36562306a36Sopenharmony_ci	for (i = 0; i < up->device_info.tx_fifo; i++) {
36662306a36Sopenharmony_ci		if (!up->context_array[i].allocated) {
36762306a36Sopenharmony_ci			/* update context */
36862306a36Sopenharmony_ci			ret = &up->context_array[i];
36962306a36Sopenharmony_ci			up->context_array[i].allocated = true;
37062306a36Sopenharmony_ci
37162306a36Sopenharmony_ci			/* stop queue if necessary */
37262306a36Sopenharmony_ci			up->available_tx_urbs--;
37362306a36Sopenharmony_ci			if (!up->available_tx_urbs)
37462306a36Sopenharmony_ci				netif_stop_queue(up->netdev);
37562306a36Sopenharmony_ci
37662306a36Sopenharmony_ci			break;
37762306a36Sopenharmony_ci		}
37862306a36Sopenharmony_ci	}
37962306a36Sopenharmony_ci
38062306a36Sopenharmony_ci	spin_unlock_irqrestore(&up->context_lock, flags);
38162306a36Sopenharmony_ci	return ret;
38262306a36Sopenharmony_ci}
38362306a36Sopenharmony_ci
38462306a36Sopenharmony_cistatic bool ucan_release_context(struct ucan_priv *up,
38562306a36Sopenharmony_ci				 struct ucan_urb_context *ctx)
38662306a36Sopenharmony_ci{
38762306a36Sopenharmony_ci	unsigned long flags;
38862306a36Sopenharmony_ci	bool ret = false;
38962306a36Sopenharmony_ci
39062306a36Sopenharmony_ci	if (WARN_ON_ONCE(!up->context_array))
39162306a36Sopenharmony_ci		return false;
39262306a36Sopenharmony_ci
39362306a36Sopenharmony_ci	/* execute context operation atomically */
39462306a36Sopenharmony_ci	spin_lock_irqsave(&up->context_lock, flags);
39562306a36Sopenharmony_ci
39662306a36Sopenharmony_ci	/* context was not allocated, maybe the device sent garbage */
39762306a36Sopenharmony_ci	if (ctx->allocated) {
39862306a36Sopenharmony_ci		ctx->allocated = false;
39962306a36Sopenharmony_ci
40062306a36Sopenharmony_ci		/* check if the queue needs to be woken */
40162306a36Sopenharmony_ci		if (!up->available_tx_urbs)
40262306a36Sopenharmony_ci			netif_wake_queue(up->netdev);
40362306a36Sopenharmony_ci		up->available_tx_urbs++;
40462306a36Sopenharmony_ci
40562306a36Sopenharmony_ci		ret = true;
40662306a36Sopenharmony_ci	}
40762306a36Sopenharmony_ci
40862306a36Sopenharmony_ci	spin_unlock_irqrestore(&up->context_lock, flags);
40962306a36Sopenharmony_ci	return ret;
41062306a36Sopenharmony_ci}
41162306a36Sopenharmony_ci
41262306a36Sopenharmony_cistatic int ucan_ctrl_command_out(struct ucan_priv *up,
41362306a36Sopenharmony_ci				 u8 cmd, u16 subcmd, u16 datalen)
41462306a36Sopenharmony_ci{
41562306a36Sopenharmony_ci	return usb_control_msg(up->udev,
41662306a36Sopenharmony_ci			       usb_sndctrlpipe(up->udev, 0),
41762306a36Sopenharmony_ci			       cmd,
41862306a36Sopenharmony_ci			       USB_DIR_OUT | USB_TYPE_VENDOR |
41962306a36Sopenharmony_ci						USB_RECIP_INTERFACE,
42062306a36Sopenharmony_ci			       subcmd,
42162306a36Sopenharmony_ci			       up->intf_index,
42262306a36Sopenharmony_ci			       up->ctl_msg_buffer,
42362306a36Sopenharmony_ci			       datalen,
42462306a36Sopenharmony_ci			       UCAN_USB_CTL_PIPE_TIMEOUT);
42562306a36Sopenharmony_ci}
42662306a36Sopenharmony_ci
42762306a36Sopenharmony_cistatic int ucan_device_request_in(struct ucan_priv *up,
42862306a36Sopenharmony_ci				  u8 cmd, u16 subcmd, u16 datalen)
42962306a36Sopenharmony_ci{
43062306a36Sopenharmony_ci	return usb_control_msg(up->udev,
43162306a36Sopenharmony_ci			       usb_rcvctrlpipe(up->udev, 0),
43262306a36Sopenharmony_ci			       cmd,
43362306a36Sopenharmony_ci			       USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
43462306a36Sopenharmony_ci			       subcmd,
43562306a36Sopenharmony_ci			       0,
43662306a36Sopenharmony_ci			       up->ctl_msg_buffer,
43762306a36Sopenharmony_ci			       datalen,
43862306a36Sopenharmony_ci			       UCAN_USB_CTL_PIPE_TIMEOUT);
43962306a36Sopenharmony_ci}
44062306a36Sopenharmony_ci
44162306a36Sopenharmony_ci/* Parse the device information structure reported by the device and
44262306a36Sopenharmony_ci * setup private variables accordingly
44362306a36Sopenharmony_ci */
44462306a36Sopenharmony_cistatic void ucan_parse_device_info(struct ucan_priv *up,
44562306a36Sopenharmony_ci				   struct ucan_ctl_cmd_device_info *device_info)
44662306a36Sopenharmony_ci{
44762306a36Sopenharmony_ci	struct can_bittiming_const *bittiming =
44862306a36Sopenharmony_ci		&up->device_info.bittiming_const;
44962306a36Sopenharmony_ci	u16 ctrlmodes;
45062306a36Sopenharmony_ci
45162306a36Sopenharmony_ci	/* store the data */
45262306a36Sopenharmony_ci	up->can.clock.freq = le32_to_cpu(device_info->freq);
45362306a36Sopenharmony_ci	up->device_info.tx_fifo = device_info->tx_fifo;
45462306a36Sopenharmony_ci	strcpy(bittiming->name, "ucan");
45562306a36Sopenharmony_ci	bittiming->tseg1_min = device_info->tseg1_min;
45662306a36Sopenharmony_ci	bittiming->tseg1_max = device_info->tseg1_max;
45762306a36Sopenharmony_ci	bittiming->tseg2_min = device_info->tseg2_min;
45862306a36Sopenharmony_ci	bittiming->tseg2_max = device_info->tseg2_max;
45962306a36Sopenharmony_ci	bittiming->sjw_max = device_info->sjw_max;
46062306a36Sopenharmony_ci	bittiming->brp_min = le32_to_cpu(device_info->brp_min);
46162306a36Sopenharmony_ci	bittiming->brp_max = le32_to_cpu(device_info->brp_max);
46262306a36Sopenharmony_ci	bittiming->brp_inc = le16_to_cpu(device_info->brp_inc);
46362306a36Sopenharmony_ci
46462306a36Sopenharmony_ci	ctrlmodes = le16_to_cpu(device_info->ctrlmodes);
46562306a36Sopenharmony_ci
46662306a36Sopenharmony_ci	up->can.ctrlmode_supported = 0;
46762306a36Sopenharmony_ci
46862306a36Sopenharmony_ci	if (ctrlmodes & UCAN_MODE_LOOPBACK)
46962306a36Sopenharmony_ci		up->can.ctrlmode_supported |= CAN_CTRLMODE_LOOPBACK;
47062306a36Sopenharmony_ci	if (ctrlmodes & UCAN_MODE_SILENT)
47162306a36Sopenharmony_ci		up->can.ctrlmode_supported |= CAN_CTRLMODE_LISTENONLY;
47262306a36Sopenharmony_ci	if (ctrlmodes & UCAN_MODE_3_SAMPLES)
47362306a36Sopenharmony_ci		up->can.ctrlmode_supported |= CAN_CTRLMODE_3_SAMPLES;
47462306a36Sopenharmony_ci	if (ctrlmodes & UCAN_MODE_ONE_SHOT)
47562306a36Sopenharmony_ci		up->can.ctrlmode_supported |= CAN_CTRLMODE_ONE_SHOT;
47662306a36Sopenharmony_ci	if (ctrlmodes & UCAN_MODE_BERR_REPORT)
47762306a36Sopenharmony_ci		up->can.ctrlmode_supported |= CAN_CTRLMODE_BERR_REPORTING;
47862306a36Sopenharmony_ci}
47962306a36Sopenharmony_ci
48062306a36Sopenharmony_ci/* Handle a CAN error frame that we have received from the device.
48162306a36Sopenharmony_ci * Returns true if the can state has changed.
48262306a36Sopenharmony_ci */
48362306a36Sopenharmony_cistatic bool ucan_handle_error_frame(struct ucan_priv *up,
48462306a36Sopenharmony_ci				    struct ucan_message_in *m,
48562306a36Sopenharmony_ci				    canid_t canid)
48662306a36Sopenharmony_ci{
48762306a36Sopenharmony_ci	enum can_state new_state = up->can.state;
48862306a36Sopenharmony_ci	struct net_device_stats *net_stats = &up->netdev->stats;
48962306a36Sopenharmony_ci	struct can_device_stats *can_stats = &up->can.can_stats;
49062306a36Sopenharmony_ci
49162306a36Sopenharmony_ci	if (canid & CAN_ERR_LOSTARB)
49262306a36Sopenharmony_ci		can_stats->arbitration_lost++;
49362306a36Sopenharmony_ci
49462306a36Sopenharmony_ci	if (canid & CAN_ERR_BUSERROR)
49562306a36Sopenharmony_ci		can_stats->bus_error++;
49662306a36Sopenharmony_ci
49762306a36Sopenharmony_ci	if (canid & CAN_ERR_ACK)
49862306a36Sopenharmony_ci		net_stats->tx_errors++;
49962306a36Sopenharmony_ci
50062306a36Sopenharmony_ci	if (canid & CAN_ERR_BUSOFF)
50162306a36Sopenharmony_ci		new_state = CAN_STATE_BUS_OFF;
50262306a36Sopenharmony_ci
50362306a36Sopenharmony_ci	/* controller problems, details in data[1] */
50462306a36Sopenharmony_ci	if (canid & CAN_ERR_CRTL) {
50562306a36Sopenharmony_ci		u8 d1 = m->msg.can_msg.data[1];
50662306a36Sopenharmony_ci
50762306a36Sopenharmony_ci		if (d1 & CAN_ERR_CRTL_RX_OVERFLOW)
50862306a36Sopenharmony_ci			net_stats->rx_over_errors++;
50962306a36Sopenharmony_ci
51062306a36Sopenharmony_ci		/* controller state bits: if multiple are set the worst wins */
51162306a36Sopenharmony_ci		if (d1 & CAN_ERR_CRTL_ACTIVE)
51262306a36Sopenharmony_ci			new_state = CAN_STATE_ERROR_ACTIVE;
51362306a36Sopenharmony_ci
51462306a36Sopenharmony_ci		if (d1 & (CAN_ERR_CRTL_RX_WARNING | CAN_ERR_CRTL_TX_WARNING))
51562306a36Sopenharmony_ci			new_state = CAN_STATE_ERROR_WARNING;
51662306a36Sopenharmony_ci
51762306a36Sopenharmony_ci		if (d1 & (CAN_ERR_CRTL_RX_PASSIVE | CAN_ERR_CRTL_TX_PASSIVE))
51862306a36Sopenharmony_ci			new_state = CAN_STATE_ERROR_PASSIVE;
51962306a36Sopenharmony_ci	}
52062306a36Sopenharmony_ci
52162306a36Sopenharmony_ci	/* protocol error, details in data[2] */
52262306a36Sopenharmony_ci	if (canid & CAN_ERR_PROT) {
52362306a36Sopenharmony_ci		u8 d2 = m->msg.can_msg.data[2];
52462306a36Sopenharmony_ci
52562306a36Sopenharmony_ci		if (d2 & CAN_ERR_PROT_TX)
52662306a36Sopenharmony_ci			net_stats->tx_errors++;
52762306a36Sopenharmony_ci		else
52862306a36Sopenharmony_ci			net_stats->rx_errors++;
52962306a36Sopenharmony_ci	}
53062306a36Sopenharmony_ci
53162306a36Sopenharmony_ci	/* no state change - we are done */
53262306a36Sopenharmony_ci	if (up->can.state == new_state)
53362306a36Sopenharmony_ci		return false;
53462306a36Sopenharmony_ci
53562306a36Sopenharmony_ci	/* we switched into a better state */
53662306a36Sopenharmony_ci	if (up->can.state > new_state) {
53762306a36Sopenharmony_ci		up->can.state = new_state;
53862306a36Sopenharmony_ci		return true;
53962306a36Sopenharmony_ci	}
54062306a36Sopenharmony_ci
54162306a36Sopenharmony_ci	/* we switched into a worse state */
54262306a36Sopenharmony_ci	up->can.state = new_state;
54362306a36Sopenharmony_ci	switch (new_state) {
54462306a36Sopenharmony_ci	case CAN_STATE_BUS_OFF:
54562306a36Sopenharmony_ci		can_stats->bus_off++;
54662306a36Sopenharmony_ci		can_bus_off(up->netdev);
54762306a36Sopenharmony_ci		break;
54862306a36Sopenharmony_ci	case CAN_STATE_ERROR_PASSIVE:
54962306a36Sopenharmony_ci		can_stats->error_passive++;
55062306a36Sopenharmony_ci		break;
55162306a36Sopenharmony_ci	case CAN_STATE_ERROR_WARNING:
55262306a36Sopenharmony_ci		can_stats->error_warning++;
55362306a36Sopenharmony_ci		break;
55462306a36Sopenharmony_ci	default:
55562306a36Sopenharmony_ci		break;
55662306a36Sopenharmony_ci	}
55762306a36Sopenharmony_ci	return true;
55862306a36Sopenharmony_ci}
55962306a36Sopenharmony_ci
56062306a36Sopenharmony_ci/* Callback on reception of a can frame via the IN endpoint
56162306a36Sopenharmony_ci *
56262306a36Sopenharmony_ci * This function allocates an skb and transferres it to the Linux
56362306a36Sopenharmony_ci * network stack
56462306a36Sopenharmony_ci */
56562306a36Sopenharmony_cistatic void ucan_rx_can_msg(struct ucan_priv *up, struct ucan_message_in *m)
56662306a36Sopenharmony_ci{
56762306a36Sopenharmony_ci	int len;
56862306a36Sopenharmony_ci	canid_t canid;
56962306a36Sopenharmony_ci	struct can_frame *cf;
57062306a36Sopenharmony_ci	struct sk_buff *skb;
57162306a36Sopenharmony_ci	struct net_device_stats *stats = &up->netdev->stats;
57262306a36Sopenharmony_ci
57362306a36Sopenharmony_ci	/* get the contents of the length field */
57462306a36Sopenharmony_ci	len = le16_to_cpu(m->len);
57562306a36Sopenharmony_ci
57662306a36Sopenharmony_ci	/* check sanity */
57762306a36Sopenharmony_ci	if (len < UCAN_IN_HDR_SIZE + sizeof(m->msg.can_msg.id)) {
57862306a36Sopenharmony_ci		netdev_warn(up->netdev, "invalid input message len: %d\n", len);
57962306a36Sopenharmony_ci		return;
58062306a36Sopenharmony_ci	}
58162306a36Sopenharmony_ci
58262306a36Sopenharmony_ci	/* handle error frames */
58362306a36Sopenharmony_ci	canid = le32_to_cpu(m->msg.can_msg.id);
58462306a36Sopenharmony_ci	if (canid & CAN_ERR_FLAG) {
58562306a36Sopenharmony_ci		bool busstate_changed = ucan_handle_error_frame(up, m, canid);
58662306a36Sopenharmony_ci
58762306a36Sopenharmony_ci		/* if berr-reporting is off only state changes get through */
58862306a36Sopenharmony_ci		if (!(up->can.ctrlmode & CAN_CTRLMODE_BERR_REPORTING) &&
58962306a36Sopenharmony_ci		    !busstate_changed)
59062306a36Sopenharmony_ci			return;
59162306a36Sopenharmony_ci	} else {
59262306a36Sopenharmony_ci		canid_t canid_mask;
59362306a36Sopenharmony_ci		/* compute the mask for canid */
59462306a36Sopenharmony_ci		canid_mask = CAN_RTR_FLAG;
59562306a36Sopenharmony_ci		if (canid & CAN_EFF_FLAG)
59662306a36Sopenharmony_ci			canid_mask |= CAN_EFF_MASK | CAN_EFF_FLAG;
59762306a36Sopenharmony_ci		else
59862306a36Sopenharmony_ci			canid_mask |= CAN_SFF_MASK;
59962306a36Sopenharmony_ci
60062306a36Sopenharmony_ci		if (canid & ~canid_mask)
60162306a36Sopenharmony_ci			netdev_warn(up->netdev,
60262306a36Sopenharmony_ci				    "unexpected bits set (canid %x, mask %x)",
60362306a36Sopenharmony_ci				    canid, canid_mask);
60462306a36Sopenharmony_ci
60562306a36Sopenharmony_ci		canid &= canid_mask;
60662306a36Sopenharmony_ci	}
60762306a36Sopenharmony_ci
60862306a36Sopenharmony_ci	/* allocate skb */
60962306a36Sopenharmony_ci	skb = alloc_can_skb(up->netdev, &cf);
61062306a36Sopenharmony_ci	if (!skb)
61162306a36Sopenharmony_ci		return;
61262306a36Sopenharmony_ci
61362306a36Sopenharmony_ci	/* fill the can frame */
61462306a36Sopenharmony_ci	cf->can_id = canid;
61562306a36Sopenharmony_ci
61662306a36Sopenharmony_ci	/* compute DLC taking RTR_FLAG into account */
61762306a36Sopenharmony_ci	cf->len = ucan_can_cc_dlc2len(&m->msg.can_msg, len);
61862306a36Sopenharmony_ci
61962306a36Sopenharmony_ci	/* copy the payload of non RTR frames */
62062306a36Sopenharmony_ci	if (!(cf->can_id & CAN_RTR_FLAG) || (cf->can_id & CAN_ERR_FLAG))
62162306a36Sopenharmony_ci		memcpy(cf->data, m->msg.can_msg.data, cf->len);
62262306a36Sopenharmony_ci
62362306a36Sopenharmony_ci	/* don't count error frames as real packets */
62462306a36Sopenharmony_ci	if (!(cf->can_id & CAN_ERR_FLAG)) {
62562306a36Sopenharmony_ci		stats->rx_packets++;
62662306a36Sopenharmony_ci		if (!(cf->can_id & CAN_RTR_FLAG))
62762306a36Sopenharmony_ci			stats->rx_bytes += cf->len;
62862306a36Sopenharmony_ci	}
62962306a36Sopenharmony_ci
63062306a36Sopenharmony_ci	/* pass it to Linux */
63162306a36Sopenharmony_ci	netif_rx(skb);
63262306a36Sopenharmony_ci}
63362306a36Sopenharmony_ci
63462306a36Sopenharmony_ci/* callback indicating completed transmission */
63562306a36Sopenharmony_cistatic void ucan_tx_complete_msg(struct ucan_priv *up,
63662306a36Sopenharmony_ci				 struct ucan_message_in *m)
63762306a36Sopenharmony_ci{
63862306a36Sopenharmony_ci	unsigned long flags;
63962306a36Sopenharmony_ci	u16 count, i;
64062306a36Sopenharmony_ci	u8 echo_index;
64162306a36Sopenharmony_ci	u16 len = le16_to_cpu(m->len);
64262306a36Sopenharmony_ci
64362306a36Sopenharmony_ci	struct ucan_urb_context *context;
64462306a36Sopenharmony_ci
64562306a36Sopenharmony_ci	if (len < UCAN_IN_HDR_SIZE || (len % 2 != 0)) {
64662306a36Sopenharmony_ci		netdev_err(up->netdev, "invalid tx complete length\n");
64762306a36Sopenharmony_ci		return;
64862306a36Sopenharmony_ci	}
64962306a36Sopenharmony_ci
65062306a36Sopenharmony_ci	count = (len - UCAN_IN_HDR_SIZE) / 2;
65162306a36Sopenharmony_ci	for (i = 0; i < count; i++) {
65262306a36Sopenharmony_ci		/* we did not submit such echo ids */
65362306a36Sopenharmony_ci		echo_index = m->msg.can_tx_complete_msg[i].echo_index;
65462306a36Sopenharmony_ci		if (echo_index >= up->device_info.tx_fifo) {
65562306a36Sopenharmony_ci			up->netdev->stats.tx_errors++;
65662306a36Sopenharmony_ci			netdev_err(up->netdev,
65762306a36Sopenharmony_ci				   "invalid echo_index %d received\n",
65862306a36Sopenharmony_ci				   echo_index);
65962306a36Sopenharmony_ci			continue;
66062306a36Sopenharmony_ci		}
66162306a36Sopenharmony_ci
66262306a36Sopenharmony_ci		/* gather information from the context */
66362306a36Sopenharmony_ci		context = &up->context_array[echo_index];
66462306a36Sopenharmony_ci
66562306a36Sopenharmony_ci		/* Release context and restart queue if necessary.
66662306a36Sopenharmony_ci		 * Also check if the context was allocated
66762306a36Sopenharmony_ci		 */
66862306a36Sopenharmony_ci		if (!ucan_release_context(up, context))
66962306a36Sopenharmony_ci			continue;
67062306a36Sopenharmony_ci
67162306a36Sopenharmony_ci		spin_lock_irqsave(&up->echo_skb_lock, flags);
67262306a36Sopenharmony_ci		if (m->msg.can_tx_complete_msg[i].flags &
67362306a36Sopenharmony_ci		    UCAN_TX_COMPLETE_SUCCESS) {
67462306a36Sopenharmony_ci			/* update statistics */
67562306a36Sopenharmony_ci			up->netdev->stats.tx_packets++;
67662306a36Sopenharmony_ci			up->netdev->stats.tx_bytes +=
67762306a36Sopenharmony_ci				can_get_echo_skb(up->netdev, echo_index, NULL);
67862306a36Sopenharmony_ci		} else {
67962306a36Sopenharmony_ci			up->netdev->stats.tx_dropped++;
68062306a36Sopenharmony_ci			can_free_echo_skb(up->netdev, echo_index, NULL);
68162306a36Sopenharmony_ci		}
68262306a36Sopenharmony_ci		spin_unlock_irqrestore(&up->echo_skb_lock, flags);
68362306a36Sopenharmony_ci	}
68462306a36Sopenharmony_ci}
68562306a36Sopenharmony_ci
68662306a36Sopenharmony_ci/* callback on reception of a USB message */
68762306a36Sopenharmony_cistatic void ucan_read_bulk_callback(struct urb *urb)
68862306a36Sopenharmony_ci{
68962306a36Sopenharmony_ci	int ret;
69062306a36Sopenharmony_ci	int pos;
69162306a36Sopenharmony_ci	struct ucan_priv *up = urb->context;
69262306a36Sopenharmony_ci	struct net_device *netdev = up->netdev;
69362306a36Sopenharmony_ci	struct ucan_message_in *m;
69462306a36Sopenharmony_ci
69562306a36Sopenharmony_ci	/* the device is not up and the driver should not receive any
69662306a36Sopenharmony_ci	 * data on the bulk in pipe
69762306a36Sopenharmony_ci	 */
69862306a36Sopenharmony_ci	if (WARN_ON(!up->context_array)) {
69962306a36Sopenharmony_ci		usb_free_coherent(up->udev,
70062306a36Sopenharmony_ci				  up->in_ep_size,
70162306a36Sopenharmony_ci				  urb->transfer_buffer,
70262306a36Sopenharmony_ci				  urb->transfer_dma);
70362306a36Sopenharmony_ci		return;
70462306a36Sopenharmony_ci	}
70562306a36Sopenharmony_ci
70662306a36Sopenharmony_ci	/* check URB status */
70762306a36Sopenharmony_ci	switch (urb->status) {
70862306a36Sopenharmony_ci	case 0:
70962306a36Sopenharmony_ci		break;
71062306a36Sopenharmony_ci	case -ENOENT:
71162306a36Sopenharmony_ci	case -EPIPE:
71262306a36Sopenharmony_ci	case -EPROTO:
71362306a36Sopenharmony_ci	case -ESHUTDOWN:
71462306a36Sopenharmony_ci	case -ETIME:
71562306a36Sopenharmony_ci		/* urb is not resubmitted -> free dma data */
71662306a36Sopenharmony_ci		usb_free_coherent(up->udev,
71762306a36Sopenharmony_ci				  up->in_ep_size,
71862306a36Sopenharmony_ci				  urb->transfer_buffer,
71962306a36Sopenharmony_ci				  urb->transfer_dma);
72062306a36Sopenharmony_ci		netdev_dbg(up->netdev, "not resubmitting urb; status: %d\n",
72162306a36Sopenharmony_ci			   urb->status);
72262306a36Sopenharmony_ci		return;
72362306a36Sopenharmony_ci	default:
72462306a36Sopenharmony_ci		goto resubmit;
72562306a36Sopenharmony_ci	}
72662306a36Sopenharmony_ci
72762306a36Sopenharmony_ci	/* sanity check */
72862306a36Sopenharmony_ci	if (!netif_device_present(netdev))
72962306a36Sopenharmony_ci		return;
73062306a36Sopenharmony_ci
73162306a36Sopenharmony_ci	/* iterate over input */
73262306a36Sopenharmony_ci	pos = 0;
73362306a36Sopenharmony_ci	while (pos < urb->actual_length) {
73462306a36Sopenharmony_ci		int len;
73562306a36Sopenharmony_ci
73662306a36Sopenharmony_ci		/* check sanity (length of header) */
73762306a36Sopenharmony_ci		if ((urb->actual_length - pos) < UCAN_IN_HDR_SIZE) {
73862306a36Sopenharmony_ci			netdev_warn(up->netdev,
73962306a36Sopenharmony_ci				    "invalid message (short; no hdr; l:%d)\n",
74062306a36Sopenharmony_ci				    urb->actual_length);
74162306a36Sopenharmony_ci			goto resubmit;
74262306a36Sopenharmony_ci		}
74362306a36Sopenharmony_ci
74462306a36Sopenharmony_ci		/* setup the message address */
74562306a36Sopenharmony_ci		m = (struct ucan_message_in *)
74662306a36Sopenharmony_ci			((u8 *)urb->transfer_buffer + pos);
74762306a36Sopenharmony_ci		len = le16_to_cpu(m->len);
74862306a36Sopenharmony_ci
74962306a36Sopenharmony_ci		/* check sanity (length of content) */
75062306a36Sopenharmony_ci		if (urb->actual_length - pos < len) {
75162306a36Sopenharmony_ci			netdev_warn(up->netdev,
75262306a36Sopenharmony_ci				    "invalid message (short; no data; l:%d)\n",
75362306a36Sopenharmony_ci				    urb->actual_length);
75462306a36Sopenharmony_ci			print_hex_dump(KERN_WARNING,
75562306a36Sopenharmony_ci				       "raw data: ",
75662306a36Sopenharmony_ci				       DUMP_PREFIX_ADDRESS,
75762306a36Sopenharmony_ci				       16,
75862306a36Sopenharmony_ci				       1,
75962306a36Sopenharmony_ci				       urb->transfer_buffer,
76062306a36Sopenharmony_ci				       urb->actual_length,
76162306a36Sopenharmony_ci				       true);
76262306a36Sopenharmony_ci
76362306a36Sopenharmony_ci			goto resubmit;
76462306a36Sopenharmony_ci		}
76562306a36Sopenharmony_ci
76662306a36Sopenharmony_ci		switch (m->type) {
76762306a36Sopenharmony_ci		case UCAN_IN_RX:
76862306a36Sopenharmony_ci			ucan_rx_can_msg(up, m);
76962306a36Sopenharmony_ci			break;
77062306a36Sopenharmony_ci		case UCAN_IN_TX_COMPLETE:
77162306a36Sopenharmony_ci			ucan_tx_complete_msg(up, m);
77262306a36Sopenharmony_ci			break;
77362306a36Sopenharmony_ci		default:
77462306a36Sopenharmony_ci			netdev_warn(up->netdev,
77562306a36Sopenharmony_ci				    "invalid message (type; t:%d)\n",
77662306a36Sopenharmony_ci				    m->type);
77762306a36Sopenharmony_ci			break;
77862306a36Sopenharmony_ci		}
77962306a36Sopenharmony_ci
78062306a36Sopenharmony_ci		/* proceed to next message */
78162306a36Sopenharmony_ci		pos += len;
78262306a36Sopenharmony_ci		/* align to 4 byte boundary */
78362306a36Sopenharmony_ci		pos = round_up(pos, 4);
78462306a36Sopenharmony_ci	}
78562306a36Sopenharmony_ci
78662306a36Sopenharmony_ciresubmit:
78762306a36Sopenharmony_ci	/* resubmit urb when done */
78862306a36Sopenharmony_ci	usb_fill_bulk_urb(urb, up->udev,
78962306a36Sopenharmony_ci			  usb_rcvbulkpipe(up->udev,
79062306a36Sopenharmony_ci					  up->in_ep_addr),
79162306a36Sopenharmony_ci			  urb->transfer_buffer,
79262306a36Sopenharmony_ci			  up->in_ep_size,
79362306a36Sopenharmony_ci			  ucan_read_bulk_callback,
79462306a36Sopenharmony_ci			  up);
79562306a36Sopenharmony_ci
79662306a36Sopenharmony_ci	usb_anchor_urb(urb, &up->rx_urbs);
79762306a36Sopenharmony_ci	ret = usb_submit_urb(urb, GFP_ATOMIC);
79862306a36Sopenharmony_ci
79962306a36Sopenharmony_ci	if (ret < 0) {
80062306a36Sopenharmony_ci		netdev_err(up->netdev,
80162306a36Sopenharmony_ci			   "failed resubmitting read bulk urb: %d\n",
80262306a36Sopenharmony_ci			   ret);
80362306a36Sopenharmony_ci
80462306a36Sopenharmony_ci		usb_unanchor_urb(urb);
80562306a36Sopenharmony_ci		usb_free_coherent(up->udev,
80662306a36Sopenharmony_ci				  up->in_ep_size,
80762306a36Sopenharmony_ci				  urb->transfer_buffer,
80862306a36Sopenharmony_ci				  urb->transfer_dma);
80962306a36Sopenharmony_ci
81062306a36Sopenharmony_ci		if (ret == -ENODEV)
81162306a36Sopenharmony_ci			netif_device_detach(netdev);
81262306a36Sopenharmony_ci	}
81362306a36Sopenharmony_ci}
81462306a36Sopenharmony_ci
81562306a36Sopenharmony_ci/* callback after transmission of a USB message */
81662306a36Sopenharmony_cistatic void ucan_write_bulk_callback(struct urb *urb)
81762306a36Sopenharmony_ci{
81862306a36Sopenharmony_ci	unsigned long flags;
81962306a36Sopenharmony_ci	struct ucan_priv *up;
82062306a36Sopenharmony_ci	struct ucan_urb_context *context = urb->context;
82162306a36Sopenharmony_ci
82262306a36Sopenharmony_ci	/* get the urb context */
82362306a36Sopenharmony_ci	if (WARN_ON_ONCE(!context))
82462306a36Sopenharmony_ci		return;
82562306a36Sopenharmony_ci
82662306a36Sopenharmony_ci	/* free up our allocated buffer */
82762306a36Sopenharmony_ci	usb_free_coherent(urb->dev,
82862306a36Sopenharmony_ci			  sizeof(struct ucan_message_out),
82962306a36Sopenharmony_ci			  urb->transfer_buffer,
83062306a36Sopenharmony_ci			  urb->transfer_dma);
83162306a36Sopenharmony_ci
83262306a36Sopenharmony_ci	up = context->up;
83362306a36Sopenharmony_ci	if (WARN_ON_ONCE(!up))
83462306a36Sopenharmony_ci		return;
83562306a36Sopenharmony_ci
83662306a36Sopenharmony_ci	/* sanity check */
83762306a36Sopenharmony_ci	if (!netif_device_present(up->netdev))
83862306a36Sopenharmony_ci		return;
83962306a36Sopenharmony_ci
84062306a36Sopenharmony_ci	/* transmission failed (USB - the device will not send a TX complete) */
84162306a36Sopenharmony_ci	if (urb->status) {
84262306a36Sopenharmony_ci		netdev_warn(up->netdev,
84362306a36Sopenharmony_ci			    "failed to transmit USB message to device: %d\n",
84462306a36Sopenharmony_ci			     urb->status);
84562306a36Sopenharmony_ci
84662306a36Sopenharmony_ci		/* update counters an cleanup */
84762306a36Sopenharmony_ci		spin_lock_irqsave(&up->echo_skb_lock, flags);
84862306a36Sopenharmony_ci		can_free_echo_skb(up->netdev, context - up->context_array, NULL);
84962306a36Sopenharmony_ci		spin_unlock_irqrestore(&up->echo_skb_lock, flags);
85062306a36Sopenharmony_ci
85162306a36Sopenharmony_ci		up->netdev->stats.tx_dropped++;
85262306a36Sopenharmony_ci
85362306a36Sopenharmony_ci		/* release context and restart the queue if necessary */
85462306a36Sopenharmony_ci		if (!ucan_release_context(up, context))
85562306a36Sopenharmony_ci			netdev_err(up->netdev,
85662306a36Sopenharmony_ci				   "urb failed, failed to release context\n");
85762306a36Sopenharmony_ci	}
85862306a36Sopenharmony_ci}
85962306a36Sopenharmony_ci
86062306a36Sopenharmony_cistatic void ucan_cleanup_rx_urbs(struct ucan_priv *up, struct urb **urbs)
86162306a36Sopenharmony_ci{
86262306a36Sopenharmony_ci	int i;
86362306a36Sopenharmony_ci
86462306a36Sopenharmony_ci	for (i = 0; i < UCAN_MAX_RX_URBS; i++) {
86562306a36Sopenharmony_ci		if (urbs[i]) {
86662306a36Sopenharmony_ci			usb_unanchor_urb(urbs[i]);
86762306a36Sopenharmony_ci			usb_free_coherent(up->udev,
86862306a36Sopenharmony_ci					  up->in_ep_size,
86962306a36Sopenharmony_ci					  urbs[i]->transfer_buffer,
87062306a36Sopenharmony_ci					  urbs[i]->transfer_dma);
87162306a36Sopenharmony_ci			usb_free_urb(urbs[i]);
87262306a36Sopenharmony_ci		}
87362306a36Sopenharmony_ci	}
87462306a36Sopenharmony_ci
87562306a36Sopenharmony_ci	memset(urbs, 0, sizeof(*urbs) * UCAN_MAX_RX_URBS);
87662306a36Sopenharmony_ci}
87762306a36Sopenharmony_ci
87862306a36Sopenharmony_cistatic int ucan_prepare_and_anchor_rx_urbs(struct ucan_priv *up,
87962306a36Sopenharmony_ci					   struct urb **urbs)
88062306a36Sopenharmony_ci{
88162306a36Sopenharmony_ci	int i;
88262306a36Sopenharmony_ci
88362306a36Sopenharmony_ci	memset(urbs, 0, sizeof(*urbs) * UCAN_MAX_RX_URBS);
88462306a36Sopenharmony_ci
88562306a36Sopenharmony_ci	for (i = 0; i < UCAN_MAX_RX_URBS; i++) {
88662306a36Sopenharmony_ci		void *buf;
88762306a36Sopenharmony_ci
88862306a36Sopenharmony_ci		urbs[i] = usb_alloc_urb(0, GFP_KERNEL);
88962306a36Sopenharmony_ci		if (!urbs[i])
89062306a36Sopenharmony_ci			goto err;
89162306a36Sopenharmony_ci
89262306a36Sopenharmony_ci		buf = usb_alloc_coherent(up->udev,
89362306a36Sopenharmony_ci					 up->in_ep_size,
89462306a36Sopenharmony_ci					 GFP_KERNEL, &urbs[i]->transfer_dma);
89562306a36Sopenharmony_ci		if (!buf) {
89662306a36Sopenharmony_ci			/* cleanup this urb */
89762306a36Sopenharmony_ci			usb_free_urb(urbs[i]);
89862306a36Sopenharmony_ci			urbs[i] = NULL;
89962306a36Sopenharmony_ci			goto err;
90062306a36Sopenharmony_ci		}
90162306a36Sopenharmony_ci
90262306a36Sopenharmony_ci		usb_fill_bulk_urb(urbs[i], up->udev,
90362306a36Sopenharmony_ci				  usb_rcvbulkpipe(up->udev,
90462306a36Sopenharmony_ci						  up->in_ep_addr),
90562306a36Sopenharmony_ci				  buf,
90662306a36Sopenharmony_ci				  up->in_ep_size,
90762306a36Sopenharmony_ci				  ucan_read_bulk_callback,
90862306a36Sopenharmony_ci				  up);
90962306a36Sopenharmony_ci
91062306a36Sopenharmony_ci		urbs[i]->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
91162306a36Sopenharmony_ci
91262306a36Sopenharmony_ci		usb_anchor_urb(urbs[i], &up->rx_urbs);
91362306a36Sopenharmony_ci	}
91462306a36Sopenharmony_ci	return 0;
91562306a36Sopenharmony_ci
91662306a36Sopenharmony_cierr:
91762306a36Sopenharmony_ci	/* cleanup other unsubmitted urbs */
91862306a36Sopenharmony_ci	ucan_cleanup_rx_urbs(up, urbs);
91962306a36Sopenharmony_ci	return -ENOMEM;
92062306a36Sopenharmony_ci}
92162306a36Sopenharmony_ci
92262306a36Sopenharmony_ci/* Submits rx urbs with the semantic: Either submit all, or cleanup
92362306a36Sopenharmony_ci * everything. I case of errors submitted urbs are killed and all urbs in
92462306a36Sopenharmony_ci * the array are freed. I case of no errors every entry in the urb
92562306a36Sopenharmony_ci * array is set to NULL.
92662306a36Sopenharmony_ci */
92762306a36Sopenharmony_cistatic int ucan_submit_rx_urbs(struct ucan_priv *up, struct urb **urbs)
92862306a36Sopenharmony_ci{
92962306a36Sopenharmony_ci	int i, ret;
93062306a36Sopenharmony_ci
93162306a36Sopenharmony_ci	/* Iterate over all urbs to submit. On success remove the urb
93262306a36Sopenharmony_ci	 * from the list.
93362306a36Sopenharmony_ci	 */
93462306a36Sopenharmony_ci	for (i = 0; i < UCAN_MAX_RX_URBS; i++) {
93562306a36Sopenharmony_ci		ret = usb_submit_urb(urbs[i], GFP_KERNEL);
93662306a36Sopenharmony_ci		if (ret) {
93762306a36Sopenharmony_ci			netdev_err(up->netdev,
93862306a36Sopenharmony_ci				   "could not submit urb; code: %d\n",
93962306a36Sopenharmony_ci				   ret);
94062306a36Sopenharmony_ci			goto err;
94162306a36Sopenharmony_ci		}
94262306a36Sopenharmony_ci
94362306a36Sopenharmony_ci		/* Anchor URB and drop reference, USB core will take
94462306a36Sopenharmony_ci		 * care of freeing it
94562306a36Sopenharmony_ci		 */
94662306a36Sopenharmony_ci		usb_free_urb(urbs[i]);
94762306a36Sopenharmony_ci		urbs[i] = NULL;
94862306a36Sopenharmony_ci	}
94962306a36Sopenharmony_ci	return 0;
95062306a36Sopenharmony_ci
95162306a36Sopenharmony_cierr:
95262306a36Sopenharmony_ci	/* Cleanup unsubmitted urbs */
95362306a36Sopenharmony_ci	ucan_cleanup_rx_urbs(up, urbs);
95462306a36Sopenharmony_ci
95562306a36Sopenharmony_ci	/* Kill urbs that are already submitted */
95662306a36Sopenharmony_ci	usb_kill_anchored_urbs(&up->rx_urbs);
95762306a36Sopenharmony_ci
95862306a36Sopenharmony_ci	return ret;
95962306a36Sopenharmony_ci}
96062306a36Sopenharmony_ci
96162306a36Sopenharmony_ci/* Open the network device */
96262306a36Sopenharmony_cistatic int ucan_open(struct net_device *netdev)
96362306a36Sopenharmony_ci{
96462306a36Sopenharmony_ci	int ret, ret_cleanup;
96562306a36Sopenharmony_ci	u16 ctrlmode;
96662306a36Sopenharmony_ci	struct urb *urbs[UCAN_MAX_RX_URBS];
96762306a36Sopenharmony_ci	struct ucan_priv *up = netdev_priv(netdev);
96862306a36Sopenharmony_ci
96962306a36Sopenharmony_ci	ret = ucan_alloc_context_array(up);
97062306a36Sopenharmony_ci	if (ret)
97162306a36Sopenharmony_ci		return ret;
97262306a36Sopenharmony_ci
97362306a36Sopenharmony_ci	/* Allocate and prepare IN URBS - allocated and anchored
97462306a36Sopenharmony_ci	 * urbs are stored in urbs[] for clean
97562306a36Sopenharmony_ci	 */
97662306a36Sopenharmony_ci	ret = ucan_prepare_and_anchor_rx_urbs(up, urbs);
97762306a36Sopenharmony_ci	if (ret)
97862306a36Sopenharmony_ci		goto err_contexts;
97962306a36Sopenharmony_ci
98062306a36Sopenharmony_ci	/* Check the control mode */
98162306a36Sopenharmony_ci	ctrlmode = 0;
98262306a36Sopenharmony_ci	if (up->can.ctrlmode & CAN_CTRLMODE_LOOPBACK)
98362306a36Sopenharmony_ci		ctrlmode |= UCAN_MODE_LOOPBACK;
98462306a36Sopenharmony_ci	if (up->can.ctrlmode & CAN_CTRLMODE_LISTENONLY)
98562306a36Sopenharmony_ci		ctrlmode |= UCAN_MODE_SILENT;
98662306a36Sopenharmony_ci	if (up->can.ctrlmode & CAN_CTRLMODE_3_SAMPLES)
98762306a36Sopenharmony_ci		ctrlmode |= UCAN_MODE_3_SAMPLES;
98862306a36Sopenharmony_ci	if (up->can.ctrlmode & CAN_CTRLMODE_ONE_SHOT)
98962306a36Sopenharmony_ci		ctrlmode |= UCAN_MODE_ONE_SHOT;
99062306a36Sopenharmony_ci
99162306a36Sopenharmony_ci	/* Enable this in any case - filtering is down within the
99262306a36Sopenharmony_ci	 * receive path
99362306a36Sopenharmony_ci	 */
99462306a36Sopenharmony_ci	ctrlmode |= UCAN_MODE_BERR_REPORT;
99562306a36Sopenharmony_ci	up->ctl_msg_buffer->cmd_start.mode = cpu_to_le16(ctrlmode);
99662306a36Sopenharmony_ci
99762306a36Sopenharmony_ci	/* Driver is ready to receive data - start the USB device */
99862306a36Sopenharmony_ci	ret = ucan_ctrl_command_out(up, UCAN_COMMAND_START, 0, 2);
99962306a36Sopenharmony_ci	if (ret < 0) {
100062306a36Sopenharmony_ci		netdev_err(up->netdev,
100162306a36Sopenharmony_ci			   "could not start device, code: %d\n",
100262306a36Sopenharmony_ci			   ret);
100362306a36Sopenharmony_ci		goto err_reset;
100462306a36Sopenharmony_ci	}
100562306a36Sopenharmony_ci
100662306a36Sopenharmony_ci	/* Call CAN layer open */
100762306a36Sopenharmony_ci	ret = open_candev(netdev);
100862306a36Sopenharmony_ci	if (ret)
100962306a36Sopenharmony_ci		goto err_stop;
101062306a36Sopenharmony_ci
101162306a36Sopenharmony_ci	/* Driver is ready to receive data. Submit RX URBS */
101262306a36Sopenharmony_ci	ret = ucan_submit_rx_urbs(up, urbs);
101362306a36Sopenharmony_ci	if (ret)
101462306a36Sopenharmony_ci		goto err_stop;
101562306a36Sopenharmony_ci
101662306a36Sopenharmony_ci	up->can.state = CAN_STATE_ERROR_ACTIVE;
101762306a36Sopenharmony_ci
101862306a36Sopenharmony_ci	/* Start the network queue */
101962306a36Sopenharmony_ci	netif_start_queue(netdev);
102062306a36Sopenharmony_ci
102162306a36Sopenharmony_ci	return 0;
102262306a36Sopenharmony_ci
102362306a36Sopenharmony_cierr_stop:
102462306a36Sopenharmony_ci	/* The device have started already stop it */
102562306a36Sopenharmony_ci	ret_cleanup = ucan_ctrl_command_out(up, UCAN_COMMAND_STOP, 0, 0);
102662306a36Sopenharmony_ci	if (ret_cleanup < 0)
102762306a36Sopenharmony_ci		netdev_err(up->netdev,
102862306a36Sopenharmony_ci			   "could not stop device, code: %d\n",
102962306a36Sopenharmony_ci			   ret_cleanup);
103062306a36Sopenharmony_ci
103162306a36Sopenharmony_cierr_reset:
103262306a36Sopenharmony_ci	/* The device might have received data, reset it for
103362306a36Sopenharmony_ci	 * consistent state
103462306a36Sopenharmony_ci	 */
103562306a36Sopenharmony_ci	ret_cleanup = ucan_ctrl_command_out(up, UCAN_COMMAND_RESET, 0, 0);
103662306a36Sopenharmony_ci	if (ret_cleanup < 0)
103762306a36Sopenharmony_ci		netdev_err(up->netdev,
103862306a36Sopenharmony_ci			   "could not reset device, code: %d\n",
103962306a36Sopenharmony_ci			   ret_cleanup);
104062306a36Sopenharmony_ci
104162306a36Sopenharmony_ci	/* clean up unsubmitted urbs */
104262306a36Sopenharmony_ci	ucan_cleanup_rx_urbs(up, urbs);
104362306a36Sopenharmony_ci
104462306a36Sopenharmony_cierr_contexts:
104562306a36Sopenharmony_ci	ucan_release_context_array(up);
104662306a36Sopenharmony_ci	return ret;
104762306a36Sopenharmony_ci}
104862306a36Sopenharmony_ci
104962306a36Sopenharmony_cistatic struct urb *ucan_prepare_tx_urb(struct ucan_priv *up,
105062306a36Sopenharmony_ci				       struct ucan_urb_context *context,
105162306a36Sopenharmony_ci				       struct can_frame *cf,
105262306a36Sopenharmony_ci				       u8 echo_index)
105362306a36Sopenharmony_ci{
105462306a36Sopenharmony_ci	int mlen;
105562306a36Sopenharmony_ci	struct urb *urb;
105662306a36Sopenharmony_ci	struct ucan_message_out *m;
105762306a36Sopenharmony_ci
105862306a36Sopenharmony_ci	/* create a URB, and a buffer for it, and copy the data to the URB */
105962306a36Sopenharmony_ci	urb = usb_alloc_urb(0, GFP_ATOMIC);
106062306a36Sopenharmony_ci	if (!urb) {
106162306a36Sopenharmony_ci		netdev_err(up->netdev, "no memory left for URBs\n");
106262306a36Sopenharmony_ci		return NULL;
106362306a36Sopenharmony_ci	}
106462306a36Sopenharmony_ci
106562306a36Sopenharmony_ci	m = usb_alloc_coherent(up->udev,
106662306a36Sopenharmony_ci			       sizeof(struct ucan_message_out),
106762306a36Sopenharmony_ci			       GFP_ATOMIC,
106862306a36Sopenharmony_ci			       &urb->transfer_dma);
106962306a36Sopenharmony_ci	if (!m) {
107062306a36Sopenharmony_ci		netdev_err(up->netdev, "no memory left for USB buffer\n");
107162306a36Sopenharmony_ci		usb_free_urb(urb);
107262306a36Sopenharmony_ci		return NULL;
107362306a36Sopenharmony_ci	}
107462306a36Sopenharmony_ci
107562306a36Sopenharmony_ci	/* build the USB message */
107662306a36Sopenharmony_ci	m->type = UCAN_OUT_TX;
107762306a36Sopenharmony_ci	m->msg.can_msg.id = cpu_to_le32(cf->can_id);
107862306a36Sopenharmony_ci
107962306a36Sopenharmony_ci	if (cf->can_id & CAN_RTR_FLAG) {
108062306a36Sopenharmony_ci		mlen = UCAN_OUT_HDR_SIZE +
108162306a36Sopenharmony_ci			offsetof(struct ucan_can_msg, dlc) +
108262306a36Sopenharmony_ci			sizeof(m->msg.can_msg.dlc);
108362306a36Sopenharmony_ci		m->msg.can_msg.dlc = cf->len;
108462306a36Sopenharmony_ci	} else {
108562306a36Sopenharmony_ci		mlen = UCAN_OUT_HDR_SIZE +
108662306a36Sopenharmony_ci			sizeof(m->msg.can_msg.id) + cf->len;
108762306a36Sopenharmony_ci		memcpy(m->msg.can_msg.data, cf->data, cf->len);
108862306a36Sopenharmony_ci	}
108962306a36Sopenharmony_ci	m->len = cpu_to_le16(mlen);
109062306a36Sopenharmony_ci
109162306a36Sopenharmony_ci	m->subtype = echo_index;
109262306a36Sopenharmony_ci
109362306a36Sopenharmony_ci	/* build the urb */
109462306a36Sopenharmony_ci	usb_fill_bulk_urb(urb, up->udev,
109562306a36Sopenharmony_ci			  usb_sndbulkpipe(up->udev,
109662306a36Sopenharmony_ci					  up->out_ep_addr),
109762306a36Sopenharmony_ci			  m, mlen, ucan_write_bulk_callback, context);
109862306a36Sopenharmony_ci	urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
109962306a36Sopenharmony_ci
110062306a36Sopenharmony_ci	return urb;
110162306a36Sopenharmony_ci}
110262306a36Sopenharmony_ci
110362306a36Sopenharmony_cistatic void ucan_clean_up_tx_urb(struct ucan_priv *up, struct urb *urb)
110462306a36Sopenharmony_ci{
110562306a36Sopenharmony_ci	usb_free_coherent(up->udev, sizeof(struct ucan_message_out),
110662306a36Sopenharmony_ci			  urb->transfer_buffer, urb->transfer_dma);
110762306a36Sopenharmony_ci	usb_free_urb(urb);
110862306a36Sopenharmony_ci}
110962306a36Sopenharmony_ci
111062306a36Sopenharmony_ci/* callback when Linux needs to send a can frame */
111162306a36Sopenharmony_cistatic netdev_tx_t ucan_start_xmit(struct sk_buff *skb,
111262306a36Sopenharmony_ci				   struct net_device *netdev)
111362306a36Sopenharmony_ci{
111462306a36Sopenharmony_ci	unsigned long flags;
111562306a36Sopenharmony_ci	int ret;
111662306a36Sopenharmony_ci	u8 echo_index;
111762306a36Sopenharmony_ci	struct urb *urb;
111862306a36Sopenharmony_ci	struct ucan_urb_context *context;
111962306a36Sopenharmony_ci	struct ucan_priv *up = netdev_priv(netdev);
112062306a36Sopenharmony_ci	struct can_frame *cf = (struct can_frame *)skb->data;
112162306a36Sopenharmony_ci
112262306a36Sopenharmony_ci	/* check skb */
112362306a36Sopenharmony_ci	if (can_dev_dropped_skb(netdev, skb))
112462306a36Sopenharmony_ci		return NETDEV_TX_OK;
112562306a36Sopenharmony_ci
112662306a36Sopenharmony_ci	/* allocate a context and slow down tx path, if fifo state is low */
112762306a36Sopenharmony_ci	context = ucan_alloc_context(up);
112862306a36Sopenharmony_ci	echo_index = context - up->context_array;
112962306a36Sopenharmony_ci
113062306a36Sopenharmony_ci	if (WARN_ON_ONCE(!context))
113162306a36Sopenharmony_ci		return NETDEV_TX_BUSY;
113262306a36Sopenharmony_ci
113362306a36Sopenharmony_ci	/* prepare urb for transmission */
113462306a36Sopenharmony_ci	urb = ucan_prepare_tx_urb(up, context, cf, echo_index);
113562306a36Sopenharmony_ci	if (!urb)
113662306a36Sopenharmony_ci		goto drop;
113762306a36Sopenharmony_ci
113862306a36Sopenharmony_ci	/* put the skb on can loopback stack */
113962306a36Sopenharmony_ci	spin_lock_irqsave(&up->echo_skb_lock, flags);
114062306a36Sopenharmony_ci	can_put_echo_skb(skb, up->netdev, echo_index, 0);
114162306a36Sopenharmony_ci	spin_unlock_irqrestore(&up->echo_skb_lock, flags);
114262306a36Sopenharmony_ci
114362306a36Sopenharmony_ci	/* transmit it */
114462306a36Sopenharmony_ci	usb_anchor_urb(urb, &up->tx_urbs);
114562306a36Sopenharmony_ci	ret = usb_submit_urb(urb, GFP_ATOMIC);
114662306a36Sopenharmony_ci
114762306a36Sopenharmony_ci	/* cleanup urb */
114862306a36Sopenharmony_ci	if (ret) {
114962306a36Sopenharmony_ci		/* on error, clean up */
115062306a36Sopenharmony_ci		usb_unanchor_urb(urb);
115162306a36Sopenharmony_ci		ucan_clean_up_tx_urb(up, urb);
115262306a36Sopenharmony_ci		if (!ucan_release_context(up, context))
115362306a36Sopenharmony_ci			netdev_err(up->netdev,
115462306a36Sopenharmony_ci				   "xmit err: failed to release context\n");
115562306a36Sopenharmony_ci
115662306a36Sopenharmony_ci		/* remove the skb from the echo stack - this also
115762306a36Sopenharmony_ci		 * frees the skb
115862306a36Sopenharmony_ci		 */
115962306a36Sopenharmony_ci		spin_lock_irqsave(&up->echo_skb_lock, flags);
116062306a36Sopenharmony_ci		can_free_echo_skb(up->netdev, echo_index, NULL);
116162306a36Sopenharmony_ci		spin_unlock_irqrestore(&up->echo_skb_lock, flags);
116262306a36Sopenharmony_ci
116362306a36Sopenharmony_ci		if (ret == -ENODEV) {
116462306a36Sopenharmony_ci			netif_device_detach(up->netdev);
116562306a36Sopenharmony_ci		} else {
116662306a36Sopenharmony_ci			netdev_warn(up->netdev,
116762306a36Sopenharmony_ci				    "xmit err: failed to submit urb %d\n",
116862306a36Sopenharmony_ci				    ret);
116962306a36Sopenharmony_ci			up->netdev->stats.tx_dropped++;
117062306a36Sopenharmony_ci		}
117162306a36Sopenharmony_ci		return NETDEV_TX_OK;
117262306a36Sopenharmony_ci	}
117362306a36Sopenharmony_ci
117462306a36Sopenharmony_ci	netif_trans_update(netdev);
117562306a36Sopenharmony_ci
117662306a36Sopenharmony_ci	/* release ref, as we do not need the urb anymore */
117762306a36Sopenharmony_ci	usb_free_urb(urb);
117862306a36Sopenharmony_ci
117962306a36Sopenharmony_ci	return NETDEV_TX_OK;
118062306a36Sopenharmony_ci
118162306a36Sopenharmony_cidrop:
118262306a36Sopenharmony_ci	if (!ucan_release_context(up, context))
118362306a36Sopenharmony_ci		netdev_err(up->netdev,
118462306a36Sopenharmony_ci			   "xmit drop: failed to release context\n");
118562306a36Sopenharmony_ci	dev_kfree_skb(skb);
118662306a36Sopenharmony_ci	up->netdev->stats.tx_dropped++;
118762306a36Sopenharmony_ci
118862306a36Sopenharmony_ci	return NETDEV_TX_OK;
118962306a36Sopenharmony_ci}
119062306a36Sopenharmony_ci
119162306a36Sopenharmony_ci/* Device goes down
119262306a36Sopenharmony_ci *
119362306a36Sopenharmony_ci * Clean up used resources
119462306a36Sopenharmony_ci */
119562306a36Sopenharmony_cistatic int ucan_close(struct net_device *netdev)
119662306a36Sopenharmony_ci{
119762306a36Sopenharmony_ci	int ret;
119862306a36Sopenharmony_ci	struct ucan_priv *up = netdev_priv(netdev);
119962306a36Sopenharmony_ci
120062306a36Sopenharmony_ci	up->can.state = CAN_STATE_STOPPED;
120162306a36Sopenharmony_ci
120262306a36Sopenharmony_ci	/* stop sending data */
120362306a36Sopenharmony_ci	usb_kill_anchored_urbs(&up->tx_urbs);
120462306a36Sopenharmony_ci
120562306a36Sopenharmony_ci	/* stop receiving data */
120662306a36Sopenharmony_ci	usb_kill_anchored_urbs(&up->rx_urbs);
120762306a36Sopenharmony_ci
120862306a36Sopenharmony_ci	/* stop and reset can device */
120962306a36Sopenharmony_ci	ret = ucan_ctrl_command_out(up, UCAN_COMMAND_STOP, 0, 0);
121062306a36Sopenharmony_ci	if (ret < 0)
121162306a36Sopenharmony_ci		netdev_err(up->netdev,
121262306a36Sopenharmony_ci			   "could not stop device, code: %d\n",
121362306a36Sopenharmony_ci			   ret);
121462306a36Sopenharmony_ci
121562306a36Sopenharmony_ci	ret = ucan_ctrl_command_out(up, UCAN_COMMAND_RESET, 0, 0);
121662306a36Sopenharmony_ci	if (ret < 0)
121762306a36Sopenharmony_ci		netdev_err(up->netdev,
121862306a36Sopenharmony_ci			   "could not reset device, code: %d\n",
121962306a36Sopenharmony_ci			   ret);
122062306a36Sopenharmony_ci
122162306a36Sopenharmony_ci	netif_stop_queue(netdev);
122262306a36Sopenharmony_ci
122362306a36Sopenharmony_ci	ucan_release_context_array(up);
122462306a36Sopenharmony_ci
122562306a36Sopenharmony_ci	close_candev(up->netdev);
122662306a36Sopenharmony_ci	return 0;
122762306a36Sopenharmony_ci}
122862306a36Sopenharmony_ci
122962306a36Sopenharmony_ci/* CAN driver callbacks */
123062306a36Sopenharmony_cistatic const struct net_device_ops ucan_netdev_ops = {
123162306a36Sopenharmony_ci	.ndo_open = ucan_open,
123262306a36Sopenharmony_ci	.ndo_stop = ucan_close,
123362306a36Sopenharmony_ci	.ndo_start_xmit = ucan_start_xmit,
123462306a36Sopenharmony_ci	.ndo_change_mtu = can_change_mtu,
123562306a36Sopenharmony_ci};
123662306a36Sopenharmony_ci
123762306a36Sopenharmony_cistatic const struct ethtool_ops ucan_ethtool_ops = {
123862306a36Sopenharmony_ci	.get_ts_info = ethtool_op_get_ts_info,
123962306a36Sopenharmony_ci};
124062306a36Sopenharmony_ci
124162306a36Sopenharmony_ci/* Request to set bittiming
124262306a36Sopenharmony_ci *
124362306a36Sopenharmony_ci * This function generates an USB set bittiming message and transmits
124462306a36Sopenharmony_ci * it to the device
124562306a36Sopenharmony_ci */
124662306a36Sopenharmony_cistatic int ucan_set_bittiming(struct net_device *netdev)
124762306a36Sopenharmony_ci{
124862306a36Sopenharmony_ci	int ret;
124962306a36Sopenharmony_ci	struct ucan_priv *up = netdev_priv(netdev);
125062306a36Sopenharmony_ci	struct ucan_ctl_cmd_set_bittiming *cmd_set_bittiming;
125162306a36Sopenharmony_ci
125262306a36Sopenharmony_ci	cmd_set_bittiming = &up->ctl_msg_buffer->cmd_set_bittiming;
125362306a36Sopenharmony_ci	cmd_set_bittiming->tq = cpu_to_le32(up->can.bittiming.tq);
125462306a36Sopenharmony_ci	cmd_set_bittiming->brp = cpu_to_le16(up->can.bittiming.brp);
125562306a36Sopenharmony_ci	cmd_set_bittiming->sample_point =
125662306a36Sopenharmony_ci	    cpu_to_le16(up->can.bittiming.sample_point);
125762306a36Sopenharmony_ci	cmd_set_bittiming->prop_seg = up->can.bittiming.prop_seg;
125862306a36Sopenharmony_ci	cmd_set_bittiming->phase_seg1 = up->can.bittiming.phase_seg1;
125962306a36Sopenharmony_ci	cmd_set_bittiming->phase_seg2 = up->can.bittiming.phase_seg2;
126062306a36Sopenharmony_ci	cmd_set_bittiming->sjw = up->can.bittiming.sjw;
126162306a36Sopenharmony_ci
126262306a36Sopenharmony_ci	ret = ucan_ctrl_command_out(up, UCAN_COMMAND_SET_BITTIMING, 0,
126362306a36Sopenharmony_ci				    sizeof(*cmd_set_bittiming));
126462306a36Sopenharmony_ci	return (ret < 0) ? ret : 0;
126562306a36Sopenharmony_ci}
126662306a36Sopenharmony_ci
126762306a36Sopenharmony_ci/* Restart the device to get it out of BUS-OFF state.
126862306a36Sopenharmony_ci * Called when the user runs "ip link set can1 type can restart".
126962306a36Sopenharmony_ci */
127062306a36Sopenharmony_cistatic int ucan_set_mode(struct net_device *netdev, enum can_mode mode)
127162306a36Sopenharmony_ci{
127262306a36Sopenharmony_ci	int ret;
127362306a36Sopenharmony_ci	unsigned long flags;
127462306a36Sopenharmony_ci	struct ucan_priv *up = netdev_priv(netdev);
127562306a36Sopenharmony_ci
127662306a36Sopenharmony_ci	switch (mode) {
127762306a36Sopenharmony_ci	case CAN_MODE_START:
127862306a36Sopenharmony_ci		netdev_dbg(up->netdev, "restarting device\n");
127962306a36Sopenharmony_ci
128062306a36Sopenharmony_ci		ret = ucan_ctrl_command_out(up, UCAN_COMMAND_RESTART, 0, 0);
128162306a36Sopenharmony_ci		up->can.state = CAN_STATE_ERROR_ACTIVE;
128262306a36Sopenharmony_ci
128362306a36Sopenharmony_ci		/* check if queue can be restarted,
128462306a36Sopenharmony_ci		 * up->available_tx_urbs must be protected by the
128562306a36Sopenharmony_ci		 * lock
128662306a36Sopenharmony_ci		 */
128762306a36Sopenharmony_ci		spin_lock_irqsave(&up->context_lock, flags);
128862306a36Sopenharmony_ci
128962306a36Sopenharmony_ci		if (up->available_tx_urbs > 0)
129062306a36Sopenharmony_ci			netif_wake_queue(up->netdev);
129162306a36Sopenharmony_ci
129262306a36Sopenharmony_ci		spin_unlock_irqrestore(&up->context_lock, flags);
129362306a36Sopenharmony_ci
129462306a36Sopenharmony_ci		return ret;
129562306a36Sopenharmony_ci	default:
129662306a36Sopenharmony_ci		return -EOPNOTSUPP;
129762306a36Sopenharmony_ci	}
129862306a36Sopenharmony_ci}
129962306a36Sopenharmony_ci
130062306a36Sopenharmony_ci/* Probe the device, reset it and gather general device information */
130162306a36Sopenharmony_cistatic int ucan_probe(struct usb_interface *intf,
130262306a36Sopenharmony_ci		      const struct usb_device_id *id)
130362306a36Sopenharmony_ci{
130462306a36Sopenharmony_ci	int ret;
130562306a36Sopenharmony_ci	int i;
130662306a36Sopenharmony_ci	u32 protocol_version;
130762306a36Sopenharmony_ci	struct usb_device *udev;
130862306a36Sopenharmony_ci	struct net_device *netdev;
130962306a36Sopenharmony_ci	struct usb_host_interface *iface_desc;
131062306a36Sopenharmony_ci	struct ucan_priv *up;
131162306a36Sopenharmony_ci	struct usb_endpoint_descriptor *ep;
131262306a36Sopenharmony_ci	u16 in_ep_size;
131362306a36Sopenharmony_ci	u16 out_ep_size;
131462306a36Sopenharmony_ci	u8 in_ep_addr;
131562306a36Sopenharmony_ci	u8 out_ep_addr;
131662306a36Sopenharmony_ci	union ucan_ctl_payload *ctl_msg_buffer;
131762306a36Sopenharmony_ci	char firmware_str[sizeof(union ucan_ctl_payload) + 1];
131862306a36Sopenharmony_ci
131962306a36Sopenharmony_ci	udev = interface_to_usbdev(intf);
132062306a36Sopenharmony_ci
132162306a36Sopenharmony_ci	/* Stage 1 - Interface Parsing
132262306a36Sopenharmony_ci	 * ---------------------------
132362306a36Sopenharmony_ci	 *
132462306a36Sopenharmony_ci	 * Identifie the device USB interface descriptor and its
132562306a36Sopenharmony_ci	 * endpoints. Probing is aborted on errors.
132662306a36Sopenharmony_ci	 */
132762306a36Sopenharmony_ci
132862306a36Sopenharmony_ci	/* check if the interface is sane */
132962306a36Sopenharmony_ci	iface_desc = intf->cur_altsetting;
133062306a36Sopenharmony_ci	if (!iface_desc)
133162306a36Sopenharmony_ci		return -ENODEV;
133262306a36Sopenharmony_ci
133362306a36Sopenharmony_ci	dev_info(&udev->dev,
133462306a36Sopenharmony_ci		 "%s: probing device on interface #%d\n",
133562306a36Sopenharmony_ci		 UCAN_DRIVER_NAME,
133662306a36Sopenharmony_ci		 iface_desc->desc.bInterfaceNumber);
133762306a36Sopenharmony_ci
133862306a36Sopenharmony_ci	/* interface sanity check */
133962306a36Sopenharmony_ci	if (iface_desc->desc.bNumEndpoints != 2) {
134062306a36Sopenharmony_ci		dev_err(&udev->dev,
134162306a36Sopenharmony_ci			"%s: invalid EP count (%d)",
134262306a36Sopenharmony_ci			UCAN_DRIVER_NAME, iface_desc->desc.bNumEndpoints);
134362306a36Sopenharmony_ci		goto err_firmware_needs_update;
134462306a36Sopenharmony_ci	}
134562306a36Sopenharmony_ci
134662306a36Sopenharmony_ci	/* check interface endpoints */
134762306a36Sopenharmony_ci	in_ep_addr = 0;
134862306a36Sopenharmony_ci	out_ep_addr = 0;
134962306a36Sopenharmony_ci	in_ep_size = 0;
135062306a36Sopenharmony_ci	out_ep_size = 0;
135162306a36Sopenharmony_ci	for (i = 0; i < iface_desc->desc.bNumEndpoints; i++) {
135262306a36Sopenharmony_ci		ep = &iface_desc->endpoint[i].desc;
135362306a36Sopenharmony_ci
135462306a36Sopenharmony_ci		if (((ep->bEndpointAddress & USB_ENDPOINT_DIR_MASK) != 0) &&
135562306a36Sopenharmony_ci		    ((ep->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) ==
135662306a36Sopenharmony_ci		     USB_ENDPOINT_XFER_BULK)) {
135762306a36Sopenharmony_ci			/* In Endpoint */
135862306a36Sopenharmony_ci			in_ep_addr = ep->bEndpointAddress;
135962306a36Sopenharmony_ci			in_ep_addr &= USB_ENDPOINT_NUMBER_MASK;
136062306a36Sopenharmony_ci			in_ep_size = le16_to_cpu(ep->wMaxPacketSize);
136162306a36Sopenharmony_ci		} else if (((ep->bEndpointAddress & USB_ENDPOINT_DIR_MASK) ==
136262306a36Sopenharmony_ci			    0) &&
136362306a36Sopenharmony_ci			   ((ep->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) ==
136462306a36Sopenharmony_ci			    USB_ENDPOINT_XFER_BULK)) {
136562306a36Sopenharmony_ci			/* Out Endpoint */
136662306a36Sopenharmony_ci			out_ep_addr = ep->bEndpointAddress;
136762306a36Sopenharmony_ci			out_ep_addr &= USB_ENDPOINT_NUMBER_MASK;
136862306a36Sopenharmony_ci			out_ep_size = le16_to_cpu(ep->wMaxPacketSize);
136962306a36Sopenharmony_ci		}
137062306a36Sopenharmony_ci	}
137162306a36Sopenharmony_ci
137262306a36Sopenharmony_ci	/* check if interface is sane */
137362306a36Sopenharmony_ci	if (!in_ep_addr || !out_ep_addr) {
137462306a36Sopenharmony_ci		dev_err(&udev->dev, "%s: invalid endpoint configuration\n",
137562306a36Sopenharmony_ci			UCAN_DRIVER_NAME);
137662306a36Sopenharmony_ci		goto err_firmware_needs_update;
137762306a36Sopenharmony_ci	}
137862306a36Sopenharmony_ci	if (in_ep_size < sizeof(struct ucan_message_in)) {
137962306a36Sopenharmony_ci		dev_err(&udev->dev, "%s: invalid in_ep MaxPacketSize\n",
138062306a36Sopenharmony_ci			UCAN_DRIVER_NAME);
138162306a36Sopenharmony_ci		goto err_firmware_needs_update;
138262306a36Sopenharmony_ci	}
138362306a36Sopenharmony_ci	if (out_ep_size < sizeof(struct ucan_message_out)) {
138462306a36Sopenharmony_ci		dev_err(&udev->dev, "%s: invalid out_ep MaxPacketSize\n",
138562306a36Sopenharmony_ci			UCAN_DRIVER_NAME);
138662306a36Sopenharmony_ci		goto err_firmware_needs_update;
138762306a36Sopenharmony_ci	}
138862306a36Sopenharmony_ci
138962306a36Sopenharmony_ci	/* Stage 2 - Device Identification
139062306a36Sopenharmony_ci	 * -------------------------------
139162306a36Sopenharmony_ci	 *
139262306a36Sopenharmony_ci	 * The device interface seems to be a ucan device. Do further
139362306a36Sopenharmony_ci	 * compatibility checks. On error probing is aborted, on
139462306a36Sopenharmony_ci	 * success this stage leaves the ctl_msg_buffer with the
139562306a36Sopenharmony_ci	 * reported contents of a GET_INFO command (supported
139662306a36Sopenharmony_ci	 * bittimings, tx_fifo depth). This information is used in
139762306a36Sopenharmony_ci	 * Stage 3 for the final driver initialisation.
139862306a36Sopenharmony_ci	 */
139962306a36Sopenharmony_ci
140062306a36Sopenharmony_ci	/* Prepare Memory for control transfers */
140162306a36Sopenharmony_ci	ctl_msg_buffer = devm_kzalloc(&udev->dev,
140262306a36Sopenharmony_ci				      sizeof(union ucan_ctl_payload),
140362306a36Sopenharmony_ci				      GFP_KERNEL);
140462306a36Sopenharmony_ci	if (!ctl_msg_buffer) {
140562306a36Sopenharmony_ci		dev_err(&udev->dev,
140662306a36Sopenharmony_ci			"%s: failed to allocate control pipe memory\n",
140762306a36Sopenharmony_ci			UCAN_DRIVER_NAME);
140862306a36Sopenharmony_ci		return -ENOMEM;
140962306a36Sopenharmony_ci	}
141062306a36Sopenharmony_ci
141162306a36Sopenharmony_ci	/* get protocol version
141262306a36Sopenharmony_ci	 *
141362306a36Sopenharmony_ci	 * note: ucan_ctrl_command_* wrappers cannot be used yet
141462306a36Sopenharmony_ci	 * because `up` is initialised in Stage 3
141562306a36Sopenharmony_ci	 */
141662306a36Sopenharmony_ci	ret = usb_control_msg(udev,
141762306a36Sopenharmony_ci			      usb_rcvctrlpipe(udev, 0),
141862306a36Sopenharmony_ci			      UCAN_COMMAND_GET,
141962306a36Sopenharmony_ci			      USB_DIR_IN | USB_TYPE_VENDOR |
142062306a36Sopenharmony_ci					USB_RECIP_INTERFACE,
142162306a36Sopenharmony_ci			      UCAN_COMMAND_GET_PROTOCOL_VERSION,
142262306a36Sopenharmony_ci			      iface_desc->desc.bInterfaceNumber,
142362306a36Sopenharmony_ci			      ctl_msg_buffer,
142462306a36Sopenharmony_ci			      sizeof(union ucan_ctl_payload),
142562306a36Sopenharmony_ci			      UCAN_USB_CTL_PIPE_TIMEOUT);
142662306a36Sopenharmony_ci
142762306a36Sopenharmony_ci	/* older firmware version do not support this command - those
142862306a36Sopenharmony_ci	 * are not supported by this drive
142962306a36Sopenharmony_ci	 */
143062306a36Sopenharmony_ci	if (ret != 4) {
143162306a36Sopenharmony_ci		dev_err(&udev->dev,
143262306a36Sopenharmony_ci			"%s: could not read protocol version, ret=%d\n",
143362306a36Sopenharmony_ci			UCAN_DRIVER_NAME, ret);
143462306a36Sopenharmony_ci		if (ret >= 0)
143562306a36Sopenharmony_ci			ret = -EINVAL;
143662306a36Sopenharmony_ci		goto err_firmware_needs_update;
143762306a36Sopenharmony_ci	}
143862306a36Sopenharmony_ci
143962306a36Sopenharmony_ci	/* this driver currently supports protocol version 3 only */
144062306a36Sopenharmony_ci	protocol_version =
144162306a36Sopenharmony_ci		le32_to_cpu(ctl_msg_buffer->cmd_get_protocol_version.version);
144262306a36Sopenharmony_ci	if (protocol_version < UCAN_PROTOCOL_VERSION_MIN ||
144362306a36Sopenharmony_ci	    protocol_version > UCAN_PROTOCOL_VERSION_MAX) {
144462306a36Sopenharmony_ci		dev_err(&udev->dev,
144562306a36Sopenharmony_ci			"%s: device protocol version %d is not supported\n",
144662306a36Sopenharmony_ci			UCAN_DRIVER_NAME, protocol_version);
144762306a36Sopenharmony_ci		goto err_firmware_needs_update;
144862306a36Sopenharmony_ci	}
144962306a36Sopenharmony_ci
145062306a36Sopenharmony_ci	/* request the device information and store it in ctl_msg_buffer
145162306a36Sopenharmony_ci	 *
145262306a36Sopenharmony_ci	 * note: ucan_ctrl_command_* wrappers cannot be used yet
145362306a36Sopenharmony_ci	 * because `up` is initialised in Stage 3
145462306a36Sopenharmony_ci	 */
145562306a36Sopenharmony_ci	ret = usb_control_msg(udev,
145662306a36Sopenharmony_ci			      usb_rcvctrlpipe(udev, 0),
145762306a36Sopenharmony_ci			      UCAN_COMMAND_GET,
145862306a36Sopenharmony_ci			      USB_DIR_IN | USB_TYPE_VENDOR |
145962306a36Sopenharmony_ci					USB_RECIP_INTERFACE,
146062306a36Sopenharmony_ci			      UCAN_COMMAND_GET_INFO,
146162306a36Sopenharmony_ci			      iface_desc->desc.bInterfaceNumber,
146262306a36Sopenharmony_ci			      ctl_msg_buffer,
146362306a36Sopenharmony_ci			      sizeof(ctl_msg_buffer->cmd_get_device_info),
146462306a36Sopenharmony_ci			      UCAN_USB_CTL_PIPE_TIMEOUT);
146562306a36Sopenharmony_ci
146662306a36Sopenharmony_ci	if (ret < 0) {
146762306a36Sopenharmony_ci		dev_err(&udev->dev, "%s: failed to retrieve device info\n",
146862306a36Sopenharmony_ci			UCAN_DRIVER_NAME);
146962306a36Sopenharmony_ci		goto err_firmware_needs_update;
147062306a36Sopenharmony_ci	}
147162306a36Sopenharmony_ci	if (ret < sizeof(ctl_msg_buffer->cmd_get_device_info)) {
147262306a36Sopenharmony_ci		dev_err(&udev->dev, "%s: device reported invalid device info\n",
147362306a36Sopenharmony_ci			UCAN_DRIVER_NAME);
147462306a36Sopenharmony_ci		goto err_firmware_needs_update;
147562306a36Sopenharmony_ci	}
147662306a36Sopenharmony_ci	if (ctl_msg_buffer->cmd_get_device_info.tx_fifo == 0) {
147762306a36Sopenharmony_ci		dev_err(&udev->dev,
147862306a36Sopenharmony_ci			"%s: device reported invalid tx-fifo size\n",
147962306a36Sopenharmony_ci			UCAN_DRIVER_NAME);
148062306a36Sopenharmony_ci		goto err_firmware_needs_update;
148162306a36Sopenharmony_ci	}
148262306a36Sopenharmony_ci
148362306a36Sopenharmony_ci	/* Stage 3 - Driver Initialisation
148462306a36Sopenharmony_ci	 * -------------------------------
148562306a36Sopenharmony_ci	 *
148662306a36Sopenharmony_ci	 * Register device to Linux, prepare private structures and
148762306a36Sopenharmony_ci	 * reset the device.
148862306a36Sopenharmony_ci	 */
148962306a36Sopenharmony_ci
149062306a36Sopenharmony_ci	/* allocate driver resources */
149162306a36Sopenharmony_ci	netdev = alloc_candev(sizeof(struct ucan_priv),
149262306a36Sopenharmony_ci			      ctl_msg_buffer->cmd_get_device_info.tx_fifo);
149362306a36Sopenharmony_ci	if (!netdev) {
149462306a36Sopenharmony_ci		dev_err(&udev->dev,
149562306a36Sopenharmony_ci			"%s: cannot allocate candev\n", UCAN_DRIVER_NAME);
149662306a36Sopenharmony_ci		return -ENOMEM;
149762306a36Sopenharmony_ci	}
149862306a36Sopenharmony_ci
149962306a36Sopenharmony_ci	up = netdev_priv(netdev);
150062306a36Sopenharmony_ci
150162306a36Sopenharmony_ci	/* initialize data */
150262306a36Sopenharmony_ci	up->udev = udev;
150362306a36Sopenharmony_ci	up->netdev = netdev;
150462306a36Sopenharmony_ci	up->intf_index = iface_desc->desc.bInterfaceNumber;
150562306a36Sopenharmony_ci	up->in_ep_addr = in_ep_addr;
150662306a36Sopenharmony_ci	up->out_ep_addr = out_ep_addr;
150762306a36Sopenharmony_ci	up->in_ep_size = in_ep_size;
150862306a36Sopenharmony_ci	up->ctl_msg_buffer = ctl_msg_buffer;
150962306a36Sopenharmony_ci	up->context_array = NULL;
151062306a36Sopenharmony_ci	up->available_tx_urbs = 0;
151162306a36Sopenharmony_ci
151262306a36Sopenharmony_ci	up->can.state = CAN_STATE_STOPPED;
151362306a36Sopenharmony_ci	up->can.bittiming_const = &up->device_info.bittiming_const;
151462306a36Sopenharmony_ci	up->can.do_set_bittiming = ucan_set_bittiming;
151562306a36Sopenharmony_ci	up->can.do_set_mode = &ucan_set_mode;
151662306a36Sopenharmony_ci	spin_lock_init(&up->context_lock);
151762306a36Sopenharmony_ci	spin_lock_init(&up->echo_skb_lock);
151862306a36Sopenharmony_ci	netdev->netdev_ops = &ucan_netdev_ops;
151962306a36Sopenharmony_ci	netdev->ethtool_ops = &ucan_ethtool_ops;
152062306a36Sopenharmony_ci
152162306a36Sopenharmony_ci	usb_set_intfdata(intf, up);
152262306a36Sopenharmony_ci	SET_NETDEV_DEV(netdev, &intf->dev);
152362306a36Sopenharmony_ci
152462306a36Sopenharmony_ci	/* parse device information
152562306a36Sopenharmony_ci	 * the data retrieved in Stage 2 is still available in
152662306a36Sopenharmony_ci	 * up->ctl_msg_buffer
152762306a36Sopenharmony_ci	 */
152862306a36Sopenharmony_ci	ucan_parse_device_info(up, &ctl_msg_buffer->cmd_get_device_info);
152962306a36Sopenharmony_ci
153062306a36Sopenharmony_ci	/* just print some device information - if available */
153162306a36Sopenharmony_ci	ret = ucan_device_request_in(up, UCAN_DEVICE_GET_FW_STRING, 0,
153262306a36Sopenharmony_ci				     sizeof(union ucan_ctl_payload));
153362306a36Sopenharmony_ci	if (ret > 0) {
153462306a36Sopenharmony_ci		/* copy string while ensuring zero termination */
153562306a36Sopenharmony_ci		strscpy(firmware_str, up->ctl_msg_buffer->raw,
153662306a36Sopenharmony_ci			sizeof(union ucan_ctl_payload) + 1);
153762306a36Sopenharmony_ci	} else {
153862306a36Sopenharmony_ci		strcpy(firmware_str, "unknown");
153962306a36Sopenharmony_ci	}
154062306a36Sopenharmony_ci
154162306a36Sopenharmony_ci	/* device is compatible, reset it */
154262306a36Sopenharmony_ci	ret = ucan_ctrl_command_out(up, UCAN_COMMAND_RESET, 0, 0);
154362306a36Sopenharmony_ci	if (ret < 0)
154462306a36Sopenharmony_ci		goto err_free_candev;
154562306a36Sopenharmony_ci
154662306a36Sopenharmony_ci	init_usb_anchor(&up->rx_urbs);
154762306a36Sopenharmony_ci	init_usb_anchor(&up->tx_urbs);
154862306a36Sopenharmony_ci
154962306a36Sopenharmony_ci	up->can.state = CAN_STATE_STOPPED;
155062306a36Sopenharmony_ci
155162306a36Sopenharmony_ci	/* register the device */
155262306a36Sopenharmony_ci	ret = register_candev(netdev);
155362306a36Sopenharmony_ci	if (ret)
155462306a36Sopenharmony_ci		goto err_free_candev;
155562306a36Sopenharmony_ci
155662306a36Sopenharmony_ci	/* initialisation complete, log device info */
155762306a36Sopenharmony_ci	netdev_info(up->netdev, "registered device\n");
155862306a36Sopenharmony_ci	netdev_info(up->netdev, "firmware string: %s\n", firmware_str);
155962306a36Sopenharmony_ci
156062306a36Sopenharmony_ci	/* success */
156162306a36Sopenharmony_ci	return 0;
156262306a36Sopenharmony_ci
156362306a36Sopenharmony_cierr_free_candev:
156462306a36Sopenharmony_ci	free_candev(netdev);
156562306a36Sopenharmony_ci	return ret;
156662306a36Sopenharmony_ci
156762306a36Sopenharmony_cierr_firmware_needs_update:
156862306a36Sopenharmony_ci	dev_err(&udev->dev,
156962306a36Sopenharmony_ci		"%s: probe failed; try to update the device firmware\n",
157062306a36Sopenharmony_ci		UCAN_DRIVER_NAME);
157162306a36Sopenharmony_ci	return -ENODEV;
157262306a36Sopenharmony_ci}
157362306a36Sopenharmony_ci
157462306a36Sopenharmony_ci/* disconnect the device */
157562306a36Sopenharmony_cistatic void ucan_disconnect(struct usb_interface *intf)
157662306a36Sopenharmony_ci{
157762306a36Sopenharmony_ci	struct ucan_priv *up = usb_get_intfdata(intf);
157862306a36Sopenharmony_ci
157962306a36Sopenharmony_ci	usb_set_intfdata(intf, NULL);
158062306a36Sopenharmony_ci
158162306a36Sopenharmony_ci	if (up) {
158262306a36Sopenharmony_ci		unregister_candev(up->netdev);
158362306a36Sopenharmony_ci		free_candev(up->netdev);
158462306a36Sopenharmony_ci	}
158562306a36Sopenharmony_ci}
158662306a36Sopenharmony_ci
158762306a36Sopenharmony_cistatic struct usb_device_id ucan_table[] = {
158862306a36Sopenharmony_ci	/* Mule (soldered onto compute modules) */
158962306a36Sopenharmony_ci	{USB_DEVICE_INTERFACE_NUMBER(0x2294, 0x425a, 0)},
159062306a36Sopenharmony_ci	/* Seal (standalone USB stick) */
159162306a36Sopenharmony_ci	{USB_DEVICE_INTERFACE_NUMBER(0x2294, 0x425b, 0)},
159262306a36Sopenharmony_ci	{} /* Terminating entry */
159362306a36Sopenharmony_ci};
159462306a36Sopenharmony_ci
159562306a36Sopenharmony_ciMODULE_DEVICE_TABLE(usb, ucan_table);
159662306a36Sopenharmony_ci/* driver callbacks */
159762306a36Sopenharmony_cistatic struct usb_driver ucan_driver = {
159862306a36Sopenharmony_ci	.name = UCAN_DRIVER_NAME,
159962306a36Sopenharmony_ci	.probe = ucan_probe,
160062306a36Sopenharmony_ci	.disconnect = ucan_disconnect,
160162306a36Sopenharmony_ci	.id_table = ucan_table,
160262306a36Sopenharmony_ci};
160362306a36Sopenharmony_ci
160462306a36Sopenharmony_cimodule_usb_driver(ucan_driver);
160562306a36Sopenharmony_ci
160662306a36Sopenharmony_ciMODULE_LICENSE("GPL v2");
160762306a36Sopenharmony_ciMODULE_AUTHOR("Martin Elshuber <martin.elshuber@theobroma-systems.com>");
160862306a36Sopenharmony_ciMODULE_AUTHOR("Jakob Unterwurzacher <jakob.unterwurzacher@theobroma-systems.com>");
160962306a36Sopenharmony_ciMODULE_DESCRIPTION("Driver for Theobroma Systems UCAN devices");
1610