14d8bc510SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
251f3baadSRemigiusz Kołłątaj /* SocketCAN driver for Microchip CAN BUS Analyzer Tool
351f3baadSRemigiusz Kołłątaj *
451f3baadSRemigiusz Kołłątaj * Copyright (C) 2017 Mobica Limited
551f3baadSRemigiusz Kołłątaj *
651f3baadSRemigiusz Kołłątaj * This driver is inspired by the 4.6.2 version of net/can/usb/usb_8dev.c
751f3baadSRemigiusz Kołłątaj */
851f3baadSRemigiusz Kołłątaj
951f3baadSRemigiusz Kołłątaj #include <asm/unaligned.h>
1051f3baadSRemigiusz Kołłątaj #include <linux/can.h>
1151f3baadSRemigiusz Kołłątaj #include <linux/can/dev.h>
1251f3baadSRemigiusz Kołłątaj #include <linux/can/error.h>
13409c188cSVincent Mailhol #include <linux/ethtool.h>
1451f3baadSRemigiusz Kołłątaj #include <linux/module.h>
1551f3baadSRemigiusz Kołłątaj #include <linux/netdevice.h>
1651f3baadSRemigiusz Kołłątaj #include <linux/signal.h>
1751f3baadSRemigiusz Kołłątaj #include <linux/slab.h>
1851f3baadSRemigiusz Kołłątaj #include <linux/usb.h>
1951f3baadSRemigiusz Kołłątaj
2051f3baadSRemigiusz Kołłątaj /* vendor and product id */
2151f3baadSRemigiusz Kołłątaj #define MCBA_MODULE_NAME "mcba_usb"
2251f3baadSRemigiusz Kołłątaj #define MCBA_VENDOR_ID 0x04d8
2351f3baadSRemigiusz Kołłątaj #define MCBA_PRODUCT_ID 0x0a30
2451f3baadSRemigiusz Kołłątaj
2551f3baadSRemigiusz Kołłątaj /* driver constants */
2651f3baadSRemigiusz Kołłątaj #define MCBA_MAX_RX_URBS 20
2751f3baadSRemigiusz Kołłątaj #define MCBA_MAX_TX_URBS 20
2851f3baadSRemigiusz Kołłątaj #define MCBA_CTX_FREE MCBA_MAX_TX_URBS
2951f3baadSRemigiusz Kołłątaj
3051f3baadSRemigiusz Kołłątaj /* RX buffer must be bigger than msg size since at the
3188bfb9a7SMarc Kleine-Budde * beginning USB messages are stacked.
3251f3baadSRemigiusz Kołłątaj */
3351f3baadSRemigiusz Kołłątaj #define MCBA_USB_RX_BUFF_SIZE 64
3451f3baadSRemigiusz Kołłątaj #define MCBA_USB_TX_BUFF_SIZE (sizeof(struct mcba_usb_msg))
3551f3baadSRemigiusz Kołłątaj
3651f3baadSRemigiusz Kołłątaj /* Microchip command id */
3751f3baadSRemigiusz Kołłątaj #define MBCA_CMD_RECEIVE_MESSAGE 0xE3
3851f3baadSRemigiusz Kołłątaj #define MBCA_CMD_I_AM_ALIVE_FROM_CAN 0xF5
3951f3baadSRemigiusz Kołłątaj #define MBCA_CMD_I_AM_ALIVE_FROM_USB 0xF7
4051f3baadSRemigiusz Kołłątaj #define MBCA_CMD_CHANGE_BIT_RATE 0xA1
4151f3baadSRemigiusz Kołłątaj #define MBCA_CMD_TRANSMIT_MESSAGE_EV 0xA3
4251f3baadSRemigiusz Kołłątaj #define MBCA_CMD_SETUP_TERMINATION_RESISTANCE 0xA8
4351f3baadSRemigiusz Kołłątaj #define MBCA_CMD_READ_FW_VERSION 0xA9
4451f3baadSRemigiusz Kołłątaj #define MBCA_CMD_NOTHING_TO_SEND 0xFF
4551f3baadSRemigiusz Kołłątaj #define MBCA_CMD_TRANSMIT_MESSAGE_RSP 0xE2
4651f3baadSRemigiusz Kołłątaj
4751f3baadSRemigiusz Kołłątaj #define MCBA_VER_REQ_USB 1
4851f3baadSRemigiusz Kołłątaj #define MCBA_VER_REQ_CAN 2
4951f3baadSRemigiusz Kołłątaj
50*1a8e3bd2SYasushi SHOJI /* Drive the CAN_RES signal LOW "0" to activate R24 and R25 */
51*1a8e3bd2SYasushi SHOJI #define MCBA_VER_TERMINATION_ON 0
52*1a8e3bd2SYasushi SHOJI #define MCBA_VER_TERMINATION_OFF 1
53*1a8e3bd2SYasushi SHOJI
5451f3baadSRemigiusz Kołłątaj #define MCBA_SIDL_EXID_MASK 0x8
5551f3baadSRemigiusz Kołłątaj #define MCBA_DLC_MASK 0xf
5651f3baadSRemigiusz Kołłątaj #define MCBA_DLC_RTR_MASK 0x40
5751f3baadSRemigiusz Kołłątaj
5851f3baadSRemigiusz Kołłątaj #define MCBA_CAN_STATE_WRN_TH 95
5951f3baadSRemigiusz Kołłątaj #define MCBA_CAN_STATE_ERR_PSV_TH 127
6051f3baadSRemigiusz Kołłątaj
6151f3baadSRemigiusz Kołłątaj #define MCBA_TERMINATION_DISABLED CAN_TERMINATION_DISABLED
6251f3baadSRemigiusz Kołłątaj #define MCBA_TERMINATION_ENABLED 120
6351f3baadSRemigiusz Kołłątaj
6451f3baadSRemigiusz Kołłątaj struct mcba_usb_ctx {
6551f3baadSRemigiusz Kołłątaj struct mcba_priv *priv;
6651f3baadSRemigiusz Kołłątaj u32 ndx;
6751f3baadSRemigiusz Kołłątaj bool can;
6851f3baadSRemigiusz Kołłątaj };
6951f3baadSRemigiusz Kołłątaj
7051f3baadSRemigiusz Kołłątaj /* Structure to hold all of our device specific stuff */
7151f3baadSRemigiusz Kołłątaj struct mcba_priv {
7251f3baadSRemigiusz Kołłątaj struct can_priv can; /* must be the first member */
7351f3baadSRemigiusz Kołłątaj struct sk_buff *echo_skb[MCBA_MAX_TX_URBS];
7451f3baadSRemigiusz Kołłątaj struct mcba_usb_ctx tx_context[MCBA_MAX_TX_URBS];
7551f3baadSRemigiusz Kołłątaj struct usb_device *udev;
7651f3baadSRemigiusz Kołłątaj struct net_device *netdev;
7751f3baadSRemigiusz Kołłątaj struct usb_anchor tx_submitted;
7851f3baadSRemigiusz Kołłątaj struct usb_anchor rx_submitted;
7951f3baadSRemigiusz Kołłątaj struct can_berr_counter bec;
8051f3baadSRemigiusz Kołłątaj bool usb_ka_first_pass;
8151f3baadSRemigiusz Kołłątaj bool can_ka_first_pass;
8251f3baadSRemigiusz Kołłątaj bool can_speed_check;
8351f3baadSRemigiusz Kołłątaj atomic_t free_ctx_cnt;
8491c02557SPavel Skripkin void *rxbuf[MCBA_MAX_RX_URBS];
8591c02557SPavel Skripkin dma_addr_t rxbuf_dma[MCBA_MAX_RX_URBS];
86136bed0bSPavel Skripkin int rx_pipe;
87136bed0bSPavel Skripkin int tx_pipe;
8851f3baadSRemigiusz Kołłątaj };
8951f3baadSRemigiusz Kołłątaj
9051f3baadSRemigiusz Kołłątaj /* CAN frame */
9151f3baadSRemigiusz Kołłątaj struct __packed mcba_usb_msg_can {
9251f3baadSRemigiusz Kołłątaj u8 cmd_id;
9351f3baadSRemigiusz Kołłątaj __be16 eid;
9451f3baadSRemigiusz Kołłątaj __be16 sid;
9551f3baadSRemigiusz Kołłątaj u8 dlc;
9651f3baadSRemigiusz Kołłątaj u8 data[8];
9751f3baadSRemigiusz Kołłątaj u8 timestamp[4];
9851f3baadSRemigiusz Kołłątaj u8 checksum;
9951f3baadSRemigiusz Kołłątaj };
10051f3baadSRemigiusz Kołłątaj
10151f3baadSRemigiusz Kołłątaj /* command frame */
10251f3baadSRemigiusz Kołłątaj struct __packed mcba_usb_msg {
10351f3baadSRemigiusz Kołłątaj u8 cmd_id;
10451f3baadSRemigiusz Kołłątaj u8 unused[18];
10551f3baadSRemigiusz Kołłątaj };
10651f3baadSRemigiusz Kołłątaj
10751f3baadSRemigiusz Kołłątaj struct __packed mcba_usb_msg_ka_usb {
10851f3baadSRemigiusz Kołłątaj u8 cmd_id;
10951f3baadSRemigiusz Kołłątaj u8 termination_state;
11051f3baadSRemigiusz Kołłątaj u8 soft_ver_major;
11151f3baadSRemigiusz Kołłątaj u8 soft_ver_minor;
11251f3baadSRemigiusz Kołłątaj u8 unused[15];
11351f3baadSRemigiusz Kołłątaj };
11451f3baadSRemigiusz Kołłątaj
11551f3baadSRemigiusz Kołłątaj struct __packed mcba_usb_msg_ka_can {
11651f3baadSRemigiusz Kołłątaj u8 cmd_id;
11751f3baadSRemigiusz Kołłątaj u8 tx_err_cnt;
11851f3baadSRemigiusz Kołłątaj u8 rx_err_cnt;
11951f3baadSRemigiusz Kołłątaj u8 rx_buff_ovfl;
12051f3baadSRemigiusz Kołłątaj u8 tx_bus_off;
12151f3baadSRemigiusz Kołłątaj __be16 can_bitrate;
12251f3baadSRemigiusz Kołłątaj __le16 rx_lost;
12351f3baadSRemigiusz Kołłątaj u8 can_stat;
12451f3baadSRemigiusz Kołłątaj u8 soft_ver_major;
12551f3baadSRemigiusz Kołłątaj u8 soft_ver_minor;
12651f3baadSRemigiusz Kołłątaj u8 debug_mode;
12751f3baadSRemigiusz Kołłątaj u8 test_complete;
12851f3baadSRemigiusz Kołłątaj u8 test_result;
12951f3baadSRemigiusz Kołłątaj u8 unused[4];
13051f3baadSRemigiusz Kołłątaj };
13151f3baadSRemigiusz Kołłątaj
13251f3baadSRemigiusz Kołłątaj struct __packed mcba_usb_msg_change_bitrate {
13351f3baadSRemigiusz Kołłątaj u8 cmd_id;
13451f3baadSRemigiusz Kołłątaj __be16 bitrate;
13551f3baadSRemigiusz Kołłątaj u8 unused[16];
13651f3baadSRemigiusz Kołłątaj };
13751f3baadSRemigiusz Kołłątaj
13851f3baadSRemigiusz Kołłątaj struct __packed mcba_usb_msg_termination {
13951f3baadSRemigiusz Kołłątaj u8 cmd_id;
14051f3baadSRemigiusz Kołłątaj u8 termination;
14151f3baadSRemigiusz Kołłątaj u8 unused[17];
14251f3baadSRemigiusz Kołłątaj };
14351f3baadSRemigiusz Kołłątaj
14451f3baadSRemigiusz Kołłątaj struct __packed mcba_usb_msg_fw_ver {
14551f3baadSRemigiusz Kołłątaj u8 cmd_id;
14651f3baadSRemigiusz Kołłątaj u8 pic;
14751f3baadSRemigiusz Kołłątaj u8 unused[17];
14851f3baadSRemigiusz Kołłątaj };
14951f3baadSRemigiusz Kołłątaj
15051f3baadSRemigiusz Kołłątaj static const struct usb_device_id mcba_usb_table[] = {
15151f3baadSRemigiusz Kołłątaj { USB_DEVICE(MCBA_VENDOR_ID, MCBA_PRODUCT_ID) },
15251f3baadSRemigiusz Kołłątaj {} /* Terminating entry */
15351f3baadSRemigiusz Kołłątaj };
15451f3baadSRemigiusz Kołłątaj
15551f3baadSRemigiusz Kołłątaj MODULE_DEVICE_TABLE(usb, mcba_usb_table);
15651f3baadSRemigiusz Kołłątaj
15751f3baadSRemigiusz Kołłątaj static const u16 mcba_termination[] = { MCBA_TERMINATION_DISABLED,
15851f3baadSRemigiusz Kołłątaj MCBA_TERMINATION_ENABLED };
15951f3baadSRemigiusz Kołłątaj
16051f3baadSRemigiusz Kołłątaj static const u32 mcba_bitrate[] = { 20000, 33333, 50000, 80000, 83333,
16151f3baadSRemigiusz Kołłątaj 100000, 125000, 150000, 175000, 200000,
16251f3baadSRemigiusz Kołłątaj 225000, 250000, 275000, 300000, 500000,
16351f3baadSRemigiusz Kołłątaj 625000, 800000, 1000000 };
16451f3baadSRemigiusz Kołłątaj
mcba_init_ctx(struct mcba_priv * priv)16551f3baadSRemigiusz Kołłątaj static inline void mcba_init_ctx(struct mcba_priv *priv)
16651f3baadSRemigiusz Kołłątaj {
16751f3baadSRemigiusz Kołłątaj int i = 0;
16851f3baadSRemigiusz Kołłątaj
16951f3baadSRemigiusz Kołłątaj for (i = 0; i < MCBA_MAX_TX_URBS; i++) {
17051f3baadSRemigiusz Kołłątaj priv->tx_context[i].ndx = MCBA_CTX_FREE;
17151f3baadSRemigiusz Kołłątaj priv->tx_context[i].priv = priv;
17251f3baadSRemigiusz Kołłątaj }
17351f3baadSRemigiusz Kołłątaj
17451f3baadSRemigiusz Kołłątaj atomic_set(&priv->free_ctx_cnt, ARRAY_SIZE(priv->tx_context));
17551f3baadSRemigiusz Kołłątaj }
17651f3baadSRemigiusz Kołłątaj
mcba_usb_get_free_ctx(struct mcba_priv * priv,struct can_frame * cf)17751f3baadSRemigiusz Kołłątaj static inline struct mcba_usb_ctx *mcba_usb_get_free_ctx(struct mcba_priv *priv,
17851f3baadSRemigiusz Kołłątaj struct can_frame *cf)
17951f3baadSRemigiusz Kołłątaj {
18051f3baadSRemigiusz Kołłątaj int i = 0;
18151f3baadSRemigiusz Kołłątaj struct mcba_usb_ctx *ctx = NULL;
18251f3baadSRemigiusz Kołłątaj
18351f3baadSRemigiusz Kołłątaj for (i = 0; i < MCBA_MAX_TX_URBS; i++) {
18451f3baadSRemigiusz Kołłątaj if (priv->tx_context[i].ndx == MCBA_CTX_FREE) {
18551f3baadSRemigiusz Kołłątaj ctx = &priv->tx_context[i];
18651f3baadSRemigiusz Kołłątaj ctx->ndx = i;
18751f3baadSRemigiusz Kołłątaj
188cc4b08c3SVincent Mailhol if (cf)
18951f3baadSRemigiusz Kołłątaj ctx->can = true;
190cc4b08c3SVincent Mailhol else
19151f3baadSRemigiusz Kołłątaj ctx->can = false;
19251f3baadSRemigiusz Kołłątaj
19351f3baadSRemigiusz Kołłątaj atomic_dec(&priv->free_ctx_cnt);
19451f3baadSRemigiusz Kołłątaj break;
19551f3baadSRemigiusz Kołłątaj }
19651f3baadSRemigiusz Kołłątaj }
19751f3baadSRemigiusz Kołłątaj
19851f3baadSRemigiusz Kołłątaj if (!atomic_read(&priv->free_ctx_cnt))
19951f3baadSRemigiusz Kołłątaj /* That was the last free ctx. Slow down tx path */
20051f3baadSRemigiusz Kołłątaj netif_stop_queue(priv->netdev);
20151f3baadSRemigiusz Kołłątaj
20251f3baadSRemigiusz Kołłątaj return ctx;
20351f3baadSRemigiusz Kołłątaj }
20451f3baadSRemigiusz Kołłątaj
20551f3baadSRemigiusz Kołłątaj /* mcba_usb_free_ctx and mcba_usb_get_free_ctx are executed by different
20651f3baadSRemigiusz Kołłątaj * threads. The order of execution in below function is important.
20751f3baadSRemigiusz Kołłątaj */
mcba_usb_free_ctx(struct mcba_usb_ctx * ctx)20851f3baadSRemigiusz Kołłątaj static inline void mcba_usb_free_ctx(struct mcba_usb_ctx *ctx)
20951f3baadSRemigiusz Kołłątaj {
21051f3baadSRemigiusz Kołłątaj /* Increase number of free ctxs before freeing ctx */
21151f3baadSRemigiusz Kołłątaj atomic_inc(&ctx->priv->free_ctx_cnt);
21251f3baadSRemigiusz Kołłątaj
21351f3baadSRemigiusz Kołłątaj ctx->ndx = MCBA_CTX_FREE;
21451f3baadSRemigiusz Kołłątaj
21551f3baadSRemigiusz Kołłątaj /* Wake up the queue once ctx is marked free */
21651f3baadSRemigiusz Kołłątaj netif_wake_queue(ctx->priv->netdev);
21751f3baadSRemigiusz Kołłątaj }
21851f3baadSRemigiusz Kołłątaj
mcba_usb_write_bulk_callback(struct urb * urb)21951f3baadSRemigiusz Kołłątaj static void mcba_usb_write_bulk_callback(struct urb *urb)
22051f3baadSRemigiusz Kołłątaj {
22151f3baadSRemigiusz Kołłątaj struct mcba_usb_ctx *ctx = urb->context;
22251f3baadSRemigiusz Kołłątaj struct net_device *netdev;
22351f3baadSRemigiusz Kołłątaj
22451f3baadSRemigiusz Kołłątaj WARN_ON(!ctx);
22551f3baadSRemigiusz Kołłątaj
22651f3baadSRemigiusz Kołłątaj netdev = ctx->priv->netdev;
22751f3baadSRemigiusz Kołłątaj
22851f3baadSRemigiusz Kołłątaj /* free up our allocated buffer */
22951f3baadSRemigiusz Kołłątaj usb_free_coherent(urb->dev, urb->transfer_buffer_length,
23051f3baadSRemigiusz Kołłątaj urb->transfer_buffer, urb->transfer_dma);
23151f3baadSRemigiusz Kołłątaj
23251f3baadSRemigiusz Kołłątaj if (ctx->can) {
23351f3baadSRemigiusz Kołłątaj if (!netif_device_present(netdev))
23451f3baadSRemigiusz Kołłątaj return;
23551f3baadSRemigiusz Kołłątaj
23651f3baadSRemigiusz Kołłątaj netdev->stats.tx_packets++;
237cc4b08c3SVincent Mailhol netdev->stats.tx_bytes += can_get_echo_skb(netdev, ctx->ndx,
238cc4b08c3SVincent Mailhol NULL);
23951f3baadSRemigiusz Kołłątaj }
24051f3baadSRemigiusz Kołłątaj
24151f3baadSRemigiusz Kołłątaj if (urb->status)
24251f3baadSRemigiusz Kołłątaj netdev_info(netdev, "Tx URB aborted (%d)\n", urb->status);
24351f3baadSRemigiusz Kołłątaj
24451f3baadSRemigiusz Kołłątaj /* Release the context */
24551f3baadSRemigiusz Kołłątaj mcba_usb_free_ctx(ctx);
24651f3baadSRemigiusz Kołłątaj }
24751f3baadSRemigiusz Kołłątaj
24851f3baadSRemigiusz Kołłątaj /* Send data to device */
mcba_usb_xmit(struct mcba_priv * priv,struct mcba_usb_msg * usb_msg,struct mcba_usb_ctx * ctx)24951f3baadSRemigiusz Kołłątaj static netdev_tx_t mcba_usb_xmit(struct mcba_priv *priv,
25051f3baadSRemigiusz Kołłątaj struct mcba_usb_msg *usb_msg,
25151f3baadSRemigiusz Kołłątaj struct mcba_usb_ctx *ctx)
25251f3baadSRemigiusz Kołłątaj {
25351f3baadSRemigiusz Kołłątaj struct urb *urb;
25451f3baadSRemigiusz Kołłątaj u8 *buf;
25551f3baadSRemigiusz Kołłątaj int err;
25651f3baadSRemigiusz Kołłątaj
25751f3baadSRemigiusz Kołłątaj /* create a URB, and a buffer for it, and copy the data to the URB */
25851f3baadSRemigiusz Kołłątaj urb = usb_alloc_urb(0, GFP_ATOMIC);
25951f3baadSRemigiusz Kołłątaj if (!urb)
26051f3baadSRemigiusz Kołłątaj return -ENOMEM;
26151f3baadSRemigiusz Kołłątaj
26251f3baadSRemigiusz Kołłątaj buf = usb_alloc_coherent(priv->udev, MCBA_USB_TX_BUFF_SIZE, GFP_ATOMIC,
26351f3baadSRemigiusz Kołłątaj &urb->transfer_dma);
26451f3baadSRemigiusz Kołłątaj if (!buf) {
26551f3baadSRemigiusz Kołłątaj err = -ENOMEM;
26651f3baadSRemigiusz Kołłątaj goto nomembuf;
26751f3baadSRemigiusz Kołłątaj }
26851f3baadSRemigiusz Kołłątaj
26951f3baadSRemigiusz Kołłątaj memcpy(buf, usb_msg, MCBA_USB_TX_BUFF_SIZE);
27051f3baadSRemigiusz Kołłątaj
271136bed0bSPavel Skripkin usb_fill_bulk_urb(urb, priv->udev, priv->tx_pipe, buf, MCBA_USB_TX_BUFF_SIZE,
272136bed0bSPavel Skripkin mcba_usb_write_bulk_callback, ctx);
27351f3baadSRemigiusz Kołłątaj
27451f3baadSRemigiusz Kołłątaj urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
27551f3baadSRemigiusz Kołłątaj usb_anchor_urb(urb, &priv->tx_submitted);
27651f3baadSRemigiusz Kołłątaj
27751f3baadSRemigiusz Kołłątaj err = usb_submit_urb(urb, GFP_ATOMIC);
27851f3baadSRemigiusz Kołłątaj if (unlikely(err))
27951f3baadSRemigiusz Kołłątaj goto failed;
28051f3baadSRemigiusz Kołłątaj
28151f3baadSRemigiusz Kołłątaj /* Release our reference to this URB, the USB core will eventually free
28251f3baadSRemigiusz Kołłątaj * it entirely.
28351f3baadSRemigiusz Kołłątaj */
28451f3baadSRemigiusz Kołłątaj usb_free_urb(urb);
28551f3baadSRemigiusz Kołłątaj
28651f3baadSRemigiusz Kołłątaj return 0;
28751f3baadSRemigiusz Kołłątaj
28851f3baadSRemigiusz Kołłątaj failed:
28951f3baadSRemigiusz Kołłątaj usb_unanchor_urb(urb);
29051f3baadSRemigiusz Kołłątaj usb_free_coherent(priv->udev, MCBA_USB_TX_BUFF_SIZE, buf,
29151f3baadSRemigiusz Kołłątaj urb->transfer_dma);
29251f3baadSRemigiusz Kołłątaj
29351f3baadSRemigiusz Kołłątaj if (err == -ENODEV)
29451f3baadSRemigiusz Kołłątaj netif_device_detach(priv->netdev);
29551f3baadSRemigiusz Kołłątaj else
29651f3baadSRemigiusz Kołłątaj netdev_warn(priv->netdev, "failed tx_urb %d\n", err);
29751f3baadSRemigiusz Kołłątaj
29851f3baadSRemigiusz Kołłątaj nomembuf:
29951f3baadSRemigiusz Kołłątaj usb_free_urb(urb);
30051f3baadSRemigiusz Kołłątaj
30151f3baadSRemigiusz Kołłątaj return err;
30251f3baadSRemigiusz Kołłątaj }
30351f3baadSRemigiusz Kołłątaj
30451f3baadSRemigiusz Kołłątaj /* Send data to device */
mcba_usb_start_xmit(struct sk_buff * skb,struct net_device * netdev)30551f3baadSRemigiusz Kołłątaj static netdev_tx_t mcba_usb_start_xmit(struct sk_buff *skb,
30651f3baadSRemigiusz Kołłątaj struct net_device *netdev)
30751f3baadSRemigiusz Kołłątaj {
30851f3baadSRemigiusz Kołłątaj struct mcba_priv *priv = netdev_priv(netdev);
30951f3baadSRemigiusz Kołłątaj struct can_frame *cf = (struct can_frame *)skb->data;
31051f3baadSRemigiusz Kołłątaj struct mcba_usb_ctx *ctx = NULL;
31151f3baadSRemigiusz Kołłątaj struct net_device_stats *stats = &priv->netdev->stats;
31251f3baadSRemigiusz Kołłątaj u16 sid;
31351f3baadSRemigiusz Kołłątaj int err;
31451f3baadSRemigiusz Kołłątaj struct mcba_usb_msg_can usb_msg = {
31551f3baadSRemigiusz Kołłątaj .cmd_id = MBCA_CMD_TRANSMIT_MESSAGE_EV
31651f3baadSRemigiusz Kołłątaj };
31751f3baadSRemigiusz Kołłątaj
318ae64438bSOliver Hartkopp if (can_dev_dropped_skb(netdev, skb))
31951f3baadSRemigiusz Kołłątaj return NETDEV_TX_OK;
32051f3baadSRemigiusz Kołłątaj
32151f3baadSRemigiusz Kołłątaj ctx = mcba_usb_get_free_ctx(priv, cf);
32251f3baadSRemigiusz Kołłątaj if (!ctx)
32351f3baadSRemigiusz Kołłątaj return NETDEV_TX_BUSY;
32451f3baadSRemigiusz Kołłątaj
32551f3baadSRemigiusz Kołłątaj if (cf->can_id & CAN_EFF_FLAG) {
32651f3baadSRemigiusz Kołłątaj /* SIDH | SIDL | EIDH | EIDL
32751f3baadSRemigiusz Kołłątaj * 28 - 21 | 20 19 18 x x x 17 16 | 15 - 8 | 7 - 0
32851f3baadSRemigiusz Kołłątaj */
32951f3baadSRemigiusz Kołłątaj sid = MCBA_SIDL_EXID_MASK;
33051f3baadSRemigiusz Kołłątaj /* store 28-18 bits */
33151f3baadSRemigiusz Kołłątaj sid |= (cf->can_id & 0x1ffc0000) >> 13;
33251f3baadSRemigiusz Kołłątaj /* store 17-16 bits */
33351f3baadSRemigiusz Kołłątaj sid |= (cf->can_id & 0x30000) >> 16;
33451f3baadSRemigiusz Kołłątaj put_unaligned_be16(sid, &usb_msg.sid);
33551f3baadSRemigiusz Kołłątaj
33651f3baadSRemigiusz Kołłątaj /* store 15-0 bits */
33751f3baadSRemigiusz Kołłątaj put_unaligned_be16(cf->can_id & 0xffff, &usb_msg.eid);
33851f3baadSRemigiusz Kołłątaj } else {
33951f3baadSRemigiusz Kołłątaj /* SIDH | SIDL
34051f3baadSRemigiusz Kołłątaj * 10 - 3 | 2 1 0 x x x x x
34151f3baadSRemigiusz Kołłątaj */
34251f3baadSRemigiusz Kołłątaj put_unaligned_be16((cf->can_id & CAN_SFF_MASK) << 5,
34351f3baadSRemigiusz Kołłątaj &usb_msg.sid);
34451f3baadSRemigiusz Kołłątaj usb_msg.eid = 0;
34551f3baadSRemigiusz Kołłątaj }
34651f3baadSRemigiusz Kołłątaj
347c7b74967SOliver Hartkopp usb_msg.dlc = cf->len;
34851f3baadSRemigiusz Kołłątaj
34951f3baadSRemigiusz Kołłątaj memcpy(usb_msg.data, cf->data, usb_msg.dlc);
35051f3baadSRemigiusz Kołłątaj
35151f3baadSRemigiusz Kołłątaj if (cf->can_id & CAN_RTR_FLAG)
35251f3baadSRemigiusz Kołłątaj usb_msg.dlc |= MCBA_DLC_RTR_MASK;
35351f3baadSRemigiusz Kołłątaj
3541dcb6e57SVincent Mailhol can_put_echo_skb(skb, priv->netdev, ctx->ndx, 0);
35581c9c8e0SMarc Kleine-Budde
35651f3baadSRemigiusz Kołłątaj err = mcba_usb_xmit(priv, (struct mcba_usb_msg *)&usb_msg, ctx);
35751f3baadSRemigiusz Kołłątaj if (err)
35851f3baadSRemigiusz Kołłątaj goto xmit_failed;
35951f3baadSRemigiusz Kołłątaj
36051f3baadSRemigiusz Kołłątaj return NETDEV_TX_OK;
36151f3baadSRemigiusz Kołłątaj
36251f3baadSRemigiusz Kołłątaj xmit_failed:
363f318482aSMarc Kleine-Budde can_free_echo_skb(priv->netdev, ctx->ndx, NULL);
36451f3baadSRemigiusz Kołłątaj mcba_usb_free_ctx(ctx);
36551f3baadSRemigiusz Kołłątaj stats->tx_dropped++;
36651f3baadSRemigiusz Kołłątaj
36751f3baadSRemigiusz Kołłątaj return NETDEV_TX_OK;
36851f3baadSRemigiusz Kołłątaj }
36951f3baadSRemigiusz Kołłątaj
37051f3baadSRemigiusz Kołłątaj /* Send cmd to device */
mcba_usb_xmit_cmd(struct mcba_priv * priv,struct mcba_usb_msg * usb_msg)37151f3baadSRemigiusz Kołłątaj static void mcba_usb_xmit_cmd(struct mcba_priv *priv,
37251f3baadSRemigiusz Kołłątaj struct mcba_usb_msg *usb_msg)
37351f3baadSRemigiusz Kołłątaj {
37451f3baadSRemigiusz Kołłątaj struct mcba_usb_ctx *ctx = NULL;
37551f3baadSRemigiusz Kołłątaj int err;
37651f3baadSRemigiusz Kołłątaj
37751f3baadSRemigiusz Kołłątaj ctx = mcba_usb_get_free_ctx(priv, NULL);
37851f3baadSRemigiusz Kołłątaj if (!ctx) {
37951f3baadSRemigiusz Kołłątaj netdev_err(priv->netdev,
38051f3baadSRemigiusz Kołłątaj "Lack of free ctx. Sending (%d) cmd aborted",
38151f3baadSRemigiusz Kołłątaj usb_msg->cmd_id);
38251f3baadSRemigiusz Kołłątaj
38351f3baadSRemigiusz Kołłątaj return;
38451f3baadSRemigiusz Kołłątaj }
38551f3baadSRemigiusz Kołłątaj
38651f3baadSRemigiusz Kołłątaj err = mcba_usb_xmit(priv, usb_msg, ctx);
38751f3baadSRemigiusz Kołłątaj if (err)
38851f3baadSRemigiusz Kołłątaj netdev_err(priv->netdev, "Failed to send cmd (%d)",
38951f3baadSRemigiusz Kołłątaj usb_msg->cmd_id);
39051f3baadSRemigiusz Kołłątaj }
39151f3baadSRemigiusz Kołłątaj
mcba_usb_xmit_change_bitrate(struct mcba_priv * priv,u16 bitrate)39251f3baadSRemigiusz Kołłątaj static void mcba_usb_xmit_change_bitrate(struct mcba_priv *priv, u16 bitrate)
39351f3baadSRemigiusz Kołłątaj {
39451f3baadSRemigiusz Kołłątaj struct mcba_usb_msg_change_bitrate usb_msg = {
39551f3baadSRemigiusz Kołłątaj .cmd_id = MBCA_CMD_CHANGE_BIT_RATE
39651f3baadSRemigiusz Kołłątaj };
39751f3baadSRemigiusz Kołłątaj
39851f3baadSRemigiusz Kołłątaj put_unaligned_be16(bitrate, &usb_msg.bitrate);
39951f3baadSRemigiusz Kołłątaj
40051f3baadSRemigiusz Kołłątaj mcba_usb_xmit_cmd(priv, (struct mcba_usb_msg *)&usb_msg);
40151f3baadSRemigiusz Kołłątaj }
40251f3baadSRemigiusz Kołłątaj
mcba_usb_xmit_read_fw_ver(struct mcba_priv * priv,u8 pic)40351f3baadSRemigiusz Kołłątaj static void mcba_usb_xmit_read_fw_ver(struct mcba_priv *priv, u8 pic)
40451f3baadSRemigiusz Kołłątaj {
40551f3baadSRemigiusz Kołłątaj struct mcba_usb_msg_fw_ver usb_msg = {
40651f3baadSRemigiusz Kołłątaj .cmd_id = MBCA_CMD_READ_FW_VERSION,
40751f3baadSRemigiusz Kołłątaj .pic = pic
40851f3baadSRemigiusz Kołłątaj };
40951f3baadSRemigiusz Kołłątaj
41051f3baadSRemigiusz Kołłątaj mcba_usb_xmit_cmd(priv, (struct mcba_usb_msg *)&usb_msg);
41151f3baadSRemigiusz Kołłątaj }
41251f3baadSRemigiusz Kołłątaj
mcba_usb_process_can(struct mcba_priv * priv,struct mcba_usb_msg_can * msg)41351f3baadSRemigiusz Kołłątaj static void mcba_usb_process_can(struct mcba_priv *priv,
41451f3baadSRemigiusz Kołłątaj struct mcba_usb_msg_can *msg)
41551f3baadSRemigiusz Kołłątaj {
41651f3baadSRemigiusz Kołłątaj struct can_frame *cf;
41751f3baadSRemigiusz Kołłątaj struct sk_buff *skb;
41851f3baadSRemigiusz Kołłątaj struct net_device_stats *stats = &priv->netdev->stats;
41951f3baadSRemigiusz Kołłątaj u16 sid;
42051f3baadSRemigiusz Kołłątaj
42151f3baadSRemigiusz Kołłątaj skb = alloc_can_skb(priv->netdev, &cf);
42251f3baadSRemigiusz Kołłątaj if (!skb)
42351f3baadSRemigiusz Kołłątaj return;
42451f3baadSRemigiusz Kołłątaj
42551f3baadSRemigiusz Kołłątaj sid = get_unaligned_be16(&msg->sid);
42651f3baadSRemigiusz Kołłątaj
42751f3baadSRemigiusz Kołłątaj if (sid & MCBA_SIDL_EXID_MASK) {
42851f3baadSRemigiusz Kołłątaj /* SIDH | SIDL | EIDH | EIDL
42951f3baadSRemigiusz Kołłątaj * 28 - 21 | 20 19 18 x x x 17 16 | 15 - 8 | 7 - 0
43051f3baadSRemigiusz Kołłątaj */
43151f3baadSRemigiusz Kołłątaj cf->can_id = CAN_EFF_FLAG;
43251f3baadSRemigiusz Kołłątaj
43351f3baadSRemigiusz Kołłątaj /* store 28-18 bits */
43451f3baadSRemigiusz Kołłątaj cf->can_id |= (sid & 0xffe0) << 13;
43551f3baadSRemigiusz Kołłątaj /* store 17-16 bits */
43651f3baadSRemigiusz Kołłątaj cf->can_id |= (sid & 3) << 16;
43751f3baadSRemigiusz Kołłątaj /* store 15-0 bits */
43851f3baadSRemigiusz Kołłątaj cf->can_id |= get_unaligned_be16(&msg->eid);
43951f3baadSRemigiusz Kołłątaj } else {
44051f3baadSRemigiusz Kołłątaj /* SIDH | SIDL
44151f3baadSRemigiusz Kołłątaj * 10 - 3 | 2 1 0 x x x x x
44251f3baadSRemigiusz Kołłątaj */
44351f3baadSRemigiusz Kołłątaj cf->can_id = (sid & 0xffe0) >> 5;
44451f3baadSRemigiusz Kołłątaj }
44551f3baadSRemigiusz Kołłątaj
446c7b74967SOliver Hartkopp cf->len = can_cc_dlc2len(msg->dlc & MCBA_DLC_MASK);
44751f3baadSRemigiusz Kołłątaj
4488e674ca7SVincent Mailhol if (msg->dlc & MCBA_DLC_RTR_MASK) {
449f68eafebSVincent Mailhol cf->can_id |= CAN_RTR_FLAG;
4508e674ca7SVincent Mailhol } else {
451c7b74967SOliver Hartkopp memcpy(cf->data, msg->data, cf->len);
45251f3baadSRemigiusz Kołłątaj
453c7b74967SOliver Hartkopp stats->rx_bytes += cf->len;
4548e674ca7SVincent Mailhol }
4558e674ca7SVincent Mailhol stats->rx_packets++;
45651f3baadSRemigiusz Kołłątaj
45751f3baadSRemigiusz Kołłątaj netif_rx(skb);
45851f3baadSRemigiusz Kołłątaj }
45951f3baadSRemigiusz Kołłątaj
mcba_usb_process_ka_usb(struct mcba_priv * priv,struct mcba_usb_msg_ka_usb * msg)46051f3baadSRemigiusz Kołłątaj static void mcba_usb_process_ka_usb(struct mcba_priv *priv,
46151f3baadSRemigiusz Kołłątaj struct mcba_usb_msg_ka_usb *msg)
46251f3baadSRemigiusz Kołłątaj {
46351f3baadSRemigiusz Kołłątaj if (unlikely(priv->usb_ka_first_pass)) {
46422d63be9STom Rix netdev_info(priv->netdev, "PIC USB version %u.%u\n",
46551f3baadSRemigiusz Kołłątaj msg->soft_ver_major, msg->soft_ver_minor);
46651f3baadSRemigiusz Kołłątaj
46751f3baadSRemigiusz Kołłątaj priv->usb_ka_first_pass = false;
46851f3baadSRemigiusz Kołłątaj }
46951f3baadSRemigiusz Kołłątaj
470*1a8e3bd2SYasushi SHOJI if (msg->termination_state == MCBA_VER_TERMINATION_ON)
47151f3baadSRemigiusz Kołłątaj priv->can.termination = MCBA_TERMINATION_ENABLED;
47251f3baadSRemigiusz Kołłątaj else
47351f3baadSRemigiusz Kołłątaj priv->can.termination = MCBA_TERMINATION_DISABLED;
47451f3baadSRemigiusz Kołłątaj }
47551f3baadSRemigiusz Kołłątaj
convert_can2host_bitrate(struct mcba_usb_msg_ka_can * msg)47651f3baadSRemigiusz Kołłątaj static u32 convert_can2host_bitrate(struct mcba_usb_msg_ka_can *msg)
47751f3baadSRemigiusz Kołłątaj {
47851f3baadSRemigiusz Kołłątaj const u32 bitrate = get_unaligned_be16(&msg->can_bitrate);
47951f3baadSRemigiusz Kołłątaj
48051f3baadSRemigiusz Kołłątaj if ((bitrate == 33) || (bitrate == 83))
48151f3baadSRemigiusz Kołłątaj return bitrate * 1000 + 333;
48251f3baadSRemigiusz Kołłątaj else
48351f3baadSRemigiusz Kołłątaj return bitrate * 1000;
48451f3baadSRemigiusz Kołłątaj }
48551f3baadSRemigiusz Kołłątaj
mcba_usb_process_ka_can(struct mcba_priv * priv,struct mcba_usb_msg_ka_can * msg)48651f3baadSRemigiusz Kołłątaj static void mcba_usb_process_ka_can(struct mcba_priv *priv,
48751f3baadSRemigiusz Kołłątaj struct mcba_usb_msg_ka_can *msg)
48851f3baadSRemigiusz Kołłątaj {
48951f3baadSRemigiusz Kołłątaj if (unlikely(priv->can_ka_first_pass)) {
49022d63be9STom Rix netdev_info(priv->netdev, "PIC CAN version %u.%u\n",
49151f3baadSRemigiusz Kołłątaj msg->soft_ver_major, msg->soft_ver_minor);
49251f3baadSRemigiusz Kołłątaj
49351f3baadSRemigiusz Kołłątaj priv->can_ka_first_pass = false;
49451f3baadSRemigiusz Kołłątaj }
49551f3baadSRemigiusz Kołłątaj
49651f3baadSRemigiusz Kołłątaj if (unlikely(priv->can_speed_check)) {
49751f3baadSRemigiusz Kołłątaj const u32 bitrate = convert_can2host_bitrate(msg);
49851f3baadSRemigiusz Kołłątaj
49951f3baadSRemigiusz Kołłątaj priv->can_speed_check = false;
50051f3baadSRemigiusz Kołłątaj
50151f3baadSRemigiusz Kołłątaj if (bitrate != priv->can.bittiming.bitrate)
50251f3baadSRemigiusz Kołłątaj netdev_err(
50351f3baadSRemigiusz Kołłątaj priv->netdev,
50451f3baadSRemigiusz Kołłątaj "Wrong bitrate reported by the device (%u). Expected %u",
50551f3baadSRemigiusz Kołłątaj bitrate, priv->can.bittiming.bitrate);
50651f3baadSRemigiusz Kołłątaj }
50751f3baadSRemigiusz Kołłątaj
50851f3baadSRemigiusz Kołłątaj priv->bec.txerr = msg->tx_err_cnt;
50951f3baadSRemigiusz Kołłątaj priv->bec.rxerr = msg->rx_err_cnt;
51051f3baadSRemigiusz Kołłątaj
51151f3baadSRemigiusz Kołłątaj if (msg->tx_bus_off)
51251f3baadSRemigiusz Kołłątaj priv->can.state = CAN_STATE_BUS_OFF;
51351f3baadSRemigiusz Kołłątaj
51451f3baadSRemigiusz Kołłątaj else if ((priv->bec.txerr > MCBA_CAN_STATE_ERR_PSV_TH) ||
51551f3baadSRemigiusz Kołłątaj (priv->bec.rxerr > MCBA_CAN_STATE_ERR_PSV_TH))
51651f3baadSRemigiusz Kołłątaj priv->can.state = CAN_STATE_ERROR_PASSIVE;
51751f3baadSRemigiusz Kołłątaj
51851f3baadSRemigiusz Kołłątaj else if ((priv->bec.txerr > MCBA_CAN_STATE_WRN_TH) ||
51951f3baadSRemigiusz Kołłątaj (priv->bec.rxerr > MCBA_CAN_STATE_WRN_TH))
52051f3baadSRemigiusz Kołłątaj priv->can.state = CAN_STATE_ERROR_WARNING;
52151f3baadSRemigiusz Kołłątaj }
52251f3baadSRemigiusz Kołłątaj
mcba_usb_process_rx(struct mcba_priv * priv,struct mcba_usb_msg * msg)52351f3baadSRemigiusz Kołłątaj static void mcba_usb_process_rx(struct mcba_priv *priv,
52451f3baadSRemigiusz Kołłątaj struct mcba_usb_msg *msg)
52551f3baadSRemigiusz Kołłątaj {
52651f3baadSRemigiusz Kołłątaj switch (msg->cmd_id) {
52751f3baadSRemigiusz Kołłątaj case MBCA_CMD_I_AM_ALIVE_FROM_CAN:
52851f3baadSRemigiusz Kołłątaj mcba_usb_process_ka_can(priv,
52951f3baadSRemigiusz Kołłątaj (struct mcba_usb_msg_ka_can *)msg);
53051f3baadSRemigiusz Kołłątaj break;
53151f3baadSRemigiusz Kołłątaj
53251f3baadSRemigiusz Kołłątaj case MBCA_CMD_I_AM_ALIVE_FROM_USB:
53351f3baadSRemigiusz Kołłątaj mcba_usb_process_ka_usb(priv,
53451f3baadSRemigiusz Kołłątaj (struct mcba_usb_msg_ka_usb *)msg);
53551f3baadSRemigiusz Kołłątaj break;
53651f3baadSRemigiusz Kołłątaj
53751f3baadSRemigiusz Kołłątaj case MBCA_CMD_RECEIVE_MESSAGE:
53851f3baadSRemigiusz Kołłątaj mcba_usb_process_can(priv, (struct mcba_usb_msg_can *)msg);
53951f3baadSRemigiusz Kołłątaj break;
54051f3baadSRemigiusz Kołłątaj
54151f3baadSRemigiusz Kołłątaj case MBCA_CMD_NOTHING_TO_SEND:
54251f3baadSRemigiusz Kołłątaj /* Side effect of communication between PIC_USB and PIC_CAN.
54351f3baadSRemigiusz Kołłątaj * PIC_CAN is telling us that it has nothing to send
54451f3baadSRemigiusz Kołłątaj */
54551f3baadSRemigiusz Kołłątaj break;
54651f3baadSRemigiusz Kołłątaj
54751f3baadSRemigiusz Kołłątaj case MBCA_CMD_TRANSMIT_MESSAGE_RSP:
54851f3baadSRemigiusz Kołłątaj /* Transmission response from the device containing timestamp */
54951f3baadSRemigiusz Kołłątaj break;
55051f3baadSRemigiusz Kołłątaj
55151f3baadSRemigiusz Kołłątaj default:
55222d63be9STom Rix netdev_warn(priv->netdev, "Unsupported msg (0x%X)",
55351f3baadSRemigiusz Kołłątaj msg->cmd_id);
55451f3baadSRemigiusz Kołłątaj break;
55551f3baadSRemigiusz Kołłątaj }
55651f3baadSRemigiusz Kołłątaj }
55751f3baadSRemigiusz Kołłątaj
55851f3baadSRemigiusz Kołłątaj /* Callback for reading data from device
55951f3baadSRemigiusz Kołłątaj *
56051f3baadSRemigiusz Kołłątaj * Check urb status, call read function and resubmit urb read operation.
56151f3baadSRemigiusz Kołłątaj */
mcba_usb_read_bulk_callback(struct urb * urb)56251f3baadSRemigiusz Kołłątaj static void mcba_usb_read_bulk_callback(struct urb *urb)
56351f3baadSRemigiusz Kołłątaj {
56451f3baadSRemigiusz Kołłątaj struct mcba_priv *priv = urb->context;
56551f3baadSRemigiusz Kołłątaj struct net_device *netdev;
56651f3baadSRemigiusz Kołłątaj int retval;
56751f3baadSRemigiusz Kołłątaj int pos = 0;
56851f3baadSRemigiusz Kołłątaj
56951f3baadSRemigiusz Kołłątaj netdev = priv->netdev;
57051f3baadSRemigiusz Kołłątaj
57151f3baadSRemigiusz Kołłątaj if (!netif_device_present(netdev))
57251f3baadSRemigiusz Kołłątaj return;
57351f3baadSRemigiusz Kołłątaj
57451f3baadSRemigiusz Kołłątaj switch (urb->status) {
57551f3baadSRemigiusz Kołłątaj case 0: /* success */
57651f3baadSRemigiusz Kołłątaj break;
57751f3baadSRemigiusz Kołłątaj
57851f3baadSRemigiusz Kołłątaj case -ENOENT:
5791cb35a33SMartin Kelly case -EPIPE:
580c7f33023SMartin Kelly case -EPROTO:
58151f3baadSRemigiusz Kołłątaj case -ESHUTDOWN:
58251f3baadSRemigiusz Kołłątaj return;
58351f3baadSRemigiusz Kołłątaj
58451f3baadSRemigiusz Kołłątaj default:
58551f3baadSRemigiusz Kołłątaj netdev_info(netdev, "Rx URB aborted (%d)\n", urb->status);
58651f3baadSRemigiusz Kołłątaj
58751f3baadSRemigiusz Kołłątaj goto resubmit_urb;
58851f3baadSRemigiusz Kołłątaj }
58951f3baadSRemigiusz Kołłątaj
59051f3baadSRemigiusz Kołłątaj while (pos < urb->actual_length) {
59151f3baadSRemigiusz Kołłątaj struct mcba_usb_msg *msg;
59251f3baadSRemigiusz Kołłątaj
59351f3baadSRemigiusz Kołłątaj if (pos + sizeof(struct mcba_usb_msg) > urb->actual_length) {
59451f3baadSRemigiusz Kołłątaj netdev_err(priv->netdev, "format error\n");
59551f3baadSRemigiusz Kołłątaj break;
59651f3baadSRemigiusz Kołłątaj }
59751f3baadSRemigiusz Kołłątaj
59851f3baadSRemigiusz Kołłątaj msg = (struct mcba_usb_msg *)(urb->transfer_buffer + pos);
59951f3baadSRemigiusz Kołłątaj mcba_usb_process_rx(priv, msg);
60051f3baadSRemigiusz Kołłątaj
60151f3baadSRemigiusz Kołłątaj pos += sizeof(struct mcba_usb_msg);
60251f3baadSRemigiusz Kołłątaj }
60351f3baadSRemigiusz Kołłątaj
60451f3baadSRemigiusz Kołłątaj resubmit_urb:
60551f3baadSRemigiusz Kołłątaj
60651f3baadSRemigiusz Kołłątaj usb_fill_bulk_urb(urb, priv->udev,
607136bed0bSPavel Skripkin priv->rx_pipe,
60851f3baadSRemigiusz Kołłątaj urb->transfer_buffer, MCBA_USB_RX_BUFF_SIZE,
60951f3baadSRemigiusz Kołłątaj mcba_usb_read_bulk_callback, priv);
61051f3baadSRemigiusz Kołłątaj
61151f3baadSRemigiusz Kołłątaj retval = usb_submit_urb(urb, GFP_ATOMIC);
61251f3baadSRemigiusz Kołłątaj
61351f3baadSRemigiusz Kołłątaj if (retval == -ENODEV)
61451f3baadSRemigiusz Kołłątaj netif_device_detach(netdev);
61551f3baadSRemigiusz Kołłątaj else if (retval)
61651f3baadSRemigiusz Kołłątaj netdev_err(netdev, "failed resubmitting read bulk urb: %d\n",
61751f3baadSRemigiusz Kołłątaj retval);
61851f3baadSRemigiusz Kołłątaj }
61951f3baadSRemigiusz Kołłątaj
62051f3baadSRemigiusz Kołłątaj /* Start USB device */
mcba_usb_start(struct mcba_priv * priv)62151f3baadSRemigiusz Kołłątaj static int mcba_usb_start(struct mcba_priv *priv)
62251f3baadSRemigiusz Kołłątaj {
62351f3baadSRemigiusz Kołłątaj struct net_device *netdev = priv->netdev;
62451f3baadSRemigiusz Kołłątaj int err, i;
62551f3baadSRemigiusz Kołłątaj
62651f3baadSRemigiusz Kołłątaj mcba_init_ctx(priv);
62751f3baadSRemigiusz Kołłątaj
62851f3baadSRemigiusz Kołłątaj for (i = 0; i < MCBA_MAX_RX_URBS; i++) {
62951f3baadSRemigiusz Kołłątaj struct urb *urb = NULL;
63051f3baadSRemigiusz Kołłątaj u8 *buf;
63191c02557SPavel Skripkin dma_addr_t buf_dma;
63251f3baadSRemigiusz Kołłątaj
63351f3baadSRemigiusz Kołłątaj /* create a URB, and a buffer for it */
63451f3baadSRemigiusz Kołłątaj urb = usb_alloc_urb(0, GFP_KERNEL);
63551f3baadSRemigiusz Kołłątaj if (!urb) {
63651f3baadSRemigiusz Kołłątaj err = -ENOMEM;
63751f3baadSRemigiusz Kołłątaj break;
63851f3baadSRemigiusz Kołłątaj }
63951f3baadSRemigiusz Kołłątaj
64051f3baadSRemigiusz Kołłątaj buf = usb_alloc_coherent(priv->udev, MCBA_USB_RX_BUFF_SIZE,
64191c02557SPavel Skripkin GFP_KERNEL, &buf_dma);
64251f3baadSRemigiusz Kołłątaj if (!buf) {
64351f3baadSRemigiusz Kołłątaj netdev_err(netdev, "No memory left for USB buffer\n");
64451f3baadSRemigiusz Kołłątaj usb_free_urb(urb);
64551f3baadSRemigiusz Kołłątaj err = -ENOMEM;
64651f3baadSRemigiusz Kołłątaj break;
64751f3baadSRemigiusz Kołłątaj }
64851f3baadSRemigiusz Kołłątaj
649fc43fb69SPavel Skripkin urb->transfer_dma = buf_dma;
650fc43fb69SPavel Skripkin
65151f3baadSRemigiusz Kołłątaj usb_fill_bulk_urb(urb, priv->udev,
652136bed0bSPavel Skripkin priv->rx_pipe,
65351f3baadSRemigiusz Kołłątaj buf, MCBA_USB_RX_BUFF_SIZE,
65451f3baadSRemigiusz Kołłątaj mcba_usb_read_bulk_callback, priv);
65551f3baadSRemigiusz Kołłątaj urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
65651f3baadSRemigiusz Kołłątaj usb_anchor_urb(urb, &priv->rx_submitted);
65751f3baadSRemigiusz Kołłątaj
65851f3baadSRemigiusz Kołłątaj err = usb_submit_urb(urb, GFP_KERNEL);
65951f3baadSRemigiusz Kołłątaj if (err) {
66051f3baadSRemigiusz Kołłątaj usb_unanchor_urb(urb);
66151f3baadSRemigiusz Kołłątaj usb_free_coherent(priv->udev, MCBA_USB_RX_BUFF_SIZE,
66291c02557SPavel Skripkin buf, buf_dma);
66351f3baadSRemigiusz Kołłątaj usb_free_urb(urb);
66451f3baadSRemigiusz Kołłątaj break;
66551f3baadSRemigiusz Kołłątaj }
66651f3baadSRemigiusz Kołłątaj
66791c02557SPavel Skripkin priv->rxbuf[i] = buf;
66891c02557SPavel Skripkin priv->rxbuf_dma[i] = buf_dma;
66991c02557SPavel Skripkin
67051f3baadSRemigiusz Kołłątaj /* Drop reference, USB core will take care of freeing it */
67151f3baadSRemigiusz Kołłątaj usb_free_urb(urb);
67251f3baadSRemigiusz Kołłątaj }
67351f3baadSRemigiusz Kołłątaj
67451f3baadSRemigiusz Kołłątaj /* Did we submit any URBs */
67551f3baadSRemigiusz Kołłątaj if (i == 0) {
67651f3baadSRemigiusz Kołłątaj netdev_warn(netdev, "couldn't setup read URBs\n");
67751f3baadSRemigiusz Kołłątaj return err;
67851f3baadSRemigiusz Kołłątaj }
67951f3baadSRemigiusz Kołłątaj
68051f3baadSRemigiusz Kołłątaj /* Warn if we've couldn't transmit all the URBs */
68151f3baadSRemigiusz Kołłątaj if (i < MCBA_MAX_RX_URBS)
68251f3baadSRemigiusz Kołłątaj netdev_warn(netdev, "rx performance may be slow\n");
68351f3baadSRemigiusz Kołłątaj
68451f3baadSRemigiusz Kołłątaj mcba_usb_xmit_read_fw_ver(priv, MCBA_VER_REQ_USB);
68551f3baadSRemigiusz Kołłątaj mcba_usb_xmit_read_fw_ver(priv, MCBA_VER_REQ_CAN);
68651f3baadSRemigiusz Kołłątaj
68751f3baadSRemigiusz Kołłątaj return err;
68851f3baadSRemigiusz Kołłątaj }
68951f3baadSRemigiusz Kołłątaj
69051f3baadSRemigiusz Kołłątaj /* Open USB device */
mcba_usb_open(struct net_device * netdev)69151f3baadSRemigiusz Kołłątaj static int mcba_usb_open(struct net_device *netdev)
69251f3baadSRemigiusz Kołłątaj {
69351f3baadSRemigiusz Kołłątaj struct mcba_priv *priv = netdev_priv(netdev);
69451f3baadSRemigiusz Kołłątaj int err;
69551f3baadSRemigiusz Kołłątaj
69651f3baadSRemigiusz Kołłątaj /* common open */
69751f3baadSRemigiusz Kołłątaj err = open_candev(netdev);
69851f3baadSRemigiusz Kołłątaj if (err)
69951f3baadSRemigiusz Kołłątaj return err;
70051f3baadSRemigiusz Kołłątaj
70151f3baadSRemigiusz Kołłątaj priv->can_speed_check = true;
70251f3baadSRemigiusz Kołłątaj priv->can.state = CAN_STATE_ERROR_ACTIVE;
70351f3baadSRemigiusz Kołłątaj
70451f3baadSRemigiusz Kołłątaj netif_start_queue(netdev);
70551f3baadSRemigiusz Kołłątaj
70651f3baadSRemigiusz Kołłątaj return 0;
70751f3baadSRemigiusz Kołłątaj }
70851f3baadSRemigiusz Kołłątaj
mcba_urb_unlink(struct mcba_priv * priv)70951f3baadSRemigiusz Kołłątaj static void mcba_urb_unlink(struct mcba_priv *priv)
71051f3baadSRemigiusz Kołłątaj {
71191c02557SPavel Skripkin int i;
71291c02557SPavel Skripkin
71351f3baadSRemigiusz Kołłątaj usb_kill_anchored_urbs(&priv->rx_submitted);
71491c02557SPavel Skripkin
71591c02557SPavel Skripkin for (i = 0; i < MCBA_MAX_RX_URBS; ++i)
71691c02557SPavel Skripkin usb_free_coherent(priv->udev, MCBA_USB_RX_BUFF_SIZE,
71791c02557SPavel Skripkin priv->rxbuf[i], priv->rxbuf_dma[i]);
71891c02557SPavel Skripkin
71951f3baadSRemigiusz Kołłątaj usb_kill_anchored_urbs(&priv->tx_submitted);
72051f3baadSRemigiusz Kołłątaj }
72151f3baadSRemigiusz Kołłątaj
72251f3baadSRemigiusz Kołłątaj /* Close USB device */
mcba_usb_close(struct net_device * netdev)72351f3baadSRemigiusz Kołłątaj static int mcba_usb_close(struct net_device *netdev)
72451f3baadSRemigiusz Kołłątaj {
72551f3baadSRemigiusz Kołłątaj struct mcba_priv *priv = netdev_priv(netdev);
72651f3baadSRemigiusz Kołłątaj
72751f3baadSRemigiusz Kołłątaj priv->can.state = CAN_STATE_STOPPED;
72851f3baadSRemigiusz Kołłątaj
72951f3baadSRemigiusz Kołłątaj netif_stop_queue(netdev);
73051f3baadSRemigiusz Kołłątaj
73151f3baadSRemigiusz Kołłątaj /* Stop polling */
73251f3baadSRemigiusz Kołłątaj mcba_urb_unlink(priv);
73351f3baadSRemigiusz Kołłątaj
73451f3baadSRemigiusz Kołłątaj close_candev(netdev);
73551f3baadSRemigiusz Kołłątaj
73651f3baadSRemigiusz Kołłątaj return 0;
73751f3baadSRemigiusz Kołłątaj }
73851f3baadSRemigiusz Kołłątaj
73951f3baadSRemigiusz Kołłątaj /* Set network device mode
74051f3baadSRemigiusz Kołłątaj *
74151f3baadSRemigiusz Kołłątaj * Maybe we should leave this function empty, because the device
74251f3baadSRemigiusz Kołłątaj * set mode variable with open command.
74351f3baadSRemigiusz Kołłątaj */
mcba_net_set_mode(struct net_device * netdev,enum can_mode mode)74451f3baadSRemigiusz Kołłątaj static int mcba_net_set_mode(struct net_device *netdev, enum can_mode mode)
74551f3baadSRemigiusz Kołłątaj {
74651f3baadSRemigiusz Kołłątaj return 0;
74751f3baadSRemigiusz Kołłątaj }
74851f3baadSRemigiusz Kołłątaj
mcba_net_get_berr_counter(const struct net_device * netdev,struct can_berr_counter * bec)74951f3baadSRemigiusz Kołłątaj static int mcba_net_get_berr_counter(const struct net_device *netdev,
75051f3baadSRemigiusz Kołłątaj struct can_berr_counter *bec)
75151f3baadSRemigiusz Kołłątaj {
75251f3baadSRemigiusz Kołłątaj struct mcba_priv *priv = netdev_priv(netdev);
75351f3baadSRemigiusz Kołłątaj
75451f3baadSRemigiusz Kołłątaj bec->txerr = priv->bec.txerr;
75551f3baadSRemigiusz Kołłątaj bec->rxerr = priv->bec.rxerr;
75651f3baadSRemigiusz Kołłątaj
75751f3baadSRemigiusz Kołłątaj return 0;
75851f3baadSRemigiusz Kołłątaj }
75951f3baadSRemigiusz Kołłątaj
76051f3baadSRemigiusz Kołłątaj static const struct net_device_ops mcba_netdev_ops = {
76151f3baadSRemigiusz Kołłątaj .ndo_open = mcba_usb_open,
76251f3baadSRemigiusz Kołłątaj .ndo_stop = mcba_usb_close,
76351f3baadSRemigiusz Kołłątaj .ndo_start_xmit = mcba_usb_start_xmit,
76451f3baadSRemigiusz Kołłątaj };
76551f3baadSRemigiusz Kołłątaj
766409c188cSVincent Mailhol static const struct ethtool_ops mcba_ethtool_ops = {
767409c188cSVincent Mailhol .get_ts_info = ethtool_op_get_ts_info,
768409c188cSVincent Mailhol };
769409c188cSVincent Mailhol
77051f3baadSRemigiusz Kołłątaj /* Microchip CANBUS has hardcoded bittiming values by default.
77151f3baadSRemigiusz Kołłątaj * This function sends request via USB to change the speed and align bittiming
77251f3baadSRemigiusz Kołłątaj * values for presentation purposes only
77351f3baadSRemigiusz Kołłątaj */
mcba_net_set_bittiming(struct net_device * netdev)77451f3baadSRemigiusz Kołłątaj static int mcba_net_set_bittiming(struct net_device *netdev)
77551f3baadSRemigiusz Kołłątaj {
77651f3baadSRemigiusz Kołłątaj struct mcba_priv *priv = netdev_priv(netdev);
77751f3baadSRemigiusz Kołłątaj const u16 bitrate_kbps = priv->can.bittiming.bitrate / 1000;
77851f3baadSRemigiusz Kołłątaj
77951f3baadSRemigiusz Kołłątaj mcba_usb_xmit_change_bitrate(priv, bitrate_kbps);
78051f3baadSRemigiusz Kołłątaj
78151f3baadSRemigiusz Kołłątaj return 0;
78251f3baadSRemigiusz Kołłątaj }
78351f3baadSRemigiusz Kołłątaj
mcba_set_termination(struct net_device * netdev,u16 term)78451f3baadSRemigiusz Kołłątaj static int mcba_set_termination(struct net_device *netdev, u16 term)
78551f3baadSRemigiusz Kołłątaj {
78651f3baadSRemigiusz Kołłątaj struct mcba_priv *priv = netdev_priv(netdev);
78751f3baadSRemigiusz Kołłątaj struct mcba_usb_msg_termination usb_msg = {
78851f3baadSRemigiusz Kołłątaj .cmd_id = MBCA_CMD_SETUP_TERMINATION_RESISTANCE
78951f3baadSRemigiusz Kołłątaj };
79051f3baadSRemigiusz Kołłątaj
79151f3baadSRemigiusz Kołłątaj if (term == MCBA_TERMINATION_ENABLED)
792*1a8e3bd2SYasushi SHOJI usb_msg.termination = MCBA_VER_TERMINATION_ON;
79351f3baadSRemigiusz Kołłątaj else
794*1a8e3bd2SYasushi SHOJI usb_msg.termination = MCBA_VER_TERMINATION_OFF;
79551f3baadSRemigiusz Kołłątaj
79651f3baadSRemigiusz Kołłątaj mcba_usb_xmit_cmd(priv, (struct mcba_usb_msg *)&usb_msg);
79751f3baadSRemigiusz Kołłątaj
79851f3baadSRemigiusz Kołłątaj return 0;
79951f3baadSRemigiusz Kołłątaj }
80051f3baadSRemigiusz Kołłątaj
mcba_usb_probe(struct usb_interface * intf,const struct usb_device_id * id)80151f3baadSRemigiusz Kołłątaj static int mcba_usb_probe(struct usb_interface *intf,
80251f3baadSRemigiusz Kołłątaj const struct usb_device_id *id)
80351f3baadSRemigiusz Kołłątaj {
80451f3baadSRemigiusz Kołłątaj struct net_device *netdev;
80551f3baadSRemigiusz Kołłątaj struct mcba_priv *priv;
80629f45adbSColin Ian King int err;
80751f3baadSRemigiusz Kołłątaj struct usb_device *usbdev = interface_to_usbdev(intf);
808136bed0bSPavel Skripkin struct usb_endpoint_descriptor *in, *out;
809136bed0bSPavel Skripkin
810136bed0bSPavel Skripkin err = usb_find_common_endpoints(intf->cur_altsetting, &in, &out, NULL, NULL);
811136bed0bSPavel Skripkin if (err) {
812136bed0bSPavel Skripkin dev_err(&intf->dev, "Can't find endpoints\n");
813136bed0bSPavel Skripkin return err;
814136bed0bSPavel Skripkin }
81551f3baadSRemigiusz Kołłątaj
81651f3baadSRemigiusz Kołłątaj netdev = alloc_candev(sizeof(struct mcba_priv), MCBA_MAX_TX_URBS);
81751f3baadSRemigiusz Kołłątaj if (!netdev) {
81851f3baadSRemigiusz Kołłątaj dev_err(&intf->dev, "Couldn't alloc candev\n");
81951f3baadSRemigiusz Kołłątaj return -ENOMEM;
82051f3baadSRemigiusz Kołłątaj }
82151f3baadSRemigiusz Kołłątaj
82251f3baadSRemigiusz Kołłątaj priv = netdev_priv(netdev);
82351f3baadSRemigiusz Kołłątaj
82451f3baadSRemigiusz Kołłątaj priv->udev = usbdev;
82551f3baadSRemigiusz Kołłątaj priv->netdev = netdev;
82651f3baadSRemigiusz Kołłątaj priv->usb_ka_first_pass = true;
82751f3baadSRemigiusz Kołłątaj priv->can_ka_first_pass = true;
82851f3baadSRemigiusz Kołłątaj priv->can_speed_check = false;
82951f3baadSRemigiusz Kołłątaj
83051f3baadSRemigiusz Kołłątaj init_usb_anchor(&priv->rx_submitted);
83151f3baadSRemigiusz Kołłątaj init_usb_anchor(&priv->tx_submitted);
83251f3baadSRemigiusz Kołłątaj
83351f3baadSRemigiusz Kołłątaj usb_set_intfdata(intf, priv);
83451f3baadSRemigiusz Kołłątaj
83551f3baadSRemigiusz Kołłątaj /* Init CAN device */
83651f3baadSRemigiusz Kołłątaj priv->can.state = CAN_STATE_STOPPED;
83751f3baadSRemigiusz Kołłątaj priv->can.termination_const = mcba_termination;
83851f3baadSRemigiusz Kołłątaj priv->can.termination_const_cnt = ARRAY_SIZE(mcba_termination);
83951f3baadSRemigiusz Kołłątaj priv->can.bitrate_const = mcba_bitrate;
84051f3baadSRemigiusz Kołłątaj priv->can.bitrate_const_cnt = ARRAY_SIZE(mcba_bitrate);
84151f3baadSRemigiusz Kołłątaj
84251f3baadSRemigiusz Kołłątaj priv->can.do_set_termination = mcba_set_termination;
84351f3baadSRemigiusz Kołłątaj priv->can.do_set_mode = mcba_net_set_mode;
84451f3baadSRemigiusz Kołłątaj priv->can.do_get_berr_counter = mcba_net_get_berr_counter;
84551f3baadSRemigiusz Kołłątaj priv->can.do_set_bittiming = mcba_net_set_bittiming;
84651f3baadSRemigiusz Kołłątaj
84751f3baadSRemigiusz Kołłątaj netdev->netdev_ops = &mcba_netdev_ops;
848409c188cSVincent Mailhol netdev->ethtool_ops = &mcba_ethtool_ops;
84951f3baadSRemigiusz Kołłątaj
85051f3baadSRemigiusz Kołłątaj netdev->flags |= IFF_ECHO; /* we support local echo */
85151f3baadSRemigiusz Kołłątaj
85251f3baadSRemigiusz Kołłątaj SET_NETDEV_DEV(netdev, &intf->dev);
85351f3baadSRemigiusz Kołłątaj
85451f3baadSRemigiusz Kołłątaj err = register_candev(netdev);
85551f3baadSRemigiusz Kołłątaj if (err) {
85651f3baadSRemigiusz Kołłątaj netdev_err(netdev, "couldn't register CAN device: %d\n", err);
85751f3baadSRemigiusz Kołłątaj
85851f3baadSRemigiusz Kołłątaj goto cleanup_free_candev;
85951f3baadSRemigiusz Kołłątaj }
86051f3baadSRemigiusz Kołłątaj
861136bed0bSPavel Skripkin priv->rx_pipe = usb_rcvbulkpipe(priv->udev, in->bEndpointAddress);
862136bed0bSPavel Skripkin priv->tx_pipe = usb_sndbulkpipe(priv->udev, out->bEndpointAddress);
863136bed0bSPavel Skripkin
86451f3baadSRemigiusz Kołłątaj /* Start USB dev only if we have successfully registered CAN device */
86551f3baadSRemigiusz Kołłątaj err = mcba_usb_start(priv);
86651f3baadSRemigiusz Kołłątaj if (err) {
86751f3baadSRemigiusz Kołłątaj if (err == -ENODEV)
86851f3baadSRemigiusz Kołłątaj netif_device_detach(priv->netdev);
86951f3baadSRemigiusz Kołłątaj
87051f3baadSRemigiusz Kołłątaj netdev_warn(netdev, "couldn't start device: %d\n", err);
87151f3baadSRemigiusz Kołłątaj
87251f3baadSRemigiusz Kołłątaj goto cleanup_unregister_candev;
87351f3baadSRemigiusz Kołłątaj }
87451f3baadSRemigiusz Kołłątaj
8753fed8dbbSMartin Kelly dev_info(&intf->dev, "Microchip CAN BUS Analyzer connected\n");
87651f3baadSRemigiusz Kołłątaj
87751f3baadSRemigiusz Kołłątaj return 0;
87851f3baadSRemigiusz Kołłątaj
87951f3baadSRemigiusz Kołłątaj cleanup_unregister_candev:
88051f3baadSRemigiusz Kołłątaj unregister_candev(priv->netdev);
88151f3baadSRemigiusz Kołłątaj
88251f3baadSRemigiusz Kołłątaj cleanup_free_candev:
88351f3baadSRemigiusz Kołłątaj free_candev(netdev);
88451f3baadSRemigiusz Kołłątaj
88551f3baadSRemigiusz Kołłątaj return err;
88651f3baadSRemigiusz Kołłątaj }
88751f3baadSRemigiusz Kołłątaj
88851f3baadSRemigiusz Kołłątaj /* Called by the usb core when driver is unloaded or device is removed */
mcba_usb_disconnect(struct usb_interface * intf)88951f3baadSRemigiusz Kołłątaj static void mcba_usb_disconnect(struct usb_interface *intf)
89051f3baadSRemigiusz Kołłątaj {
89151f3baadSRemigiusz Kołłątaj struct mcba_priv *priv = usb_get_intfdata(intf);
89251f3baadSRemigiusz Kołłątaj
89351f3baadSRemigiusz Kołłątaj usb_set_intfdata(intf, NULL);
89451f3baadSRemigiusz Kołłątaj
89551f3baadSRemigiusz Kołłątaj netdev_info(priv->netdev, "device disconnected\n");
89651f3baadSRemigiusz Kołłątaj
89751f3baadSRemigiusz Kołłątaj unregister_candev(priv->netdev);
89851f3baadSRemigiusz Kołłątaj mcba_urb_unlink(priv);
8994d663649SJohan Hovold free_candev(priv->netdev);
90051f3baadSRemigiusz Kołłątaj }
90151f3baadSRemigiusz Kołłątaj
90251f3baadSRemigiusz Kołłątaj static struct usb_driver mcba_usb_driver = {
90351f3baadSRemigiusz Kołłątaj .name = MCBA_MODULE_NAME,
90451f3baadSRemigiusz Kołłątaj .probe = mcba_usb_probe,
90551f3baadSRemigiusz Kołłątaj .disconnect = mcba_usb_disconnect,
90651f3baadSRemigiusz Kołłątaj .id_table = mcba_usb_table,
90751f3baadSRemigiusz Kołłątaj };
90851f3baadSRemigiusz Kołłątaj
90951f3baadSRemigiusz Kołłątaj module_usb_driver(mcba_usb_driver);
91051f3baadSRemigiusz Kołłątaj
91151f3baadSRemigiusz Kołłątaj MODULE_AUTHOR("Remigiusz Kołłątaj <remigiusz.kollataj@mobica.com>");
91251f3baadSRemigiusz Kołłątaj MODULE_DESCRIPTION("SocketCAN driver for Microchip CAN BUS Analyzer Tool");
91351f3baadSRemigiusz Kołłątaj MODULE_LICENSE("GPL v2");
914