162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * CAN driver for "8 devices" USB2CAN converter
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Copyright (C) 2012 Bernd Krumboeck (krumboeck@universalnet.at)
662306a36Sopenharmony_ci *
762306a36Sopenharmony_ci * This driver is inspired by the 3.2.0 version of drivers/net/can/usb/ems_usb.c
862306a36Sopenharmony_ci * and drivers/net/can/usb/esd_usb2.c
962306a36Sopenharmony_ci *
1062306a36Sopenharmony_ci * Many thanks to Gerhard Bertelsmann (info@gerhard-bertelsmann.de)
1162306a36Sopenharmony_ci * for testing and fixing this driver. Also many thanks to "8 devices",
1262306a36Sopenharmony_ci * who were very cooperative and answered my questions.
1362306a36Sopenharmony_ci */
1462306a36Sopenharmony_ci
1562306a36Sopenharmony_ci#include <linux/ethtool.h>
1662306a36Sopenharmony_ci#include <linux/signal.h>
1762306a36Sopenharmony_ci#include <linux/slab.h>
1862306a36Sopenharmony_ci#include <linux/module.h>
1962306a36Sopenharmony_ci#include <linux/netdevice.h>
2062306a36Sopenharmony_ci#include <linux/usb.h>
2162306a36Sopenharmony_ci
2262306a36Sopenharmony_ci#include <linux/can.h>
2362306a36Sopenharmony_ci#include <linux/can/dev.h>
2462306a36Sopenharmony_ci#include <linux/can/error.h>
2562306a36Sopenharmony_ci
2662306a36Sopenharmony_ci/* driver constants */
2762306a36Sopenharmony_ci#define MAX_RX_URBS			20
2862306a36Sopenharmony_ci#define MAX_TX_URBS			20
2962306a36Sopenharmony_ci#define RX_BUFFER_SIZE			64
3062306a36Sopenharmony_ci
3162306a36Sopenharmony_ci/* vendor and product id */
3262306a36Sopenharmony_ci#define USB_8DEV_VENDOR_ID		0x0483
3362306a36Sopenharmony_ci#define USB_8DEV_PRODUCT_ID		0x1234
3462306a36Sopenharmony_ci
3562306a36Sopenharmony_ci/* endpoints */
3662306a36Sopenharmony_cienum usb_8dev_endpoint {
3762306a36Sopenharmony_ci	USB_8DEV_ENDP_DATA_RX = 1,
3862306a36Sopenharmony_ci	USB_8DEV_ENDP_DATA_TX,
3962306a36Sopenharmony_ci	USB_8DEV_ENDP_CMD_RX,
4062306a36Sopenharmony_ci	USB_8DEV_ENDP_CMD_TX
4162306a36Sopenharmony_ci};
4262306a36Sopenharmony_ci
4362306a36Sopenharmony_ci/* device CAN clock */
4462306a36Sopenharmony_ci#define USB_8DEV_ABP_CLOCK		32000000
4562306a36Sopenharmony_ci
4662306a36Sopenharmony_ci/* setup flags */
4762306a36Sopenharmony_ci#define USB_8DEV_SILENT			0x01
4862306a36Sopenharmony_ci#define USB_8DEV_LOOPBACK		0x02
4962306a36Sopenharmony_ci#define USB_8DEV_DISABLE_AUTO_RESTRANS	0x04
5062306a36Sopenharmony_ci#define USB_8DEV_STATUS_FRAME		0x08
5162306a36Sopenharmony_ci
5262306a36Sopenharmony_ci/* commands */
5362306a36Sopenharmony_cienum usb_8dev_cmd {
5462306a36Sopenharmony_ci	USB_8DEV_RESET = 1,
5562306a36Sopenharmony_ci	USB_8DEV_OPEN,
5662306a36Sopenharmony_ci	USB_8DEV_CLOSE,
5762306a36Sopenharmony_ci	USB_8DEV_SET_SPEED,
5862306a36Sopenharmony_ci	USB_8DEV_SET_MASK_FILTER,
5962306a36Sopenharmony_ci	USB_8DEV_GET_STATUS,
6062306a36Sopenharmony_ci	USB_8DEV_GET_STATISTICS,
6162306a36Sopenharmony_ci	USB_8DEV_GET_SERIAL,
6262306a36Sopenharmony_ci	USB_8DEV_GET_SOFTW_VER,
6362306a36Sopenharmony_ci	USB_8DEV_GET_HARDW_VER,
6462306a36Sopenharmony_ci	USB_8DEV_RESET_TIMESTAMP,
6562306a36Sopenharmony_ci	USB_8DEV_GET_SOFTW_HARDW_VER
6662306a36Sopenharmony_ci};
6762306a36Sopenharmony_ci
6862306a36Sopenharmony_ci/* command options */
6962306a36Sopenharmony_ci#define USB_8DEV_BAUD_MANUAL		0x09
7062306a36Sopenharmony_ci#define USB_8DEV_CMD_START		0x11
7162306a36Sopenharmony_ci#define USB_8DEV_CMD_END		0x22
7262306a36Sopenharmony_ci
7362306a36Sopenharmony_ci#define USB_8DEV_CMD_SUCCESS		0
7462306a36Sopenharmony_ci#define USB_8DEV_CMD_ERROR		255
7562306a36Sopenharmony_ci
7662306a36Sopenharmony_ci#define USB_8DEV_CMD_TIMEOUT		1000
7762306a36Sopenharmony_ci
7862306a36Sopenharmony_ci/* frames */
7962306a36Sopenharmony_ci#define USB_8DEV_DATA_START		0x55
8062306a36Sopenharmony_ci#define USB_8DEV_DATA_END		0xAA
8162306a36Sopenharmony_ci
8262306a36Sopenharmony_ci#define USB_8DEV_TYPE_CAN_FRAME		0
8362306a36Sopenharmony_ci#define USB_8DEV_TYPE_ERROR_FRAME	3
8462306a36Sopenharmony_ci
8562306a36Sopenharmony_ci#define USB_8DEV_EXTID			0x01
8662306a36Sopenharmony_ci#define USB_8DEV_RTR			0x02
8762306a36Sopenharmony_ci#define USB_8DEV_ERR_FLAG		0x04
8862306a36Sopenharmony_ci
8962306a36Sopenharmony_ci/* status */
9062306a36Sopenharmony_ci#define USB_8DEV_STATUSMSG_OK		0x00  /* Normal condition. */
9162306a36Sopenharmony_ci#define USB_8DEV_STATUSMSG_OVERRUN	0x01  /* Overrun occurred when sending */
9262306a36Sopenharmony_ci#define USB_8DEV_STATUSMSG_BUSLIGHT	0x02  /* Error counter has reached 96 */
9362306a36Sopenharmony_ci#define USB_8DEV_STATUSMSG_BUSHEAVY	0x03  /* Error count. has reached 128 */
9462306a36Sopenharmony_ci#define USB_8DEV_STATUSMSG_BUSOFF	0x04  /* Device is in BUSOFF */
9562306a36Sopenharmony_ci#define USB_8DEV_STATUSMSG_STUFF	0x20  /* Stuff Error */
9662306a36Sopenharmony_ci#define USB_8DEV_STATUSMSG_FORM		0x21  /* Form Error */
9762306a36Sopenharmony_ci#define USB_8DEV_STATUSMSG_ACK		0x23  /* Ack Error */
9862306a36Sopenharmony_ci#define USB_8DEV_STATUSMSG_BIT0		0x24  /* Bit1 Error */
9962306a36Sopenharmony_ci#define USB_8DEV_STATUSMSG_BIT1		0x25  /* Bit0 Error */
10062306a36Sopenharmony_ci#define USB_8DEV_STATUSMSG_CRC		0x27  /* CRC Error */
10162306a36Sopenharmony_ci
10262306a36Sopenharmony_ci#define USB_8DEV_RP_MASK		0x7F  /* Mask for Receive Error Bit */
10362306a36Sopenharmony_ci
10462306a36Sopenharmony_ci
10562306a36Sopenharmony_ci/* table of devices that work with this driver */
10662306a36Sopenharmony_cistatic const struct usb_device_id usb_8dev_table[] = {
10762306a36Sopenharmony_ci	{ USB_DEVICE(USB_8DEV_VENDOR_ID, USB_8DEV_PRODUCT_ID) },
10862306a36Sopenharmony_ci	{ }					/* Terminating entry */
10962306a36Sopenharmony_ci};
11062306a36Sopenharmony_ci
11162306a36Sopenharmony_ciMODULE_DEVICE_TABLE(usb, usb_8dev_table);
11262306a36Sopenharmony_ci
11362306a36Sopenharmony_cistruct usb_8dev_tx_urb_context {
11462306a36Sopenharmony_ci	struct usb_8dev_priv *priv;
11562306a36Sopenharmony_ci
11662306a36Sopenharmony_ci	u32 echo_index;
11762306a36Sopenharmony_ci};
11862306a36Sopenharmony_ci
11962306a36Sopenharmony_ci/* Structure to hold all of our device specific stuff */
12062306a36Sopenharmony_cistruct usb_8dev_priv {
12162306a36Sopenharmony_ci	struct can_priv can; /* must be the first member */
12262306a36Sopenharmony_ci
12362306a36Sopenharmony_ci	struct usb_device *udev;
12462306a36Sopenharmony_ci	struct net_device *netdev;
12562306a36Sopenharmony_ci
12662306a36Sopenharmony_ci	atomic_t active_tx_urbs;
12762306a36Sopenharmony_ci	struct usb_anchor tx_submitted;
12862306a36Sopenharmony_ci	struct usb_8dev_tx_urb_context tx_contexts[MAX_TX_URBS];
12962306a36Sopenharmony_ci
13062306a36Sopenharmony_ci	struct usb_anchor rx_submitted;
13162306a36Sopenharmony_ci
13262306a36Sopenharmony_ci	struct can_berr_counter bec;
13362306a36Sopenharmony_ci
13462306a36Sopenharmony_ci	u8 *cmd_msg_buffer;
13562306a36Sopenharmony_ci
13662306a36Sopenharmony_ci	struct mutex usb_8dev_cmd_lock;
13762306a36Sopenharmony_ci	void *rxbuf[MAX_RX_URBS];
13862306a36Sopenharmony_ci	dma_addr_t rxbuf_dma[MAX_RX_URBS];
13962306a36Sopenharmony_ci};
14062306a36Sopenharmony_ci
14162306a36Sopenharmony_ci/* tx frame */
14262306a36Sopenharmony_cistruct __packed usb_8dev_tx_msg {
14362306a36Sopenharmony_ci	u8 begin;
14462306a36Sopenharmony_ci	u8 flags;	/* RTR and EXT_ID flag */
14562306a36Sopenharmony_ci	__be32 id;	/* upper 3 bits not used */
14662306a36Sopenharmony_ci	u8 dlc;		/* data length code 0-8 bytes */
14762306a36Sopenharmony_ci	u8 data[8];	/* 64-bit data */
14862306a36Sopenharmony_ci	u8 end;
14962306a36Sopenharmony_ci};
15062306a36Sopenharmony_ci
15162306a36Sopenharmony_ci/* rx frame */
15262306a36Sopenharmony_cistruct __packed usb_8dev_rx_msg {
15362306a36Sopenharmony_ci	u8 begin;
15462306a36Sopenharmony_ci	u8 type;		/* frame type */
15562306a36Sopenharmony_ci	u8 flags;		/* RTR and EXT_ID flag */
15662306a36Sopenharmony_ci	__be32 id;		/* upper 3 bits not used */
15762306a36Sopenharmony_ci	u8 dlc;			/* data length code 0-8 bytes */
15862306a36Sopenharmony_ci	u8 data[8];		/* 64-bit data */
15962306a36Sopenharmony_ci	__be32 timestamp;	/* 32-bit timestamp */
16062306a36Sopenharmony_ci	u8 end;
16162306a36Sopenharmony_ci};
16262306a36Sopenharmony_ci
16362306a36Sopenharmony_ci/* command frame */
16462306a36Sopenharmony_cistruct __packed usb_8dev_cmd_msg {
16562306a36Sopenharmony_ci	u8 begin;
16662306a36Sopenharmony_ci	u8 channel;	/* unknown - always 0 */
16762306a36Sopenharmony_ci	u8 command;	/* command to execute */
16862306a36Sopenharmony_ci	u8 opt1;	/* optional parameter / return value */
16962306a36Sopenharmony_ci	u8 opt2;	/* optional parameter 2 */
17062306a36Sopenharmony_ci	u8 data[10];	/* optional parameter and data */
17162306a36Sopenharmony_ci	u8 end;
17262306a36Sopenharmony_ci};
17362306a36Sopenharmony_ci
17462306a36Sopenharmony_cistatic int usb_8dev_send_cmd_msg(struct usb_8dev_priv *priv, u8 *msg, int size)
17562306a36Sopenharmony_ci{
17662306a36Sopenharmony_ci	int actual_length;
17762306a36Sopenharmony_ci
17862306a36Sopenharmony_ci	return usb_bulk_msg(priv->udev,
17962306a36Sopenharmony_ci			    usb_sndbulkpipe(priv->udev, USB_8DEV_ENDP_CMD_TX),
18062306a36Sopenharmony_ci			    msg, size, &actual_length, USB_8DEV_CMD_TIMEOUT);
18162306a36Sopenharmony_ci}
18262306a36Sopenharmony_ci
18362306a36Sopenharmony_cistatic int usb_8dev_wait_cmd_msg(struct usb_8dev_priv *priv, u8 *msg, int size,
18462306a36Sopenharmony_ci				int *actual_length)
18562306a36Sopenharmony_ci{
18662306a36Sopenharmony_ci	return usb_bulk_msg(priv->udev,
18762306a36Sopenharmony_ci			    usb_rcvbulkpipe(priv->udev, USB_8DEV_ENDP_CMD_RX),
18862306a36Sopenharmony_ci			    msg, size, actual_length, USB_8DEV_CMD_TIMEOUT);
18962306a36Sopenharmony_ci}
19062306a36Sopenharmony_ci
19162306a36Sopenharmony_ci/* Send command to device and receive result.
19262306a36Sopenharmony_ci * Command was successful when opt1 = 0.
19362306a36Sopenharmony_ci */
19462306a36Sopenharmony_cistatic int usb_8dev_send_cmd(struct usb_8dev_priv *priv,
19562306a36Sopenharmony_ci			     struct usb_8dev_cmd_msg *out,
19662306a36Sopenharmony_ci			     struct usb_8dev_cmd_msg *in)
19762306a36Sopenharmony_ci{
19862306a36Sopenharmony_ci	int err;
19962306a36Sopenharmony_ci	int num_bytes_read;
20062306a36Sopenharmony_ci	struct net_device *netdev;
20162306a36Sopenharmony_ci
20262306a36Sopenharmony_ci	netdev = priv->netdev;
20362306a36Sopenharmony_ci
20462306a36Sopenharmony_ci	out->begin = USB_8DEV_CMD_START;
20562306a36Sopenharmony_ci	out->end = USB_8DEV_CMD_END;
20662306a36Sopenharmony_ci
20762306a36Sopenharmony_ci	mutex_lock(&priv->usb_8dev_cmd_lock);
20862306a36Sopenharmony_ci
20962306a36Sopenharmony_ci	memcpy(priv->cmd_msg_buffer, out,
21062306a36Sopenharmony_ci		sizeof(struct usb_8dev_cmd_msg));
21162306a36Sopenharmony_ci
21262306a36Sopenharmony_ci	err = usb_8dev_send_cmd_msg(priv, priv->cmd_msg_buffer,
21362306a36Sopenharmony_ci				    sizeof(struct usb_8dev_cmd_msg));
21462306a36Sopenharmony_ci	if (err < 0) {
21562306a36Sopenharmony_ci		netdev_err(netdev, "sending command message failed\n");
21662306a36Sopenharmony_ci		goto failed;
21762306a36Sopenharmony_ci	}
21862306a36Sopenharmony_ci
21962306a36Sopenharmony_ci	err = usb_8dev_wait_cmd_msg(priv, priv->cmd_msg_buffer,
22062306a36Sopenharmony_ci				    sizeof(struct usb_8dev_cmd_msg),
22162306a36Sopenharmony_ci				    &num_bytes_read);
22262306a36Sopenharmony_ci	if (err < 0) {
22362306a36Sopenharmony_ci		netdev_err(netdev, "no command message answer\n");
22462306a36Sopenharmony_ci		goto failed;
22562306a36Sopenharmony_ci	}
22662306a36Sopenharmony_ci
22762306a36Sopenharmony_ci	memcpy(in, priv->cmd_msg_buffer, sizeof(struct usb_8dev_cmd_msg));
22862306a36Sopenharmony_ci
22962306a36Sopenharmony_ci	if (in->begin != USB_8DEV_CMD_START || in->end != USB_8DEV_CMD_END ||
23062306a36Sopenharmony_ci			num_bytes_read != 16 || in->opt1 != 0)
23162306a36Sopenharmony_ci		err = -EPROTO;
23262306a36Sopenharmony_ci
23362306a36Sopenharmony_cifailed:
23462306a36Sopenharmony_ci	mutex_unlock(&priv->usb_8dev_cmd_lock);
23562306a36Sopenharmony_ci	return err;
23662306a36Sopenharmony_ci}
23762306a36Sopenharmony_ci
23862306a36Sopenharmony_ci/* Send open command to device */
23962306a36Sopenharmony_cistatic int usb_8dev_cmd_open(struct usb_8dev_priv *priv)
24062306a36Sopenharmony_ci{
24162306a36Sopenharmony_ci	struct can_bittiming *bt = &priv->can.bittiming;
24262306a36Sopenharmony_ci	struct usb_8dev_cmd_msg outmsg;
24362306a36Sopenharmony_ci	struct usb_8dev_cmd_msg inmsg;
24462306a36Sopenharmony_ci	u32 ctrlmode = priv->can.ctrlmode;
24562306a36Sopenharmony_ci	u32 flags = USB_8DEV_STATUS_FRAME;
24662306a36Sopenharmony_ci	__be32 beflags;
24762306a36Sopenharmony_ci	__be16 bebrp;
24862306a36Sopenharmony_ci
24962306a36Sopenharmony_ci	memset(&outmsg, 0, sizeof(outmsg));
25062306a36Sopenharmony_ci	outmsg.command = USB_8DEV_OPEN;
25162306a36Sopenharmony_ci	outmsg.opt1 = USB_8DEV_BAUD_MANUAL;
25262306a36Sopenharmony_ci	outmsg.data[0] = bt->prop_seg + bt->phase_seg1;
25362306a36Sopenharmony_ci	outmsg.data[1] = bt->phase_seg2;
25462306a36Sopenharmony_ci	outmsg.data[2] = bt->sjw;
25562306a36Sopenharmony_ci
25662306a36Sopenharmony_ci	/* BRP */
25762306a36Sopenharmony_ci	bebrp = cpu_to_be16((u16)bt->brp);
25862306a36Sopenharmony_ci	memcpy(&outmsg.data[3], &bebrp, sizeof(bebrp));
25962306a36Sopenharmony_ci
26062306a36Sopenharmony_ci	/* flags */
26162306a36Sopenharmony_ci	if (ctrlmode & CAN_CTRLMODE_LOOPBACK)
26262306a36Sopenharmony_ci		flags |= USB_8DEV_LOOPBACK;
26362306a36Sopenharmony_ci	if (ctrlmode & CAN_CTRLMODE_LISTENONLY)
26462306a36Sopenharmony_ci		flags |= USB_8DEV_SILENT;
26562306a36Sopenharmony_ci	if (ctrlmode & CAN_CTRLMODE_ONE_SHOT)
26662306a36Sopenharmony_ci		flags |= USB_8DEV_DISABLE_AUTO_RESTRANS;
26762306a36Sopenharmony_ci
26862306a36Sopenharmony_ci	beflags = cpu_to_be32(flags);
26962306a36Sopenharmony_ci	memcpy(&outmsg.data[5], &beflags, sizeof(beflags));
27062306a36Sopenharmony_ci
27162306a36Sopenharmony_ci	return usb_8dev_send_cmd(priv, &outmsg, &inmsg);
27262306a36Sopenharmony_ci}
27362306a36Sopenharmony_ci
27462306a36Sopenharmony_ci/* Send close command to device */
27562306a36Sopenharmony_cistatic int usb_8dev_cmd_close(struct usb_8dev_priv *priv)
27662306a36Sopenharmony_ci{
27762306a36Sopenharmony_ci	struct usb_8dev_cmd_msg inmsg;
27862306a36Sopenharmony_ci	struct usb_8dev_cmd_msg outmsg = {
27962306a36Sopenharmony_ci		.channel = 0,
28062306a36Sopenharmony_ci		.command = USB_8DEV_CLOSE,
28162306a36Sopenharmony_ci		.opt1 = 0,
28262306a36Sopenharmony_ci		.opt2 = 0
28362306a36Sopenharmony_ci	};
28462306a36Sopenharmony_ci
28562306a36Sopenharmony_ci	return usb_8dev_send_cmd(priv, &outmsg, &inmsg);
28662306a36Sopenharmony_ci}
28762306a36Sopenharmony_ci
28862306a36Sopenharmony_ci/* Get firmware and hardware version */
28962306a36Sopenharmony_cistatic int usb_8dev_cmd_version(struct usb_8dev_priv *priv, u32 *res)
29062306a36Sopenharmony_ci{
29162306a36Sopenharmony_ci	struct usb_8dev_cmd_msg	inmsg;
29262306a36Sopenharmony_ci	struct usb_8dev_cmd_msg	outmsg = {
29362306a36Sopenharmony_ci		.channel = 0,
29462306a36Sopenharmony_ci		.command = USB_8DEV_GET_SOFTW_HARDW_VER,
29562306a36Sopenharmony_ci		.opt1 = 0,
29662306a36Sopenharmony_ci		.opt2 = 0
29762306a36Sopenharmony_ci	};
29862306a36Sopenharmony_ci
29962306a36Sopenharmony_ci	int err = usb_8dev_send_cmd(priv, &outmsg, &inmsg);
30062306a36Sopenharmony_ci	if (err)
30162306a36Sopenharmony_ci		return err;
30262306a36Sopenharmony_ci
30362306a36Sopenharmony_ci	*res = be32_to_cpup((__be32 *)inmsg.data);
30462306a36Sopenharmony_ci
30562306a36Sopenharmony_ci	return err;
30662306a36Sopenharmony_ci}
30762306a36Sopenharmony_ci
30862306a36Sopenharmony_ci/* Set network device mode
30962306a36Sopenharmony_ci *
31062306a36Sopenharmony_ci * Maybe we should leave this function empty, because the device
31162306a36Sopenharmony_ci * set mode variable with open command.
31262306a36Sopenharmony_ci */
31362306a36Sopenharmony_cistatic int usb_8dev_set_mode(struct net_device *netdev, enum can_mode mode)
31462306a36Sopenharmony_ci{
31562306a36Sopenharmony_ci	struct usb_8dev_priv *priv = netdev_priv(netdev);
31662306a36Sopenharmony_ci	int err = 0;
31762306a36Sopenharmony_ci
31862306a36Sopenharmony_ci	switch (mode) {
31962306a36Sopenharmony_ci	case CAN_MODE_START:
32062306a36Sopenharmony_ci		err = usb_8dev_cmd_open(priv);
32162306a36Sopenharmony_ci		if (err)
32262306a36Sopenharmony_ci			netdev_warn(netdev, "couldn't start device");
32362306a36Sopenharmony_ci		break;
32462306a36Sopenharmony_ci
32562306a36Sopenharmony_ci	default:
32662306a36Sopenharmony_ci		return -EOPNOTSUPP;
32762306a36Sopenharmony_ci	}
32862306a36Sopenharmony_ci
32962306a36Sopenharmony_ci	return err;
33062306a36Sopenharmony_ci}
33162306a36Sopenharmony_ci
33262306a36Sopenharmony_ci/* Read error/status frames */
33362306a36Sopenharmony_cistatic void usb_8dev_rx_err_msg(struct usb_8dev_priv *priv,
33462306a36Sopenharmony_ci				struct usb_8dev_rx_msg *msg)
33562306a36Sopenharmony_ci{
33662306a36Sopenharmony_ci	struct can_frame *cf;
33762306a36Sopenharmony_ci	struct sk_buff *skb;
33862306a36Sopenharmony_ci	struct net_device_stats *stats = &priv->netdev->stats;
33962306a36Sopenharmony_ci
34062306a36Sopenharmony_ci	/* Error message:
34162306a36Sopenharmony_ci	 * byte 0: Status
34262306a36Sopenharmony_ci	 * byte 1: bit   7: Receive Passive
34362306a36Sopenharmony_ci	 * byte 1: bit 0-6: Receive Error Counter
34462306a36Sopenharmony_ci	 * byte 2: Transmit Error Counter
34562306a36Sopenharmony_ci	 * byte 3: Always 0 (maybe reserved for future use)
34662306a36Sopenharmony_ci	 */
34762306a36Sopenharmony_ci
34862306a36Sopenharmony_ci	u8 state = msg->data[0];
34962306a36Sopenharmony_ci	u8 rxerr = msg->data[1] & USB_8DEV_RP_MASK;
35062306a36Sopenharmony_ci	u8 txerr = msg->data[2];
35162306a36Sopenharmony_ci	int rx_errors = 0;
35262306a36Sopenharmony_ci	int tx_errors = 0;
35362306a36Sopenharmony_ci
35462306a36Sopenharmony_ci	skb = alloc_can_err_skb(priv->netdev, &cf);
35562306a36Sopenharmony_ci	if (!skb)
35662306a36Sopenharmony_ci		return;
35762306a36Sopenharmony_ci
35862306a36Sopenharmony_ci	switch (state) {
35962306a36Sopenharmony_ci	case USB_8DEV_STATUSMSG_OK:
36062306a36Sopenharmony_ci		priv->can.state = CAN_STATE_ERROR_ACTIVE;
36162306a36Sopenharmony_ci		cf->can_id |= CAN_ERR_PROT;
36262306a36Sopenharmony_ci		cf->data[2] = CAN_ERR_PROT_ACTIVE;
36362306a36Sopenharmony_ci		break;
36462306a36Sopenharmony_ci	case USB_8DEV_STATUSMSG_BUSOFF:
36562306a36Sopenharmony_ci		priv->can.state = CAN_STATE_BUS_OFF;
36662306a36Sopenharmony_ci		cf->can_id |= CAN_ERR_BUSOFF;
36762306a36Sopenharmony_ci		priv->can.can_stats.bus_off++;
36862306a36Sopenharmony_ci		can_bus_off(priv->netdev);
36962306a36Sopenharmony_ci		break;
37062306a36Sopenharmony_ci	case USB_8DEV_STATUSMSG_OVERRUN:
37162306a36Sopenharmony_ci	case USB_8DEV_STATUSMSG_BUSLIGHT:
37262306a36Sopenharmony_ci	case USB_8DEV_STATUSMSG_BUSHEAVY:
37362306a36Sopenharmony_ci		cf->can_id |= CAN_ERR_CRTL;
37462306a36Sopenharmony_ci		break;
37562306a36Sopenharmony_ci	default:
37662306a36Sopenharmony_ci		priv->can.state = CAN_STATE_ERROR_WARNING;
37762306a36Sopenharmony_ci		cf->can_id |= CAN_ERR_PROT | CAN_ERR_BUSERROR;
37862306a36Sopenharmony_ci		priv->can.can_stats.bus_error++;
37962306a36Sopenharmony_ci		break;
38062306a36Sopenharmony_ci	}
38162306a36Sopenharmony_ci
38262306a36Sopenharmony_ci	switch (state) {
38362306a36Sopenharmony_ci	case USB_8DEV_STATUSMSG_OK:
38462306a36Sopenharmony_ci	case USB_8DEV_STATUSMSG_BUSOFF:
38562306a36Sopenharmony_ci		break;
38662306a36Sopenharmony_ci	case USB_8DEV_STATUSMSG_ACK:
38762306a36Sopenharmony_ci		cf->can_id |= CAN_ERR_ACK;
38862306a36Sopenharmony_ci		tx_errors = 1;
38962306a36Sopenharmony_ci		break;
39062306a36Sopenharmony_ci	case USB_8DEV_STATUSMSG_CRC:
39162306a36Sopenharmony_ci		cf->data[3] = CAN_ERR_PROT_LOC_CRC_SEQ;
39262306a36Sopenharmony_ci		rx_errors = 1;
39362306a36Sopenharmony_ci		break;
39462306a36Sopenharmony_ci	case USB_8DEV_STATUSMSG_BIT0:
39562306a36Sopenharmony_ci		cf->data[2] |= CAN_ERR_PROT_BIT0;
39662306a36Sopenharmony_ci		tx_errors = 1;
39762306a36Sopenharmony_ci		break;
39862306a36Sopenharmony_ci	case USB_8DEV_STATUSMSG_BIT1:
39962306a36Sopenharmony_ci		cf->data[2] |= CAN_ERR_PROT_BIT1;
40062306a36Sopenharmony_ci		tx_errors = 1;
40162306a36Sopenharmony_ci		break;
40262306a36Sopenharmony_ci	case USB_8DEV_STATUSMSG_FORM:
40362306a36Sopenharmony_ci		cf->data[2] |= CAN_ERR_PROT_FORM;
40462306a36Sopenharmony_ci		rx_errors = 1;
40562306a36Sopenharmony_ci		break;
40662306a36Sopenharmony_ci	case USB_8DEV_STATUSMSG_STUFF:
40762306a36Sopenharmony_ci		cf->data[2] |= CAN_ERR_PROT_STUFF;
40862306a36Sopenharmony_ci		rx_errors = 1;
40962306a36Sopenharmony_ci		break;
41062306a36Sopenharmony_ci	case USB_8DEV_STATUSMSG_OVERRUN:
41162306a36Sopenharmony_ci		cf->data[1] = CAN_ERR_CRTL_RX_OVERFLOW;
41262306a36Sopenharmony_ci		stats->rx_over_errors++;
41362306a36Sopenharmony_ci		rx_errors = 1;
41462306a36Sopenharmony_ci		break;
41562306a36Sopenharmony_ci	case USB_8DEV_STATUSMSG_BUSLIGHT:
41662306a36Sopenharmony_ci		priv->can.state = CAN_STATE_ERROR_WARNING;
41762306a36Sopenharmony_ci		cf->data[1] = (txerr > rxerr) ?
41862306a36Sopenharmony_ci			CAN_ERR_CRTL_TX_WARNING :
41962306a36Sopenharmony_ci			CAN_ERR_CRTL_RX_WARNING;
42062306a36Sopenharmony_ci		priv->can.can_stats.error_warning++;
42162306a36Sopenharmony_ci		break;
42262306a36Sopenharmony_ci	case USB_8DEV_STATUSMSG_BUSHEAVY:
42362306a36Sopenharmony_ci		priv->can.state = CAN_STATE_ERROR_PASSIVE;
42462306a36Sopenharmony_ci		cf->data[1] = (txerr > rxerr) ?
42562306a36Sopenharmony_ci			CAN_ERR_CRTL_TX_PASSIVE :
42662306a36Sopenharmony_ci			CAN_ERR_CRTL_RX_PASSIVE;
42762306a36Sopenharmony_ci		priv->can.can_stats.error_passive++;
42862306a36Sopenharmony_ci		break;
42962306a36Sopenharmony_ci	default:
43062306a36Sopenharmony_ci		netdev_warn(priv->netdev,
43162306a36Sopenharmony_ci			    "Unknown status/error message (%d)\n", state);
43262306a36Sopenharmony_ci		break;
43362306a36Sopenharmony_ci	}
43462306a36Sopenharmony_ci
43562306a36Sopenharmony_ci	if (tx_errors) {
43662306a36Sopenharmony_ci		cf->data[2] |= CAN_ERR_PROT_TX;
43762306a36Sopenharmony_ci		stats->tx_errors++;
43862306a36Sopenharmony_ci	}
43962306a36Sopenharmony_ci
44062306a36Sopenharmony_ci	if (rx_errors)
44162306a36Sopenharmony_ci		stats->rx_errors++;
44262306a36Sopenharmony_ci	if (priv->can.state != CAN_STATE_BUS_OFF) {
44362306a36Sopenharmony_ci		cf->can_id |= CAN_ERR_CNT;
44462306a36Sopenharmony_ci		cf->data[6] = txerr;
44562306a36Sopenharmony_ci		cf->data[7] = rxerr;
44662306a36Sopenharmony_ci	}
44762306a36Sopenharmony_ci
44862306a36Sopenharmony_ci	priv->bec.txerr = txerr;
44962306a36Sopenharmony_ci	priv->bec.rxerr = rxerr;
45062306a36Sopenharmony_ci
45162306a36Sopenharmony_ci	netif_rx(skb);
45262306a36Sopenharmony_ci}
45362306a36Sopenharmony_ci
45462306a36Sopenharmony_ci/* Read data and status frames */
45562306a36Sopenharmony_cistatic void usb_8dev_rx_can_msg(struct usb_8dev_priv *priv,
45662306a36Sopenharmony_ci				struct usb_8dev_rx_msg *msg)
45762306a36Sopenharmony_ci{
45862306a36Sopenharmony_ci	struct can_frame *cf;
45962306a36Sopenharmony_ci	struct sk_buff *skb;
46062306a36Sopenharmony_ci	struct net_device_stats *stats = &priv->netdev->stats;
46162306a36Sopenharmony_ci
46262306a36Sopenharmony_ci	if (msg->type == USB_8DEV_TYPE_ERROR_FRAME &&
46362306a36Sopenharmony_ci		   msg->flags == USB_8DEV_ERR_FLAG) {
46462306a36Sopenharmony_ci		usb_8dev_rx_err_msg(priv, msg);
46562306a36Sopenharmony_ci	} else if (msg->type == USB_8DEV_TYPE_CAN_FRAME) {
46662306a36Sopenharmony_ci		skb = alloc_can_skb(priv->netdev, &cf);
46762306a36Sopenharmony_ci		if (!skb)
46862306a36Sopenharmony_ci			return;
46962306a36Sopenharmony_ci
47062306a36Sopenharmony_ci		cf->can_id = be32_to_cpu(msg->id);
47162306a36Sopenharmony_ci		can_frame_set_cc_len(cf, msg->dlc & 0xF, priv->can.ctrlmode);
47262306a36Sopenharmony_ci
47362306a36Sopenharmony_ci		if (msg->flags & USB_8DEV_EXTID)
47462306a36Sopenharmony_ci			cf->can_id |= CAN_EFF_FLAG;
47562306a36Sopenharmony_ci
47662306a36Sopenharmony_ci		if (msg->flags & USB_8DEV_RTR) {
47762306a36Sopenharmony_ci			cf->can_id |= CAN_RTR_FLAG;
47862306a36Sopenharmony_ci		} else {
47962306a36Sopenharmony_ci			memcpy(cf->data, msg->data, cf->len);
48062306a36Sopenharmony_ci			stats->rx_bytes += cf->len;
48162306a36Sopenharmony_ci		}
48262306a36Sopenharmony_ci		stats->rx_packets++;
48362306a36Sopenharmony_ci
48462306a36Sopenharmony_ci		netif_rx(skb);
48562306a36Sopenharmony_ci	} else {
48662306a36Sopenharmony_ci		netdev_warn(priv->netdev, "frame type %d unknown",
48762306a36Sopenharmony_ci			 msg->type);
48862306a36Sopenharmony_ci	}
48962306a36Sopenharmony_ci
49062306a36Sopenharmony_ci}
49162306a36Sopenharmony_ci
49262306a36Sopenharmony_ci/* Callback for reading data from device
49362306a36Sopenharmony_ci *
49462306a36Sopenharmony_ci * Check urb status, call read function and resubmit urb read operation.
49562306a36Sopenharmony_ci */
49662306a36Sopenharmony_cistatic void usb_8dev_read_bulk_callback(struct urb *urb)
49762306a36Sopenharmony_ci{
49862306a36Sopenharmony_ci	struct usb_8dev_priv *priv = urb->context;
49962306a36Sopenharmony_ci	struct net_device *netdev;
50062306a36Sopenharmony_ci	int retval;
50162306a36Sopenharmony_ci	int pos = 0;
50262306a36Sopenharmony_ci
50362306a36Sopenharmony_ci	netdev = priv->netdev;
50462306a36Sopenharmony_ci
50562306a36Sopenharmony_ci	if (!netif_device_present(netdev))
50662306a36Sopenharmony_ci		return;
50762306a36Sopenharmony_ci
50862306a36Sopenharmony_ci	switch (urb->status) {
50962306a36Sopenharmony_ci	case 0: /* success */
51062306a36Sopenharmony_ci		break;
51162306a36Sopenharmony_ci
51262306a36Sopenharmony_ci	case -ENOENT:
51362306a36Sopenharmony_ci	case -EPIPE:
51462306a36Sopenharmony_ci	case -EPROTO:
51562306a36Sopenharmony_ci	case -ESHUTDOWN:
51662306a36Sopenharmony_ci		return;
51762306a36Sopenharmony_ci
51862306a36Sopenharmony_ci	default:
51962306a36Sopenharmony_ci		netdev_info(netdev, "Rx URB aborted (%d)\n",
52062306a36Sopenharmony_ci			 urb->status);
52162306a36Sopenharmony_ci		goto resubmit_urb;
52262306a36Sopenharmony_ci	}
52362306a36Sopenharmony_ci
52462306a36Sopenharmony_ci	while (pos < urb->actual_length) {
52562306a36Sopenharmony_ci		struct usb_8dev_rx_msg *msg;
52662306a36Sopenharmony_ci
52762306a36Sopenharmony_ci		if (pos + sizeof(struct usb_8dev_rx_msg) > urb->actual_length) {
52862306a36Sopenharmony_ci			netdev_err(priv->netdev, "format error\n");
52962306a36Sopenharmony_ci			break;
53062306a36Sopenharmony_ci		}
53162306a36Sopenharmony_ci
53262306a36Sopenharmony_ci		msg = (struct usb_8dev_rx_msg *)(urb->transfer_buffer + pos);
53362306a36Sopenharmony_ci		usb_8dev_rx_can_msg(priv, msg);
53462306a36Sopenharmony_ci
53562306a36Sopenharmony_ci		pos += sizeof(struct usb_8dev_rx_msg);
53662306a36Sopenharmony_ci	}
53762306a36Sopenharmony_ci
53862306a36Sopenharmony_ciresubmit_urb:
53962306a36Sopenharmony_ci	usb_fill_bulk_urb(urb, priv->udev,
54062306a36Sopenharmony_ci			  usb_rcvbulkpipe(priv->udev, USB_8DEV_ENDP_DATA_RX),
54162306a36Sopenharmony_ci			  urb->transfer_buffer, RX_BUFFER_SIZE,
54262306a36Sopenharmony_ci			  usb_8dev_read_bulk_callback, priv);
54362306a36Sopenharmony_ci
54462306a36Sopenharmony_ci	retval = usb_submit_urb(urb, GFP_ATOMIC);
54562306a36Sopenharmony_ci
54662306a36Sopenharmony_ci	if (retval == -ENODEV)
54762306a36Sopenharmony_ci		netif_device_detach(netdev);
54862306a36Sopenharmony_ci	else if (retval)
54962306a36Sopenharmony_ci		netdev_err(netdev,
55062306a36Sopenharmony_ci			"failed resubmitting read bulk urb: %d\n", retval);
55162306a36Sopenharmony_ci}
55262306a36Sopenharmony_ci
55362306a36Sopenharmony_ci/* Callback handler for write operations
55462306a36Sopenharmony_ci *
55562306a36Sopenharmony_ci * Free allocated buffers, check transmit status and
55662306a36Sopenharmony_ci * calculate statistic.
55762306a36Sopenharmony_ci */
55862306a36Sopenharmony_cistatic void usb_8dev_write_bulk_callback(struct urb *urb)
55962306a36Sopenharmony_ci{
56062306a36Sopenharmony_ci	struct usb_8dev_tx_urb_context *context = urb->context;
56162306a36Sopenharmony_ci	struct usb_8dev_priv *priv;
56262306a36Sopenharmony_ci	struct net_device *netdev;
56362306a36Sopenharmony_ci
56462306a36Sopenharmony_ci	BUG_ON(!context);
56562306a36Sopenharmony_ci
56662306a36Sopenharmony_ci	priv = context->priv;
56762306a36Sopenharmony_ci	netdev = priv->netdev;
56862306a36Sopenharmony_ci
56962306a36Sopenharmony_ci	/* free up our allocated buffer */
57062306a36Sopenharmony_ci	usb_free_coherent(urb->dev, urb->transfer_buffer_length,
57162306a36Sopenharmony_ci			  urb->transfer_buffer, urb->transfer_dma);
57262306a36Sopenharmony_ci
57362306a36Sopenharmony_ci	atomic_dec(&priv->active_tx_urbs);
57462306a36Sopenharmony_ci
57562306a36Sopenharmony_ci	if (!netif_device_present(netdev))
57662306a36Sopenharmony_ci		return;
57762306a36Sopenharmony_ci
57862306a36Sopenharmony_ci	if (urb->status)
57962306a36Sopenharmony_ci		netdev_info(netdev, "Tx URB aborted (%d)\n",
58062306a36Sopenharmony_ci			 urb->status);
58162306a36Sopenharmony_ci
58262306a36Sopenharmony_ci	netdev->stats.tx_packets++;
58362306a36Sopenharmony_ci	netdev->stats.tx_bytes += can_get_echo_skb(netdev, context->echo_index, NULL);
58462306a36Sopenharmony_ci
58562306a36Sopenharmony_ci	/* Release context */
58662306a36Sopenharmony_ci	context->echo_index = MAX_TX_URBS;
58762306a36Sopenharmony_ci
58862306a36Sopenharmony_ci	netif_wake_queue(netdev);
58962306a36Sopenharmony_ci}
59062306a36Sopenharmony_ci
59162306a36Sopenharmony_ci/* Send data to device */
59262306a36Sopenharmony_cistatic netdev_tx_t usb_8dev_start_xmit(struct sk_buff *skb,
59362306a36Sopenharmony_ci				      struct net_device *netdev)
59462306a36Sopenharmony_ci{
59562306a36Sopenharmony_ci	struct usb_8dev_priv *priv = netdev_priv(netdev);
59662306a36Sopenharmony_ci	struct net_device_stats *stats = &netdev->stats;
59762306a36Sopenharmony_ci	struct can_frame *cf = (struct can_frame *) skb->data;
59862306a36Sopenharmony_ci	struct usb_8dev_tx_msg *msg;
59962306a36Sopenharmony_ci	struct urb *urb;
60062306a36Sopenharmony_ci	struct usb_8dev_tx_urb_context *context = NULL;
60162306a36Sopenharmony_ci	u8 *buf;
60262306a36Sopenharmony_ci	int i, err;
60362306a36Sopenharmony_ci	size_t size = sizeof(struct usb_8dev_tx_msg);
60462306a36Sopenharmony_ci
60562306a36Sopenharmony_ci	if (can_dev_dropped_skb(netdev, skb))
60662306a36Sopenharmony_ci		return NETDEV_TX_OK;
60762306a36Sopenharmony_ci
60862306a36Sopenharmony_ci	/* create a URB, and a buffer for it, and copy the data to the URB */
60962306a36Sopenharmony_ci	urb = usb_alloc_urb(0, GFP_ATOMIC);
61062306a36Sopenharmony_ci	if (!urb)
61162306a36Sopenharmony_ci		goto nomem;
61262306a36Sopenharmony_ci
61362306a36Sopenharmony_ci	buf = usb_alloc_coherent(priv->udev, size, GFP_ATOMIC,
61462306a36Sopenharmony_ci				 &urb->transfer_dma);
61562306a36Sopenharmony_ci	if (!buf) {
61662306a36Sopenharmony_ci		netdev_err(netdev, "No memory left for USB buffer\n");
61762306a36Sopenharmony_ci		goto nomembuf;
61862306a36Sopenharmony_ci	}
61962306a36Sopenharmony_ci
62062306a36Sopenharmony_ci	memset(buf, 0, size);
62162306a36Sopenharmony_ci
62262306a36Sopenharmony_ci	msg = (struct usb_8dev_tx_msg *)buf;
62362306a36Sopenharmony_ci	msg->begin = USB_8DEV_DATA_START;
62462306a36Sopenharmony_ci	msg->flags = 0x00;
62562306a36Sopenharmony_ci
62662306a36Sopenharmony_ci	if (cf->can_id & CAN_RTR_FLAG)
62762306a36Sopenharmony_ci		msg->flags |= USB_8DEV_RTR;
62862306a36Sopenharmony_ci
62962306a36Sopenharmony_ci	if (cf->can_id & CAN_EFF_FLAG)
63062306a36Sopenharmony_ci		msg->flags |= USB_8DEV_EXTID;
63162306a36Sopenharmony_ci
63262306a36Sopenharmony_ci	msg->id = cpu_to_be32(cf->can_id & CAN_ERR_MASK);
63362306a36Sopenharmony_ci	msg->dlc = can_get_cc_dlc(cf, priv->can.ctrlmode);
63462306a36Sopenharmony_ci	memcpy(msg->data, cf->data, cf->len);
63562306a36Sopenharmony_ci	msg->end = USB_8DEV_DATA_END;
63662306a36Sopenharmony_ci
63762306a36Sopenharmony_ci	for (i = 0; i < MAX_TX_URBS; i++) {
63862306a36Sopenharmony_ci		if (priv->tx_contexts[i].echo_index == MAX_TX_URBS) {
63962306a36Sopenharmony_ci			context = &priv->tx_contexts[i];
64062306a36Sopenharmony_ci			break;
64162306a36Sopenharmony_ci		}
64262306a36Sopenharmony_ci	}
64362306a36Sopenharmony_ci
64462306a36Sopenharmony_ci	/* May never happen! When this happens we'd more URBs in flight as
64562306a36Sopenharmony_ci	 * allowed (MAX_TX_URBS).
64662306a36Sopenharmony_ci	 */
64762306a36Sopenharmony_ci	if (!context)
64862306a36Sopenharmony_ci		goto nofreecontext;
64962306a36Sopenharmony_ci
65062306a36Sopenharmony_ci	context->priv = priv;
65162306a36Sopenharmony_ci	context->echo_index = i;
65262306a36Sopenharmony_ci
65362306a36Sopenharmony_ci	usb_fill_bulk_urb(urb, priv->udev,
65462306a36Sopenharmony_ci			  usb_sndbulkpipe(priv->udev, USB_8DEV_ENDP_DATA_TX),
65562306a36Sopenharmony_ci			  buf, size, usb_8dev_write_bulk_callback, context);
65662306a36Sopenharmony_ci	urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
65762306a36Sopenharmony_ci	usb_anchor_urb(urb, &priv->tx_submitted);
65862306a36Sopenharmony_ci
65962306a36Sopenharmony_ci	can_put_echo_skb(skb, netdev, context->echo_index, 0);
66062306a36Sopenharmony_ci
66162306a36Sopenharmony_ci	atomic_inc(&priv->active_tx_urbs);
66262306a36Sopenharmony_ci
66362306a36Sopenharmony_ci	err = usb_submit_urb(urb, GFP_ATOMIC);
66462306a36Sopenharmony_ci	if (unlikely(err)) {
66562306a36Sopenharmony_ci		can_free_echo_skb(netdev, context->echo_index, NULL);
66662306a36Sopenharmony_ci
66762306a36Sopenharmony_ci		usb_unanchor_urb(urb);
66862306a36Sopenharmony_ci		usb_free_coherent(priv->udev, size, buf, urb->transfer_dma);
66962306a36Sopenharmony_ci
67062306a36Sopenharmony_ci		atomic_dec(&priv->active_tx_urbs);
67162306a36Sopenharmony_ci
67262306a36Sopenharmony_ci		if (err == -ENODEV)
67362306a36Sopenharmony_ci			netif_device_detach(netdev);
67462306a36Sopenharmony_ci		else
67562306a36Sopenharmony_ci			netdev_warn(netdev, "failed tx_urb %d\n", err);
67662306a36Sopenharmony_ci		stats->tx_dropped++;
67762306a36Sopenharmony_ci	} else if (atomic_read(&priv->active_tx_urbs) >= MAX_TX_URBS)
67862306a36Sopenharmony_ci		/* Slow down tx path */
67962306a36Sopenharmony_ci		netif_stop_queue(netdev);
68062306a36Sopenharmony_ci
68162306a36Sopenharmony_ci	/* Release our reference to this URB, the USB core will eventually free
68262306a36Sopenharmony_ci	 * it entirely.
68362306a36Sopenharmony_ci	 */
68462306a36Sopenharmony_ci	usb_free_urb(urb);
68562306a36Sopenharmony_ci
68662306a36Sopenharmony_ci	return NETDEV_TX_OK;
68762306a36Sopenharmony_ci
68862306a36Sopenharmony_cinofreecontext:
68962306a36Sopenharmony_ci	usb_free_coherent(priv->udev, size, buf, urb->transfer_dma);
69062306a36Sopenharmony_ci	usb_free_urb(urb);
69162306a36Sopenharmony_ci
69262306a36Sopenharmony_ci	netdev_warn(netdev, "couldn't find free context");
69362306a36Sopenharmony_ci
69462306a36Sopenharmony_ci	return NETDEV_TX_BUSY;
69562306a36Sopenharmony_ci
69662306a36Sopenharmony_cinomembuf:
69762306a36Sopenharmony_ci	usb_free_urb(urb);
69862306a36Sopenharmony_ci
69962306a36Sopenharmony_cinomem:
70062306a36Sopenharmony_ci	dev_kfree_skb(skb);
70162306a36Sopenharmony_ci	stats->tx_dropped++;
70262306a36Sopenharmony_ci
70362306a36Sopenharmony_ci	return NETDEV_TX_OK;
70462306a36Sopenharmony_ci}
70562306a36Sopenharmony_ci
70662306a36Sopenharmony_cistatic int usb_8dev_get_berr_counter(const struct net_device *netdev,
70762306a36Sopenharmony_ci				     struct can_berr_counter *bec)
70862306a36Sopenharmony_ci{
70962306a36Sopenharmony_ci	struct usb_8dev_priv *priv = netdev_priv(netdev);
71062306a36Sopenharmony_ci
71162306a36Sopenharmony_ci	bec->txerr = priv->bec.txerr;
71262306a36Sopenharmony_ci	bec->rxerr = priv->bec.rxerr;
71362306a36Sopenharmony_ci
71462306a36Sopenharmony_ci	return 0;
71562306a36Sopenharmony_ci}
71662306a36Sopenharmony_ci
71762306a36Sopenharmony_ci/* Start USB device */
71862306a36Sopenharmony_cistatic int usb_8dev_start(struct usb_8dev_priv *priv)
71962306a36Sopenharmony_ci{
72062306a36Sopenharmony_ci	struct net_device *netdev = priv->netdev;
72162306a36Sopenharmony_ci	int err, i;
72262306a36Sopenharmony_ci
72362306a36Sopenharmony_ci	for (i = 0; i < MAX_RX_URBS; i++) {
72462306a36Sopenharmony_ci		struct urb *urb = NULL;
72562306a36Sopenharmony_ci		u8 *buf;
72662306a36Sopenharmony_ci		dma_addr_t buf_dma;
72762306a36Sopenharmony_ci
72862306a36Sopenharmony_ci		/* create a URB, and a buffer for it */
72962306a36Sopenharmony_ci		urb = usb_alloc_urb(0, GFP_KERNEL);
73062306a36Sopenharmony_ci		if (!urb) {
73162306a36Sopenharmony_ci			err = -ENOMEM;
73262306a36Sopenharmony_ci			break;
73362306a36Sopenharmony_ci		}
73462306a36Sopenharmony_ci
73562306a36Sopenharmony_ci		buf = usb_alloc_coherent(priv->udev, RX_BUFFER_SIZE, GFP_KERNEL,
73662306a36Sopenharmony_ci					 &buf_dma);
73762306a36Sopenharmony_ci		if (!buf) {
73862306a36Sopenharmony_ci			netdev_err(netdev, "No memory left for USB buffer\n");
73962306a36Sopenharmony_ci			usb_free_urb(urb);
74062306a36Sopenharmony_ci			err = -ENOMEM;
74162306a36Sopenharmony_ci			break;
74262306a36Sopenharmony_ci		}
74362306a36Sopenharmony_ci
74462306a36Sopenharmony_ci		urb->transfer_dma = buf_dma;
74562306a36Sopenharmony_ci
74662306a36Sopenharmony_ci		usb_fill_bulk_urb(urb, priv->udev,
74762306a36Sopenharmony_ci				  usb_rcvbulkpipe(priv->udev,
74862306a36Sopenharmony_ci						  USB_8DEV_ENDP_DATA_RX),
74962306a36Sopenharmony_ci				  buf, RX_BUFFER_SIZE,
75062306a36Sopenharmony_ci				  usb_8dev_read_bulk_callback, priv);
75162306a36Sopenharmony_ci		urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
75262306a36Sopenharmony_ci		usb_anchor_urb(urb, &priv->rx_submitted);
75362306a36Sopenharmony_ci
75462306a36Sopenharmony_ci		err = usb_submit_urb(urb, GFP_KERNEL);
75562306a36Sopenharmony_ci		if (err) {
75662306a36Sopenharmony_ci			usb_unanchor_urb(urb);
75762306a36Sopenharmony_ci			usb_free_coherent(priv->udev, RX_BUFFER_SIZE, buf,
75862306a36Sopenharmony_ci					  urb->transfer_dma);
75962306a36Sopenharmony_ci			usb_free_urb(urb);
76062306a36Sopenharmony_ci			break;
76162306a36Sopenharmony_ci		}
76262306a36Sopenharmony_ci
76362306a36Sopenharmony_ci		priv->rxbuf[i] = buf;
76462306a36Sopenharmony_ci		priv->rxbuf_dma[i] = buf_dma;
76562306a36Sopenharmony_ci
76662306a36Sopenharmony_ci		/* Drop reference, USB core will take care of freeing it */
76762306a36Sopenharmony_ci		usb_free_urb(urb);
76862306a36Sopenharmony_ci	}
76962306a36Sopenharmony_ci
77062306a36Sopenharmony_ci	/* Did we submit any URBs */
77162306a36Sopenharmony_ci	if (i == 0) {
77262306a36Sopenharmony_ci		netdev_warn(netdev, "couldn't setup read URBs\n");
77362306a36Sopenharmony_ci		return err;
77462306a36Sopenharmony_ci	}
77562306a36Sopenharmony_ci
77662306a36Sopenharmony_ci	/* Warn if we've couldn't transmit all the URBs */
77762306a36Sopenharmony_ci	if (i < MAX_RX_URBS)
77862306a36Sopenharmony_ci		netdev_warn(netdev, "rx performance may be slow\n");
77962306a36Sopenharmony_ci
78062306a36Sopenharmony_ci	err = usb_8dev_cmd_open(priv);
78162306a36Sopenharmony_ci	if (err)
78262306a36Sopenharmony_ci		goto failed;
78362306a36Sopenharmony_ci
78462306a36Sopenharmony_ci	priv->can.state = CAN_STATE_ERROR_ACTIVE;
78562306a36Sopenharmony_ci
78662306a36Sopenharmony_ci	return 0;
78762306a36Sopenharmony_ci
78862306a36Sopenharmony_cifailed:
78962306a36Sopenharmony_ci	if (err == -ENODEV)
79062306a36Sopenharmony_ci		netif_device_detach(priv->netdev);
79162306a36Sopenharmony_ci
79262306a36Sopenharmony_ci	netdev_warn(netdev, "couldn't submit control: %d\n", err);
79362306a36Sopenharmony_ci
79462306a36Sopenharmony_ci	return err;
79562306a36Sopenharmony_ci}
79662306a36Sopenharmony_ci
79762306a36Sopenharmony_ci/* Open USB device */
79862306a36Sopenharmony_cistatic int usb_8dev_open(struct net_device *netdev)
79962306a36Sopenharmony_ci{
80062306a36Sopenharmony_ci	struct usb_8dev_priv *priv = netdev_priv(netdev);
80162306a36Sopenharmony_ci	int err;
80262306a36Sopenharmony_ci
80362306a36Sopenharmony_ci	/* common open */
80462306a36Sopenharmony_ci	err = open_candev(netdev);
80562306a36Sopenharmony_ci	if (err)
80662306a36Sopenharmony_ci		return err;
80762306a36Sopenharmony_ci
80862306a36Sopenharmony_ci	/* finally start device */
80962306a36Sopenharmony_ci	err = usb_8dev_start(priv);
81062306a36Sopenharmony_ci	if (err) {
81162306a36Sopenharmony_ci		if (err == -ENODEV)
81262306a36Sopenharmony_ci			netif_device_detach(priv->netdev);
81362306a36Sopenharmony_ci
81462306a36Sopenharmony_ci		netdev_warn(netdev, "couldn't start device: %d\n",
81562306a36Sopenharmony_ci			 err);
81662306a36Sopenharmony_ci
81762306a36Sopenharmony_ci		close_candev(netdev);
81862306a36Sopenharmony_ci
81962306a36Sopenharmony_ci		return err;
82062306a36Sopenharmony_ci	}
82162306a36Sopenharmony_ci
82262306a36Sopenharmony_ci	netif_start_queue(netdev);
82362306a36Sopenharmony_ci
82462306a36Sopenharmony_ci	return 0;
82562306a36Sopenharmony_ci}
82662306a36Sopenharmony_ci
82762306a36Sopenharmony_cistatic void unlink_all_urbs(struct usb_8dev_priv *priv)
82862306a36Sopenharmony_ci{
82962306a36Sopenharmony_ci	int i;
83062306a36Sopenharmony_ci
83162306a36Sopenharmony_ci	usb_kill_anchored_urbs(&priv->rx_submitted);
83262306a36Sopenharmony_ci
83362306a36Sopenharmony_ci	for (i = 0; i < MAX_RX_URBS; ++i)
83462306a36Sopenharmony_ci		usb_free_coherent(priv->udev, RX_BUFFER_SIZE,
83562306a36Sopenharmony_ci				  priv->rxbuf[i], priv->rxbuf_dma[i]);
83662306a36Sopenharmony_ci
83762306a36Sopenharmony_ci	usb_kill_anchored_urbs(&priv->tx_submitted);
83862306a36Sopenharmony_ci	atomic_set(&priv->active_tx_urbs, 0);
83962306a36Sopenharmony_ci
84062306a36Sopenharmony_ci	for (i = 0; i < MAX_TX_URBS; i++)
84162306a36Sopenharmony_ci		priv->tx_contexts[i].echo_index = MAX_TX_URBS;
84262306a36Sopenharmony_ci}
84362306a36Sopenharmony_ci
84462306a36Sopenharmony_ci/* Close USB device */
84562306a36Sopenharmony_cistatic int usb_8dev_close(struct net_device *netdev)
84662306a36Sopenharmony_ci{
84762306a36Sopenharmony_ci	struct usb_8dev_priv *priv = netdev_priv(netdev);
84862306a36Sopenharmony_ci	int err = 0;
84962306a36Sopenharmony_ci
85062306a36Sopenharmony_ci	/* Send CLOSE command to CAN controller */
85162306a36Sopenharmony_ci	err = usb_8dev_cmd_close(priv);
85262306a36Sopenharmony_ci	if (err)
85362306a36Sopenharmony_ci		netdev_warn(netdev, "couldn't stop device");
85462306a36Sopenharmony_ci
85562306a36Sopenharmony_ci	priv->can.state = CAN_STATE_STOPPED;
85662306a36Sopenharmony_ci
85762306a36Sopenharmony_ci	netif_stop_queue(netdev);
85862306a36Sopenharmony_ci
85962306a36Sopenharmony_ci	/* Stop polling */
86062306a36Sopenharmony_ci	unlink_all_urbs(priv);
86162306a36Sopenharmony_ci
86262306a36Sopenharmony_ci	close_candev(netdev);
86362306a36Sopenharmony_ci
86462306a36Sopenharmony_ci	return err;
86562306a36Sopenharmony_ci}
86662306a36Sopenharmony_ci
86762306a36Sopenharmony_cistatic const struct net_device_ops usb_8dev_netdev_ops = {
86862306a36Sopenharmony_ci	.ndo_open = usb_8dev_open,
86962306a36Sopenharmony_ci	.ndo_stop = usb_8dev_close,
87062306a36Sopenharmony_ci	.ndo_start_xmit = usb_8dev_start_xmit,
87162306a36Sopenharmony_ci	.ndo_change_mtu = can_change_mtu,
87262306a36Sopenharmony_ci};
87362306a36Sopenharmony_ci
87462306a36Sopenharmony_cistatic const struct ethtool_ops usb_8dev_ethtool_ops = {
87562306a36Sopenharmony_ci	.get_ts_info = ethtool_op_get_ts_info,
87662306a36Sopenharmony_ci};
87762306a36Sopenharmony_ci
87862306a36Sopenharmony_cistatic const struct can_bittiming_const usb_8dev_bittiming_const = {
87962306a36Sopenharmony_ci	.name = KBUILD_MODNAME,
88062306a36Sopenharmony_ci	.tseg1_min = 1,
88162306a36Sopenharmony_ci	.tseg1_max = 16,
88262306a36Sopenharmony_ci	.tseg2_min = 1,
88362306a36Sopenharmony_ci	.tseg2_max = 8,
88462306a36Sopenharmony_ci	.sjw_max = 4,
88562306a36Sopenharmony_ci	.brp_min = 1,
88662306a36Sopenharmony_ci	.brp_max = 1024,
88762306a36Sopenharmony_ci	.brp_inc = 1,
88862306a36Sopenharmony_ci};
88962306a36Sopenharmony_ci
89062306a36Sopenharmony_ci/* Probe USB device
89162306a36Sopenharmony_ci *
89262306a36Sopenharmony_ci * Check device and firmware.
89362306a36Sopenharmony_ci * Set supported modes and bittiming constants.
89462306a36Sopenharmony_ci * Allocate some memory.
89562306a36Sopenharmony_ci */
89662306a36Sopenharmony_cistatic int usb_8dev_probe(struct usb_interface *intf,
89762306a36Sopenharmony_ci			 const struct usb_device_id *id)
89862306a36Sopenharmony_ci{
89962306a36Sopenharmony_ci	struct net_device *netdev;
90062306a36Sopenharmony_ci	struct usb_8dev_priv *priv;
90162306a36Sopenharmony_ci	int i, err = -ENOMEM;
90262306a36Sopenharmony_ci	u32 version;
90362306a36Sopenharmony_ci	char buf[18];
90462306a36Sopenharmony_ci	struct usb_device *usbdev = interface_to_usbdev(intf);
90562306a36Sopenharmony_ci
90662306a36Sopenharmony_ci	/* product id looks strange, better we also check iProduct string */
90762306a36Sopenharmony_ci	if (usb_string(usbdev, usbdev->descriptor.iProduct, buf,
90862306a36Sopenharmony_ci		       sizeof(buf)) > 0 && strcmp(buf, "USB2CAN converter")) {
90962306a36Sopenharmony_ci		dev_info(&usbdev->dev, "ignoring: not an USB2CAN converter\n");
91062306a36Sopenharmony_ci		return -ENODEV;
91162306a36Sopenharmony_ci	}
91262306a36Sopenharmony_ci
91362306a36Sopenharmony_ci	netdev = alloc_candev(sizeof(struct usb_8dev_priv), MAX_TX_URBS);
91462306a36Sopenharmony_ci	if (!netdev) {
91562306a36Sopenharmony_ci		dev_err(&intf->dev, "Couldn't alloc candev\n");
91662306a36Sopenharmony_ci		return -ENOMEM;
91762306a36Sopenharmony_ci	}
91862306a36Sopenharmony_ci
91962306a36Sopenharmony_ci	priv = netdev_priv(netdev);
92062306a36Sopenharmony_ci
92162306a36Sopenharmony_ci	priv->udev = usbdev;
92262306a36Sopenharmony_ci	priv->netdev = netdev;
92362306a36Sopenharmony_ci
92462306a36Sopenharmony_ci	priv->can.state = CAN_STATE_STOPPED;
92562306a36Sopenharmony_ci	priv->can.clock.freq = USB_8DEV_ABP_CLOCK;
92662306a36Sopenharmony_ci	priv->can.bittiming_const = &usb_8dev_bittiming_const;
92762306a36Sopenharmony_ci	priv->can.do_set_mode = usb_8dev_set_mode;
92862306a36Sopenharmony_ci	priv->can.do_get_berr_counter = usb_8dev_get_berr_counter;
92962306a36Sopenharmony_ci	priv->can.ctrlmode_supported = CAN_CTRLMODE_LOOPBACK |
93062306a36Sopenharmony_ci				      CAN_CTRLMODE_LISTENONLY |
93162306a36Sopenharmony_ci				      CAN_CTRLMODE_ONE_SHOT |
93262306a36Sopenharmony_ci				      CAN_CTRLMODE_CC_LEN8_DLC;
93362306a36Sopenharmony_ci
93462306a36Sopenharmony_ci	netdev->netdev_ops = &usb_8dev_netdev_ops;
93562306a36Sopenharmony_ci	netdev->ethtool_ops = &usb_8dev_ethtool_ops;
93662306a36Sopenharmony_ci
93762306a36Sopenharmony_ci	netdev->flags |= IFF_ECHO; /* we support local echo */
93862306a36Sopenharmony_ci
93962306a36Sopenharmony_ci	init_usb_anchor(&priv->rx_submitted);
94062306a36Sopenharmony_ci
94162306a36Sopenharmony_ci	init_usb_anchor(&priv->tx_submitted);
94262306a36Sopenharmony_ci	atomic_set(&priv->active_tx_urbs, 0);
94362306a36Sopenharmony_ci
94462306a36Sopenharmony_ci	for (i = 0; i < MAX_TX_URBS; i++)
94562306a36Sopenharmony_ci		priv->tx_contexts[i].echo_index = MAX_TX_URBS;
94662306a36Sopenharmony_ci
94762306a36Sopenharmony_ci	priv->cmd_msg_buffer = devm_kzalloc(&intf->dev, sizeof(struct usb_8dev_cmd_msg),
94862306a36Sopenharmony_ci					    GFP_KERNEL);
94962306a36Sopenharmony_ci	if (!priv->cmd_msg_buffer)
95062306a36Sopenharmony_ci		goto cleanup_candev;
95162306a36Sopenharmony_ci
95262306a36Sopenharmony_ci	usb_set_intfdata(intf, priv);
95362306a36Sopenharmony_ci
95462306a36Sopenharmony_ci	SET_NETDEV_DEV(netdev, &intf->dev);
95562306a36Sopenharmony_ci
95662306a36Sopenharmony_ci	mutex_init(&priv->usb_8dev_cmd_lock);
95762306a36Sopenharmony_ci
95862306a36Sopenharmony_ci	err = register_candev(netdev);
95962306a36Sopenharmony_ci	if (err) {
96062306a36Sopenharmony_ci		netdev_err(netdev,
96162306a36Sopenharmony_ci			"couldn't register CAN device: %d\n", err);
96262306a36Sopenharmony_ci		goto cleanup_candev;
96362306a36Sopenharmony_ci	}
96462306a36Sopenharmony_ci
96562306a36Sopenharmony_ci	err = usb_8dev_cmd_version(priv, &version);
96662306a36Sopenharmony_ci	if (err) {
96762306a36Sopenharmony_ci		netdev_err(netdev, "can't get firmware version\n");
96862306a36Sopenharmony_ci		goto cleanup_unregister_candev;
96962306a36Sopenharmony_ci	} else {
97062306a36Sopenharmony_ci		netdev_info(netdev,
97162306a36Sopenharmony_ci			 "firmware: %d.%d, hardware: %d.%d\n",
97262306a36Sopenharmony_ci			 (version>>24) & 0xff, (version>>16) & 0xff,
97362306a36Sopenharmony_ci			 (version>>8) & 0xff, version & 0xff);
97462306a36Sopenharmony_ci	}
97562306a36Sopenharmony_ci
97662306a36Sopenharmony_ci	return 0;
97762306a36Sopenharmony_ci
97862306a36Sopenharmony_cicleanup_unregister_candev:
97962306a36Sopenharmony_ci	unregister_netdev(priv->netdev);
98062306a36Sopenharmony_ci
98162306a36Sopenharmony_cicleanup_candev:
98262306a36Sopenharmony_ci	free_candev(netdev);
98362306a36Sopenharmony_ci
98462306a36Sopenharmony_ci	return err;
98562306a36Sopenharmony_ci
98662306a36Sopenharmony_ci}
98762306a36Sopenharmony_ci
98862306a36Sopenharmony_ci/* Called by the usb core when driver is unloaded or device is removed */
98962306a36Sopenharmony_cistatic void usb_8dev_disconnect(struct usb_interface *intf)
99062306a36Sopenharmony_ci{
99162306a36Sopenharmony_ci	struct usb_8dev_priv *priv = usb_get_intfdata(intf);
99262306a36Sopenharmony_ci
99362306a36Sopenharmony_ci	usb_set_intfdata(intf, NULL);
99462306a36Sopenharmony_ci
99562306a36Sopenharmony_ci	if (priv) {
99662306a36Sopenharmony_ci		netdev_info(priv->netdev, "device disconnected\n");
99762306a36Sopenharmony_ci
99862306a36Sopenharmony_ci		unregister_netdev(priv->netdev);
99962306a36Sopenharmony_ci		unlink_all_urbs(priv);
100062306a36Sopenharmony_ci		free_candev(priv->netdev);
100162306a36Sopenharmony_ci	}
100262306a36Sopenharmony_ci
100362306a36Sopenharmony_ci}
100462306a36Sopenharmony_ci
100562306a36Sopenharmony_cistatic struct usb_driver usb_8dev_driver = {
100662306a36Sopenharmony_ci	.name =		KBUILD_MODNAME,
100762306a36Sopenharmony_ci	.probe =	usb_8dev_probe,
100862306a36Sopenharmony_ci	.disconnect =	usb_8dev_disconnect,
100962306a36Sopenharmony_ci	.id_table =	usb_8dev_table,
101062306a36Sopenharmony_ci};
101162306a36Sopenharmony_ci
101262306a36Sopenharmony_cimodule_usb_driver(usb_8dev_driver);
101362306a36Sopenharmony_ci
101462306a36Sopenharmony_ciMODULE_AUTHOR("Bernd Krumboeck <krumboeck@universalnet.at>");
101562306a36Sopenharmony_ciMODULE_DESCRIPTION("CAN driver for 8 devices USB2CAN interfaces");
101662306a36Sopenharmony_ciMODULE_LICENSE("GPL v2");
1017