diff options
Diffstat (limited to 'drivers/net/can/usb/gs_usb.c')
-rw-r--r-- | drivers/net/can/usb/gs_usb.c | 76 |
1 files changed, 63 insertions, 13 deletions
diff --git a/drivers/net/can/usb/gs_usb.c b/drivers/net/can/usb/gs_usb.c index f0065d40eb24..838744d2ce34 100644 --- a/drivers/net/can/usb/gs_usb.c +++ b/drivers/net/can/usb/gs_usb.c @@ -66,6 +66,7 @@ enum gs_usb_breq { GS_USB_BREQ_BT_CONST_EXT, GS_USB_BREQ_SET_TERMINATION, GS_USB_BREQ_GET_TERMINATION, + GS_USB_BREQ_GET_STATE, }; enum gs_can_mode { @@ -134,6 +135,8 @@ struct gs_device_config { /* GS_CAN_FEATURE_REQ_USB_QUIRK_LPC546XX BIT(9) */ /* GS_CAN_FEATURE_BT_CONST_EXT BIT(10) */ /* GS_CAN_FEATURE_TERMINATION BIT(11) */ +#define GS_CAN_MODE_BERR_REPORTING BIT(12) +/* GS_CAN_FEATURE_GET_STATE BIT(13) */ struct gs_device_mode { __le32 mode; @@ -174,7 +177,9 @@ struct gs_device_termination_state { #define GS_CAN_FEATURE_REQ_USB_QUIRK_LPC546XX BIT(9) #define GS_CAN_FEATURE_BT_CONST_EXT BIT(10) #define GS_CAN_FEATURE_TERMINATION BIT(11) -#define GS_CAN_FEATURE_MASK GENMASK(11, 0) +#define GS_CAN_FEATURE_BERR_REPORTING BIT(12) +#define GS_CAN_FEATURE_GET_STATE BIT(13) +#define GS_CAN_FEATURE_MASK GENMASK(13, 0) /* internal quirks - keep in GS_CAN_FEATURE space for now */ @@ -723,7 +728,7 @@ static netdev_tx_t gs_can_start_xmit(struct sk_buff *skb, unsigned int idx; struct gs_tx_context *txc; - if (can_dropped_invalid_skb(netdev, skb)) + if (can_dev_dropped_skb(netdev, skb)) return NETDEV_TX_OK; /* find an empty context to keep track of transmission */ @@ -843,8 +848,6 @@ static int gs_can_open(struct net_device *netdev) ctrlmode = dev->can.ctrlmode; if (ctrlmode & CAN_CTRLMODE_FD) { - flags |= GS_CAN_MODE_FD; - if (dev->feature & GS_CAN_FEATURE_REQ_USB_QUIRK_LPC546XX) dev->hf_size_tx = struct_size(hf, canfd_quirk, 1); else @@ -911,25 +914,29 @@ static int gs_can_open(struct net_device *netdev) /* flags */ if (ctrlmode & CAN_CTRLMODE_LOOPBACK) flags |= GS_CAN_MODE_LOOP_BACK; - else if (ctrlmode & CAN_CTRLMODE_LISTENONLY) + + if (ctrlmode & CAN_CTRLMODE_LISTENONLY) flags |= GS_CAN_MODE_LISTEN_ONLY; - /* Controller is not allowed to retry TX - * this mode is unavailable on atmels uc3c hardware - */ + if (ctrlmode & CAN_CTRLMODE_3_SAMPLES) + flags |= GS_CAN_MODE_TRIPLE_SAMPLE; + if (ctrlmode & CAN_CTRLMODE_ONE_SHOT) flags |= GS_CAN_MODE_ONE_SHOT; - if (ctrlmode & CAN_CTRLMODE_3_SAMPLES) - flags |= GS_CAN_MODE_TRIPLE_SAMPLE; + if (ctrlmode & CAN_CTRLMODE_BERR_REPORTING) + flags |= GS_CAN_MODE_BERR_REPORTING; + + if (ctrlmode & CAN_CTRLMODE_FD) + flags |= GS_CAN_MODE_FD; /* if hardware supports timestamps, enable it */ - if (dev->feature & GS_CAN_FEATURE_HW_TIMESTAMP) + if (dev->feature & GS_CAN_FEATURE_HW_TIMESTAMP) { flags |= GS_CAN_MODE_HW_TIMESTAMP; - /* start polling timestamp */ - if (dev->feature & GS_CAN_FEATURE_HW_TIMESTAMP) + /* start polling timestamp */ gs_usb_timestamp_init(dev); + } /* finally start device */ dev->can.state = CAN_STATE_ERROR_ACTIVE; @@ -954,6 +961,42 @@ static int gs_can_open(struct net_device *netdev) return 0; } +static int gs_usb_get_state(const struct net_device *netdev, + struct can_berr_counter *bec, + enum can_state *state) +{ + struct gs_can *dev = netdev_priv(netdev); + struct gs_device_state ds; + int rc; + + rc = usb_control_msg_recv(interface_to_usbdev(dev->iface), 0, + GS_USB_BREQ_GET_STATE, + USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_INTERFACE, + dev->channel, 0, + &ds, sizeof(ds), + USB_CTRL_GET_TIMEOUT, + GFP_KERNEL); + if (rc) + return rc; + + if (le32_to_cpu(ds.state) >= CAN_STATE_MAX) + return -EOPNOTSUPP; + + *state = le32_to_cpu(ds.state); + bec->txerr = le32_to_cpu(ds.txerr); + bec->rxerr = le32_to_cpu(ds.rxerr); + + return 0; +} + +static int gs_usb_can_get_berr_counter(const struct net_device *netdev, + struct can_berr_counter *bec) +{ + enum can_state state; + + return gs_usb_get_state(netdev, bec, &state); +} + static int gs_can_close(struct net_device *netdev) { int rc; @@ -1153,6 +1196,7 @@ static struct gs_can *gs_make_candev(unsigned int channel, netdev->ethtool_ops = &gs_usb_ethtool_ops; netdev->flags |= IFF_ECHO; /* we support full roundtrip echo */ + netdev->dev_id = channel; /* dev setup */ strcpy(dev->bt_const.name, KBUILD_MODNAME); @@ -1224,6 +1268,12 @@ static struct gs_can *gs_make_candev(unsigned int channel, } } + if (feature & GS_CAN_FEATURE_BERR_REPORTING) + dev->can.ctrlmode_supported |= CAN_CTRLMODE_BERR_REPORTING; + + if (feature & GS_CAN_FEATURE_GET_STATE) + dev->can.do_get_berr_counter = gs_usb_can_get_berr_counter; + /* The CANtact Pro from LinkLayer Labs is based on the * LPC54616 µC, which is affected by the NXP LPC USB transfer * erratum. However, the current firmware (version 2) doesn't |