diff options
Diffstat (limited to 'drivers/net/can/usb/ucan.c')
| -rw-r--r-- | drivers/net/can/usb/ucan.c | 111 |
1 files changed, 53 insertions, 58 deletions
diff --git a/drivers/net/can/usb/ucan.c b/drivers/net/can/usb/ucan.c index 81e942f713e6..de61d9da99e3 100644 --- a/drivers/net/can/usb/ucan.c +++ b/drivers/net/can/usb/ucan.c @@ -28,6 +28,7 @@ #include <linux/can.h> #include <linux/can/dev.h> #include <linux/can/error.h> +#include <linux/ethtool.h> #include <linux/module.h> #include <linux/netdevice.h> #include <linux/signal.h> @@ -185,7 +186,7 @@ union ucan_ctl_payload { */ struct ucan_ctl_cmd_get_protocol_version cmd_get_protocol_version; - u8 raw[128]; + u8 fw_str[128]; } __packed; enum { @@ -244,9 +245,10 @@ struct ucan_message_in { /* CAN transmission complete * (type == UCAN_IN_TX_COMPLETE) */ - struct ucan_tx_complete_entry_t can_tx_complete_msg[0]; + DECLARE_FLEX_ARRAY(struct ucan_tx_complete_entry_t, + can_tx_complete_msg); } __aligned(0x4) msg; -} __packed; +} __packed __aligned(0x4); /* Macros to calculate message lengths */ #define UCAN_OUT_HDR_SIZE offsetof(struct ucan_message_out, msg) @@ -259,7 +261,6 @@ struct ucan_priv; /* Context Information for transmission URBs */ struct ucan_urb_context { struct ucan_priv *up; - u8 dlc; bool allocated; }; @@ -276,7 +277,6 @@ struct ucan_priv { /* linux USB device structures */ struct usb_device *udev; - struct usb_interface *intf; struct net_device *netdev; /* lock for can->echo_skb (used around @@ -284,7 +284,7 @@ struct ucan_priv { */ spinlock_t echo_skb_lock; - /* usb device information information */ + /* usb device information */ u8 intf_index; u8 in_ep_addr; u8 out_ep_addr; @@ -303,12 +303,12 @@ struct ucan_priv { struct ucan_urb_context *context_array; }; -static u8 ucan_get_can_dlc(struct ucan_can_msg *msg, u16 len) +static u8 ucan_can_cc_dlc2len(struct ucan_can_msg *msg, u16 len) { if (le32_to_cpu(msg->id) & CAN_RTR_FLAG) - return get_can_dlc(msg->dlc); + return can_cc_dlc2len(msg->dlc); else - return get_can_dlc(len - (UCAN_IN_HDR_SIZE + sizeof(msg->id))); + return can_cc_dlc2len(len - (UCAN_IN_HDR_SIZE + sizeof(msg->id))); } static void ucan_release_context_array(struct ucan_priv *up) @@ -424,18 +424,20 @@ static int ucan_ctrl_command_out(struct ucan_priv *up, UCAN_USB_CTL_PIPE_TIMEOUT); } -static int ucan_device_request_in(struct ucan_priv *up, - u8 cmd, u16 subcmd, u16 datalen) +static void ucan_get_fw_str(struct ucan_priv *up, char *fw_str, size_t size) { - return usb_control_msg(up->udev, - usb_rcvctrlpipe(up->udev, 0), - cmd, - USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, - subcmd, - 0, - up->ctl_msg_buffer, - datalen, - UCAN_USB_CTL_PIPE_TIMEOUT); + int ret; + + ret = usb_control_msg(up->udev, usb_rcvctrlpipe(up->udev, 0), + UCAN_DEVICE_GET_FW_STRING, + USB_DIR_IN | USB_TYPE_VENDOR | + USB_RECIP_DEVICE, + 0, 0, fw_str, size - 1, + UCAN_USB_CTL_PIPE_TIMEOUT); + if (ret > 0) + fw_str[ret] = '\0'; + else + strscpy(fw_str, "unknown", size); } /* Parse the device information structure reported by the device and @@ -614,15 +616,18 @@ static void ucan_rx_can_msg(struct ucan_priv *up, struct ucan_message_in *m) cf->can_id = canid; /* compute DLC taking RTR_FLAG into account */ - cf->can_dlc = ucan_get_can_dlc(&m->msg.can_msg, len); + cf->len = ucan_can_cc_dlc2len(&m->msg.can_msg, len); /* copy the payload of non RTR frames */ if (!(cf->can_id & CAN_RTR_FLAG) || (cf->can_id & CAN_ERR_FLAG)) - memcpy(cf->data, m->msg.can_msg.data, cf->can_dlc); + memcpy(cf->data, m->msg.can_msg.data, cf->len); /* don't count error frames as real packets */ - stats->rx_packets++; - stats->rx_bytes += cf->can_dlc; + if (!(cf->can_id & CAN_ERR_FLAG)) { + stats->rx_packets++; + if (!(cf->can_id & CAN_RTR_FLAG)) + stats->rx_bytes += cf->len; + } /* pass it to Linux */ netif_rx(skb); @@ -634,7 +639,7 @@ static void ucan_tx_complete_msg(struct ucan_priv *up, { unsigned long flags; u16 count, i; - u8 echo_index, dlc; + u8 echo_index; u16 len = le16_to_cpu(m->len); struct ucan_urb_context *context; @@ -658,7 +663,6 @@ static void ucan_tx_complete_msg(struct ucan_priv *up, /* gather information from the context */ context = &up->context_array[echo_index]; - dlc = READ_ONCE(context->dlc); /* Release context and restart queue if necessary. * Also check if the context was allocated @@ -671,11 +675,11 @@ static void ucan_tx_complete_msg(struct ucan_priv *up, UCAN_TX_COMPLETE_SUCCESS) { /* update statistics */ up->netdev->stats.tx_packets++; - up->netdev->stats.tx_bytes += dlc; - can_get_echo_skb(up->netdev, echo_index); + up->netdev->stats.tx_bytes += + can_get_echo_skb(up->netdev, echo_index, NULL); } else { up->netdev->stats.tx_dropped++; - can_free_echo_skb(up->netdev, echo_index); + can_free_echo_skb(up->netdev, echo_index, NULL); } spin_unlock_irqrestore(&up->echo_skb_lock, flags); } @@ -843,7 +847,7 @@ static void ucan_write_bulk_callback(struct urb *urb) /* update counters an cleanup */ spin_lock_irqsave(&up->echo_skb_lock, flags); - can_free_echo_skb(up->netdev, context - up->context_array); + can_free_echo_skb(up->netdev, context - up->context_array, NULL); spin_unlock_irqrestore(&up->echo_skb_lock, flags); up->netdev->stats.tx_dropped++; @@ -1078,16 +1082,14 @@ static struct urb *ucan_prepare_tx_urb(struct ucan_priv *up, mlen = UCAN_OUT_HDR_SIZE + offsetof(struct ucan_can_msg, dlc) + sizeof(m->msg.can_msg.dlc); - m->msg.can_msg.dlc = cf->can_dlc; + m->msg.can_msg.dlc = cf->len; } else { mlen = UCAN_OUT_HDR_SIZE + - sizeof(m->msg.can_msg.id) + cf->can_dlc; - memcpy(m->msg.can_msg.data, cf->data, cf->can_dlc); + sizeof(m->msg.can_msg.id) + cf->len; + memcpy(m->msg.can_msg.data, cf->data, cf->len); } m->len = cpu_to_le16(mlen); - context->dlc = cf->can_dlc; - m->subtype = echo_index; /* build the urb */ @@ -1120,7 +1122,7 @@ static netdev_tx_t ucan_start_xmit(struct sk_buff *skb, struct can_frame *cf = (struct can_frame *)skb->data; /* check skb */ - if (can_dropped_invalid_skb(netdev, skb)) + if (can_dev_dropped_skb(netdev, skb)) return NETDEV_TX_OK; /* allocate a context and slow down tx path, if fifo state is low */ @@ -1137,7 +1139,7 @@ static netdev_tx_t ucan_start_xmit(struct sk_buff *skb, /* put the skb on can loopback stack */ spin_lock_irqsave(&up->echo_skb_lock, flags); - can_put_echo_skb(skb, up->netdev, echo_index); + can_put_echo_skb(skb, up->netdev, echo_index, 0); spin_unlock_irqrestore(&up->echo_skb_lock, flags); /* transmit it */ @@ -1157,7 +1159,7 @@ static netdev_tx_t ucan_start_xmit(struct sk_buff *skb, * frees the skb */ spin_lock_irqsave(&up->echo_skb_lock, flags); - can_free_echo_skb(up->netdev, echo_index); + can_free_echo_skb(up->netdev, echo_index, NULL); spin_unlock_irqrestore(&up->echo_skb_lock, flags); if (ret == -ENODEV) { @@ -1231,7 +1233,10 @@ static const struct net_device_ops ucan_netdev_ops = { .ndo_open = ucan_open, .ndo_stop = ucan_close, .ndo_start_xmit = ucan_start_xmit, - .ndo_change_mtu = can_change_mtu, +}; + +static const struct ethtool_ops ucan_ethtool_ops = { + .get_ts_info = ethtool_op_get_ts_info, }; /* Request to set bittiming @@ -1310,7 +1315,6 @@ static int ucan_probe(struct usb_interface *intf, u8 in_ep_addr; u8 out_ep_addr; union ucan_ctl_payload *ctl_msg_buffer; - char firmware_str[sizeof(union ucan_ctl_payload) + 1]; udev = interface_to_usbdev(intf); @@ -1393,7 +1397,7 @@ static int ucan_probe(struct usb_interface *intf, * Stage 3 for the final driver initialisation. */ - /* Prepare Memory for control transferes */ + /* Prepare Memory for control transfers */ ctl_msg_buffer = devm_kzalloc(&udev->dev, sizeof(union ucan_ctl_payload), GFP_KERNEL); @@ -1445,7 +1449,7 @@ static int ucan_probe(struct usb_interface *intf, /* request the device information and store it in ctl_msg_buffer * - * note: ucan_ctrl_command_* wrappers connot be used yet + * note: ucan_ctrl_command_* wrappers cannot be used yet * because `up` is initialised in Stage 3 */ ret = usb_control_msg(udev, @@ -1494,9 +1498,8 @@ static int ucan_probe(struct usb_interface *intf, up = netdev_priv(netdev); - /* initialze data */ + /* initialize data */ up->udev = udev; - up->intf = intf; up->netdev = netdev; up->intf_index = iface_desc->desc.bInterfaceNumber; up->in_ep_addr = in_ep_addr; @@ -1513,6 +1516,7 @@ static int ucan_probe(struct usb_interface *intf, spin_lock_init(&up->context_lock); spin_lock_init(&up->echo_skb_lock); netdev->netdev_ops = &ucan_netdev_ops; + netdev->ethtool_ops = &ucan_ethtool_ops; usb_set_intfdata(intf, up); SET_NETDEV_DEV(netdev, &intf->dev); @@ -1523,18 +1527,6 @@ static int ucan_probe(struct usb_interface *intf, */ ucan_parse_device_info(up, &ctl_msg_buffer->cmd_get_device_info); - /* just print some device information - if available */ - ret = ucan_device_request_in(up, UCAN_DEVICE_GET_FW_STRING, 0, - sizeof(union ucan_ctl_payload)); - if (ret > 0) { - /* copy string while ensuring zero terminiation */ - strncpy(firmware_str, up->ctl_msg_buffer->raw, - sizeof(union ucan_ctl_payload)); - firmware_str[sizeof(union ucan_ctl_payload)] = '\0'; - } else { - strcpy(firmware_str, "unknown"); - } - /* device is compatible, reset it */ ret = ucan_ctrl_command_out(up, UCAN_COMMAND_RESET, 0, 0); if (ret < 0) @@ -1552,7 +1544,10 @@ static int ucan_probe(struct usb_interface *intf, /* initialisation complete, log device info */ netdev_info(up->netdev, "registered device\n"); - netdev_info(up->netdev, "firmware string: %s\n", firmware_str); + ucan_get_fw_str(up, up->ctl_msg_buffer->fw_str, + sizeof(up->ctl_msg_buffer->fw_str)); + netdev_info(up->netdev, "firmware string: %s\n", + up->ctl_msg_buffer->fw_str); /* success */ return 0; @@ -1576,7 +1571,7 @@ static void ucan_disconnect(struct usb_interface *intf) usb_set_intfdata(intf, NULL); if (up) { - unregister_netdev(up->netdev); + unregister_candev(up->netdev); free_candev(up->netdev); } } |
