xref: /linux/drivers/net/can/usb/ucan.c (revision aa9832e4501264a43db671bba09fe4d8bc39fcff)
19f2d3eaeSJakob Unterwurzacher // SPDX-License-Identifier: GPL-2.0
29f2d3eaeSJakob Unterwurzacher 
39f2d3eaeSJakob Unterwurzacher /* Driver for Theobroma Systems UCAN devices, Protocol Version 3
49f2d3eaeSJakob Unterwurzacher  *
59f2d3eaeSJakob Unterwurzacher  * Copyright (C) 2018 Theobroma Systems Design und Consulting GmbH
69f2d3eaeSJakob Unterwurzacher  *
79f2d3eaeSJakob Unterwurzacher  *
89f2d3eaeSJakob Unterwurzacher  * General Description:
99f2d3eaeSJakob Unterwurzacher  *
109f2d3eaeSJakob Unterwurzacher  * The USB Device uses three Endpoints:
119f2d3eaeSJakob Unterwurzacher  *
129f2d3eaeSJakob Unterwurzacher  *   CONTROL Endpoint: Is used the setup the device (start, stop,
139f2d3eaeSJakob Unterwurzacher  *   info, configure).
149f2d3eaeSJakob Unterwurzacher  *
159f2d3eaeSJakob Unterwurzacher  *   IN Endpoint: The device sends CAN Frame Messages and Device
169f2d3eaeSJakob Unterwurzacher  *   Information using the IN endpoint.
179f2d3eaeSJakob Unterwurzacher  *
189f2d3eaeSJakob Unterwurzacher  *   OUT Endpoint: The driver sends configuration requests, and CAN
199f2d3eaeSJakob Unterwurzacher  *   Frames on the out endpoint.
209f2d3eaeSJakob Unterwurzacher  *
219f2d3eaeSJakob Unterwurzacher  * Error Handling:
229f2d3eaeSJakob Unterwurzacher  *
239f2d3eaeSJakob Unterwurzacher  *   If error reporting is turned on the device encodes error into CAN
249f2d3eaeSJakob Unterwurzacher  *   error frames (see uapi/linux/can/error.h) and sends it using the
259f2d3eaeSJakob Unterwurzacher  *   IN Endpoint. The driver updates statistics and forward it.
269f2d3eaeSJakob Unterwurzacher  */
279f2d3eaeSJakob Unterwurzacher 
289f2d3eaeSJakob Unterwurzacher #include <linux/can.h>
299f2d3eaeSJakob Unterwurzacher #include <linux/can/dev.h>
309f2d3eaeSJakob Unterwurzacher #include <linux/can/error.h>
31409c188cSVincent Mailhol #include <linux/ethtool.h>
329f2d3eaeSJakob Unterwurzacher #include <linux/module.h>
339f2d3eaeSJakob Unterwurzacher #include <linux/netdevice.h>
349f2d3eaeSJakob Unterwurzacher #include <linux/signal.h>
359f2d3eaeSJakob Unterwurzacher #include <linux/skbuff.h>
369f2d3eaeSJakob Unterwurzacher #include <linux/slab.h>
379f2d3eaeSJakob Unterwurzacher #include <linux/usb.h>
389f2d3eaeSJakob Unterwurzacher 
399f2d3eaeSJakob Unterwurzacher #define UCAN_DRIVER_NAME "ucan"
409f2d3eaeSJakob Unterwurzacher #define UCAN_MAX_RX_URBS 8
419f2d3eaeSJakob Unterwurzacher /* the CAN controller needs a while to enable/disable the bus */
429f2d3eaeSJakob Unterwurzacher #define UCAN_USB_CTL_PIPE_TIMEOUT 1000
439f2d3eaeSJakob Unterwurzacher /* this driver currently supports protocol version 3 only */
449f2d3eaeSJakob Unterwurzacher #define UCAN_PROTOCOL_VERSION_MIN 3
459f2d3eaeSJakob Unterwurzacher #define UCAN_PROTOCOL_VERSION_MAX 3
469f2d3eaeSJakob Unterwurzacher 
479f2d3eaeSJakob Unterwurzacher /* UCAN Message Definitions
489f2d3eaeSJakob Unterwurzacher  * ------------------------
499f2d3eaeSJakob Unterwurzacher  *
509f2d3eaeSJakob Unterwurzacher  *  ucan_message_out_t and ucan_message_in_t define the messages
519f2d3eaeSJakob Unterwurzacher  *  transmitted on the OUT and IN endpoint.
529f2d3eaeSJakob Unterwurzacher  *
539f2d3eaeSJakob Unterwurzacher  *  Multibyte fields are transmitted with little endianness
549f2d3eaeSJakob Unterwurzacher  *
559f2d3eaeSJakob Unterwurzacher  *  INTR Endpoint: a single uint32_t storing the current space in the fifo
569f2d3eaeSJakob Unterwurzacher  *
579f2d3eaeSJakob Unterwurzacher  *  OUT Endpoint: single message of type ucan_message_out_t is
589f2d3eaeSJakob Unterwurzacher  *    transmitted on the out endpoint
599f2d3eaeSJakob Unterwurzacher  *
609f2d3eaeSJakob Unterwurzacher  *  IN Endpoint: multiple messages ucan_message_in_t concateted in
619f2d3eaeSJakob Unterwurzacher  *    the following way:
629f2d3eaeSJakob Unterwurzacher  *
639f2d3eaeSJakob Unterwurzacher  *	m[n].len <=> the length if message n(including the header in bytes)
649f2d3eaeSJakob Unterwurzacher  *	m[n] is is aligned to a 4 byte boundary, hence
659f2d3eaeSJakob Unterwurzacher  *	  offset(m[0])	 := 0;
669f2d3eaeSJakob Unterwurzacher  *	  offset(m[n+1]) := offset(m[n]) + (m[n].len + 3) & 3
679f2d3eaeSJakob Unterwurzacher  *
689f2d3eaeSJakob Unterwurzacher  *	this implies that
699f2d3eaeSJakob Unterwurzacher  *	  offset(m[n]) % 4 <=> 0
709f2d3eaeSJakob Unterwurzacher  */
719f2d3eaeSJakob Unterwurzacher 
729f2d3eaeSJakob Unterwurzacher /* Device Global Commands */
739f2d3eaeSJakob Unterwurzacher enum {
749f2d3eaeSJakob Unterwurzacher 	UCAN_DEVICE_GET_FW_STRING = 0,
759f2d3eaeSJakob Unterwurzacher };
769f2d3eaeSJakob Unterwurzacher 
779f2d3eaeSJakob Unterwurzacher /* UCAN Commands */
789f2d3eaeSJakob Unterwurzacher enum {
799f2d3eaeSJakob Unterwurzacher 	/* start the can transceiver - val defines the operation mode */
809f2d3eaeSJakob Unterwurzacher 	UCAN_COMMAND_START = 0,
819f2d3eaeSJakob Unterwurzacher 	/* cancel pending transmissions and stop the can transceiver */
829f2d3eaeSJakob Unterwurzacher 	UCAN_COMMAND_STOP = 1,
839f2d3eaeSJakob Unterwurzacher 	/* send can transceiver into low-power sleep mode */
849f2d3eaeSJakob Unterwurzacher 	UCAN_COMMAND_SLEEP = 2,
859f2d3eaeSJakob Unterwurzacher 	/* wake up can transceiver from low-power sleep mode */
869f2d3eaeSJakob Unterwurzacher 	UCAN_COMMAND_WAKEUP = 3,
879f2d3eaeSJakob Unterwurzacher 	/* reset the can transceiver */
889f2d3eaeSJakob Unterwurzacher 	UCAN_COMMAND_RESET = 4,
899f2d3eaeSJakob Unterwurzacher 	/* get piece of info from the can transceiver - subcmd defines what
909f2d3eaeSJakob Unterwurzacher 	 * piece
919f2d3eaeSJakob Unterwurzacher 	 */
929f2d3eaeSJakob Unterwurzacher 	UCAN_COMMAND_GET = 5,
939f2d3eaeSJakob Unterwurzacher 	/* clear or disable hardware filter - subcmd defines which of the two */
949f2d3eaeSJakob Unterwurzacher 	UCAN_COMMAND_FILTER = 6,
959f2d3eaeSJakob Unterwurzacher 	/* Setup bittiming */
969f2d3eaeSJakob Unterwurzacher 	UCAN_COMMAND_SET_BITTIMING = 7,
979f2d3eaeSJakob Unterwurzacher 	/* recover from bus-off state */
989f2d3eaeSJakob Unterwurzacher 	UCAN_COMMAND_RESTART = 8,
999f2d3eaeSJakob Unterwurzacher };
1009f2d3eaeSJakob Unterwurzacher 
1019f2d3eaeSJakob Unterwurzacher /* UCAN_COMMAND_START and UCAN_COMMAND_GET_INFO operation modes (bitmap).
1029f2d3eaeSJakob Unterwurzacher  * Undefined bits must be set to 0.
1039f2d3eaeSJakob Unterwurzacher  */
1049f2d3eaeSJakob Unterwurzacher enum {
1059f2d3eaeSJakob Unterwurzacher 	UCAN_MODE_LOOPBACK = BIT(0),
1069f2d3eaeSJakob Unterwurzacher 	UCAN_MODE_SILENT = BIT(1),
1079f2d3eaeSJakob Unterwurzacher 	UCAN_MODE_3_SAMPLES = BIT(2),
1089f2d3eaeSJakob Unterwurzacher 	UCAN_MODE_ONE_SHOT = BIT(3),
1099f2d3eaeSJakob Unterwurzacher 	UCAN_MODE_BERR_REPORT = BIT(4),
1109f2d3eaeSJakob Unterwurzacher };
1119f2d3eaeSJakob Unterwurzacher 
1129f2d3eaeSJakob Unterwurzacher /* UCAN_COMMAND_GET subcommands */
1139f2d3eaeSJakob Unterwurzacher enum {
1149f2d3eaeSJakob Unterwurzacher 	UCAN_COMMAND_GET_INFO = 0,
1159f2d3eaeSJakob Unterwurzacher 	UCAN_COMMAND_GET_PROTOCOL_VERSION = 1,
1169f2d3eaeSJakob Unterwurzacher };
1179f2d3eaeSJakob Unterwurzacher 
1189f2d3eaeSJakob Unterwurzacher /* UCAN_COMMAND_FILTER subcommands */
1199f2d3eaeSJakob Unterwurzacher enum {
1209f2d3eaeSJakob Unterwurzacher 	UCAN_FILTER_CLEAR = 0,
1219f2d3eaeSJakob Unterwurzacher 	UCAN_FILTER_DISABLE = 1,
1229f2d3eaeSJakob Unterwurzacher 	UCAN_FILTER_ENABLE = 2,
1239f2d3eaeSJakob Unterwurzacher };
1249f2d3eaeSJakob Unterwurzacher 
1259f2d3eaeSJakob Unterwurzacher /* OUT endpoint message types */
1269f2d3eaeSJakob Unterwurzacher enum {
1279f2d3eaeSJakob Unterwurzacher 	UCAN_OUT_TX = 2,     /* transmit a CAN frame */
1289f2d3eaeSJakob Unterwurzacher };
1299f2d3eaeSJakob Unterwurzacher 
1309f2d3eaeSJakob Unterwurzacher /* IN endpoint message types */
1319f2d3eaeSJakob Unterwurzacher enum {
1329f2d3eaeSJakob Unterwurzacher 	UCAN_IN_TX_COMPLETE = 1,  /* CAN frame transmission completed */
1339f2d3eaeSJakob Unterwurzacher 	UCAN_IN_RX = 2,           /* CAN frame received */
1349f2d3eaeSJakob Unterwurzacher };
1359f2d3eaeSJakob Unterwurzacher 
1369f2d3eaeSJakob Unterwurzacher struct ucan_ctl_cmd_start {
1379f2d3eaeSJakob Unterwurzacher 	__le16 mode;         /* OR-ing any of UCAN_MODE_* */
1389f2d3eaeSJakob Unterwurzacher } __packed;
1399f2d3eaeSJakob Unterwurzacher 
1409f2d3eaeSJakob Unterwurzacher struct ucan_ctl_cmd_set_bittiming {
1419f2d3eaeSJakob Unterwurzacher 	__le32 tq;           /* Time quanta (TQ) in nanoseconds */
1429f2d3eaeSJakob Unterwurzacher 	__le16 brp;          /* TQ Prescaler */
1439f2d3eaeSJakob Unterwurzacher 	__le16 sample_point; /* Samplepoint on tenth percent */
1449f2d3eaeSJakob Unterwurzacher 	u8 prop_seg;         /* Propagation segment in TQs */
1459f2d3eaeSJakob Unterwurzacher 	u8 phase_seg1;       /* Phase buffer segment 1 in TQs */
1469f2d3eaeSJakob Unterwurzacher 	u8 phase_seg2;       /* Phase buffer segment 2 in TQs */
1479f2d3eaeSJakob Unterwurzacher 	u8 sjw;              /* Synchronisation jump width in TQs */
1489f2d3eaeSJakob Unterwurzacher } __packed;
1499f2d3eaeSJakob Unterwurzacher 
1509f2d3eaeSJakob Unterwurzacher struct ucan_ctl_cmd_device_info {
1519f2d3eaeSJakob Unterwurzacher 	__le32 freq;         /* Clock Frequency for tq generation */
1529f2d3eaeSJakob Unterwurzacher 	u8 tx_fifo;          /* Size of the transmission fifo */
1539f2d3eaeSJakob Unterwurzacher 	u8 sjw_max;          /* can_bittiming fields... */
1549f2d3eaeSJakob Unterwurzacher 	u8 tseg1_min;
1559f2d3eaeSJakob Unterwurzacher 	u8 tseg1_max;
1569f2d3eaeSJakob Unterwurzacher 	u8 tseg2_min;
1579f2d3eaeSJakob Unterwurzacher 	u8 tseg2_max;
1589f2d3eaeSJakob Unterwurzacher 	__le16 brp_inc;
1599f2d3eaeSJakob Unterwurzacher 	__le32 brp_min;
1609f2d3eaeSJakob Unterwurzacher 	__le32 brp_max;      /* ...can_bittiming fields */
1619f2d3eaeSJakob Unterwurzacher 	__le16 ctrlmodes;    /* supported control modes */
1629f2d3eaeSJakob Unterwurzacher 	__le16 hwfilter;     /* Number of HW filter banks */
1639f2d3eaeSJakob Unterwurzacher 	__le16 rxmboxes;     /* Number of receive Mailboxes */
1649f2d3eaeSJakob Unterwurzacher } __packed;
1659f2d3eaeSJakob Unterwurzacher 
1669f2d3eaeSJakob Unterwurzacher struct ucan_ctl_cmd_get_protocol_version {
1679f2d3eaeSJakob Unterwurzacher 	__le32 version;
1689f2d3eaeSJakob Unterwurzacher } __packed;
1699f2d3eaeSJakob Unterwurzacher 
1709f2d3eaeSJakob Unterwurzacher union ucan_ctl_payload {
1719f2d3eaeSJakob Unterwurzacher 	/* Setup Bittiming
1729f2d3eaeSJakob Unterwurzacher 	 * bmRequest == UCAN_COMMAND_START
1739f2d3eaeSJakob Unterwurzacher 	 */
1749f2d3eaeSJakob Unterwurzacher 	struct ucan_ctl_cmd_start cmd_start;
1759f2d3eaeSJakob Unterwurzacher 	/* Setup Bittiming
1769f2d3eaeSJakob Unterwurzacher 	 * bmRequest == UCAN_COMMAND_SET_BITTIMING
1779f2d3eaeSJakob Unterwurzacher 	 */
1789f2d3eaeSJakob Unterwurzacher 	struct ucan_ctl_cmd_set_bittiming cmd_set_bittiming;
1799f2d3eaeSJakob Unterwurzacher 	/* Get Device Information
1809f2d3eaeSJakob Unterwurzacher 	 * bmRequest == UCAN_COMMAND_GET; wValue = UCAN_COMMAND_GET_INFO
1819f2d3eaeSJakob Unterwurzacher 	 */
1829f2d3eaeSJakob Unterwurzacher 	struct ucan_ctl_cmd_device_info cmd_get_device_info;
1839f2d3eaeSJakob Unterwurzacher 	/* Get Protocol Version
1849f2d3eaeSJakob Unterwurzacher 	 * bmRequest == UCAN_COMMAND_GET;
1859f2d3eaeSJakob Unterwurzacher 	 * wValue = UCAN_COMMAND_GET_PROTOCOL_VERSION
1869f2d3eaeSJakob Unterwurzacher 	 */
1879f2d3eaeSJakob Unterwurzacher 	struct ucan_ctl_cmd_get_protocol_version cmd_get_protocol_version;
1889f2d3eaeSJakob Unterwurzacher 
1899f2d3eaeSJakob Unterwurzacher 	u8 raw[128];
1909f2d3eaeSJakob Unterwurzacher } __packed;
1919f2d3eaeSJakob Unterwurzacher 
1929f2d3eaeSJakob Unterwurzacher enum {
1939f2d3eaeSJakob Unterwurzacher 	UCAN_TX_COMPLETE_SUCCESS = BIT(0),
1949f2d3eaeSJakob Unterwurzacher };
1959f2d3eaeSJakob Unterwurzacher 
1969f2d3eaeSJakob Unterwurzacher /* Transmission Complete within ucan_message_in */
1979f2d3eaeSJakob Unterwurzacher struct ucan_tx_complete_entry_t {
1989f2d3eaeSJakob Unterwurzacher 	u8 echo_index;
1999f2d3eaeSJakob Unterwurzacher 	u8 flags;
2009f2d3eaeSJakob Unterwurzacher } __packed __aligned(0x2);
2019f2d3eaeSJakob Unterwurzacher 
2029f2d3eaeSJakob Unterwurzacher /* CAN Data message format within ucan_message_in/out */
2039f2d3eaeSJakob Unterwurzacher struct ucan_can_msg {
2049f2d3eaeSJakob Unterwurzacher 	/* note DLC is computed by
2059f2d3eaeSJakob Unterwurzacher 	 *    msg.len - sizeof (msg.len)
2069f2d3eaeSJakob Unterwurzacher 	 *            - sizeof (msg.type)
2079f2d3eaeSJakob Unterwurzacher 	 *            - sizeof (msg.can_msg.id)
2089f2d3eaeSJakob Unterwurzacher 	 */
2099f2d3eaeSJakob Unterwurzacher 	__le32 id;
2109f2d3eaeSJakob Unterwurzacher 
2119f2d3eaeSJakob Unterwurzacher 	union {
2129f2d3eaeSJakob Unterwurzacher 		u8 data[CAN_MAX_DLEN];  /* Data of CAN frames */
2139f2d3eaeSJakob Unterwurzacher 		u8 dlc;                 /* RTR dlc */
2149f2d3eaeSJakob Unterwurzacher 	};
2159f2d3eaeSJakob Unterwurzacher } __packed;
2169f2d3eaeSJakob Unterwurzacher 
2179f2d3eaeSJakob Unterwurzacher /* OUT Endpoint, outbound messages */
2189f2d3eaeSJakob Unterwurzacher struct ucan_message_out {
2199f2d3eaeSJakob Unterwurzacher 	__le16 len; /* Length of the content include header */
2209f2d3eaeSJakob Unterwurzacher 	u8 type;    /* UCAN_OUT_TX and friends */
2219f2d3eaeSJakob Unterwurzacher 	u8 subtype; /* command sub type */
2229f2d3eaeSJakob Unterwurzacher 
2239f2d3eaeSJakob Unterwurzacher 	union {
2249f2d3eaeSJakob Unterwurzacher 		/* Transmit CAN frame
2259f2d3eaeSJakob Unterwurzacher 		 * (type == UCAN_TX) && ((msg.can_msg.id & CAN_RTR_FLAG) == 0)
2269f2d3eaeSJakob Unterwurzacher 		 * subtype stores the echo id
2279f2d3eaeSJakob Unterwurzacher 		 */
2289f2d3eaeSJakob Unterwurzacher 		struct ucan_can_msg can_msg;
2299f2d3eaeSJakob Unterwurzacher 	} msg;
2309f2d3eaeSJakob Unterwurzacher } __packed __aligned(0x4);
2319f2d3eaeSJakob Unterwurzacher 
2329f2d3eaeSJakob Unterwurzacher /* IN Endpoint, inbound messages */
2339f2d3eaeSJakob Unterwurzacher struct ucan_message_in {
2349f2d3eaeSJakob Unterwurzacher 	__le16 len; /* Length of the content include header */
2359f2d3eaeSJakob Unterwurzacher 	u8 type;    /* UCAN_IN_RX and friends */
2369f2d3eaeSJakob Unterwurzacher 	u8 subtype; /* command sub type */
2379f2d3eaeSJakob Unterwurzacher 
2389f2d3eaeSJakob Unterwurzacher 	union {
2399f2d3eaeSJakob Unterwurzacher 		/* CAN Frame received
2409f2d3eaeSJakob Unterwurzacher 		 * (type == UCAN_IN_RX)
2419f2d3eaeSJakob Unterwurzacher 		 * && ((msg.can_msg.id & CAN_RTR_FLAG) == 0)
2429f2d3eaeSJakob Unterwurzacher 		 */
2439f2d3eaeSJakob Unterwurzacher 		struct ucan_can_msg can_msg;
2449f2d3eaeSJakob Unterwurzacher 
2459f2d3eaeSJakob Unterwurzacher 		/* CAN transmission complete
2469f2d3eaeSJakob Unterwurzacher 		 * (type == UCAN_IN_TX_COMPLETE)
2479f2d3eaeSJakob Unterwurzacher 		 */
248b2df8a1bSGustavo A. R. Silva 		DECLARE_FLEX_ARRAY(struct ucan_tx_complete_entry_t,
249b2df8a1bSGustavo A. R. Silva 				   can_tx_complete_msg);
2509f2d3eaeSJakob Unterwurzacher 	} __aligned(0x4) msg;
25127868a8fSArnd Bergmann } __packed __aligned(0x4);
2529f2d3eaeSJakob Unterwurzacher 
2539f2d3eaeSJakob Unterwurzacher /* Macros to calculate message lengths */
2549f2d3eaeSJakob Unterwurzacher #define UCAN_OUT_HDR_SIZE offsetof(struct ucan_message_out, msg)
2559f2d3eaeSJakob Unterwurzacher 
2569f2d3eaeSJakob Unterwurzacher #define UCAN_IN_HDR_SIZE offsetof(struct ucan_message_in, msg)
2579f2d3eaeSJakob Unterwurzacher #define UCAN_IN_LEN(member) (UCAN_OUT_HDR_SIZE + sizeof(member))
2589f2d3eaeSJakob Unterwurzacher 
2599f2d3eaeSJakob Unterwurzacher struct ucan_priv;
2609f2d3eaeSJakob Unterwurzacher 
2619f2d3eaeSJakob Unterwurzacher /* Context Information for transmission URBs */
2629f2d3eaeSJakob Unterwurzacher struct ucan_urb_context {
2639f2d3eaeSJakob Unterwurzacher 	struct ucan_priv *up;
2649f2d3eaeSJakob Unterwurzacher 	bool allocated;
2659f2d3eaeSJakob Unterwurzacher };
2669f2d3eaeSJakob Unterwurzacher 
2679f2d3eaeSJakob Unterwurzacher /* Information reported by the USB device */
2689f2d3eaeSJakob Unterwurzacher struct ucan_device_info {
2699f2d3eaeSJakob Unterwurzacher 	struct can_bittiming_const bittiming_const;
2709f2d3eaeSJakob Unterwurzacher 	u8 tx_fifo;
2719f2d3eaeSJakob Unterwurzacher };
2729f2d3eaeSJakob Unterwurzacher 
2739f2d3eaeSJakob Unterwurzacher /* Driver private data */
2749f2d3eaeSJakob Unterwurzacher struct ucan_priv {
2759f2d3eaeSJakob Unterwurzacher 	/* must be the first member */
2769f2d3eaeSJakob Unterwurzacher 	struct can_priv can;
2779f2d3eaeSJakob Unterwurzacher 
2789f2d3eaeSJakob Unterwurzacher 	/* linux USB device structures */
2799f2d3eaeSJakob Unterwurzacher 	struct usb_device *udev;
2809f2d3eaeSJakob Unterwurzacher 	struct usb_interface *intf;
2819f2d3eaeSJakob Unterwurzacher 	struct net_device *netdev;
2829f2d3eaeSJakob Unterwurzacher 
2839f2d3eaeSJakob Unterwurzacher 	/* lock for can->echo_skb (used around
2849f2d3eaeSJakob Unterwurzacher 	 * can_put/get/free_echo_skb
2859f2d3eaeSJakob Unterwurzacher 	 */
2869f2d3eaeSJakob Unterwurzacher 	spinlock_t echo_skb_lock;
2879f2d3eaeSJakob Unterwurzacher 
2889f2d3eaeSJakob Unterwurzacher 	/* usb device information information */
2899f2d3eaeSJakob Unterwurzacher 	u8 intf_index;
2909f2d3eaeSJakob Unterwurzacher 	u8 in_ep_addr;
2919f2d3eaeSJakob Unterwurzacher 	u8 out_ep_addr;
2929f2d3eaeSJakob Unterwurzacher 	u16 in_ep_size;
2939f2d3eaeSJakob Unterwurzacher 
2949f2d3eaeSJakob Unterwurzacher 	/* transmission and reception buffers */
2959f2d3eaeSJakob Unterwurzacher 	struct usb_anchor rx_urbs;
2969f2d3eaeSJakob Unterwurzacher 	struct usb_anchor tx_urbs;
2979f2d3eaeSJakob Unterwurzacher 
2989f2d3eaeSJakob Unterwurzacher 	union ucan_ctl_payload *ctl_msg_buffer;
2999f2d3eaeSJakob Unterwurzacher 	struct ucan_device_info device_info;
3009f2d3eaeSJakob Unterwurzacher 
3019f2d3eaeSJakob Unterwurzacher 	/* transmission control information and locks */
3029f2d3eaeSJakob Unterwurzacher 	spinlock_t context_lock;
3039f2d3eaeSJakob Unterwurzacher 	unsigned int available_tx_urbs;
3049f2d3eaeSJakob Unterwurzacher 	struct ucan_urb_context *context_array;
3059f2d3eaeSJakob Unterwurzacher };
3069f2d3eaeSJakob Unterwurzacher 
30769d98969SOliver Hartkopp static u8 ucan_can_cc_dlc2len(struct ucan_can_msg *msg, u16 len)
3089f2d3eaeSJakob Unterwurzacher {
3099f2d3eaeSJakob Unterwurzacher 	if (le32_to_cpu(msg->id) & CAN_RTR_FLAG)
31069d98969SOliver Hartkopp 		return can_cc_dlc2len(msg->dlc);
3119f2d3eaeSJakob Unterwurzacher 	else
31269d98969SOliver Hartkopp 		return can_cc_dlc2len(len - (UCAN_IN_HDR_SIZE + sizeof(msg->id)));
3139f2d3eaeSJakob Unterwurzacher }
3149f2d3eaeSJakob Unterwurzacher 
3159f2d3eaeSJakob Unterwurzacher static void ucan_release_context_array(struct ucan_priv *up)
3169f2d3eaeSJakob Unterwurzacher {
3179f2d3eaeSJakob Unterwurzacher 	if (!up->context_array)
3189f2d3eaeSJakob Unterwurzacher 		return;
3199f2d3eaeSJakob Unterwurzacher 
3209f2d3eaeSJakob Unterwurzacher 	/* lock is not needed because, driver is currently opening or closing */
3219f2d3eaeSJakob Unterwurzacher 	up->available_tx_urbs = 0;
3229f2d3eaeSJakob Unterwurzacher 
3239f2d3eaeSJakob Unterwurzacher 	kfree(up->context_array);
3249f2d3eaeSJakob Unterwurzacher 	up->context_array = NULL;
3259f2d3eaeSJakob Unterwurzacher }
3269f2d3eaeSJakob Unterwurzacher 
3279f2d3eaeSJakob Unterwurzacher static int ucan_alloc_context_array(struct ucan_priv *up)
3289f2d3eaeSJakob Unterwurzacher {
3299f2d3eaeSJakob Unterwurzacher 	int i;
3309f2d3eaeSJakob Unterwurzacher 
3319f2d3eaeSJakob Unterwurzacher 	/* release contexts if any */
3329f2d3eaeSJakob Unterwurzacher 	ucan_release_context_array(up);
3339f2d3eaeSJakob Unterwurzacher 
3349f2d3eaeSJakob Unterwurzacher 	up->context_array = kcalloc(up->device_info.tx_fifo,
3359f2d3eaeSJakob Unterwurzacher 				    sizeof(*up->context_array),
3369f2d3eaeSJakob Unterwurzacher 				    GFP_KERNEL);
3379f2d3eaeSJakob Unterwurzacher 	if (!up->context_array) {
3389f2d3eaeSJakob Unterwurzacher 		netdev_err(up->netdev,
3399f2d3eaeSJakob Unterwurzacher 			   "Not enough memory to allocate tx contexts\n");
3409f2d3eaeSJakob Unterwurzacher 		return -ENOMEM;
3419f2d3eaeSJakob Unterwurzacher 	}
3429f2d3eaeSJakob Unterwurzacher 
3439f2d3eaeSJakob Unterwurzacher 	for (i = 0; i < up->device_info.tx_fifo; i++) {
3449f2d3eaeSJakob Unterwurzacher 		up->context_array[i].allocated = false;
3459f2d3eaeSJakob Unterwurzacher 		up->context_array[i].up = up;
3469f2d3eaeSJakob Unterwurzacher 	}
3479f2d3eaeSJakob Unterwurzacher 
3489f2d3eaeSJakob Unterwurzacher 	/* lock is not needed because, driver is currently opening */
3499f2d3eaeSJakob Unterwurzacher 	up->available_tx_urbs = up->device_info.tx_fifo;
3509f2d3eaeSJakob Unterwurzacher 
3519f2d3eaeSJakob Unterwurzacher 	return 0;
3529f2d3eaeSJakob Unterwurzacher }
3539f2d3eaeSJakob Unterwurzacher 
3549f2d3eaeSJakob Unterwurzacher static struct ucan_urb_context *ucan_alloc_context(struct ucan_priv *up)
3559f2d3eaeSJakob Unterwurzacher {
3569f2d3eaeSJakob Unterwurzacher 	int i;
3579f2d3eaeSJakob Unterwurzacher 	unsigned long flags;
3589f2d3eaeSJakob Unterwurzacher 	struct ucan_urb_context *ret = NULL;
3599f2d3eaeSJakob Unterwurzacher 
3609f2d3eaeSJakob Unterwurzacher 	if (WARN_ON_ONCE(!up->context_array))
3619f2d3eaeSJakob Unterwurzacher 		return NULL;
3629f2d3eaeSJakob Unterwurzacher 
3639f2d3eaeSJakob Unterwurzacher 	/* execute context operation atomically */
3649f2d3eaeSJakob Unterwurzacher 	spin_lock_irqsave(&up->context_lock, flags);
3659f2d3eaeSJakob Unterwurzacher 
3669f2d3eaeSJakob Unterwurzacher 	for (i = 0; i < up->device_info.tx_fifo; i++) {
3679f2d3eaeSJakob Unterwurzacher 		if (!up->context_array[i].allocated) {
3689f2d3eaeSJakob Unterwurzacher 			/* update context */
3699f2d3eaeSJakob Unterwurzacher 			ret = &up->context_array[i];
3709f2d3eaeSJakob Unterwurzacher 			up->context_array[i].allocated = true;
3719f2d3eaeSJakob Unterwurzacher 
3729f2d3eaeSJakob Unterwurzacher 			/* stop queue if necessary */
3739f2d3eaeSJakob Unterwurzacher 			up->available_tx_urbs--;
3749f2d3eaeSJakob Unterwurzacher 			if (!up->available_tx_urbs)
3759f2d3eaeSJakob Unterwurzacher 				netif_stop_queue(up->netdev);
3769f2d3eaeSJakob Unterwurzacher 
3779f2d3eaeSJakob Unterwurzacher 			break;
3789f2d3eaeSJakob Unterwurzacher 		}
3799f2d3eaeSJakob Unterwurzacher 	}
3809f2d3eaeSJakob Unterwurzacher 
3819f2d3eaeSJakob Unterwurzacher 	spin_unlock_irqrestore(&up->context_lock, flags);
3829f2d3eaeSJakob Unterwurzacher 	return ret;
3839f2d3eaeSJakob Unterwurzacher }
3849f2d3eaeSJakob Unterwurzacher 
3859f2d3eaeSJakob Unterwurzacher static bool ucan_release_context(struct ucan_priv *up,
3869f2d3eaeSJakob Unterwurzacher 				 struct ucan_urb_context *ctx)
3879f2d3eaeSJakob Unterwurzacher {
3889f2d3eaeSJakob Unterwurzacher 	unsigned long flags;
3899f2d3eaeSJakob Unterwurzacher 	bool ret = false;
3909f2d3eaeSJakob Unterwurzacher 
3919f2d3eaeSJakob Unterwurzacher 	if (WARN_ON_ONCE(!up->context_array))
3929f2d3eaeSJakob Unterwurzacher 		return false;
3939f2d3eaeSJakob Unterwurzacher 
3949f2d3eaeSJakob Unterwurzacher 	/* execute context operation atomically */
3959f2d3eaeSJakob Unterwurzacher 	spin_lock_irqsave(&up->context_lock, flags);
3969f2d3eaeSJakob Unterwurzacher 
3979f2d3eaeSJakob Unterwurzacher 	/* context was not allocated, maybe the device sent garbage */
3989f2d3eaeSJakob Unterwurzacher 	if (ctx->allocated) {
3999f2d3eaeSJakob Unterwurzacher 		ctx->allocated = false;
4009f2d3eaeSJakob Unterwurzacher 
4019f2d3eaeSJakob Unterwurzacher 		/* check if the queue needs to be woken */
4029f2d3eaeSJakob Unterwurzacher 		if (!up->available_tx_urbs)
4039f2d3eaeSJakob Unterwurzacher 			netif_wake_queue(up->netdev);
4049f2d3eaeSJakob Unterwurzacher 		up->available_tx_urbs++;
4059f2d3eaeSJakob Unterwurzacher 
4069f2d3eaeSJakob Unterwurzacher 		ret = true;
4079f2d3eaeSJakob Unterwurzacher 	}
4089f2d3eaeSJakob Unterwurzacher 
4099f2d3eaeSJakob Unterwurzacher 	spin_unlock_irqrestore(&up->context_lock, flags);
4109f2d3eaeSJakob Unterwurzacher 	return ret;
4119f2d3eaeSJakob Unterwurzacher }
4129f2d3eaeSJakob Unterwurzacher 
4139f2d3eaeSJakob Unterwurzacher static int ucan_ctrl_command_out(struct ucan_priv *up,
4149f2d3eaeSJakob Unterwurzacher 				 u8 cmd, u16 subcmd, u16 datalen)
4159f2d3eaeSJakob Unterwurzacher {
4169f2d3eaeSJakob Unterwurzacher 	return usb_control_msg(up->udev,
4179f2d3eaeSJakob Unterwurzacher 			       usb_sndctrlpipe(up->udev, 0),
4189f2d3eaeSJakob Unterwurzacher 			       cmd,
4199f2d3eaeSJakob Unterwurzacher 			       USB_DIR_OUT | USB_TYPE_VENDOR |
4209f2d3eaeSJakob Unterwurzacher 						USB_RECIP_INTERFACE,
4219f2d3eaeSJakob Unterwurzacher 			       subcmd,
4229f2d3eaeSJakob Unterwurzacher 			       up->intf_index,
4239f2d3eaeSJakob Unterwurzacher 			       up->ctl_msg_buffer,
4249f2d3eaeSJakob Unterwurzacher 			       datalen,
4259f2d3eaeSJakob Unterwurzacher 			       UCAN_USB_CTL_PIPE_TIMEOUT);
4269f2d3eaeSJakob Unterwurzacher }
4279f2d3eaeSJakob Unterwurzacher 
4289f2d3eaeSJakob Unterwurzacher static int ucan_device_request_in(struct ucan_priv *up,
4299f2d3eaeSJakob Unterwurzacher 				  u8 cmd, u16 subcmd, u16 datalen)
4309f2d3eaeSJakob Unterwurzacher {
4319f2d3eaeSJakob Unterwurzacher 	return usb_control_msg(up->udev,
4329f2d3eaeSJakob Unterwurzacher 			       usb_rcvctrlpipe(up->udev, 0),
4339f2d3eaeSJakob Unterwurzacher 			       cmd,
4349f2d3eaeSJakob Unterwurzacher 			       USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
4359f2d3eaeSJakob Unterwurzacher 			       subcmd,
4369f2d3eaeSJakob Unterwurzacher 			       0,
4379f2d3eaeSJakob Unterwurzacher 			       up->ctl_msg_buffer,
4389f2d3eaeSJakob Unterwurzacher 			       datalen,
4399f2d3eaeSJakob Unterwurzacher 			       UCAN_USB_CTL_PIPE_TIMEOUT);
4409f2d3eaeSJakob Unterwurzacher }
4419f2d3eaeSJakob Unterwurzacher 
4429f2d3eaeSJakob Unterwurzacher /* Parse the device information structure reported by the device and
4439f2d3eaeSJakob Unterwurzacher  * setup private variables accordingly
4449f2d3eaeSJakob Unterwurzacher  */
4459f2d3eaeSJakob Unterwurzacher static void ucan_parse_device_info(struct ucan_priv *up,
4469f2d3eaeSJakob Unterwurzacher 				   struct ucan_ctl_cmd_device_info *device_info)
4479f2d3eaeSJakob Unterwurzacher {
4489f2d3eaeSJakob Unterwurzacher 	struct can_bittiming_const *bittiming =
4499f2d3eaeSJakob Unterwurzacher 		&up->device_info.bittiming_const;
4509f2d3eaeSJakob Unterwurzacher 	u16 ctrlmodes;
4519f2d3eaeSJakob Unterwurzacher 
4529f2d3eaeSJakob Unterwurzacher 	/* store the data */
4539f2d3eaeSJakob Unterwurzacher 	up->can.clock.freq = le32_to_cpu(device_info->freq);
4549f2d3eaeSJakob Unterwurzacher 	up->device_info.tx_fifo = device_info->tx_fifo;
4559f2d3eaeSJakob Unterwurzacher 	strcpy(bittiming->name, "ucan");
4569f2d3eaeSJakob Unterwurzacher 	bittiming->tseg1_min = device_info->tseg1_min;
4579f2d3eaeSJakob Unterwurzacher 	bittiming->tseg1_max = device_info->tseg1_max;
4589f2d3eaeSJakob Unterwurzacher 	bittiming->tseg2_min = device_info->tseg2_min;
4599f2d3eaeSJakob Unterwurzacher 	bittiming->tseg2_max = device_info->tseg2_max;
4609f2d3eaeSJakob Unterwurzacher 	bittiming->sjw_max = device_info->sjw_max;
4619f2d3eaeSJakob Unterwurzacher 	bittiming->brp_min = le32_to_cpu(device_info->brp_min);
4629f2d3eaeSJakob Unterwurzacher 	bittiming->brp_max = le32_to_cpu(device_info->brp_max);
4639f2d3eaeSJakob Unterwurzacher 	bittiming->brp_inc = le16_to_cpu(device_info->brp_inc);
4649f2d3eaeSJakob Unterwurzacher 
4659f2d3eaeSJakob Unterwurzacher 	ctrlmodes = le16_to_cpu(device_info->ctrlmodes);
4669f2d3eaeSJakob Unterwurzacher 
4679f2d3eaeSJakob Unterwurzacher 	up->can.ctrlmode_supported = 0;
4689f2d3eaeSJakob Unterwurzacher 
4699f2d3eaeSJakob Unterwurzacher 	if (ctrlmodes & UCAN_MODE_LOOPBACK)
4709f2d3eaeSJakob Unterwurzacher 		up->can.ctrlmode_supported |= CAN_CTRLMODE_LOOPBACK;
4719f2d3eaeSJakob Unterwurzacher 	if (ctrlmodes & UCAN_MODE_SILENT)
4729f2d3eaeSJakob Unterwurzacher 		up->can.ctrlmode_supported |= CAN_CTRLMODE_LISTENONLY;
4739f2d3eaeSJakob Unterwurzacher 	if (ctrlmodes & UCAN_MODE_3_SAMPLES)
4749f2d3eaeSJakob Unterwurzacher 		up->can.ctrlmode_supported |= CAN_CTRLMODE_3_SAMPLES;
4759f2d3eaeSJakob Unterwurzacher 	if (ctrlmodes & UCAN_MODE_ONE_SHOT)
4769f2d3eaeSJakob Unterwurzacher 		up->can.ctrlmode_supported |= CAN_CTRLMODE_ONE_SHOT;
4779f2d3eaeSJakob Unterwurzacher 	if (ctrlmodes & UCAN_MODE_BERR_REPORT)
4789f2d3eaeSJakob Unterwurzacher 		up->can.ctrlmode_supported |= CAN_CTRLMODE_BERR_REPORTING;
4799f2d3eaeSJakob Unterwurzacher }
4809f2d3eaeSJakob Unterwurzacher 
4819f2d3eaeSJakob Unterwurzacher /* Handle a CAN error frame that we have received from the device.
4829f2d3eaeSJakob Unterwurzacher  * Returns true if the can state has changed.
4839f2d3eaeSJakob Unterwurzacher  */
4849f2d3eaeSJakob Unterwurzacher static bool ucan_handle_error_frame(struct ucan_priv *up,
4859f2d3eaeSJakob Unterwurzacher 				    struct ucan_message_in *m,
4869f2d3eaeSJakob Unterwurzacher 				    canid_t canid)
4879f2d3eaeSJakob Unterwurzacher {
4889f2d3eaeSJakob Unterwurzacher 	enum can_state new_state = up->can.state;
4899f2d3eaeSJakob Unterwurzacher 	struct net_device_stats *net_stats = &up->netdev->stats;
4909f2d3eaeSJakob Unterwurzacher 	struct can_device_stats *can_stats = &up->can.can_stats;
4919f2d3eaeSJakob Unterwurzacher 
4929f2d3eaeSJakob Unterwurzacher 	if (canid & CAN_ERR_LOSTARB)
4939f2d3eaeSJakob Unterwurzacher 		can_stats->arbitration_lost++;
4949f2d3eaeSJakob Unterwurzacher 
4959f2d3eaeSJakob Unterwurzacher 	if (canid & CAN_ERR_BUSERROR)
4969f2d3eaeSJakob Unterwurzacher 		can_stats->bus_error++;
4979f2d3eaeSJakob Unterwurzacher 
4989f2d3eaeSJakob Unterwurzacher 	if (canid & CAN_ERR_ACK)
4999f2d3eaeSJakob Unterwurzacher 		net_stats->tx_errors++;
5009f2d3eaeSJakob Unterwurzacher 
5019f2d3eaeSJakob Unterwurzacher 	if (canid & CAN_ERR_BUSOFF)
5029f2d3eaeSJakob Unterwurzacher 		new_state = CAN_STATE_BUS_OFF;
5039f2d3eaeSJakob Unterwurzacher 
5049f2d3eaeSJakob Unterwurzacher 	/* controller problems, details in data[1] */
5059f2d3eaeSJakob Unterwurzacher 	if (canid & CAN_ERR_CRTL) {
5069f2d3eaeSJakob Unterwurzacher 		u8 d1 = m->msg.can_msg.data[1];
5079f2d3eaeSJakob Unterwurzacher 
5089f2d3eaeSJakob Unterwurzacher 		if (d1 & CAN_ERR_CRTL_RX_OVERFLOW)
5099f2d3eaeSJakob Unterwurzacher 			net_stats->rx_over_errors++;
5109f2d3eaeSJakob Unterwurzacher 
5119f2d3eaeSJakob Unterwurzacher 		/* controller state bits: if multiple are set the worst wins */
5129f2d3eaeSJakob Unterwurzacher 		if (d1 & CAN_ERR_CRTL_ACTIVE)
5139f2d3eaeSJakob Unterwurzacher 			new_state = CAN_STATE_ERROR_ACTIVE;
5149f2d3eaeSJakob Unterwurzacher 
5159f2d3eaeSJakob Unterwurzacher 		if (d1 & (CAN_ERR_CRTL_RX_WARNING | CAN_ERR_CRTL_TX_WARNING))
5169f2d3eaeSJakob Unterwurzacher 			new_state = CAN_STATE_ERROR_WARNING;
5179f2d3eaeSJakob Unterwurzacher 
5189f2d3eaeSJakob Unterwurzacher 		if (d1 & (CAN_ERR_CRTL_RX_PASSIVE | CAN_ERR_CRTL_TX_PASSIVE))
5199f2d3eaeSJakob Unterwurzacher 			new_state = CAN_STATE_ERROR_PASSIVE;
5209f2d3eaeSJakob Unterwurzacher 	}
5219f2d3eaeSJakob Unterwurzacher 
5229f2d3eaeSJakob Unterwurzacher 	/* protocol error, details in data[2] */
5239f2d3eaeSJakob Unterwurzacher 	if (canid & CAN_ERR_PROT) {
5249f2d3eaeSJakob Unterwurzacher 		u8 d2 = m->msg.can_msg.data[2];
5259f2d3eaeSJakob Unterwurzacher 
5269f2d3eaeSJakob Unterwurzacher 		if (d2 & CAN_ERR_PROT_TX)
5279f2d3eaeSJakob Unterwurzacher 			net_stats->tx_errors++;
5289f2d3eaeSJakob Unterwurzacher 		else
5299f2d3eaeSJakob Unterwurzacher 			net_stats->rx_errors++;
5309f2d3eaeSJakob Unterwurzacher 	}
5319f2d3eaeSJakob Unterwurzacher 
5329f2d3eaeSJakob Unterwurzacher 	/* no state change - we are done */
5339f2d3eaeSJakob Unterwurzacher 	if (up->can.state == new_state)
5349f2d3eaeSJakob Unterwurzacher 		return false;
5359f2d3eaeSJakob Unterwurzacher 
5369f2d3eaeSJakob Unterwurzacher 	/* we switched into a better state */
5379f2d3eaeSJakob Unterwurzacher 	if (up->can.state > new_state) {
5389f2d3eaeSJakob Unterwurzacher 		up->can.state = new_state;
5399f2d3eaeSJakob Unterwurzacher 		return true;
5409f2d3eaeSJakob Unterwurzacher 	}
5419f2d3eaeSJakob Unterwurzacher 
5429f2d3eaeSJakob Unterwurzacher 	/* we switched into a worse state */
5439f2d3eaeSJakob Unterwurzacher 	up->can.state = new_state;
5449f2d3eaeSJakob Unterwurzacher 	switch (new_state) {
5459f2d3eaeSJakob Unterwurzacher 	case CAN_STATE_BUS_OFF:
5469f2d3eaeSJakob Unterwurzacher 		can_stats->bus_off++;
5479f2d3eaeSJakob Unterwurzacher 		can_bus_off(up->netdev);
5489f2d3eaeSJakob Unterwurzacher 		break;
5499f2d3eaeSJakob Unterwurzacher 	case CAN_STATE_ERROR_PASSIVE:
5509f2d3eaeSJakob Unterwurzacher 		can_stats->error_passive++;
5519f2d3eaeSJakob Unterwurzacher 		break;
5529f2d3eaeSJakob Unterwurzacher 	case CAN_STATE_ERROR_WARNING:
5539f2d3eaeSJakob Unterwurzacher 		can_stats->error_warning++;
5549f2d3eaeSJakob Unterwurzacher 		break;
5559f2d3eaeSJakob Unterwurzacher 	default:
5569f2d3eaeSJakob Unterwurzacher 		break;
5579f2d3eaeSJakob Unterwurzacher 	}
5589f2d3eaeSJakob Unterwurzacher 	return true;
5599f2d3eaeSJakob Unterwurzacher }
5609f2d3eaeSJakob Unterwurzacher 
5619f2d3eaeSJakob Unterwurzacher /* Callback on reception of a can frame via the IN endpoint
5629f2d3eaeSJakob Unterwurzacher  *
5639f2d3eaeSJakob Unterwurzacher  * This function allocates an skb and transferres it to the Linux
5649f2d3eaeSJakob Unterwurzacher  * network stack
5659f2d3eaeSJakob Unterwurzacher  */
5669f2d3eaeSJakob Unterwurzacher static void ucan_rx_can_msg(struct ucan_priv *up, struct ucan_message_in *m)
5679f2d3eaeSJakob Unterwurzacher {
5689f2d3eaeSJakob Unterwurzacher 	int len;
5699f2d3eaeSJakob Unterwurzacher 	canid_t canid;
5709f2d3eaeSJakob Unterwurzacher 	struct can_frame *cf;
5719f2d3eaeSJakob Unterwurzacher 	struct sk_buff *skb;
5729f2d3eaeSJakob Unterwurzacher 	struct net_device_stats *stats = &up->netdev->stats;
5739f2d3eaeSJakob Unterwurzacher 
5749f2d3eaeSJakob Unterwurzacher 	/* get the contents of the length field */
5759f2d3eaeSJakob Unterwurzacher 	len = le16_to_cpu(m->len);
5769f2d3eaeSJakob Unterwurzacher 
5779f2d3eaeSJakob Unterwurzacher 	/* check sanity */
5789f2d3eaeSJakob Unterwurzacher 	if (len < UCAN_IN_HDR_SIZE + sizeof(m->msg.can_msg.id)) {
5799f2d3eaeSJakob Unterwurzacher 		netdev_warn(up->netdev, "invalid input message len: %d\n", len);
5809f2d3eaeSJakob Unterwurzacher 		return;
5819f2d3eaeSJakob Unterwurzacher 	}
5829f2d3eaeSJakob Unterwurzacher 
5839f2d3eaeSJakob Unterwurzacher 	/* handle error frames */
5849f2d3eaeSJakob Unterwurzacher 	canid = le32_to_cpu(m->msg.can_msg.id);
5859f2d3eaeSJakob Unterwurzacher 	if (canid & CAN_ERR_FLAG) {
5869f2d3eaeSJakob Unterwurzacher 		bool busstate_changed = ucan_handle_error_frame(up, m, canid);
5879f2d3eaeSJakob Unterwurzacher 
5889f2d3eaeSJakob Unterwurzacher 		/* if berr-reporting is off only state changes get through */
5899f2d3eaeSJakob Unterwurzacher 		if (!(up->can.ctrlmode & CAN_CTRLMODE_BERR_REPORTING) &&
5909f2d3eaeSJakob Unterwurzacher 		    !busstate_changed)
5919f2d3eaeSJakob Unterwurzacher 			return;
5929f2d3eaeSJakob Unterwurzacher 	} else {
5939f2d3eaeSJakob Unterwurzacher 		canid_t canid_mask;
5949f2d3eaeSJakob Unterwurzacher 		/* compute the mask for canid */
5959f2d3eaeSJakob Unterwurzacher 		canid_mask = CAN_RTR_FLAG;
5969f2d3eaeSJakob Unterwurzacher 		if (canid & CAN_EFF_FLAG)
5979f2d3eaeSJakob Unterwurzacher 			canid_mask |= CAN_EFF_MASK | CAN_EFF_FLAG;
5989f2d3eaeSJakob Unterwurzacher 		else
5999f2d3eaeSJakob Unterwurzacher 			canid_mask |= CAN_SFF_MASK;
6009f2d3eaeSJakob Unterwurzacher 
6019f2d3eaeSJakob Unterwurzacher 		if (canid & ~canid_mask)
6029f2d3eaeSJakob Unterwurzacher 			netdev_warn(up->netdev,
6039f2d3eaeSJakob Unterwurzacher 				    "unexpected bits set (canid %x, mask %x)",
6049f2d3eaeSJakob Unterwurzacher 				    canid, canid_mask);
6059f2d3eaeSJakob Unterwurzacher 
6069f2d3eaeSJakob Unterwurzacher 		canid &= canid_mask;
6079f2d3eaeSJakob Unterwurzacher 	}
6089f2d3eaeSJakob Unterwurzacher 
6099f2d3eaeSJakob Unterwurzacher 	/* allocate skb */
6109f2d3eaeSJakob Unterwurzacher 	skb = alloc_can_skb(up->netdev, &cf);
6119f2d3eaeSJakob Unterwurzacher 	if (!skb)
6129f2d3eaeSJakob Unterwurzacher 		return;
6139f2d3eaeSJakob Unterwurzacher 
6149f2d3eaeSJakob Unterwurzacher 	/* fill the can frame */
6159f2d3eaeSJakob Unterwurzacher 	cf->can_id = canid;
6169f2d3eaeSJakob Unterwurzacher 
6179f2d3eaeSJakob Unterwurzacher 	/* compute DLC taking RTR_FLAG into account */
618c7b74967SOliver Hartkopp 	cf->len = ucan_can_cc_dlc2len(&m->msg.can_msg, len);
6199f2d3eaeSJakob Unterwurzacher 
6209f2d3eaeSJakob Unterwurzacher 	/* copy the payload of non RTR frames */
6219f2d3eaeSJakob Unterwurzacher 	if (!(cf->can_id & CAN_RTR_FLAG) || (cf->can_id & CAN_ERR_FLAG))
622c7b74967SOliver Hartkopp 		memcpy(cf->data, m->msg.can_msg.data, cf->len);
6239f2d3eaeSJakob Unterwurzacher 
6249f2d3eaeSJakob Unterwurzacher 	/* don't count error frames as real packets */
625676068dbSVincent Mailhol 	if (!(cf->can_id & CAN_ERR_FLAG)) {
6269f2d3eaeSJakob Unterwurzacher 		stats->rx_packets++;
6278e674ca7SVincent Mailhol 		if (!(cf->can_id & CAN_RTR_FLAG))
628c7b74967SOliver Hartkopp 			stats->rx_bytes += cf->len;
629676068dbSVincent Mailhol 	}
6309f2d3eaeSJakob Unterwurzacher 
6319f2d3eaeSJakob Unterwurzacher 	/* pass it to Linux */
6329f2d3eaeSJakob Unterwurzacher 	netif_rx(skb);
6339f2d3eaeSJakob Unterwurzacher }
6349f2d3eaeSJakob Unterwurzacher 
6359f2d3eaeSJakob Unterwurzacher /* callback indicating completed transmission */
6369f2d3eaeSJakob Unterwurzacher static void ucan_tx_complete_msg(struct ucan_priv *up,
6379f2d3eaeSJakob Unterwurzacher 				 struct ucan_message_in *m)
6389f2d3eaeSJakob Unterwurzacher {
6399f2d3eaeSJakob Unterwurzacher 	unsigned long flags;
6409f2d3eaeSJakob Unterwurzacher 	u16 count, i;
641cc4b08c3SVincent Mailhol 	u8 echo_index;
6429f2d3eaeSJakob Unterwurzacher 	u16 len = le16_to_cpu(m->len);
6439f2d3eaeSJakob Unterwurzacher 
6449f2d3eaeSJakob Unterwurzacher 	struct ucan_urb_context *context;
6459f2d3eaeSJakob Unterwurzacher 
6469f2d3eaeSJakob Unterwurzacher 	if (len < UCAN_IN_HDR_SIZE || (len % 2 != 0)) {
6479f2d3eaeSJakob Unterwurzacher 		netdev_err(up->netdev, "invalid tx complete length\n");
6489f2d3eaeSJakob Unterwurzacher 		return;
6499f2d3eaeSJakob Unterwurzacher 	}
6509f2d3eaeSJakob Unterwurzacher 
6519f2d3eaeSJakob Unterwurzacher 	count = (len - UCAN_IN_HDR_SIZE) / 2;
6529f2d3eaeSJakob Unterwurzacher 	for (i = 0; i < count; i++) {
6539f2d3eaeSJakob Unterwurzacher 		/* we did not submit such echo ids */
6549f2d3eaeSJakob Unterwurzacher 		echo_index = m->msg.can_tx_complete_msg[i].echo_index;
6559f2d3eaeSJakob Unterwurzacher 		if (echo_index >= up->device_info.tx_fifo) {
6569f2d3eaeSJakob Unterwurzacher 			up->netdev->stats.tx_errors++;
6579f2d3eaeSJakob Unterwurzacher 			netdev_err(up->netdev,
6589f2d3eaeSJakob Unterwurzacher 				   "invalid echo_index %d received\n",
6599f2d3eaeSJakob Unterwurzacher 				   echo_index);
6609f2d3eaeSJakob Unterwurzacher 			continue;
6619f2d3eaeSJakob Unterwurzacher 		}
6629f2d3eaeSJakob Unterwurzacher 
6639f2d3eaeSJakob Unterwurzacher 		/* gather information from the context */
6649f2d3eaeSJakob Unterwurzacher 		context = &up->context_array[echo_index];
6659f2d3eaeSJakob Unterwurzacher 
6669f2d3eaeSJakob Unterwurzacher 		/* Release context and restart queue if necessary.
6679f2d3eaeSJakob Unterwurzacher 		 * Also check if the context was allocated
6689f2d3eaeSJakob Unterwurzacher 		 */
6699f2d3eaeSJakob Unterwurzacher 		if (!ucan_release_context(up, context))
6709f2d3eaeSJakob Unterwurzacher 			continue;
6719f2d3eaeSJakob Unterwurzacher 
6729f2d3eaeSJakob Unterwurzacher 		spin_lock_irqsave(&up->echo_skb_lock, flags);
6739f2d3eaeSJakob Unterwurzacher 		if (m->msg.can_tx_complete_msg[i].flags &
6749f2d3eaeSJakob Unterwurzacher 		    UCAN_TX_COMPLETE_SUCCESS) {
6759f2d3eaeSJakob Unterwurzacher 			/* update statistics */
6769f2d3eaeSJakob Unterwurzacher 			up->netdev->stats.tx_packets++;
677cc4b08c3SVincent Mailhol 			up->netdev->stats.tx_bytes +=
6789420e1d4SMarc Kleine-Budde 				can_get_echo_skb(up->netdev, echo_index, NULL);
6799f2d3eaeSJakob Unterwurzacher 		} else {
6809f2d3eaeSJakob Unterwurzacher 			up->netdev->stats.tx_dropped++;
681f318482aSMarc Kleine-Budde 			can_free_echo_skb(up->netdev, echo_index, NULL);
6829f2d3eaeSJakob Unterwurzacher 		}
6839f2d3eaeSJakob Unterwurzacher 		spin_unlock_irqrestore(&up->echo_skb_lock, flags);
6849f2d3eaeSJakob Unterwurzacher 	}
6859f2d3eaeSJakob Unterwurzacher }
6869f2d3eaeSJakob Unterwurzacher 
6879f2d3eaeSJakob Unterwurzacher /* callback on reception of a USB message */
6889f2d3eaeSJakob Unterwurzacher static void ucan_read_bulk_callback(struct urb *urb)
6899f2d3eaeSJakob Unterwurzacher {
6909f2d3eaeSJakob Unterwurzacher 	int ret;
6919f2d3eaeSJakob Unterwurzacher 	int pos;
6929f2d3eaeSJakob Unterwurzacher 	struct ucan_priv *up = urb->context;
6939f2d3eaeSJakob Unterwurzacher 	struct net_device *netdev = up->netdev;
6949f2d3eaeSJakob Unterwurzacher 	struct ucan_message_in *m;
6959f2d3eaeSJakob Unterwurzacher 
6969f2d3eaeSJakob Unterwurzacher 	/* the device is not up and the driver should not receive any
6979f2d3eaeSJakob Unterwurzacher 	 * data on the bulk in pipe
6989f2d3eaeSJakob Unterwurzacher 	 */
6999f2d3eaeSJakob Unterwurzacher 	if (WARN_ON(!up->context_array)) {
7009f2d3eaeSJakob Unterwurzacher 		usb_free_coherent(up->udev,
7019f2d3eaeSJakob Unterwurzacher 				  up->in_ep_size,
7029f2d3eaeSJakob Unterwurzacher 				  urb->transfer_buffer,
7039f2d3eaeSJakob Unterwurzacher 				  urb->transfer_dma);
7049f2d3eaeSJakob Unterwurzacher 		return;
7059f2d3eaeSJakob Unterwurzacher 	}
7069f2d3eaeSJakob Unterwurzacher 
7079f2d3eaeSJakob Unterwurzacher 	/* check URB status */
7089f2d3eaeSJakob Unterwurzacher 	switch (urb->status) {
7099f2d3eaeSJakob Unterwurzacher 	case 0:
7109f2d3eaeSJakob Unterwurzacher 		break;
7119f2d3eaeSJakob Unterwurzacher 	case -ENOENT:
7129f2d3eaeSJakob Unterwurzacher 	case -EPIPE:
7139f2d3eaeSJakob Unterwurzacher 	case -EPROTO:
7149f2d3eaeSJakob Unterwurzacher 	case -ESHUTDOWN:
7159f2d3eaeSJakob Unterwurzacher 	case -ETIME:
7169f2d3eaeSJakob Unterwurzacher 		/* urb is not resubmitted -> free dma data */
7179f2d3eaeSJakob Unterwurzacher 		usb_free_coherent(up->udev,
7189f2d3eaeSJakob Unterwurzacher 				  up->in_ep_size,
7199f2d3eaeSJakob Unterwurzacher 				  urb->transfer_buffer,
7209f2d3eaeSJakob Unterwurzacher 				  urb->transfer_dma);
7213b17d417SColin Ian King 		netdev_dbg(up->netdev, "not resubmitting urb; status: %d\n",
7229f2d3eaeSJakob Unterwurzacher 			   urb->status);
7239f2d3eaeSJakob Unterwurzacher 		return;
7249f2d3eaeSJakob Unterwurzacher 	default:
7259f2d3eaeSJakob Unterwurzacher 		goto resubmit;
7269f2d3eaeSJakob Unterwurzacher 	}
7279f2d3eaeSJakob Unterwurzacher 
7289f2d3eaeSJakob Unterwurzacher 	/* sanity check */
7299f2d3eaeSJakob Unterwurzacher 	if (!netif_device_present(netdev))
7309f2d3eaeSJakob Unterwurzacher 		return;
7319f2d3eaeSJakob Unterwurzacher 
7329f2d3eaeSJakob Unterwurzacher 	/* iterate over input */
7339f2d3eaeSJakob Unterwurzacher 	pos = 0;
7349f2d3eaeSJakob Unterwurzacher 	while (pos < urb->actual_length) {
7359f2d3eaeSJakob Unterwurzacher 		int len;
7369f2d3eaeSJakob Unterwurzacher 
7379f2d3eaeSJakob Unterwurzacher 		/* check sanity (length of header) */
7389f2d3eaeSJakob Unterwurzacher 		if ((urb->actual_length - pos) < UCAN_IN_HDR_SIZE) {
7399f2d3eaeSJakob Unterwurzacher 			netdev_warn(up->netdev,
7409f2d3eaeSJakob Unterwurzacher 				    "invalid message (short; no hdr; l:%d)\n",
7419f2d3eaeSJakob Unterwurzacher 				    urb->actual_length);
7429f2d3eaeSJakob Unterwurzacher 			goto resubmit;
7439f2d3eaeSJakob Unterwurzacher 		}
7449f2d3eaeSJakob Unterwurzacher 
7459f2d3eaeSJakob Unterwurzacher 		/* setup the message address */
7469f2d3eaeSJakob Unterwurzacher 		m = (struct ucan_message_in *)
7479f2d3eaeSJakob Unterwurzacher 			((u8 *)urb->transfer_buffer + pos);
7489f2d3eaeSJakob Unterwurzacher 		len = le16_to_cpu(m->len);
7499f2d3eaeSJakob Unterwurzacher 
7509f2d3eaeSJakob Unterwurzacher 		/* check sanity (length of content) */
7519f2d3eaeSJakob Unterwurzacher 		if (urb->actual_length - pos < len) {
7529f2d3eaeSJakob Unterwurzacher 			netdev_warn(up->netdev,
7539f2d3eaeSJakob Unterwurzacher 				    "invalid message (short; no data; l:%d)\n",
7549f2d3eaeSJakob Unterwurzacher 				    urb->actual_length);
7559f2d3eaeSJakob Unterwurzacher 			print_hex_dump(KERN_WARNING,
7569f2d3eaeSJakob Unterwurzacher 				       "raw data: ",
7579f2d3eaeSJakob Unterwurzacher 				       DUMP_PREFIX_ADDRESS,
7589f2d3eaeSJakob Unterwurzacher 				       16,
7599f2d3eaeSJakob Unterwurzacher 				       1,
7609f2d3eaeSJakob Unterwurzacher 				       urb->transfer_buffer,
7619f2d3eaeSJakob Unterwurzacher 				       urb->actual_length,
7629f2d3eaeSJakob Unterwurzacher 				       true);
7639f2d3eaeSJakob Unterwurzacher 
7649f2d3eaeSJakob Unterwurzacher 			goto resubmit;
7659f2d3eaeSJakob Unterwurzacher 		}
7669f2d3eaeSJakob Unterwurzacher 
7679f2d3eaeSJakob Unterwurzacher 		switch (m->type) {
7689f2d3eaeSJakob Unterwurzacher 		case UCAN_IN_RX:
7699f2d3eaeSJakob Unterwurzacher 			ucan_rx_can_msg(up, m);
7709f2d3eaeSJakob Unterwurzacher 			break;
7719f2d3eaeSJakob Unterwurzacher 		case UCAN_IN_TX_COMPLETE:
7729f2d3eaeSJakob Unterwurzacher 			ucan_tx_complete_msg(up, m);
7739f2d3eaeSJakob Unterwurzacher 			break;
7749f2d3eaeSJakob Unterwurzacher 		default:
7759f2d3eaeSJakob Unterwurzacher 			netdev_warn(up->netdev,
7769f2d3eaeSJakob Unterwurzacher 				    "invalid message (type; t:%d)\n",
7779f2d3eaeSJakob Unterwurzacher 				    m->type);
7789f2d3eaeSJakob Unterwurzacher 			break;
7799f2d3eaeSJakob Unterwurzacher 		}
7809f2d3eaeSJakob Unterwurzacher 
7819f2d3eaeSJakob Unterwurzacher 		/* proceed to next message */
7829f2d3eaeSJakob Unterwurzacher 		pos += len;
7839f2d3eaeSJakob Unterwurzacher 		/* align to 4 byte boundary */
7849f2d3eaeSJakob Unterwurzacher 		pos = round_up(pos, 4);
7859f2d3eaeSJakob Unterwurzacher 	}
7869f2d3eaeSJakob Unterwurzacher 
7879f2d3eaeSJakob Unterwurzacher resubmit:
7889f2d3eaeSJakob Unterwurzacher 	/* resubmit urb when done */
7899f2d3eaeSJakob Unterwurzacher 	usb_fill_bulk_urb(urb, up->udev,
7909f2d3eaeSJakob Unterwurzacher 			  usb_rcvbulkpipe(up->udev,
7919f2d3eaeSJakob Unterwurzacher 					  up->in_ep_addr),
7929f2d3eaeSJakob Unterwurzacher 			  urb->transfer_buffer,
7939f2d3eaeSJakob Unterwurzacher 			  up->in_ep_size,
7949f2d3eaeSJakob Unterwurzacher 			  ucan_read_bulk_callback,
7959f2d3eaeSJakob Unterwurzacher 			  up);
7969f2d3eaeSJakob Unterwurzacher 
7979f2d3eaeSJakob Unterwurzacher 	usb_anchor_urb(urb, &up->rx_urbs);
798870db5d1SJohan Hovold 	ret = usb_submit_urb(urb, GFP_ATOMIC);
7999f2d3eaeSJakob Unterwurzacher 
8009f2d3eaeSJakob Unterwurzacher 	if (ret < 0) {
8019f2d3eaeSJakob Unterwurzacher 		netdev_err(up->netdev,
8029f2d3eaeSJakob Unterwurzacher 			   "failed resubmitting read bulk urb: %d\n",
8039f2d3eaeSJakob Unterwurzacher 			   ret);
8049f2d3eaeSJakob Unterwurzacher 
8059f2d3eaeSJakob Unterwurzacher 		usb_unanchor_urb(urb);
8069f2d3eaeSJakob Unterwurzacher 		usb_free_coherent(up->udev,
8079f2d3eaeSJakob Unterwurzacher 				  up->in_ep_size,
8089f2d3eaeSJakob Unterwurzacher 				  urb->transfer_buffer,
8099f2d3eaeSJakob Unterwurzacher 				  urb->transfer_dma);
8109f2d3eaeSJakob Unterwurzacher 
8119f2d3eaeSJakob Unterwurzacher 		if (ret == -ENODEV)
8129f2d3eaeSJakob Unterwurzacher 			netif_device_detach(netdev);
8139f2d3eaeSJakob Unterwurzacher 	}
8149f2d3eaeSJakob Unterwurzacher }
8159f2d3eaeSJakob Unterwurzacher 
8169f2d3eaeSJakob Unterwurzacher /* callback after transmission of a USB message */
8179f2d3eaeSJakob Unterwurzacher static void ucan_write_bulk_callback(struct urb *urb)
8189f2d3eaeSJakob Unterwurzacher {
8199f2d3eaeSJakob Unterwurzacher 	unsigned long flags;
8209f2d3eaeSJakob Unterwurzacher 	struct ucan_priv *up;
8219f2d3eaeSJakob Unterwurzacher 	struct ucan_urb_context *context = urb->context;
8229f2d3eaeSJakob Unterwurzacher 
8239f2d3eaeSJakob Unterwurzacher 	/* get the urb context */
8249f2d3eaeSJakob Unterwurzacher 	if (WARN_ON_ONCE(!context))
8259f2d3eaeSJakob Unterwurzacher 		return;
8269f2d3eaeSJakob Unterwurzacher 
8279f2d3eaeSJakob Unterwurzacher 	/* free up our allocated buffer */
8289f2d3eaeSJakob Unterwurzacher 	usb_free_coherent(urb->dev,
8299f2d3eaeSJakob Unterwurzacher 			  sizeof(struct ucan_message_out),
8309f2d3eaeSJakob Unterwurzacher 			  urb->transfer_buffer,
8319f2d3eaeSJakob Unterwurzacher 			  urb->transfer_dma);
8329f2d3eaeSJakob Unterwurzacher 
8339f2d3eaeSJakob Unterwurzacher 	up = context->up;
8349f2d3eaeSJakob Unterwurzacher 	if (WARN_ON_ONCE(!up))
8359f2d3eaeSJakob Unterwurzacher 		return;
8369f2d3eaeSJakob Unterwurzacher 
8379f2d3eaeSJakob Unterwurzacher 	/* sanity check */
8389f2d3eaeSJakob Unterwurzacher 	if (!netif_device_present(up->netdev))
8399f2d3eaeSJakob Unterwurzacher 		return;
8409f2d3eaeSJakob Unterwurzacher 
8419f2d3eaeSJakob Unterwurzacher 	/* transmission failed (USB - the device will not send a TX complete) */
8429f2d3eaeSJakob Unterwurzacher 	if (urb->status) {
8439f2d3eaeSJakob Unterwurzacher 		netdev_warn(up->netdev,
8449f2d3eaeSJakob Unterwurzacher 			    "failed to transmit USB message to device: %d\n",
8459f2d3eaeSJakob Unterwurzacher 			     urb->status);
8469f2d3eaeSJakob Unterwurzacher 
8479f2d3eaeSJakob Unterwurzacher 		/* update counters an cleanup */
8489f2d3eaeSJakob Unterwurzacher 		spin_lock_irqsave(&up->echo_skb_lock, flags);
849f318482aSMarc Kleine-Budde 		can_free_echo_skb(up->netdev, context - up->context_array, NULL);
8509f2d3eaeSJakob Unterwurzacher 		spin_unlock_irqrestore(&up->echo_skb_lock, flags);
8519f2d3eaeSJakob Unterwurzacher 
8529f2d3eaeSJakob Unterwurzacher 		up->netdev->stats.tx_dropped++;
8539f2d3eaeSJakob Unterwurzacher 
8549f2d3eaeSJakob Unterwurzacher 		/* release context and restart the queue if necessary */
8559f2d3eaeSJakob Unterwurzacher 		if (!ucan_release_context(up, context))
8569f2d3eaeSJakob Unterwurzacher 			netdev_err(up->netdev,
8579f2d3eaeSJakob Unterwurzacher 				   "urb failed, failed to release context\n");
8589f2d3eaeSJakob Unterwurzacher 	}
8599f2d3eaeSJakob Unterwurzacher }
8609f2d3eaeSJakob Unterwurzacher 
8619f2d3eaeSJakob Unterwurzacher static void ucan_cleanup_rx_urbs(struct ucan_priv *up, struct urb **urbs)
8629f2d3eaeSJakob Unterwurzacher {
8639f2d3eaeSJakob Unterwurzacher 	int i;
8649f2d3eaeSJakob Unterwurzacher 
8659f2d3eaeSJakob Unterwurzacher 	for (i = 0; i < UCAN_MAX_RX_URBS; i++) {
8669f2d3eaeSJakob Unterwurzacher 		if (urbs[i]) {
8679f2d3eaeSJakob Unterwurzacher 			usb_unanchor_urb(urbs[i]);
8689f2d3eaeSJakob Unterwurzacher 			usb_free_coherent(up->udev,
8699f2d3eaeSJakob Unterwurzacher 					  up->in_ep_size,
8709f2d3eaeSJakob Unterwurzacher 					  urbs[i]->transfer_buffer,
8719f2d3eaeSJakob Unterwurzacher 					  urbs[i]->transfer_dma);
8729f2d3eaeSJakob Unterwurzacher 			usb_free_urb(urbs[i]);
8739f2d3eaeSJakob Unterwurzacher 		}
8749f2d3eaeSJakob Unterwurzacher 	}
8759f2d3eaeSJakob Unterwurzacher 
8769f2d3eaeSJakob Unterwurzacher 	memset(urbs, 0, sizeof(*urbs) * UCAN_MAX_RX_URBS);
8779f2d3eaeSJakob Unterwurzacher }
8789f2d3eaeSJakob Unterwurzacher 
8799f2d3eaeSJakob Unterwurzacher static int ucan_prepare_and_anchor_rx_urbs(struct ucan_priv *up,
8809f2d3eaeSJakob Unterwurzacher 					   struct urb **urbs)
8819f2d3eaeSJakob Unterwurzacher {
8829f2d3eaeSJakob Unterwurzacher 	int i;
8839f2d3eaeSJakob Unterwurzacher 
8849f2d3eaeSJakob Unterwurzacher 	memset(urbs, 0, sizeof(*urbs) * UCAN_MAX_RX_URBS);
8859f2d3eaeSJakob Unterwurzacher 
8869f2d3eaeSJakob Unterwurzacher 	for (i = 0; i < UCAN_MAX_RX_URBS; i++) {
8879f2d3eaeSJakob Unterwurzacher 		void *buf;
8889f2d3eaeSJakob Unterwurzacher 
8899f2d3eaeSJakob Unterwurzacher 		urbs[i] = usb_alloc_urb(0, GFP_KERNEL);
8909f2d3eaeSJakob Unterwurzacher 		if (!urbs[i])
8919f2d3eaeSJakob Unterwurzacher 			goto err;
8929f2d3eaeSJakob Unterwurzacher 
8939f2d3eaeSJakob Unterwurzacher 		buf = usb_alloc_coherent(up->udev,
8949f2d3eaeSJakob Unterwurzacher 					 up->in_ep_size,
8959f2d3eaeSJakob Unterwurzacher 					 GFP_KERNEL, &urbs[i]->transfer_dma);
8969f2d3eaeSJakob Unterwurzacher 		if (!buf) {
8979f2d3eaeSJakob Unterwurzacher 			/* cleanup this urb */
8989f2d3eaeSJakob Unterwurzacher 			usb_free_urb(urbs[i]);
8999f2d3eaeSJakob Unterwurzacher 			urbs[i] = NULL;
9009f2d3eaeSJakob Unterwurzacher 			goto err;
9019f2d3eaeSJakob Unterwurzacher 		}
9029f2d3eaeSJakob Unterwurzacher 
9039f2d3eaeSJakob Unterwurzacher 		usb_fill_bulk_urb(urbs[i], up->udev,
9049f2d3eaeSJakob Unterwurzacher 				  usb_rcvbulkpipe(up->udev,
9059f2d3eaeSJakob Unterwurzacher 						  up->in_ep_addr),
9069f2d3eaeSJakob Unterwurzacher 				  buf,
9079f2d3eaeSJakob Unterwurzacher 				  up->in_ep_size,
9089f2d3eaeSJakob Unterwurzacher 				  ucan_read_bulk_callback,
9099f2d3eaeSJakob Unterwurzacher 				  up);
9109f2d3eaeSJakob Unterwurzacher 
9119f2d3eaeSJakob Unterwurzacher 		urbs[i]->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
9129f2d3eaeSJakob Unterwurzacher 
9139f2d3eaeSJakob Unterwurzacher 		usb_anchor_urb(urbs[i], &up->rx_urbs);
9149f2d3eaeSJakob Unterwurzacher 	}
9159f2d3eaeSJakob Unterwurzacher 	return 0;
9169f2d3eaeSJakob Unterwurzacher 
9179f2d3eaeSJakob Unterwurzacher err:
9189f2d3eaeSJakob Unterwurzacher 	/* cleanup other unsubmitted urbs */
9199f2d3eaeSJakob Unterwurzacher 	ucan_cleanup_rx_urbs(up, urbs);
9209f2d3eaeSJakob Unterwurzacher 	return -ENOMEM;
9219f2d3eaeSJakob Unterwurzacher }
9229f2d3eaeSJakob Unterwurzacher 
9239f2d3eaeSJakob Unterwurzacher /* Submits rx urbs with the semantic: Either submit all, or cleanup
9249f2d3eaeSJakob Unterwurzacher  * everything. I case of errors submitted urbs are killed and all urbs in
9259f2d3eaeSJakob Unterwurzacher  * the array are freed. I case of no errors every entry in the urb
9269f2d3eaeSJakob Unterwurzacher  * array is set to NULL.
9279f2d3eaeSJakob Unterwurzacher  */
9289f2d3eaeSJakob Unterwurzacher static int ucan_submit_rx_urbs(struct ucan_priv *up, struct urb **urbs)
9299f2d3eaeSJakob Unterwurzacher {
9309f2d3eaeSJakob Unterwurzacher 	int i, ret;
9319f2d3eaeSJakob Unterwurzacher 
9329f2d3eaeSJakob Unterwurzacher 	/* Iterate over all urbs to submit. On success remove the urb
9339f2d3eaeSJakob Unterwurzacher 	 * from the list.
9349f2d3eaeSJakob Unterwurzacher 	 */
9359f2d3eaeSJakob Unterwurzacher 	for (i = 0; i < UCAN_MAX_RX_URBS; i++) {
9369f2d3eaeSJakob Unterwurzacher 		ret = usb_submit_urb(urbs[i], GFP_KERNEL);
9379f2d3eaeSJakob Unterwurzacher 		if (ret) {
9389f2d3eaeSJakob Unterwurzacher 			netdev_err(up->netdev,
9399f2d3eaeSJakob Unterwurzacher 				   "could not submit urb; code: %d\n",
9409f2d3eaeSJakob Unterwurzacher 				   ret);
9419f2d3eaeSJakob Unterwurzacher 			goto err;
9429f2d3eaeSJakob Unterwurzacher 		}
9439f2d3eaeSJakob Unterwurzacher 
9449f2d3eaeSJakob Unterwurzacher 		/* Anchor URB and drop reference, USB core will take
9459f2d3eaeSJakob Unterwurzacher 		 * care of freeing it
9469f2d3eaeSJakob Unterwurzacher 		 */
9479f2d3eaeSJakob Unterwurzacher 		usb_free_urb(urbs[i]);
9489f2d3eaeSJakob Unterwurzacher 		urbs[i] = NULL;
9499f2d3eaeSJakob Unterwurzacher 	}
9509f2d3eaeSJakob Unterwurzacher 	return 0;
9519f2d3eaeSJakob Unterwurzacher 
9529f2d3eaeSJakob Unterwurzacher err:
9539f2d3eaeSJakob Unterwurzacher 	/* Cleanup unsubmitted urbs */
9549f2d3eaeSJakob Unterwurzacher 	ucan_cleanup_rx_urbs(up, urbs);
9559f2d3eaeSJakob Unterwurzacher 
9569f2d3eaeSJakob Unterwurzacher 	/* Kill urbs that are already submitted */
9579f2d3eaeSJakob Unterwurzacher 	usb_kill_anchored_urbs(&up->rx_urbs);
9589f2d3eaeSJakob Unterwurzacher 
9599f2d3eaeSJakob Unterwurzacher 	return ret;
9609f2d3eaeSJakob Unterwurzacher }
9619f2d3eaeSJakob Unterwurzacher 
9629f2d3eaeSJakob Unterwurzacher /* Open the network device */
9639f2d3eaeSJakob Unterwurzacher static int ucan_open(struct net_device *netdev)
9649f2d3eaeSJakob Unterwurzacher {
9659f2d3eaeSJakob Unterwurzacher 	int ret, ret_cleanup;
9669f2d3eaeSJakob Unterwurzacher 	u16 ctrlmode;
9679f2d3eaeSJakob Unterwurzacher 	struct urb *urbs[UCAN_MAX_RX_URBS];
9689f2d3eaeSJakob Unterwurzacher 	struct ucan_priv *up = netdev_priv(netdev);
9699f2d3eaeSJakob Unterwurzacher 
9709f2d3eaeSJakob Unterwurzacher 	ret = ucan_alloc_context_array(up);
9719f2d3eaeSJakob Unterwurzacher 	if (ret)
9729f2d3eaeSJakob Unterwurzacher 		return ret;
9739f2d3eaeSJakob Unterwurzacher 
9749f2d3eaeSJakob Unterwurzacher 	/* Allocate and prepare IN URBS - allocated and anchored
9759f2d3eaeSJakob Unterwurzacher 	 * urbs are stored in urbs[] for clean
9769f2d3eaeSJakob Unterwurzacher 	 */
9779f2d3eaeSJakob Unterwurzacher 	ret = ucan_prepare_and_anchor_rx_urbs(up, urbs);
9789f2d3eaeSJakob Unterwurzacher 	if (ret)
9799f2d3eaeSJakob Unterwurzacher 		goto err_contexts;
9809f2d3eaeSJakob Unterwurzacher 
9819f2d3eaeSJakob Unterwurzacher 	/* Check the control mode */
9829f2d3eaeSJakob Unterwurzacher 	ctrlmode = 0;
9839f2d3eaeSJakob Unterwurzacher 	if (up->can.ctrlmode & CAN_CTRLMODE_LOOPBACK)
9849f2d3eaeSJakob Unterwurzacher 		ctrlmode |= UCAN_MODE_LOOPBACK;
9859f2d3eaeSJakob Unterwurzacher 	if (up->can.ctrlmode & CAN_CTRLMODE_LISTENONLY)
9869f2d3eaeSJakob Unterwurzacher 		ctrlmode |= UCAN_MODE_SILENT;
9879f2d3eaeSJakob Unterwurzacher 	if (up->can.ctrlmode & CAN_CTRLMODE_3_SAMPLES)
9889f2d3eaeSJakob Unterwurzacher 		ctrlmode |= UCAN_MODE_3_SAMPLES;
9899f2d3eaeSJakob Unterwurzacher 	if (up->can.ctrlmode & CAN_CTRLMODE_ONE_SHOT)
9909f2d3eaeSJakob Unterwurzacher 		ctrlmode |= UCAN_MODE_ONE_SHOT;
9919f2d3eaeSJakob Unterwurzacher 
9929f2d3eaeSJakob Unterwurzacher 	/* Enable this in any case - filtering is down within the
9939f2d3eaeSJakob Unterwurzacher 	 * receive path
9949f2d3eaeSJakob Unterwurzacher 	 */
9959f2d3eaeSJakob Unterwurzacher 	ctrlmode |= UCAN_MODE_BERR_REPORT;
9969f2d3eaeSJakob Unterwurzacher 	up->ctl_msg_buffer->cmd_start.mode = cpu_to_le16(ctrlmode);
9979f2d3eaeSJakob Unterwurzacher 
9989f2d3eaeSJakob Unterwurzacher 	/* Driver is ready to receive data - start the USB device */
9999f2d3eaeSJakob Unterwurzacher 	ret = ucan_ctrl_command_out(up, UCAN_COMMAND_START, 0, 2);
10009f2d3eaeSJakob Unterwurzacher 	if (ret < 0) {
10019f2d3eaeSJakob Unterwurzacher 		netdev_err(up->netdev,
10029f2d3eaeSJakob Unterwurzacher 			   "could not start device, code: %d\n",
10039f2d3eaeSJakob Unterwurzacher 			   ret);
10049f2d3eaeSJakob Unterwurzacher 		goto err_reset;
10059f2d3eaeSJakob Unterwurzacher 	}
10069f2d3eaeSJakob Unterwurzacher 
10079f2d3eaeSJakob Unterwurzacher 	/* Call CAN layer open */
10089f2d3eaeSJakob Unterwurzacher 	ret = open_candev(netdev);
10099f2d3eaeSJakob Unterwurzacher 	if (ret)
10109f2d3eaeSJakob Unterwurzacher 		goto err_stop;
10119f2d3eaeSJakob Unterwurzacher 
10129f2d3eaeSJakob Unterwurzacher 	/* Driver is ready to receive data. Submit RX URBS */
10139f2d3eaeSJakob Unterwurzacher 	ret = ucan_submit_rx_urbs(up, urbs);
10149f2d3eaeSJakob Unterwurzacher 	if (ret)
10159f2d3eaeSJakob Unterwurzacher 		goto err_stop;
10169f2d3eaeSJakob Unterwurzacher 
10179f2d3eaeSJakob Unterwurzacher 	up->can.state = CAN_STATE_ERROR_ACTIVE;
10189f2d3eaeSJakob Unterwurzacher 
10199f2d3eaeSJakob Unterwurzacher 	/* Start the network queue */
10209f2d3eaeSJakob Unterwurzacher 	netif_start_queue(netdev);
10219f2d3eaeSJakob Unterwurzacher 
10229f2d3eaeSJakob Unterwurzacher 	return 0;
10239f2d3eaeSJakob Unterwurzacher 
10249f2d3eaeSJakob Unterwurzacher err_stop:
10259f2d3eaeSJakob Unterwurzacher 	/* The device have started already stop it */
10269f2d3eaeSJakob Unterwurzacher 	ret_cleanup = ucan_ctrl_command_out(up, UCAN_COMMAND_STOP, 0, 0);
10279f2d3eaeSJakob Unterwurzacher 	if (ret_cleanup < 0)
10289f2d3eaeSJakob Unterwurzacher 		netdev_err(up->netdev,
10299f2d3eaeSJakob Unterwurzacher 			   "could not stop device, code: %d\n",
10309f2d3eaeSJakob Unterwurzacher 			   ret_cleanup);
10319f2d3eaeSJakob Unterwurzacher 
10329f2d3eaeSJakob Unterwurzacher err_reset:
10339f2d3eaeSJakob Unterwurzacher 	/* The device might have received data, reset it for
10349f2d3eaeSJakob Unterwurzacher 	 * consistent state
10359f2d3eaeSJakob Unterwurzacher 	 */
10369f2d3eaeSJakob Unterwurzacher 	ret_cleanup = ucan_ctrl_command_out(up, UCAN_COMMAND_RESET, 0, 0);
10379f2d3eaeSJakob Unterwurzacher 	if (ret_cleanup < 0)
10389f2d3eaeSJakob Unterwurzacher 		netdev_err(up->netdev,
10399f2d3eaeSJakob Unterwurzacher 			   "could not reset device, code: %d\n",
10409f2d3eaeSJakob Unterwurzacher 			   ret_cleanup);
10419f2d3eaeSJakob Unterwurzacher 
10429f2d3eaeSJakob Unterwurzacher 	/* clean up unsubmitted urbs */
10439f2d3eaeSJakob Unterwurzacher 	ucan_cleanup_rx_urbs(up, urbs);
10449f2d3eaeSJakob Unterwurzacher 
10459f2d3eaeSJakob Unterwurzacher err_contexts:
10469f2d3eaeSJakob Unterwurzacher 	ucan_release_context_array(up);
10479f2d3eaeSJakob Unterwurzacher 	return ret;
10489f2d3eaeSJakob Unterwurzacher }
10499f2d3eaeSJakob Unterwurzacher 
10509f2d3eaeSJakob Unterwurzacher static struct urb *ucan_prepare_tx_urb(struct ucan_priv *up,
10519f2d3eaeSJakob Unterwurzacher 				       struct ucan_urb_context *context,
10529f2d3eaeSJakob Unterwurzacher 				       struct can_frame *cf,
10539f2d3eaeSJakob Unterwurzacher 				       u8 echo_index)
10549f2d3eaeSJakob Unterwurzacher {
10559f2d3eaeSJakob Unterwurzacher 	int mlen;
10569f2d3eaeSJakob Unterwurzacher 	struct urb *urb;
10579f2d3eaeSJakob Unterwurzacher 	struct ucan_message_out *m;
10589f2d3eaeSJakob Unterwurzacher 
10599f2d3eaeSJakob Unterwurzacher 	/* create a URB, and a buffer for it, and copy the data to the URB */
10609f2d3eaeSJakob Unterwurzacher 	urb = usb_alloc_urb(0, GFP_ATOMIC);
10619f2d3eaeSJakob Unterwurzacher 	if (!urb) {
10629f2d3eaeSJakob Unterwurzacher 		netdev_err(up->netdev, "no memory left for URBs\n");
10639f2d3eaeSJakob Unterwurzacher 		return NULL;
10649f2d3eaeSJakob Unterwurzacher 	}
10659f2d3eaeSJakob Unterwurzacher 
10669f2d3eaeSJakob Unterwurzacher 	m = usb_alloc_coherent(up->udev,
10679f2d3eaeSJakob Unterwurzacher 			       sizeof(struct ucan_message_out),
10689f2d3eaeSJakob Unterwurzacher 			       GFP_ATOMIC,
10699f2d3eaeSJakob Unterwurzacher 			       &urb->transfer_dma);
10709f2d3eaeSJakob Unterwurzacher 	if (!m) {
10719f2d3eaeSJakob Unterwurzacher 		netdev_err(up->netdev, "no memory left for USB buffer\n");
10729f2d3eaeSJakob Unterwurzacher 		usb_free_urb(urb);
10739f2d3eaeSJakob Unterwurzacher 		return NULL;
10749f2d3eaeSJakob Unterwurzacher 	}
10759f2d3eaeSJakob Unterwurzacher 
10769f2d3eaeSJakob Unterwurzacher 	/* build the USB message */
10779f2d3eaeSJakob Unterwurzacher 	m->type = UCAN_OUT_TX;
10789f2d3eaeSJakob Unterwurzacher 	m->msg.can_msg.id = cpu_to_le32(cf->can_id);
10799f2d3eaeSJakob Unterwurzacher 
10809f2d3eaeSJakob Unterwurzacher 	if (cf->can_id & CAN_RTR_FLAG) {
10819f2d3eaeSJakob Unterwurzacher 		mlen = UCAN_OUT_HDR_SIZE +
10829f2d3eaeSJakob Unterwurzacher 			offsetof(struct ucan_can_msg, dlc) +
10839f2d3eaeSJakob Unterwurzacher 			sizeof(m->msg.can_msg.dlc);
1084c7b74967SOliver Hartkopp 		m->msg.can_msg.dlc = cf->len;
10859f2d3eaeSJakob Unterwurzacher 	} else {
10869f2d3eaeSJakob Unterwurzacher 		mlen = UCAN_OUT_HDR_SIZE +
1087c7b74967SOliver Hartkopp 			sizeof(m->msg.can_msg.id) + cf->len;
1088c7b74967SOliver Hartkopp 		memcpy(m->msg.can_msg.data, cf->data, cf->len);
10899f2d3eaeSJakob Unterwurzacher 	}
10909f2d3eaeSJakob Unterwurzacher 	m->len = cpu_to_le16(mlen);
10919f2d3eaeSJakob Unterwurzacher 
10929f2d3eaeSJakob Unterwurzacher 	m->subtype = echo_index;
10939f2d3eaeSJakob Unterwurzacher 
10949f2d3eaeSJakob Unterwurzacher 	/* build the urb */
10959f2d3eaeSJakob Unterwurzacher 	usb_fill_bulk_urb(urb, up->udev,
10969f2d3eaeSJakob Unterwurzacher 			  usb_sndbulkpipe(up->udev,
10979f2d3eaeSJakob Unterwurzacher 					  up->out_ep_addr),
10989f2d3eaeSJakob Unterwurzacher 			  m, mlen, ucan_write_bulk_callback, context);
10999f2d3eaeSJakob Unterwurzacher 	urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
11009f2d3eaeSJakob Unterwurzacher 
11019f2d3eaeSJakob Unterwurzacher 	return urb;
11029f2d3eaeSJakob Unterwurzacher }
11039f2d3eaeSJakob Unterwurzacher 
11049f2d3eaeSJakob Unterwurzacher static void ucan_clean_up_tx_urb(struct ucan_priv *up, struct urb *urb)
11059f2d3eaeSJakob Unterwurzacher {
11069f2d3eaeSJakob Unterwurzacher 	usb_free_coherent(up->udev, sizeof(struct ucan_message_out),
11079f2d3eaeSJakob Unterwurzacher 			  urb->transfer_buffer, urb->transfer_dma);
11089f2d3eaeSJakob Unterwurzacher 	usb_free_urb(urb);
11099f2d3eaeSJakob Unterwurzacher }
11109f2d3eaeSJakob Unterwurzacher 
11119f2d3eaeSJakob Unterwurzacher /* callback when Linux needs to send a can frame */
11129f2d3eaeSJakob Unterwurzacher static netdev_tx_t ucan_start_xmit(struct sk_buff *skb,
11139f2d3eaeSJakob Unterwurzacher 				   struct net_device *netdev)
11149f2d3eaeSJakob Unterwurzacher {
11159f2d3eaeSJakob Unterwurzacher 	unsigned long flags;
11169f2d3eaeSJakob Unterwurzacher 	int ret;
11179f2d3eaeSJakob Unterwurzacher 	u8 echo_index;
11189f2d3eaeSJakob Unterwurzacher 	struct urb *urb;
11199f2d3eaeSJakob Unterwurzacher 	struct ucan_urb_context *context;
11209f2d3eaeSJakob Unterwurzacher 	struct ucan_priv *up = netdev_priv(netdev);
11219f2d3eaeSJakob Unterwurzacher 	struct can_frame *cf = (struct can_frame *)skb->data;
11229f2d3eaeSJakob Unterwurzacher 
11239f2d3eaeSJakob Unterwurzacher 	/* check skb */
11249f2d3eaeSJakob Unterwurzacher 	if (can_dropped_invalid_skb(netdev, skb))
11259f2d3eaeSJakob Unterwurzacher 		return NETDEV_TX_OK;
11269f2d3eaeSJakob Unterwurzacher 
11279f2d3eaeSJakob Unterwurzacher 	/* allocate a context and slow down tx path, if fifo state is low */
11289f2d3eaeSJakob Unterwurzacher 	context = ucan_alloc_context(up);
11299f2d3eaeSJakob Unterwurzacher 	echo_index = context - up->context_array;
11309f2d3eaeSJakob Unterwurzacher 
11319f2d3eaeSJakob Unterwurzacher 	if (WARN_ON_ONCE(!context))
11329f2d3eaeSJakob Unterwurzacher 		return NETDEV_TX_BUSY;
11339f2d3eaeSJakob Unterwurzacher 
11349f2d3eaeSJakob Unterwurzacher 	/* prepare urb for transmission */
11359f2d3eaeSJakob Unterwurzacher 	urb = ucan_prepare_tx_urb(up, context, cf, echo_index);
11369f2d3eaeSJakob Unterwurzacher 	if (!urb)
11379f2d3eaeSJakob Unterwurzacher 		goto drop;
11389f2d3eaeSJakob Unterwurzacher 
11399f2d3eaeSJakob Unterwurzacher 	/* put the skb on can loopback stack */
11409f2d3eaeSJakob Unterwurzacher 	spin_lock_irqsave(&up->echo_skb_lock, flags);
11411dcb6e57SVincent Mailhol 	can_put_echo_skb(skb, up->netdev, echo_index, 0);
11429f2d3eaeSJakob Unterwurzacher 	spin_unlock_irqrestore(&up->echo_skb_lock, flags);
11439f2d3eaeSJakob Unterwurzacher 
11449f2d3eaeSJakob Unterwurzacher 	/* transmit it */
11459f2d3eaeSJakob Unterwurzacher 	usb_anchor_urb(urb, &up->tx_urbs);
11469f2d3eaeSJakob Unterwurzacher 	ret = usb_submit_urb(urb, GFP_ATOMIC);
11479f2d3eaeSJakob Unterwurzacher 
11489f2d3eaeSJakob Unterwurzacher 	/* cleanup urb */
11499f2d3eaeSJakob Unterwurzacher 	if (ret) {
11509f2d3eaeSJakob Unterwurzacher 		/* on error, clean up */
11519f2d3eaeSJakob Unterwurzacher 		usb_unanchor_urb(urb);
11529f2d3eaeSJakob Unterwurzacher 		ucan_clean_up_tx_urb(up, urb);
11539f2d3eaeSJakob Unterwurzacher 		if (!ucan_release_context(up, context))
11549f2d3eaeSJakob Unterwurzacher 			netdev_err(up->netdev,
11559f2d3eaeSJakob Unterwurzacher 				   "xmit err: failed to release context\n");
11569f2d3eaeSJakob Unterwurzacher 
11579f2d3eaeSJakob Unterwurzacher 		/* remove the skb from the echo stack - this also
11589f2d3eaeSJakob Unterwurzacher 		 * frees the skb
11599f2d3eaeSJakob Unterwurzacher 		 */
11609f2d3eaeSJakob Unterwurzacher 		spin_lock_irqsave(&up->echo_skb_lock, flags);
1161f318482aSMarc Kleine-Budde 		can_free_echo_skb(up->netdev, echo_index, NULL);
11629f2d3eaeSJakob Unterwurzacher 		spin_unlock_irqrestore(&up->echo_skb_lock, flags);
11639f2d3eaeSJakob Unterwurzacher 
11649f2d3eaeSJakob Unterwurzacher 		if (ret == -ENODEV) {
11659f2d3eaeSJakob Unterwurzacher 			netif_device_detach(up->netdev);
11669f2d3eaeSJakob Unterwurzacher 		} else {
11679f2d3eaeSJakob Unterwurzacher 			netdev_warn(up->netdev,
11689f2d3eaeSJakob Unterwurzacher 				    "xmit err: failed to submit urb %d\n",
11699f2d3eaeSJakob Unterwurzacher 				    ret);
11709f2d3eaeSJakob Unterwurzacher 			up->netdev->stats.tx_dropped++;
11719f2d3eaeSJakob Unterwurzacher 		}
11729f2d3eaeSJakob Unterwurzacher 		return NETDEV_TX_OK;
11739f2d3eaeSJakob Unterwurzacher 	}
11749f2d3eaeSJakob Unterwurzacher 
11759f2d3eaeSJakob Unterwurzacher 	netif_trans_update(netdev);
11769f2d3eaeSJakob Unterwurzacher 
11779f2d3eaeSJakob Unterwurzacher 	/* release ref, as we do not need the urb anymore */
11789f2d3eaeSJakob Unterwurzacher 	usb_free_urb(urb);
11799f2d3eaeSJakob Unterwurzacher 
11809f2d3eaeSJakob Unterwurzacher 	return NETDEV_TX_OK;
11819f2d3eaeSJakob Unterwurzacher 
11829f2d3eaeSJakob Unterwurzacher drop:
11839f2d3eaeSJakob Unterwurzacher 	if (!ucan_release_context(up, context))
11849f2d3eaeSJakob Unterwurzacher 		netdev_err(up->netdev,
11859f2d3eaeSJakob Unterwurzacher 			   "xmit drop: failed to release context\n");
11869f2d3eaeSJakob Unterwurzacher 	dev_kfree_skb(skb);
11879f2d3eaeSJakob Unterwurzacher 	up->netdev->stats.tx_dropped++;
11889f2d3eaeSJakob Unterwurzacher 
11899f2d3eaeSJakob Unterwurzacher 	return NETDEV_TX_OK;
11909f2d3eaeSJakob Unterwurzacher }
11919f2d3eaeSJakob Unterwurzacher 
11929f2d3eaeSJakob Unterwurzacher /* Device goes down
11939f2d3eaeSJakob Unterwurzacher  *
11949f2d3eaeSJakob Unterwurzacher  * Clean up used resources
11959f2d3eaeSJakob Unterwurzacher  */
11969f2d3eaeSJakob Unterwurzacher static int ucan_close(struct net_device *netdev)
11979f2d3eaeSJakob Unterwurzacher {
11989f2d3eaeSJakob Unterwurzacher 	int ret;
11999f2d3eaeSJakob Unterwurzacher 	struct ucan_priv *up = netdev_priv(netdev);
12009f2d3eaeSJakob Unterwurzacher 
12019f2d3eaeSJakob Unterwurzacher 	up->can.state = CAN_STATE_STOPPED;
12029f2d3eaeSJakob Unterwurzacher 
12039f2d3eaeSJakob Unterwurzacher 	/* stop sending data */
12049f2d3eaeSJakob Unterwurzacher 	usb_kill_anchored_urbs(&up->tx_urbs);
12059f2d3eaeSJakob Unterwurzacher 
12069f2d3eaeSJakob Unterwurzacher 	/* stop receiving data */
12079f2d3eaeSJakob Unterwurzacher 	usb_kill_anchored_urbs(&up->rx_urbs);
12089f2d3eaeSJakob Unterwurzacher 
12099f2d3eaeSJakob Unterwurzacher 	/* stop and reset can device */
12109f2d3eaeSJakob Unterwurzacher 	ret = ucan_ctrl_command_out(up, UCAN_COMMAND_STOP, 0, 0);
12119f2d3eaeSJakob Unterwurzacher 	if (ret < 0)
12129f2d3eaeSJakob Unterwurzacher 		netdev_err(up->netdev,
12139f2d3eaeSJakob Unterwurzacher 			   "could not stop device, code: %d\n",
12149f2d3eaeSJakob Unterwurzacher 			   ret);
12159f2d3eaeSJakob Unterwurzacher 
12169f2d3eaeSJakob Unterwurzacher 	ret = ucan_ctrl_command_out(up, UCAN_COMMAND_RESET, 0, 0);
12179f2d3eaeSJakob Unterwurzacher 	if (ret < 0)
12189f2d3eaeSJakob Unterwurzacher 		netdev_err(up->netdev,
12199f2d3eaeSJakob Unterwurzacher 			   "could not reset device, code: %d\n",
12209f2d3eaeSJakob Unterwurzacher 			   ret);
12219f2d3eaeSJakob Unterwurzacher 
12229f2d3eaeSJakob Unterwurzacher 	netif_stop_queue(netdev);
12239f2d3eaeSJakob Unterwurzacher 
12249f2d3eaeSJakob Unterwurzacher 	ucan_release_context_array(up);
12259f2d3eaeSJakob Unterwurzacher 
12269f2d3eaeSJakob Unterwurzacher 	close_candev(up->netdev);
12279f2d3eaeSJakob Unterwurzacher 	return 0;
12289f2d3eaeSJakob Unterwurzacher }
12299f2d3eaeSJakob Unterwurzacher 
12309f2d3eaeSJakob Unterwurzacher /* CAN driver callbacks */
12319f2d3eaeSJakob Unterwurzacher static const struct net_device_ops ucan_netdev_ops = {
12329f2d3eaeSJakob Unterwurzacher 	.ndo_open = ucan_open,
12339f2d3eaeSJakob Unterwurzacher 	.ndo_stop = ucan_close,
12349f2d3eaeSJakob Unterwurzacher 	.ndo_start_xmit = ucan_start_xmit,
12359f2d3eaeSJakob Unterwurzacher 	.ndo_change_mtu = can_change_mtu,
12369f2d3eaeSJakob Unterwurzacher };
12379f2d3eaeSJakob Unterwurzacher 
1238409c188cSVincent Mailhol static const struct ethtool_ops ucan_ethtool_ops = {
1239409c188cSVincent Mailhol 	.get_ts_info = ethtool_op_get_ts_info,
1240409c188cSVincent Mailhol };
1241409c188cSVincent Mailhol 
12429f2d3eaeSJakob Unterwurzacher /* Request to set bittiming
12439f2d3eaeSJakob Unterwurzacher  *
12449f2d3eaeSJakob Unterwurzacher  * This function generates an USB set bittiming message and transmits
12459f2d3eaeSJakob Unterwurzacher  * it to the device
12469f2d3eaeSJakob Unterwurzacher  */
12479f2d3eaeSJakob Unterwurzacher static int ucan_set_bittiming(struct net_device *netdev)
12489f2d3eaeSJakob Unterwurzacher {
12499f2d3eaeSJakob Unterwurzacher 	int ret;
12509f2d3eaeSJakob Unterwurzacher 	struct ucan_priv *up = netdev_priv(netdev);
12519f2d3eaeSJakob Unterwurzacher 	struct ucan_ctl_cmd_set_bittiming *cmd_set_bittiming;
12529f2d3eaeSJakob Unterwurzacher 
12539f2d3eaeSJakob Unterwurzacher 	cmd_set_bittiming = &up->ctl_msg_buffer->cmd_set_bittiming;
12549f2d3eaeSJakob Unterwurzacher 	cmd_set_bittiming->tq = cpu_to_le32(up->can.bittiming.tq);
12559f2d3eaeSJakob Unterwurzacher 	cmd_set_bittiming->brp = cpu_to_le16(up->can.bittiming.brp);
12569f2d3eaeSJakob Unterwurzacher 	cmd_set_bittiming->sample_point =
12579f2d3eaeSJakob Unterwurzacher 	    cpu_to_le16(up->can.bittiming.sample_point);
12589f2d3eaeSJakob Unterwurzacher 	cmd_set_bittiming->prop_seg = up->can.bittiming.prop_seg;
12599f2d3eaeSJakob Unterwurzacher 	cmd_set_bittiming->phase_seg1 = up->can.bittiming.phase_seg1;
12609f2d3eaeSJakob Unterwurzacher 	cmd_set_bittiming->phase_seg2 = up->can.bittiming.phase_seg2;
12619f2d3eaeSJakob Unterwurzacher 	cmd_set_bittiming->sjw = up->can.bittiming.sjw;
12629f2d3eaeSJakob Unterwurzacher 
12639f2d3eaeSJakob Unterwurzacher 	ret = ucan_ctrl_command_out(up, UCAN_COMMAND_SET_BITTIMING, 0,
12649f2d3eaeSJakob Unterwurzacher 				    sizeof(*cmd_set_bittiming));
12659f2d3eaeSJakob Unterwurzacher 	return (ret < 0) ? ret : 0;
12669f2d3eaeSJakob Unterwurzacher }
12679f2d3eaeSJakob Unterwurzacher 
12689f2d3eaeSJakob Unterwurzacher /* Restart the device to get it out of BUS-OFF state.
12699f2d3eaeSJakob Unterwurzacher  * Called when the user runs "ip link set can1 type can restart".
12709f2d3eaeSJakob Unterwurzacher  */
12719f2d3eaeSJakob Unterwurzacher static int ucan_set_mode(struct net_device *netdev, enum can_mode mode)
12729f2d3eaeSJakob Unterwurzacher {
12739f2d3eaeSJakob Unterwurzacher 	int ret;
12749f2d3eaeSJakob Unterwurzacher 	unsigned long flags;
12759f2d3eaeSJakob Unterwurzacher 	struct ucan_priv *up = netdev_priv(netdev);
12769f2d3eaeSJakob Unterwurzacher 
12779f2d3eaeSJakob Unterwurzacher 	switch (mode) {
12789f2d3eaeSJakob Unterwurzacher 	case CAN_MODE_START:
12799f2d3eaeSJakob Unterwurzacher 		netdev_dbg(up->netdev, "restarting device\n");
12809f2d3eaeSJakob Unterwurzacher 
12819f2d3eaeSJakob Unterwurzacher 		ret = ucan_ctrl_command_out(up, UCAN_COMMAND_RESTART, 0, 0);
12829f2d3eaeSJakob Unterwurzacher 		up->can.state = CAN_STATE_ERROR_ACTIVE;
12839f2d3eaeSJakob Unterwurzacher 
12849f2d3eaeSJakob Unterwurzacher 		/* check if queue can be restarted,
12859f2d3eaeSJakob Unterwurzacher 		 * up->available_tx_urbs must be protected by the
12869f2d3eaeSJakob Unterwurzacher 		 * lock
12879f2d3eaeSJakob Unterwurzacher 		 */
12889f2d3eaeSJakob Unterwurzacher 		spin_lock_irqsave(&up->context_lock, flags);
12899f2d3eaeSJakob Unterwurzacher 
12909f2d3eaeSJakob Unterwurzacher 		if (up->available_tx_urbs > 0)
12919f2d3eaeSJakob Unterwurzacher 			netif_wake_queue(up->netdev);
12929f2d3eaeSJakob Unterwurzacher 
12939f2d3eaeSJakob Unterwurzacher 		spin_unlock_irqrestore(&up->context_lock, flags);
12949f2d3eaeSJakob Unterwurzacher 
12959f2d3eaeSJakob Unterwurzacher 		return ret;
12969f2d3eaeSJakob Unterwurzacher 	default:
12979f2d3eaeSJakob Unterwurzacher 		return -EOPNOTSUPP;
12989f2d3eaeSJakob Unterwurzacher 	}
12999f2d3eaeSJakob Unterwurzacher }
13009f2d3eaeSJakob Unterwurzacher 
13019f2d3eaeSJakob Unterwurzacher /* Probe the device, reset it and gather general device information */
13029f2d3eaeSJakob Unterwurzacher static int ucan_probe(struct usb_interface *intf,
13039f2d3eaeSJakob Unterwurzacher 		      const struct usb_device_id *id)
13049f2d3eaeSJakob Unterwurzacher {
13059f2d3eaeSJakob Unterwurzacher 	int ret;
13069f2d3eaeSJakob Unterwurzacher 	int i;
13079f2d3eaeSJakob Unterwurzacher 	u32 protocol_version;
13089f2d3eaeSJakob Unterwurzacher 	struct usb_device *udev;
13099f2d3eaeSJakob Unterwurzacher 	struct net_device *netdev;
13109f2d3eaeSJakob Unterwurzacher 	struct usb_host_interface *iface_desc;
13119f2d3eaeSJakob Unterwurzacher 	struct ucan_priv *up;
13129f2d3eaeSJakob Unterwurzacher 	struct usb_endpoint_descriptor *ep;
13139f2d3eaeSJakob Unterwurzacher 	u16 in_ep_size;
13149f2d3eaeSJakob Unterwurzacher 	u16 out_ep_size;
13159f2d3eaeSJakob Unterwurzacher 	u8 in_ep_addr;
13169f2d3eaeSJakob Unterwurzacher 	u8 out_ep_addr;
13179f2d3eaeSJakob Unterwurzacher 	union ucan_ctl_payload *ctl_msg_buffer;
13189f2d3eaeSJakob Unterwurzacher 	char firmware_str[sizeof(union ucan_ctl_payload) + 1];
13199f2d3eaeSJakob Unterwurzacher 
13209f2d3eaeSJakob Unterwurzacher 	udev = interface_to_usbdev(intf);
13219f2d3eaeSJakob Unterwurzacher 
13229f2d3eaeSJakob Unterwurzacher 	/* Stage 1 - Interface Parsing
13239f2d3eaeSJakob Unterwurzacher 	 * ---------------------------
13249f2d3eaeSJakob Unterwurzacher 	 *
13259f2d3eaeSJakob Unterwurzacher 	 * Identifie the device USB interface descriptor and its
13269f2d3eaeSJakob Unterwurzacher 	 * endpoints. Probing is aborted on errors.
13279f2d3eaeSJakob Unterwurzacher 	 */
13289f2d3eaeSJakob Unterwurzacher 
13299f2d3eaeSJakob Unterwurzacher 	/* check if the interface is sane */
13309f2d3eaeSJakob Unterwurzacher 	iface_desc = intf->cur_altsetting;
13319f2d3eaeSJakob Unterwurzacher 	if (!iface_desc)
13329f2d3eaeSJakob Unterwurzacher 		return -ENODEV;
13339f2d3eaeSJakob Unterwurzacher 
13349f2d3eaeSJakob Unterwurzacher 	dev_info(&udev->dev,
13359f2d3eaeSJakob Unterwurzacher 		 "%s: probing device on interface #%d\n",
13369f2d3eaeSJakob Unterwurzacher 		 UCAN_DRIVER_NAME,
13379f2d3eaeSJakob Unterwurzacher 		 iface_desc->desc.bInterfaceNumber);
13389f2d3eaeSJakob Unterwurzacher 
13399f2d3eaeSJakob Unterwurzacher 	/* interface sanity check */
13409f2d3eaeSJakob Unterwurzacher 	if (iface_desc->desc.bNumEndpoints != 2) {
13419f2d3eaeSJakob Unterwurzacher 		dev_err(&udev->dev,
13429f2d3eaeSJakob Unterwurzacher 			"%s: invalid EP count (%d)",
13439f2d3eaeSJakob Unterwurzacher 			UCAN_DRIVER_NAME, iface_desc->desc.bNumEndpoints);
13449f2d3eaeSJakob Unterwurzacher 		goto err_firmware_needs_update;
13459f2d3eaeSJakob Unterwurzacher 	}
13469f2d3eaeSJakob Unterwurzacher 
13479f2d3eaeSJakob Unterwurzacher 	/* check interface endpoints */
13489f2d3eaeSJakob Unterwurzacher 	in_ep_addr = 0;
13499f2d3eaeSJakob Unterwurzacher 	out_ep_addr = 0;
13509f2d3eaeSJakob Unterwurzacher 	in_ep_size = 0;
13519f2d3eaeSJakob Unterwurzacher 	out_ep_size = 0;
13529f2d3eaeSJakob Unterwurzacher 	for (i = 0; i < iface_desc->desc.bNumEndpoints; i++) {
13539f2d3eaeSJakob Unterwurzacher 		ep = &iface_desc->endpoint[i].desc;
13549f2d3eaeSJakob Unterwurzacher 
13559f2d3eaeSJakob Unterwurzacher 		if (((ep->bEndpointAddress & USB_ENDPOINT_DIR_MASK) != 0) &&
13569f2d3eaeSJakob Unterwurzacher 		    ((ep->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) ==
13579f2d3eaeSJakob Unterwurzacher 		     USB_ENDPOINT_XFER_BULK)) {
13589f2d3eaeSJakob Unterwurzacher 			/* In Endpoint */
13599f2d3eaeSJakob Unterwurzacher 			in_ep_addr = ep->bEndpointAddress;
13609f2d3eaeSJakob Unterwurzacher 			in_ep_addr &= USB_ENDPOINT_NUMBER_MASK;
13619f2d3eaeSJakob Unterwurzacher 			in_ep_size = le16_to_cpu(ep->wMaxPacketSize);
13629f2d3eaeSJakob Unterwurzacher 		} else if (((ep->bEndpointAddress & USB_ENDPOINT_DIR_MASK) ==
13639f2d3eaeSJakob Unterwurzacher 			    0) &&
13649f2d3eaeSJakob Unterwurzacher 			   ((ep->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) ==
13659f2d3eaeSJakob Unterwurzacher 			    USB_ENDPOINT_XFER_BULK)) {
13669f2d3eaeSJakob Unterwurzacher 			/* Out Endpoint */
13679f2d3eaeSJakob Unterwurzacher 			out_ep_addr = ep->bEndpointAddress;
13689f2d3eaeSJakob Unterwurzacher 			out_ep_addr &= USB_ENDPOINT_NUMBER_MASK;
13699f2d3eaeSJakob Unterwurzacher 			out_ep_size = le16_to_cpu(ep->wMaxPacketSize);
13709f2d3eaeSJakob Unterwurzacher 		}
13719f2d3eaeSJakob Unterwurzacher 	}
13729f2d3eaeSJakob Unterwurzacher 
13739f2d3eaeSJakob Unterwurzacher 	/* check if interface is sane */
13749f2d3eaeSJakob Unterwurzacher 	if (!in_ep_addr || !out_ep_addr) {
13759f2d3eaeSJakob Unterwurzacher 		dev_err(&udev->dev, "%s: invalid endpoint configuration\n",
13769f2d3eaeSJakob Unterwurzacher 			UCAN_DRIVER_NAME);
13779f2d3eaeSJakob Unterwurzacher 		goto err_firmware_needs_update;
13789f2d3eaeSJakob Unterwurzacher 	}
13799f2d3eaeSJakob Unterwurzacher 	if (in_ep_size < sizeof(struct ucan_message_in)) {
13809f2d3eaeSJakob Unterwurzacher 		dev_err(&udev->dev, "%s: invalid in_ep MaxPacketSize\n",
13819f2d3eaeSJakob Unterwurzacher 			UCAN_DRIVER_NAME);
13829f2d3eaeSJakob Unterwurzacher 		goto err_firmware_needs_update;
13839f2d3eaeSJakob Unterwurzacher 	}
13849f2d3eaeSJakob Unterwurzacher 	if (out_ep_size < sizeof(struct ucan_message_out)) {
13859f2d3eaeSJakob Unterwurzacher 		dev_err(&udev->dev, "%s: invalid out_ep MaxPacketSize\n",
13869f2d3eaeSJakob Unterwurzacher 			UCAN_DRIVER_NAME);
13879f2d3eaeSJakob Unterwurzacher 		goto err_firmware_needs_update;
13889f2d3eaeSJakob Unterwurzacher 	}
13899f2d3eaeSJakob Unterwurzacher 
13909f2d3eaeSJakob Unterwurzacher 	/* Stage 2 - Device Identification
13919f2d3eaeSJakob Unterwurzacher 	 * -------------------------------
13929f2d3eaeSJakob Unterwurzacher 	 *
13939f2d3eaeSJakob Unterwurzacher 	 * The device interface seems to be a ucan device. Do further
13949f2d3eaeSJakob Unterwurzacher 	 * compatibility checks. On error probing is aborted, on
13959f2d3eaeSJakob Unterwurzacher 	 * success this stage leaves the ctl_msg_buffer with the
13969f2d3eaeSJakob Unterwurzacher 	 * reported contents of a GET_INFO command (supported
13979f2d3eaeSJakob Unterwurzacher 	 * bittimings, tx_fifo depth). This information is used in
13989f2d3eaeSJakob Unterwurzacher 	 * Stage 3 for the final driver initialisation.
13999f2d3eaeSJakob Unterwurzacher 	 */
14009f2d3eaeSJakob Unterwurzacher 
1401c34983c9SJulia Lawall 	/* Prepare Memory for control transfers */
14029f2d3eaeSJakob Unterwurzacher 	ctl_msg_buffer = devm_kzalloc(&udev->dev,
14039f2d3eaeSJakob Unterwurzacher 				      sizeof(union ucan_ctl_payload),
14049f2d3eaeSJakob Unterwurzacher 				      GFP_KERNEL);
14059f2d3eaeSJakob Unterwurzacher 	if (!ctl_msg_buffer) {
14069f2d3eaeSJakob Unterwurzacher 		dev_err(&udev->dev,
14079f2d3eaeSJakob Unterwurzacher 			"%s: failed to allocate control pipe memory\n",
14089f2d3eaeSJakob Unterwurzacher 			UCAN_DRIVER_NAME);
14099f2d3eaeSJakob Unterwurzacher 		return -ENOMEM;
14109f2d3eaeSJakob Unterwurzacher 	}
14119f2d3eaeSJakob Unterwurzacher 
14129f2d3eaeSJakob Unterwurzacher 	/* get protocol version
14139f2d3eaeSJakob Unterwurzacher 	 *
14149f2d3eaeSJakob Unterwurzacher 	 * note: ucan_ctrl_command_* wrappers cannot be used yet
14159f2d3eaeSJakob Unterwurzacher 	 * because `up` is initialised in Stage 3
14169f2d3eaeSJakob Unterwurzacher 	 */
14179f2d3eaeSJakob Unterwurzacher 	ret = usb_control_msg(udev,
14189f2d3eaeSJakob Unterwurzacher 			      usb_rcvctrlpipe(udev, 0),
14199f2d3eaeSJakob Unterwurzacher 			      UCAN_COMMAND_GET,
14209f2d3eaeSJakob Unterwurzacher 			      USB_DIR_IN | USB_TYPE_VENDOR |
14219f2d3eaeSJakob Unterwurzacher 					USB_RECIP_INTERFACE,
14229f2d3eaeSJakob Unterwurzacher 			      UCAN_COMMAND_GET_PROTOCOL_VERSION,
14239f2d3eaeSJakob Unterwurzacher 			      iface_desc->desc.bInterfaceNumber,
14249f2d3eaeSJakob Unterwurzacher 			      ctl_msg_buffer,
14259f2d3eaeSJakob Unterwurzacher 			      sizeof(union ucan_ctl_payload),
14269f2d3eaeSJakob Unterwurzacher 			      UCAN_USB_CTL_PIPE_TIMEOUT);
14279f2d3eaeSJakob Unterwurzacher 
14289f2d3eaeSJakob Unterwurzacher 	/* older firmware version do not support this command - those
14299f2d3eaeSJakob Unterwurzacher 	 * are not supported by this drive
14309f2d3eaeSJakob Unterwurzacher 	 */
14319f2d3eaeSJakob Unterwurzacher 	if (ret != 4) {
14329f2d3eaeSJakob Unterwurzacher 		dev_err(&udev->dev,
14339f2d3eaeSJakob Unterwurzacher 			"%s: could not read protocol version, ret=%d\n",
14349f2d3eaeSJakob Unterwurzacher 			UCAN_DRIVER_NAME, ret);
14359f2d3eaeSJakob Unterwurzacher 		if (ret >= 0)
14369f2d3eaeSJakob Unterwurzacher 			ret = -EINVAL;
14379f2d3eaeSJakob Unterwurzacher 		goto err_firmware_needs_update;
14389f2d3eaeSJakob Unterwurzacher 	}
14399f2d3eaeSJakob Unterwurzacher 
14409f2d3eaeSJakob Unterwurzacher 	/* this driver currently supports protocol version 3 only */
14419f2d3eaeSJakob Unterwurzacher 	protocol_version =
14429f2d3eaeSJakob Unterwurzacher 		le32_to_cpu(ctl_msg_buffer->cmd_get_protocol_version.version);
14439f2d3eaeSJakob Unterwurzacher 	if (protocol_version < UCAN_PROTOCOL_VERSION_MIN ||
14449f2d3eaeSJakob Unterwurzacher 	    protocol_version > UCAN_PROTOCOL_VERSION_MAX) {
14459f2d3eaeSJakob Unterwurzacher 		dev_err(&udev->dev,
14469f2d3eaeSJakob Unterwurzacher 			"%s: device protocol version %d is not supported\n",
14479f2d3eaeSJakob Unterwurzacher 			UCAN_DRIVER_NAME, protocol_version);
14489f2d3eaeSJakob Unterwurzacher 		goto err_firmware_needs_update;
14499f2d3eaeSJakob Unterwurzacher 	}
14509f2d3eaeSJakob Unterwurzacher 
14519f2d3eaeSJakob Unterwurzacher 	/* request the device information and store it in ctl_msg_buffer
14529f2d3eaeSJakob Unterwurzacher 	 *
145388bfb9a7SMarc Kleine-Budde 	 * note: ucan_ctrl_command_* wrappers cannot be used yet
14549f2d3eaeSJakob Unterwurzacher 	 * because `up` is initialised in Stage 3
14559f2d3eaeSJakob Unterwurzacher 	 */
14569f2d3eaeSJakob Unterwurzacher 	ret = usb_control_msg(udev,
14579f2d3eaeSJakob Unterwurzacher 			      usb_rcvctrlpipe(udev, 0),
14589f2d3eaeSJakob Unterwurzacher 			      UCAN_COMMAND_GET,
14599f2d3eaeSJakob Unterwurzacher 			      USB_DIR_IN | USB_TYPE_VENDOR |
14609f2d3eaeSJakob Unterwurzacher 					USB_RECIP_INTERFACE,
14619f2d3eaeSJakob Unterwurzacher 			      UCAN_COMMAND_GET_INFO,
14629f2d3eaeSJakob Unterwurzacher 			      iface_desc->desc.bInterfaceNumber,
14639f2d3eaeSJakob Unterwurzacher 			      ctl_msg_buffer,
14649f2d3eaeSJakob Unterwurzacher 			      sizeof(ctl_msg_buffer->cmd_get_device_info),
14659f2d3eaeSJakob Unterwurzacher 			      UCAN_USB_CTL_PIPE_TIMEOUT);
14669f2d3eaeSJakob Unterwurzacher 
14679f2d3eaeSJakob Unterwurzacher 	if (ret < 0) {
14689f2d3eaeSJakob Unterwurzacher 		dev_err(&udev->dev, "%s: failed to retrieve device info\n",
14699f2d3eaeSJakob Unterwurzacher 			UCAN_DRIVER_NAME);
14709f2d3eaeSJakob Unterwurzacher 		goto err_firmware_needs_update;
14719f2d3eaeSJakob Unterwurzacher 	}
14729f2d3eaeSJakob Unterwurzacher 	if (ret < sizeof(ctl_msg_buffer->cmd_get_device_info)) {
14739f2d3eaeSJakob Unterwurzacher 		dev_err(&udev->dev, "%s: device reported invalid device info\n",
14749f2d3eaeSJakob Unterwurzacher 			UCAN_DRIVER_NAME);
14759f2d3eaeSJakob Unterwurzacher 		goto err_firmware_needs_update;
14769f2d3eaeSJakob Unterwurzacher 	}
14779f2d3eaeSJakob Unterwurzacher 	if (ctl_msg_buffer->cmd_get_device_info.tx_fifo == 0) {
14789f2d3eaeSJakob Unterwurzacher 		dev_err(&udev->dev,
14799f2d3eaeSJakob Unterwurzacher 			"%s: device reported invalid tx-fifo size\n",
14809f2d3eaeSJakob Unterwurzacher 			UCAN_DRIVER_NAME);
14819f2d3eaeSJakob Unterwurzacher 		goto err_firmware_needs_update;
14829f2d3eaeSJakob Unterwurzacher 	}
14839f2d3eaeSJakob Unterwurzacher 
14849f2d3eaeSJakob Unterwurzacher 	/* Stage 3 - Driver Initialisation
14859f2d3eaeSJakob Unterwurzacher 	 * -------------------------------
14869f2d3eaeSJakob Unterwurzacher 	 *
14879f2d3eaeSJakob Unterwurzacher 	 * Register device to Linux, prepare private structures and
14889f2d3eaeSJakob Unterwurzacher 	 * reset the device.
14899f2d3eaeSJakob Unterwurzacher 	 */
14909f2d3eaeSJakob Unterwurzacher 
14919f2d3eaeSJakob Unterwurzacher 	/* allocate driver resources */
14929f2d3eaeSJakob Unterwurzacher 	netdev = alloc_candev(sizeof(struct ucan_priv),
14939f2d3eaeSJakob Unterwurzacher 			      ctl_msg_buffer->cmd_get_device_info.tx_fifo);
14949f2d3eaeSJakob Unterwurzacher 	if (!netdev) {
14959f2d3eaeSJakob Unterwurzacher 		dev_err(&udev->dev,
14969f2d3eaeSJakob Unterwurzacher 			"%s: cannot allocate candev\n", UCAN_DRIVER_NAME);
14979f2d3eaeSJakob Unterwurzacher 		return -ENOMEM;
14989f2d3eaeSJakob Unterwurzacher 	}
14999f2d3eaeSJakob Unterwurzacher 
15009f2d3eaeSJakob Unterwurzacher 	up = netdev_priv(netdev);
15019f2d3eaeSJakob Unterwurzacher 
150288bfb9a7SMarc Kleine-Budde 	/* initialize data */
15039f2d3eaeSJakob Unterwurzacher 	up->udev = udev;
15049f2d3eaeSJakob Unterwurzacher 	up->intf = intf;
15059f2d3eaeSJakob Unterwurzacher 	up->netdev = netdev;
15069f2d3eaeSJakob Unterwurzacher 	up->intf_index = iface_desc->desc.bInterfaceNumber;
15079f2d3eaeSJakob Unterwurzacher 	up->in_ep_addr = in_ep_addr;
15089f2d3eaeSJakob Unterwurzacher 	up->out_ep_addr = out_ep_addr;
15099f2d3eaeSJakob Unterwurzacher 	up->in_ep_size = in_ep_size;
15109f2d3eaeSJakob Unterwurzacher 	up->ctl_msg_buffer = ctl_msg_buffer;
15119f2d3eaeSJakob Unterwurzacher 	up->context_array = NULL;
15129f2d3eaeSJakob Unterwurzacher 	up->available_tx_urbs = 0;
15139f2d3eaeSJakob Unterwurzacher 
15149f2d3eaeSJakob Unterwurzacher 	up->can.state = CAN_STATE_STOPPED;
15159f2d3eaeSJakob Unterwurzacher 	up->can.bittiming_const = &up->device_info.bittiming_const;
15169f2d3eaeSJakob Unterwurzacher 	up->can.do_set_bittiming = ucan_set_bittiming;
15179f2d3eaeSJakob Unterwurzacher 	up->can.do_set_mode = &ucan_set_mode;
15189f2d3eaeSJakob Unterwurzacher 	spin_lock_init(&up->context_lock);
15199f2d3eaeSJakob Unterwurzacher 	spin_lock_init(&up->echo_skb_lock);
15209f2d3eaeSJakob Unterwurzacher 	netdev->netdev_ops = &ucan_netdev_ops;
1521409c188cSVincent Mailhol 	netdev->ethtool_ops = &ucan_ethtool_ops;
15229f2d3eaeSJakob Unterwurzacher 
15239f2d3eaeSJakob Unterwurzacher 	usb_set_intfdata(intf, up);
15249f2d3eaeSJakob Unterwurzacher 	SET_NETDEV_DEV(netdev, &intf->dev);
15259f2d3eaeSJakob Unterwurzacher 
15269f2d3eaeSJakob Unterwurzacher 	/* parse device information
15279f2d3eaeSJakob Unterwurzacher 	 * the data retrieved in Stage 2 is still available in
15289f2d3eaeSJakob Unterwurzacher 	 * up->ctl_msg_buffer
15299f2d3eaeSJakob Unterwurzacher 	 */
15309f2d3eaeSJakob Unterwurzacher 	ucan_parse_device_info(up, &ctl_msg_buffer->cmd_get_device_info);
15319f2d3eaeSJakob Unterwurzacher 
15329f2d3eaeSJakob Unterwurzacher 	/* just print some device information - if available */
15339f2d3eaeSJakob Unterwurzacher 	ret = ucan_device_request_in(up, UCAN_DEVICE_GET_FW_STRING, 0,
15349f2d3eaeSJakob Unterwurzacher 				     sizeof(union ucan_ctl_payload));
15359f2d3eaeSJakob Unterwurzacher 	if (ret > 0) {
1536c34983c9SJulia Lawall 		/* copy string while ensuring zero termination */
15379f2d3eaeSJakob Unterwurzacher 		strncpy(firmware_str, up->ctl_msg_buffer->raw,
15389f2d3eaeSJakob Unterwurzacher 			sizeof(union ucan_ctl_payload));
15399f2d3eaeSJakob Unterwurzacher 		firmware_str[sizeof(union ucan_ctl_payload)] = '\0';
15409f2d3eaeSJakob Unterwurzacher 	} else {
15419f2d3eaeSJakob Unterwurzacher 		strcpy(firmware_str, "unknown");
15429f2d3eaeSJakob Unterwurzacher 	}
15439f2d3eaeSJakob Unterwurzacher 
15449f2d3eaeSJakob Unterwurzacher 	/* device is compatible, reset it */
15459f2d3eaeSJakob Unterwurzacher 	ret = ucan_ctrl_command_out(up, UCAN_COMMAND_RESET, 0, 0);
15469f2d3eaeSJakob Unterwurzacher 	if (ret < 0)
15479f2d3eaeSJakob Unterwurzacher 		goto err_free_candev;
15489f2d3eaeSJakob Unterwurzacher 
15499f2d3eaeSJakob Unterwurzacher 	init_usb_anchor(&up->rx_urbs);
15509f2d3eaeSJakob Unterwurzacher 	init_usb_anchor(&up->tx_urbs);
15519f2d3eaeSJakob Unterwurzacher 
15529f2d3eaeSJakob Unterwurzacher 	up->can.state = CAN_STATE_STOPPED;
15539f2d3eaeSJakob Unterwurzacher 
15549f2d3eaeSJakob Unterwurzacher 	/* register the device */
15559f2d3eaeSJakob Unterwurzacher 	ret = register_candev(netdev);
15569f2d3eaeSJakob Unterwurzacher 	if (ret)
15579f2d3eaeSJakob Unterwurzacher 		goto err_free_candev;
15589f2d3eaeSJakob Unterwurzacher 
15599f2d3eaeSJakob Unterwurzacher 	/* initialisation complete, log device info */
15609f2d3eaeSJakob Unterwurzacher 	netdev_info(up->netdev, "registered device\n");
15619f2d3eaeSJakob Unterwurzacher 	netdev_info(up->netdev, "firmware string: %s\n", firmware_str);
15629f2d3eaeSJakob Unterwurzacher 
15639f2d3eaeSJakob Unterwurzacher 	/* success */
15649f2d3eaeSJakob Unterwurzacher 	return 0;
15659f2d3eaeSJakob Unterwurzacher 
15669f2d3eaeSJakob Unterwurzacher err_free_candev:
15679f2d3eaeSJakob Unterwurzacher 	free_candev(netdev);
15689f2d3eaeSJakob Unterwurzacher 	return ret;
15699f2d3eaeSJakob Unterwurzacher 
15709f2d3eaeSJakob Unterwurzacher err_firmware_needs_update:
15719f2d3eaeSJakob Unterwurzacher 	dev_err(&udev->dev,
15729f2d3eaeSJakob Unterwurzacher 		"%s: probe failed; try to update the device firmware\n",
15739f2d3eaeSJakob Unterwurzacher 		UCAN_DRIVER_NAME);
15749f2d3eaeSJakob Unterwurzacher 	return -ENODEV;
15759f2d3eaeSJakob Unterwurzacher }
15769f2d3eaeSJakob Unterwurzacher 
15779f2d3eaeSJakob Unterwurzacher /* disconnect the device */
15789f2d3eaeSJakob Unterwurzacher static void ucan_disconnect(struct usb_interface *intf)
15799f2d3eaeSJakob Unterwurzacher {
15809f2d3eaeSJakob Unterwurzacher 	struct ucan_priv *up = usb_get_intfdata(intf);
15819f2d3eaeSJakob Unterwurzacher 
15829f2d3eaeSJakob Unterwurzacher 	usb_set_intfdata(intf, NULL);
15839f2d3eaeSJakob Unterwurzacher 
15849f2d3eaeSJakob Unterwurzacher 	if (up) {
1585*aa9832e4SDongliang Mu 		unregister_candev(up->netdev);
15869f2d3eaeSJakob Unterwurzacher 		free_candev(up->netdev);
15879f2d3eaeSJakob Unterwurzacher 	}
15889f2d3eaeSJakob Unterwurzacher }
15899f2d3eaeSJakob Unterwurzacher 
15909f2d3eaeSJakob Unterwurzacher static struct usb_device_id ucan_table[] = {
15919f2d3eaeSJakob Unterwurzacher 	/* Mule (soldered onto compute modules) */
15929f2d3eaeSJakob Unterwurzacher 	{USB_DEVICE_INTERFACE_NUMBER(0x2294, 0x425a, 0)},
15939f2d3eaeSJakob Unterwurzacher 	/* Seal (standalone USB stick) */
15949f2d3eaeSJakob Unterwurzacher 	{USB_DEVICE_INTERFACE_NUMBER(0x2294, 0x425b, 0)},
15959f2d3eaeSJakob Unterwurzacher 	{} /* Terminating entry */
15969f2d3eaeSJakob Unterwurzacher };
15979f2d3eaeSJakob Unterwurzacher 
15989f2d3eaeSJakob Unterwurzacher MODULE_DEVICE_TABLE(usb, ucan_table);
15999f2d3eaeSJakob Unterwurzacher /* driver callbacks */
16009f2d3eaeSJakob Unterwurzacher static struct usb_driver ucan_driver = {
16019f2d3eaeSJakob Unterwurzacher 	.name = UCAN_DRIVER_NAME,
16029f2d3eaeSJakob Unterwurzacher 	.probe = ucan_probe,
16039f2d3eaeSJakob Unterwurzacher 	.disconnect = ucan_disconnect,
16049f2d3eaeSJakob Unterwurzacher 	.id_table = ucan_table,
16059f2d3eaeSJakob Unterwurzacher };
16069f2d3eaeSJakob Unterwurzacher 
16079f2d3eaeSJakob Unterwurzacher module_usb_driver(ucan_driver);
16089f2d3eaeSJakob Unterwurzacher 
16099f2d3eaeSJakob Unterwurzacher MODULE_LICENSE("GPL v2");
16109f2d3eaeSJakob Unterwurzacher MODULE_AUTHOR("Martin Elshuber <martin.elshuber@theobroma-systems.com>");
16119f2d3eaeSJakob Unterwurzacher MODULE_AUTHOR("Jakob Unterwurzacher <jakob.unterwurzacher@theobroma-systems.com>");
16129f2d3eaeSJakob Unterwurzacher MODULE_DESCRIPTION("Driver for Theobroma Systems UCAN devices");
1613