diff options
Diffstat (limited to 'drivers/net/can/usb/peak_usb/pcan_usb.c')
-rw-r--r-- | drivers/net/can/usb/peak_usb/pcan_usb.c | 106 |
1 files changed, 66 insertions, 40 deletions
diff --git a/drivers/net/can/usb/peak_usb/pcan_usb.c b/drivers/net/can/usb/peak_usb/pcan_usb.c index e393e8457d77..1d6f77252f01 100644 --- a/drivers/net/can/usb/peak_usb/pcan_usb.c +++ b/drivers/net/can/usb/peak_usb/pcan_usb.c @@ -11,6 +11,7 @@ #include <linux/netdevice.h> #include <linux/usb.h> #include <linux/module.h> +#include <linux/ethtool.h> #include <linux/can.h> #include <linux/can/dev.h> @@ -40,6 +41,7 @@ #define PCAN_USB_CMD_REGISTER 9 #define PCAN_USB_CMD_EXT_VCC 10 #define PCAN_USB_CMD_ERR_FR 11 +#define PCAN_USB_CMD_LED 12 /* PCAN_USB_CMD_SET_BUS number arg */ #define PCAN_USB_BUS_XCVER 2 @@ -248,6 +250,15 @@ static int pcan_usb_set_ext_vcc(struct peak_usb_device *dev, u8 onoff) return pcan_usb_send_cmd(dev, PCAN_USB_CMD_EXT_VCC, PCAN_USB_SET, args); } +static int pcan_usb_set_led(struct peak_usb_device *dev, u8 onoff) +{ + u8 args[PCAN_USB_CMD_ARGS_LEN] = { + [0] = !!onoff, + }; + + return pcan_usb_send_cmd(dev, PCAN_USB_CMD_LED, PCAN_USB_SET, args); +} + /* * set bittiming value to can */ @@ -354,16 +365,11 @@ static int pcan_usb_get_serial(struct peak_usb_device *dev, u32 *serial_number) int err; err = pcan_usb_wait_rsp(dev, PCAN_USB_CMD_SN, PCAN_USB_GET, args); - if (err) { - netdev_err(dev->netdev, "getting serial failure: %d\n", err); - } else if (serial_number) { - __le32 tmp32; - - memcpy(&tmp32, args, 4); - *serial_number = le32_to_cpu(tmp32); - } + if (err) + return err; + *serial_number = le32_to_cpup((__le32 *)args); - return err; + return 0; } /* @@ -377,8 +383,8 @@ static int pcan_usb_get_device_id(struct peak_usb_device *dev, u32 *device_id) err = pcan_usb_wait_rsp(dev, PCAN_USB_CMD_DEVID, PCAN_USB_GET, args); if (err) netdev_err(dev->netdev, "getting device id failure: %d\n", err); - else if (device_id) - *device_id = args[0]; + + *device_id = args[0]; return err; } @@ -388,14 +394,10 @@ static int pcan_usb_get_device_id(struct peak_usb_device *dev, u32 *device_id) */ static int pcan_usb_update_ts(struct pcan_usb_msg_context *mc) { - __le16 tmp16; - - if ((mc->ptr+2) > mc->end) + if ((mc->ptr + 2) > mc->end) return -EINVAL; - memcpy(&tmp16, mc->ptr, 2); - - mc->ts16 = le16_to_cpu(tmp16); + mc->ts16 = get_unaligned_le16(mc->ptr); if (mc->rec_idx > 0) peak_usb_update_ts_now(&mc->pdev->time_ref, mc->ts16); @@ -412,16 +414,13 @@ static int pcan_usb_decode_ts(struct pcan_usb_msg_context *mc, u8 first_packet) { /* only 1st packet supplies a word timestamp */ if (first_packet) { - __le16 tmp16; - if ((mc->ptr + 2) > mc->end) return -EINVAL; - memcpy(&tmp16, mc->ptr, 2); - mc->ptr += 2; - - mc->ts16 = le16_to_cpu(tmp16); + mc->ts16 = get_unaligned_le16(mc->ptr); mc->prev_ts8 = mc->ts16 & 0x00ff; + + mc->ptr += 2; } else { u8 ts8; @@ -711,25 +710,17 @@ static int pcan_usb_decode_data(struct pcan_usb_msg_context *mc, u8 status_len) return -ENOMEM; if (status_len & PCAN_USB_STATUSLEN_EXT_ID) { - __le32 tmp32; - if ((mc->ptr + 4) > mc->end) goto decode_failed; - memcpy(&tmp32, mc->ptr, 4); + cf->can_id = get_unaligned_le32(mc->ptr) >> 3 | CAN_EFF_FLAG; mc->ptr += 4; - - cf->can_id = (le32_to_cpu(tmp32) >> 3) | CAN_EFF_FLAG; } else { - __le16 tmp16; - if ((mc->ptr + 2) > mc->end) goto decode_failed; - memcpy(&tmp16, mc->ptr, 2); + cf->can_id = get_unaligned_le16(mc->ptr) >> 5; mc->ptr += 2; - - cf->can_id = le16_to_cpu(tmp16) >> 5; } can_frame_set_cc_len(cf, rec_len, mc->pdev->dev.can.ctrlmode); @@ -843,15 +834,15 @@ static int pcan_usb_encode_msg(struct peak_usb_device *dev, struct sk_buff *skb, /* can id */ if (cf->can_id & CAN_EFF_FLAG) { - __le32 tmp32 = cpu_to_le32((cf->can_id & CAN_ERR_MASK) << 3); - *pc |= PCAN_USB_STATUSLEN_EXT_ID; - memcpy(++pc, &tmp32, 4); + pc++; + + put_unaligned_le32((cf->can_id & CAN_ERR_MASK) << 3, pc); pc += 4; } else { - __le16 tmp16 = cpu_to_le16((cf->can_id & CAN_ERR_MASK) << 5); + pc++; - memcpy(++pc, &tmp16, 2); + put_unaligned_le16((cf->can_id & CAN_ERR_MASK) << 5, pc); pc += 2; } @@ -971,6 +962,40 @@ static int pcan_usb_probe(struct usb_interface *intf) return 0; } +static int pcan_usb_set_phys_id(struct net_device *netdev, + enum ethtool_phys_id_state state) +{ + struct peak_usb_device *dev = netdev_priv(netdev); + int err = 0; + + switch (state) { + case ETHTOOL_ID_ACTIVE: + /* call ON/OFF twice a second */ + return 2; + + case ETHTOOL_ID_OFF: + err = pcan_usb_set_led(dev, 0); + break; + + case ETHTOOL_ID_ON: + fallthrough; + + case ETHTOOL_ID_INACTIVE: + /* restore LED default */ + err = pcan_usb_set_led(dev, 1); + break; + + default: + break; + } + + return err; +} + +static const struct ethtool_ops pcan_usb_ethtool_ops = { + .set_phys_id = pcan_usb_set_phys_id, +}; + /* * describe the PCAN-USB adapter */ @@ -994,16 +1019,17 @@ const struct peak_usb_adapter pcan_usb = { CAN_CTRLMODE_BERR_REPORTING | CAN_CTRLMODE_CC_LEN8_DLC, .clock = { - .freq = PCAN_USB_CRYSTAL_HZ / 2 , + .freq = PCAN_USB_CRYSTAL_HZ / 2, }, .bittiming_const = &pcan_usb_const, /* size of device private data */ .sizeof_dev_private = sizeof(struct pcan_usb), + .ethtool_ops = &pcan_usb_ethtool_ops, + /* timestamps usage */ .ts_used_bits = 16, - .ts_period = 24575, /* calibration period in ts. */ .us_per_ts_scale = PCAN_USB_TS_US_PER_TICK, /* us=(ts*scale) */ .us_per_ts_shift = PCAN_USB_TS_DIV_SHIFTER, /* >> shift */ |