From 404ffaa95a3e88f844461d3f92e03d3423ee9920 Mon Sep 17 00:00:00 2001 From: Stephane Grosjean Date: Mon, 16 Jan 2023 20:09:25 +0000 Subject: [PATCH 1/8] can: peak_usb: rename device_id to CAN channel ID The so-called "device id" is a user-defined identifier value that can be set individually for each CAN interface of a PEAK USB device. Contrary to a static serial number, the value can be changed by the user. With this ID, each CAN interface can be uniquely identified even if the USB device does not export a proper serial number or the USB device exports multiple CAN interfaces. In order to not confuse it with the device ID used by the USB core and emphasize the link to the CAN interface, the functions and variables for reading this user-defined value are renamed to CAN channel ID. Signed-off-by: Stephane Grosjean Signed-off-by: Lukas Magel Link: https://lore.kernel.org/all/20230116200932.157769-2-lukas.magel@posteo.net Signed-off-by: Marc Kleine-Budde --- drivers/net/can/usb/peak_usb/pcan_usb.c | 10 +++++----- drivers/net/can/usb/peak_usb/pcan_usb_core.c | 8 ++++---- drivers/net/can/usb/peak_usb/pcan_usb_core.h | 5 +++-- drivers/net/can/usb/peak_usb/pcan_usb_fd.c | 2 +- drivers/net/can/usb/peak_usb/pcan_usb_pro.c | 8 ++++---- 5 files changed, 17 insertions(+), 16 deletions(-) diff --git a/drivers/net/can/usb/peak_usb/pcan_usb.c b/drivers/net/can/usb/peak_usb/pcan_usb.c index 687dd542f7f68..7b3282e5c8807 100644 --- a/drivers/net/can/usb/peak_usb/pcan_usb.c +++ b/drivers/net/can/usb/peak_usb/pcan_usb.c @@ -381,19 +381,19 @@ static int pcan_usb_get_serial(struct peak_usb_device *dev, u32 *serial_number) } /* - * read device id from device + * read can channel id from device */ -static int pcan_usb_get_device_id(struct peak_usb_device *dev, u32 *device_id) +static int pcan_usb_get_can_channel_id(struct peak_usb_device *dev, u32 *can_ch_id) { u8 args[PCAN_USB_CMD_ARGS_LEN]; int err; 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); + netdev_err(dev->netdev, "getting can channel id failure: %d\n", err); else - *device_id = args[0]; + *can_ch_id = args[0]; return err; } @@ -1017,7 +1017,7 @@ const struct peak_usb_adapter pcan_usb = { .dev_init = pcan_usb_init, .dev_set_bus = pcan_usb_write_mode, .dev_set_bittiming = pcan_usb_set_bittiming, - .dev_get_device_id = pcan_usb_get_device_id, + .dev_get_can_channel_id = pcan_usb_get_can_channel_id, .dev_decode_buf = pcan_usb_decode_buf, .dev_encode_msg = pcan_usb_encode_msg, .dev_start = pcan_usb_start, diff --git a/drivers/net/can/usb/peak_usb/pcan_usb_core.c b/drivers/net/can/usb/peak_usb/pcan_usb_core.c index 1d996d3320fef..440abbe4bf415 100644 --- a/drivers/net/can/usb/peak_usb/pcan_usb_core.c +++ b/drivers/net/can/usb/peak_usb/pcan_usb_core.c @@ -921,12 +921,12 @@ static int peak_usb_create_dev(const struct peak_usb_adapter *peak_usb_adapter, goto adap_dev_free; } - /* get device number early */ - if (dev->adapter->dev_get_device_id) - dev->adapter->dev_get_device_id(dev, &dev->device_number); + /* get CAN channel id early */ + if (dev->adapter->dev_get_can_channel_id) + dev->adapter->dev_get_can_channel_id(dev, &dev->can_channel_id); netdev_info(netdev, "attached to %s channel %u (device %u)\n", - peak_usb_adapter->name, ctrl_idx, dev->device_number); + peak_usb_adapter->name, ctrl_idx, dev->can_channel_id); return 0; diff --git a/drivers/net/can/usb/peak_usb/pcan_usb_core.h b/drivers/net/can/usb/peak_usb/pcan_usb_core.h index f6bdd8b3f2901..6de0429c268f2 100644 --- a/drivers/net/can/usb/peak_usb/pcan_usb_core.h +++ b/drivers/net/can/usb/peak_usb/pcan_usb_core.h @@ -60,7 +60,7 @@ struct peak_usb_adapter { int (*dev_set_data_bittiming)(struct peak_usb_device *dev, struct can_bittiming *bt); int (*dev_set_bus)(struct peak_usb_device *dev, u8 onoff); - int (*dev_get_device_id)(struct peak_usb_device *dev, u32 *device_id); + int (*dev_get_can_channel_id)(struct peak_usb_device *dev, u32 *can_ch_id); int (*dev_decode_buf)(struct peak_usb_device *dev, struct urb *urb); int (*dev_encode_msg)(struct peak_usb_device *dev, struct sk_buff *skb, u8 *obuf, size_t *size); @@ -122,7 +122,8 @@ struct peak_usb_device { u8 *cmd_buf; struct usb_anchor rx_submitted; - u32 device_number; + /* equivalent to the device ID in the Windows API */ + u32 can_channel_id; u8 device_rev; u8 ep_msg_in; diff --git a/drivers/net/can/usb/peak_usb/pcan_usb_fd.c b/drivers/net/can/usb/peak_usb/pcan_usb_fd.c index 2ea1500df393f..2e0955900ebec 100644 --- a/drivers/net/can/usb/peak_usb/pcan_usb_fd.c +++ b/drivers/net/can/usb/peak_usb/pcan_usb_fd.c @@ -972,7 +972,7 @@ static int pcan_usb_fd_init(struct peak_usb_device *dev) } pdev->usb_if->dev[dev->ctrl_idx] = dev; - dev->device_number = + dev->can_channel_id = le32_to_cpu(pdev->usb_if->fw_info.dev_id[dev->ctrl_idx]); /* if vendor rsp is of type 2, then it contains EP numbers to diff --git a/drivers/net/can/usb/peak_usb/pcan_usb_pro.c b/drivers/net/can/usb/peak_usb/pcan_usb_pro.c index 5d8f6a40bb2c1..3a13cfef47bba 100644 --- a/drivers/net/can/usb/peak_usb/pcan_usb_pro.c +++ b/drivers/net/can/usb/peak_usb/pcan_usb_pro.c @@ -419,8 +419,8 @@ static int pcan_usb_pro_set_led(struct peak_usb_device *dev, u8 mode, return pcan_usb_pro_send_cmd(dev, &um); } -static int pcan_usb_pro_get_device_id(struct peak_usb_device *dev, - u32 *device_id) +static int pcan_usb_pro_get_can_channel_id(struct peak_usb_device *dev, + u32 *can_ch_id) { struct pcan_usb_pro_devid *pdn; struct pcan_usb_pro_msg um; @@ -439,7 +439,7 @@ static int pcan_usb_pro_get_device_id(struct peak_usb_device *dev, return err; pdn = (struct pcan_usb_pro_devid *)pc; - *device_id = le32_to_cpu(pdn->dev_num); + *can_ch_id = le32_to_cpu(pdn->dev_num); return err; } @@ -1076,7 +1076,7 @@ const struct peak_usb_adapter pcan_usb_pro = { .dev_free = pcan_usb_pro_free, .dev_set_bus = pcan_usb_pro_set_bus, .dev_set_bittiming = pcan_usb_pro_set_bittiming, - .dev_get_device_id = pcan_usb_pro_get_device_id, + .dev_get_can_channel_id = pcan_usb_pro_get_can_channel_id, .dev_decode_buf = pcan_usb_pro_decode_buf, .dev_encode_msg = pcan_usb_pro_encode_msg, .dev_start = pcan_usb_pro_start, From 517ad5e6761feca12f0fc78e7c6304560da853f4 Mon Sep 17 00:00:00 2001 From: Stephane Grosjean Date: Mon, 16 Jan 2023 20:09:26 +0000 Subject: [PATCH 2/8] can: peak_usb: add callback to read CAN channel ID of PEAK CAN-FD devices This patch adds a new function that allows to read the CAN channel ID from the non volatile memory of the USB CAN-FD PEAK devices. The CAN channel ID is a user-configurable u8/u32 identifier value that can be set individually for each PEAK CAN interface. Signed-off-by: Stephane Grosjean Signed-off-by: Lukas Magel Link: https://lore.kernel.org/all/20230116200932.157769-3-lukas.magel@posteo.net Signed-off-by: Marc Kleine-Budde --- drivers/net/can/usb/peak_usb/pcan_usb_core.c | 3 +- drivers/net/can/usb/peak_usb/pcan_usb_fd.c | 33 +++++++++++++++++--- 2 files changed, 30 insertions(+), 6 deletions(-) diff --git a/drivers/net/can/usb/peak_usb/pcan_usb_core.c b/drivers/net/can/usb/peak_usb/pcan_usb_core.c index 440abbe4bf415..4a5155a385b87 100644 --- a/drivers/net/can/usb/peak_usb/pcan_usb_core.c +++ b/drivers/net/can/usb/peak_usb/pcan_usb_core.c @@ -922,8 +922,7 @@ static int peak_usb_create_dev(const struct peak_usb_adapter *peak_usb_adapter, } /* get CAN channel id early */ - if (dev->adapter->dev_get_can_channel_id) - dev->adapter->dev_get_can_channel_id(dev, &dev->can_channel_id); + dev->adapter->dev_get_can_channel_id(dev, &dev->can_channel_id); netdev_info(netdev, "attached to %s channel %u (device %u)\n", peak_usb_adapter->name, ctrl_idx, dev->can_channel_id); diff --git a/drivers/net/can/usb/peak_usb/pcan_usb_fd.c b/drivers/net/can/usb/peak_usb/pcan_usb_fd.c index 2e0955900ebec..a70ef0c7a800c 100644 --- a/drivers/net/can/usb/peak_usb/pcan_usb_fd.c +++ b/drivers/net/can/usb/peak_usb/pcan_usb_fd.c @@ -234,6 +234,15 @@ static int pcan_usb_fd_send_cmd(struct peak_usb_device *dev, void *cmd_tail) return err; } +static int pcan_usb_fd_read_fwinfo(struct peak_usb_device *dev, + struct pcan_ufd_fw_info *fw_info) +{ + return pcan_usb_pro_send_req(dev, PCAN_USBPRO_REQ_INFO, + PCAN_USBPRO_INFO_FW, + fw_info, + sizeof(*fw_info)); +} + /* build the commands list in the given buffer, to enter operational mode */ static int pcan_usb_fd_build_restart_cmd(struct peak_usb_device *dev, u8 *buf) { @@ -434,6 +443,21 @@ static int pcan_usb_fd_set_bittiming_fast(struct peak_usb_device *dev, return pcan_usb_fd_send_cmd(dev, ++cmd); } +/* read user CAN channel id from device */ +static int pcan_usb_fd_get_can_channel_id(struct peak_usb_device *dev, + u32 *can_ch_id) +{ + int err; + struct pcan_usb_fd_if *usb_if = pcan_usb_fd_dev_if(dev); + + err = pcan_usb_fd_read_fwinfo(dev, &usb_if->fw_info); + if (err) + return err; + + *can_ch_id = le32_to_cpu(usb_if->fw_info.dev_id[dev->ctrl_idx]); + return err; +} + /* handle restart but in asynchronously way * (uses PCAN-USB Pro code to complete asynchronous request) */ @@ -907,10 +931,7 @@ static int pcan_usb_fd_init(struct peak_usb_device *dev) fw_info = &pdev->usb_if->fw_info; - err = pcan_usb_pro_send_req(dev, PCAN_USBPRO_REQ_INFO, - PCAN_USBPRO_INFO_FW, - fw_info, - sizeof(*fw_info)); + err = pcan_usb_fd_read_fwinfo(dev, fw_info); if (err) { dev_err(dev->netdev->dev.parent, "unable to read %s firmware info (err %d)\n", @@ -1148,6 +1169,7 @@ const struct peak_usb_adapter pcan_usb_fd = { .dev_set_bus = pcan_usb_fd_set_bus, .dev_set_bittiming = pcan_usb_fd_set_bittiming_slow, .dev_set_data_bittiming = pcan_usb_fd_set_bittiming_fast, + .dev_get_can_channel_id = pcan_usb_fd_get_can_channel_id, .dev_decode_buf = pcan_usb_fd_decode_buf, .dev_start = pcan_usb_fd_start, .dev_stop = pcan_usb_fd_stop, @@ -1222,6 +1244,7 @@ const struct peak_usb_adapter pcan_usb_chip = { .dev_set_bus = pcan_usb_fd_set_bus, .dev_set_bittiming = pcan_usb_fd_set_bittiming_slow, .dev_set_data_bittiming = pcan_usb_fd_set_bittiming_fast, + .dev_get_can_channel_id = pcan_usb_fd_get_can_channel_id, .dev_decode_buf = pcan_usb_fd_decode_buf, .dev_start = pcan_usb_fd_start, .dev_stop = pcan_usb_fd_stop, @@ -1296,6 +1319,7 @@ const struct peak_usb_adapter pcan_usb_pro_fd = { .dev_set_bus = pcan_usb_fd_set_bus, .dev_set_bittiming = pcan_usb_fd_set_bittiming_slow, .dev_set_data_bittiming = pcan_usb_fd_set_bittiming_fast, + .dev_get_can_channel_id = pcan_usb_fd_get_can_channel_id, .dev_decode_buf = pcan_usb_fd_decode_buf, .dev_start = pcan_usb_fd_start, .dev_stop = pcan_usb_fd_stop, @@ -1370,6 +1394,7 @@ const struct peak_usb_adapter pcan_usb_x6 = { .dev_set_bus = pcan_usb_fd_set_bus, .dev_set_bittiming = pcan_usb_fd_set_bittiming_slow, .dev_set_data_bittiming = pcan_usb_fd_set_bittiming_fast, + .dev_get_can_channel_id = pcan_usb_fd_get_can_channel_id, .dev_decode_buf = pcan_usb_fd_decode_buf, .dev_start = pcan_usb_fd_start, .dev_stop = pcan_usb_fd_stop, From e7a7b3d22503d79ccd0c2536080ed3f7b10a23f6 Mon Sep 17 00:00:00 2001 From: Stephane Grosjean Date: Mon, 16 Jan 2023 20:09:27 +0000 Subject: [PATCH 3/8] can: peak_usb: allow flashing of the CAN channel ID This patch adds callbacks that allow the user to set a new self-defined CAN channel ID to all USB - CAN/CANFD interfaces of PEAK-System managed by this driver, namely: - PCAN-USB - PCAN-USB FD - PCAN-USB Pro FD - PCAN-USB X6 - PCAN-Chip USB - PCAN-USB Pro The callback functions write the CAN channel ID to the non-volatile memory of the devices. Signed-off-by: Stephane Grosjean Signed-off-by: Lukas Magel Link: https://lore.kernel.org/all/20230116200932.157769-4-lukas.magel@posteo.net Signed-off-by: Marc Kleine-Budde --- drivers/net/can/usb/peak_usb/pcan_usb.c | 20 +++++++++++++++ drivers/net/can/usb/peak_usb/pcan_usb_core.h | 1 + drivers/net/can/usb/peak_usb/pcan_usb_fd.c | 26 ++++++++++++++++++++ drivers/net/can/usb/peak_usb/pcan_usb_pro.c | 15 +++++++++++ drivers/net/can/usb/peak_usb/pcan_usb_pro.h | 1 + 5 files changed, 63 insertions(+) diff --git a/drivers/net/can/usb/peak_usb/pcan_usb.c b/drivers/net/can/usb/peak_usb/pcan_usb.c index 7b3282e5c8807..44e894a1f2c23 100644 --- a/drivers/net/can/usb/peak_usb/pcan_usb.c +++ b/drivers/net/can/usb/peak_usb/pcan_usb.c @@ -398,6 +398,25 @@ static int pcan_usb_get_can_channel_id(struct peak_usb_device *dev, u32 *can_ch_ return err; } +/* set a new CAN channel id in the flash memory of the device */ +static int pcan_usb_set_can_channel_id(struct peak_usb_device *dev, u32 can_ch_id) +{ + u8 args[PCAN_USB_CMD_ARGS_LEN]; + + /* this kind of device supports 8-bit values only */ + if (can_ch_id > U8_MAX) + return -EINVAL; + + /* during the flash process the device disconnects during ~1.25 s.: + * prohibit access when interface is UP + */ + if (dev->netdev->flags & IFF_UP) + return -EBUSY; + + args[0] = can_ch_id; + return pcan_usb_send_cmd(dev, PCAN_USB_CMD_DEVID, PCAN_USB_SET, args); +} + /* * update current time ref with received timestamp */ @@ -1018,6 +1037,7 @@ const struct peak_usb_adapter pcan_usb = { .dev_set_bus = pcan_usb_write_mode, .dev_set_bittiming = pcan_usb_set_bittiming, .dev_get_can_channel_id = pcan_usb_get_can_channel_id, + .dev_set_can_channel_id = pcan_usb_set_can_channel_id, .dev_decode_buf = pcan_usb_decode_buf, .dev_encode_msg = pcan_usb_encode_msg, .dev_start = pcan_usb_start, diff --git a/drivers/net/can/usb/peak_usb/pcan_usb_core.h b/drivers/net/can/usb/peak_usb/pcan_usb_core.h index 6de0429c268f2..1e461aef0f2a7 100644 --- a/drivers/net/can/usb/peak_usb/pcan_usb_core.h +++ b/drivers/net/can/usb/peak_usb/pcan_usb_core.h @@ -61,6 +61,7 @@ struct peak_usb_adapter { struct can_bittiming *bt); int (*dev_set_bus)(struct peak_usb_device *dev, u8 onoff); int (*dev_get_can_channel_id)(struct peak_usb_device *dev, u32 *can_ch_id); + int (*dev_set_can_channel_id)(struct peak_usb_device *dev, u32 can_ch_id); int (*dev_decode_buf)(struct peak_usb_device *dev, struct urb *urb); int (*dev_encode_msg)(struct peak_usb_device *dev, struct sk_buff *skb, u8 *obuf, size_t *size); diff --git a/drivers/net/can/usb/peak_usb/pcan_usb_fd.c b/drivers/net/can/usb/peak_usb/pcan_usb_fd.c index a70ef0c7a800c..1ea4cfdfd6401 100644 --- a/drivers/net/can/usb/peak_usb/pcan_usb_fd.c +++ b/drivers/net/can/usb/peak_usb/pcan_usb_fd.c @@ -147,6 +147,15 @@ struct __packed pcan_ufd_ovr_msg { u8 unused[3]; }; +#define PCAN_UFD_CMD_DEVID_SET 0x81 + +struct __packed pcan_ufd_device_id { + __le16 opcode_channel; + + u16 unused; + __le32 device_id; +}; + static inline int pufd_omsg_get_channel(struct pcan_ufd_ovr_msg *om) { return om->channel & 0xf; @@ -458,6 +467,19 @@ static int pcan_usb_fd_get_can_channel_id(struct peak_usb_device *dev, return err; } +/* set a new CAN channel id in the flash memory of the device */ +static int pcan_usb_fd_set_can_channel_id(struct peak_usb_device *dev, u32 can_ch_id) +{ + struct pcan_ufd_device_id *cmd = pcan_usb_fd_cmd_buffer(dev); + + cmd->opcode_channel = pucan_cmd_opcode_channel(dev->ctrl_idx, + PCAN_UFD_CMD_DEVID_SET); + cmd->device_id = cpu_to_le32(can_ch_id); + + /* send the command */ + return pcan_usb_fd_send_cmd(dev, ++cmd); +} + /* handle restart but in asynchronously way * (uses PCAN-USB Pro code to complete asynchronous request) */ @@ -1170,6 +1192,7 @@ const struct peak_usb_adapter pcan_usb_fd = { .dev_set_bittiming = pcan_usb_fd_set_bittiming_slow, .dev_set_data_bittiming = pcan_usb_fd_set_bittiming_fast, .dev_get_can_channel_id = pcan_usb_fd_get_can_channel_id, + .dev_set_can_channel_id = pcan_usb_fd_set_can_channel_id, .dev_decode_buf = pcan_usb_fd_decode_buf, .dev_start = pcan_usb_fd_start, .dev_stop = pcan_usb_fd_stop, @@ -1245,6 +1268,7 @@ const struct peak_usb_adapter pcan_usb_chip = { .dev_set_bittiming = pcan_usb_fd_set_bittiming_slow, .dev_set_data_bittiming = pcan_usb_fd_set_bittiming_fast, .dev_get_can_channel_id = pcan_usb_fd_get_can_channel_id, + .dev_set_can_channel_id = pcan_usb_fd_set_can_channel_id, .dev_decode_buf = pcan_usb_fd_decode_buf, .dev_start = pcan_usb_fd_start, .dev_stop = pcan_usb_fd_stop, @@ -1320,6 +1344,7 @@ const struct peak_usb_adapter pcan_usb_pro_fd = { .dev_set_bittiming = pcan_usb_fd_set_bittiming_slow, .dev_set_data_bittiming = pcan_usb_fd_set_bittiming_fast, .dev_get_can_channel_id = pcan_usb_fd_get_can_channel_id, + .dev_set_can_channel_id = pcan_usb_fd_set_can_channel_id, .dev_decode_buf = pcan_usb_fd_decode_buf, .dev_start = pcan_usb_fd_start, .dev_stop = pcan_usb_fd_stop, @@ -1395,6 +1420,7 @@ const struct peak_usb_adapter pcan_usb_x6 = { .dev_set_bittiming = pcan_usb_fd_set_bittiming_slow, .dev_set_data_bittiming = pcan_usb_fd_set_bittiming_fast, .dev_get_can_channel_id = pcan_usb_fd_get_can_channel_id, + .dev_set_can_channel_id = pcan_usb_fd_set_can_channel_id, .dev_decode_buf = pcan_usb_fd_decode_buf, .dev_start = pcan_usb_fd_start, .dev_stop = pcan_usb_fd_stop, diff --git a/drivers/net/can/usb/peak_usb/pcan_usb_pro.c b/drivers/net/can/usb/peak_usb/pcan_usb_pro.c index 3a13cfef47bba..061f04c20f960 100644 --- a/drivers/net/can/usb/peak_usb/pcan_usb_pro.c +++ b/drivers/net/can/usb/peak_usb/pcan_usb_pro.c @@ -76,6 +76,7 @@ static u16 pcan_usb_pro_sizeof_rec[256] = { [PCAN_USBPRO_SETFILTR] = sizeof(struct pcan_usb_pro_filter), [PCAN_USBPRO_SETTS] = sizeof(struct pcan_usb_pro_setts), [PCAN_USBPRO_GETDEVID] = sizeof(struct pcan_usb_pro_devid), + [PCAN_USBPRO_SETDEVID] = sizeof(struct pcan_usb_pro_devid), [PCAN_USBPRO_SETLED] = sizeof(struct pcan_usb_pro_setled), [PCAN_USBPRO_RXMSG8] = sizeof(struct pcan_usb_pro_rxmsg), [PCAN_USBPRO_RXMSG4] = sizeof(struct pcan_usb_pro_rxmsg) - 4, @@ -149,6 +150,7 @@ static int pcan_msg_add_rec(struct pcan_usb_pro_msg *pm, int id, ...) case PCAN_USBPRO_SETBTR: case PCAN_USBPRO_GETDEVID: + case PCAN_USBPRO_SETDEVID: *pc++ = va_arg(ap, int); pc += 2; *(__le32 *)pc = cpu_to_le32(va_arg(ap, u32)); @@ -444,6 +446,18 @@ static int pcan_usb_pro_get_can_channel_id(struct peak_usb_device *dev, return err; } +static int pcan_usb_pro_set_can_channel_id(struct peak_usb_device *dev, + u32 can_ch_id) +{ + struct pcan_usb_pro_msg um; + + pcan_msg_init_empty(&um, dev->cmd_buf, PCAN_USB_MAX_CMD_LEN); + pcan_msg_add_rec(&um, PCAN_USBPRO_SETDEVID, dev->ctrl_idx, + can_ch_id); + + return pcan_usb_pro_send_cmd(dev, &um); +} + static int pcan_usb_pro_set_bittiming(struct peak_usb_device *dev, struct can_bittiming *bt) { @@ -1077,6 +1091,7 @@ const struct peak_usb_adapter pcan_usb_pro = { .dev_set_bus = pcan_usb_pro_set_bus, .dev_set_bittiming = pcan_usb_pro_set_bittiming, .dev_get_can_channel_id = pcan_usb_pro_get_can_channel_id, + .dev_set_can_channel_id = pcan_usb_pro_set_can_channel_id, .dev_decode_buf = pcan_usb_pro_decode_buf, .dev_encode_msg = pcan_usb_pro_encode_msg, .dev_start = pcan_usb_pro_start, diff --git a/drivers/net/can/usb/peak_usb/pcan_usb_pro.h b/drivers/net/can/usb/peak_usb/pcan_usb_pro.h index a34e0fc021c96..28e740af905d9 100644 --- a/drivers/net/can/usb/peak_usb/pcan_usb_pro.h +++ b/drivers/net/can/usb/peak_usb/pcan_usb_pro.h @@ -62,6 +62,7 @@ struct __packed pcan_usb_pro_fwinfo { #define PCAN_USBPRO_SETBTR 0x02 #define PCAN_USBPRO_SETBUSACT 0x04 #define PCAN_USBPRO_SETSILENT 0x05 +#define PCAN_USBPRO_SETDEVID 0x06 #define PCAN_USBPRO_SETFILTR 0x0a #define PCAN_USBPRO_SETTS 0x10 #define PCAN_USBPRO_GETDEVID 0x12 From e1bd882252439dae49c40cfe80997cde5955939f Mon Sep 17 00:00:00 2001 From: Stephane Grosjean Date: Mon, 16 Jan 2023 20:09:28 +0000 Subject: [PATCH 4/8] can: peak_usb: replace unregister_netdev() with unregister_candev() This patch changes the call to unregister_netdev() in peak_usb_disconnect() with unregister_candev(). Signed-off-by: Stephane Grosjean Signed-off-by: Lukas Magel Link: https://lore.kernel.org/all/20230116200932.157769-5-lukas.magel@posteo.net Signed-off-by: Marc Kleine-Budde --- drivers/net/can/usb/peak_usb/pcan_usb_core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/can/usb/peak_usb/pcan_usb_core.c b/drivers/net/can/usb/peak_usb/pcan_usb_core.c index 4a5155a385b87..3a73eac314ff5 100644 --- a/drivers/net/can/usb/peak_usb/pcan_usb_core.c +++ b/drivers/net/can/usb/peak_usb/pcan_usb_core.c @@ -963,7 +963,7 @@ static void peak_usb_disconnect(struct usb_interface *intf) dev->state &= ~PCAN_USB_STATE_CONNECTED; strscpy(name, netdev->name, IFNAMSIZ); - unregister_netdev(netdev); + unregister_candev(netdev); kfree(dev->cmd_buf); dev->next_siblings = NULL; From 36d007c6fc7962cb70ff4b1496d1e24f8b1c1300 Mon Sep 17 00:00:00 2001 From: Stephane Grosjean Date: Mon, 16 Jan 2023 20:09:29 +0000 Subject: [PATCH 5/8] can: peak_usb: add ethtool interface to user-configurable CAN channel identifier This patch introduces 3 new functions implementing support for ethtool access to the CAN channel ID of all USB CAN network interfaces managed by the driver. With this patch, it is possible to read/write the CAN channel ID from/to the EEPROM via the ethtool interface. The CAN channel ID is a user-configurable device identifier that can be set individually for each CAN interface of a PEAK USB device. Depending on the device, the identifier has a length of 8 or 32 bit. The identifier is stored in the non-volatile memory of the device. The identifier of a CAN interface can be read/written as an 8 or 32 bit byte string in native (little-endian) byte order, where the length depends on the device type. Signed-off-by: Stephane Grosjean Signed-off-by: Lukas Magel Link: https://lore.kernel.org/all/20230116200932.157769-6-lukas.magel@posteo.net Signed-off-by: Marc Kleine-Budde --- drivers/net/can/usb/peak_usb/pcan_usb.c | 9 +++ drivers/net/can/usb/peak_usb/pcan_usb_core.c | 80 ++++++++++++++++++++ drivers/net/can/usb/peak_usb/pcan_usb_core.h | 6 ++ drivers/net/can/usb/peak_usb/pcan_usb_fd.c | 3 + drivers/net/can/usb/peak_usb/pcan_usb_pro.c | 3 + 5 files changed, 101 insertions(+) diff --git a/drivers/net/can/usb/peak_usb/pcan_usb.c b/drivers/net/can/usb/peak_usb/pcan_usb.c index 44e894a1f2c23..bead4f4ba4726 100644 --- a/drivers/net/can/usb/peak_usb/pcan_usb.c +++ b/drivers/net/can/usb/peak_usb/pcan_usb.c @@ -982,9 +982,18 @@ static int pcan_usb_set_phys_id(struct net_device *netdev, return err; } +/* This device only handles 8-bit CAN channel id. */ +static int pcan_usb_get_eeprom_len(struct net_device *netdev) +{ + return sizeof(u8); +} + static const struct ethtool_ops pcan_usb_ethtool_ops = { .set_phys_id = pcan_usb_set_phys_id, .get_ts_info = pcan_get_ts_info, + .get_eeprom_len = pcan_usb_get_eeprom_len, + .get_eeprom = peak_usb_get_eeprom, + .set_eeprom = peak_usb_set_eeprom, }; /* diff --git a/drivers/net/can/usb/peak_usb/pcan_usb_core.c b/drivers/net/can/usb/peak_usb/pcan_usb_core.c index 3a73eac314ff5..3bfd27742ae46 100644 --- a/drivers/net/can/usb/peak_usb/pcan_usb_core.c +++ b/drivers/net/can/usb/peak_usb/pcan_usb_core.c @@ -808,6 +808,86 @@ static const struct net_device_ops peak_usb_netdev_ops = { .ndo_change_mtu = can_change_mtu, }; +/* CAN-USB devices generally handle 32-bit CAN channel IDs. + * In case one doesn't, then it have to overload this function. + */ +int peak_usb_get_eeprom_len(struct net_device *netdev) +{ + return sizeof(u32); +} + +/* Every CAN-USB device exports the dev_get_can_channel_id() operation. It is used + * here to fill the data buffer with the user defined CAN channel ID. + */ +int peak_usb_get_eeprom(struct net_device *netdev, + struct ethtool_eeprom *eeprom, u8 *data) +{ + struct peak_usb_device *dev = netdev_priv(netdev); + u32 ch_id; + __le32 ch_id_le; + int err; + + err = dev->adapter->dev_get_can_channel_id(dev, &ch_id); + if (err) + return err; + + /* ethtool operates on individual bytes. The byte order of the CAN + * channel id in memory depends on the kernel architecture. We + * convert the CAN channel id back to the native byte order of the PEAK + * device itself to ensure that the order is consistent for all + * host architectures. + */ + ch_id_le = cpu_to_le32(ch_id); + memcpy(data, (u8 *)&ch_id_le + eeprom->offset, eeprom->len); + + /* update cached value */ + dev->can_channel_id = ch_id; + return err; +} + +/* Every CAN-USB device exports the dev_get_can_channel_id()/dev_set_can_channel_id() + * operations. They are used here to set the new user defined CAN channel ID. + */ +int peak_usb_set_eeprom(struct net_device *netdev, + struct ethtool_eeprom *eeprom, u8 *data) +{ + struct peak_usb_device *dev = netdev_priv(netdev); + u32 ch_id; + __le32 ch_id_le; + int err; + + /* first, read the current user defined CAN channel ID */ + err = dev->adapter->dev_get_can_channel_id(dev, &ch_id); + if (err) { + netdev_err(netdev, "Failed to init CAN channel id (err %d)\n", err); + return err; + } + + /* do update the value with user given bytes. + * ethtool operates on individual bytes. The byte order of the CAN + * channel ID in memory depends on the kernel architecture. We + * convert the CAN channel ID back to the native byte order of the PEAK + * device itself to ensure that the order is consistent for all + * host architectures. + */ + ch_id_le = cpu_to_le32(ch_id); + memcpy((u8 *)&ch_id_le + eeprom->offset, data, eeprom->len); + ch_id = le32_to_cpu(ch_id_le); + + /* flash the new value now */ + err = dev->adapter->dev_set_can_channel_id(dev, ch_id); + if (err) { + netdev_err(netdev, "Failed to write new CAN channel id (err %d)\n", + err); + return err; + } + + /* update cached value with the new one */ + dev->can_channel_id = ch_id; + + return 0; +} + int pcan_get_ts_info(struct net_device *dev, struct ethtool_ts_info *info) { info->so_timestamping = diff --git a/drivers/net/can/usb/peak_usb/pcan_usb_core.h b/drivers/net/can/usb/peak_usb/pcan_usb_core.h index 1e461aef0f2a7..980e315186cfd 100644 --- a/drivers/net/can/usb/peak_usb/pcan_usb_core.h +++ b/drivers/net/can/usb/peak_usb/pcan_usb_core.h @@ -149,4 +149,10 @@ void peak_usb_async_complete(struct urb *urb); void peak_usb_restart_complete(struct peak_usb_device *dev); int pcan_get_ts_info(struct net_device *dev, struct ethtool_ts_info *info); +/* common 32-bit CAN channel ID ethtool management */ +int peak_usb_get_eeprom_len(struct net_device *netdev); +int peak_usb_get_eeprom(struct net_device *netdev, + struct ethtool_eeprom *eeprom, u8 *data); +int peak_usb_set_eeprom(struct net_device *netdev, + struct ethtool_eeprom *eeprom, u8 *data); #endif diff --git a/drivers/net/can/usb/peak_usb/pcan_usb_fd.c b/drivers/net/can/usb/peak_usb/pcan_usb_fd.c index 1ea4cfdfd6401..fd925ae963313 100644 --- a/drivers/net/can/usb/peak_usb/pcan_usb_fd.c +++ b/drivers/net/can/usb/peak_usb/pcan_usb_fd.c @@ -1124,6 +1124,9 @@ static int pcan_usb_fd_set_phys_id(struct net_device *netdev, static const struct ethtool_ops pcan_usb_fd_ethtool_ops = { .set_phys_id = pcan_usb_fd_set_phys_id, .get_ts_info = pcan_get_ts_info, + .get_eeprom_len = peak_usb_get_eeprom_len, + .get_eeprom = peak_usb_get_eeprom, + .set_eeprom = peak_usb_set_eeprom, }; /* describes the PCAN-USB FD adapter */ diff --git a/drivers/net/can/usb/peak_usb/pcan_usb_pro.c b/drivers/net/can/usb/peak_usb/pcan_usb_pro.c index 061f04c20f960..0c805d9672bf1 100644 --- a/drivers/net/can/usb/peak_usb/pcan_usb_pro.c +++ b/drivers/net/can/usb/peak_usb/pcan_usb_pro.c @@ -1037,6 +1037,9 @@ static int pcan_usb_pro_set_phys_id(struct net_device *netdev, static const struct ethtool_ops pcan_usb_pro_ethtool_ops = { .set_phys_id = pcan_usb_pro_set_phys_id, .get_ts_info = pcan_get_ts_info, + .get_eeprom_len = peak_usb_get_eeprom_len, + .get_eeprom = peak_usb_get_eeprom, + .set_eeprom = peak_usb_set_eeprom, }; /* From 6d02f6daeb44c0099ace2e3597d56420eecfaeb2 Mon Sep 17 00:00:00 2001 From: Lukas Magel Date: Mon, 16 Jan 2023 20:09:30 +0000 Subject: [PATCH 6/8] can: peak_usb: export PCAN CAN channel ID as sysfs device attribute This patch exports the CAN channel ID as a sysfs attribute. The CAN channel ID is a user-configurable u8/u32 identifier that can be set individually for each CAN interface of a PEAK USB device. Exporting the channel ID as a sysfs attribute allows users to easily read the ID and to write udev rules that can match against the ID. This is especially useful for PEAK USB devices that do not export a serial number at SUB level. Signed-off-by: Stephane Grosjean Signed-off-by: Lukas Magel Link: https://lore.kernel.org/all/20230116200932.157769-7-lukas.magel@posteo.net Signed-off-by: Marc Kleine-Budde --- .../ABI/testing/sysfs-class-net-peak_usb | 19 ++++++++++++++ drivers/net/can/usb/peak_usb/pcan_usb_core.c | 25 +++++++++++++++++++ 2 files changed, 44 insertions(+) create mode 100644 Documentation/ABI/testing/sysfs-class-net-peak_usb diff --git a/Documentation/ABI/testing/sysfs-class-net-peak_usb b/Documentation/ABI/testing/sysfs-class-net-peak_usb new file mode 100644 index 0000000000000..9e3d0bf4d4b2f --- /dev/null +++ b/Documentation/ABI/testing/sysfs-class-net-peak_usb @@ -0,0 +1,19 @@ + +What: /sys/class/net//peak_usb/can_channel_id +Date: November 2022 +KernelVersion: 6.2 +Contact: Stephane Grosjean +Description: + PEAK PCAN-USB devices support user-configurable CAN channel + identifiers. Contrary to a USB serial number, these identifiers + are writable and can be set per CAN interface. This means that + if a USB device exports multiple CAN interfaces, each of them + can be assigned a unique channel ID. + This attribute provides read-only access to the currently + configured value of the channel identifier. Depending on the + device type, the identifier has a length of 8 or 32 bit. The + value read from this attribute is always an 8 digit 32 bit + hexadecimal value in big endian format. If the device only + supports an 8 bit identifier, the upper 24 bit of the value are + set to zero. + diff --git a/drivers/net/can/usb/peak_usb/pcan_usb_core.c b/drivers/net/can/usb/peak_usb/pcan_usb_core.c index 3bfd27742ae46..676923bd4213b 100644 --- a/drivers/net/can/usb/peak_usb/pcan_usb_core.c +++ b/drivers/net/can/usb/peak_usb/pcan_usb_core.c @@ -15,6 +15,8 @@ #include #include #include +#include +#include #include #include @@ -53,6 +55,26 @@ static const struct usb_device_id peak_usb_table[] = { MODULE_DEVICE_TABLE(usb, peak_usb_table); +static ssize_t can_channel_id_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct net_device *netdev = to_net_dev(dev); + struct peak_usb_device *peak_dev = netdev_priv(netdev); + + return sysfs_emit(buf, "%08X\n", peak_dev->can_channel_id); +} +static DEVICE_ATTR_RO(can_channel_id); + +/* mutable to avoid cast in attribute_group */ +static struct attribute *peak_usb_sysfs_attrs[] = { + &dev_attr_can_channel_id.attr, + NULL, +}; + +static const struct attribute_group peak_usb_sysfs_group = { + .name = "peak_usb", + .attrs = peak_usb_sysfs_attrs, +}; + /* * dump memory */ @@ -961,6 +983,9 @@ static int peak_usb_create_dev(const struct peak_usb_adapter *peak_usb_adapter, /* add ethtool support */ netdev->ethtool_ops = peak_usb_adapter->ethtool_ops; + /* register peak_usb sysfs files */ + netdev->sysfs_groups[0] = &peak_usb_sysfs_group; + init_usb_anchor(&dev->rx_submitted); init_usb_anchor(&dev->tx_submitted); From 09ce908e50c9ee43732015c36c32b18efe7b9ab6 Mon Sep 17 00:00:00 2001 From: Lukas Magel Date: Mon, 16 Jan 2023 20:09:31 +0000 Subject: [PATCH 7/8] can: peak_usb: align CAN channel ID format in log with sysfs attribute Previously, the CAN channel ID was printed to the kernel log in decimal upon connecting a new PEAK device. This behavior is inconsistent with the hexadecimal format of the CAN channel ID sysfs attribute. This patch updates the log message to output the id in hexadecimal. Signed-off-by: Lukas Magel Link: https://lore.kernel.org/all/20230116200932.157769-8-lukas.magel@posteo.net Signed-off-by: Marc Kleine-Budde --- drivers/net/can/usb/peak_usb/pcan_usb_core.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/can/usb/peak_usb/pcan_usb_core.c b/drivers/net/can/usb/peak_usb/pcan_usb_core.c index 676923bd4213b..2bd62c8f2b253 100644 --- a/drivers/net/can/usb/peak_usb/pcan_usb_core.c +++ b/drivers/net/can/usb/peak_usb/pcan_usb_core.c @@ -1029,8 +1029,8 @@ static int peak_usb_create_dev(const struct peak_usb_adapter *peak_usb_adapter, /* get CAN channel id early */ dev->adapter->dev_get_can_channel_id(dev, &dev->can_channel_id); - netdev_info(netdev, "attached to %s channel %u (device %u)\n", - peak_usb_adapter->name, ctrl_idx, dev->can_channel_id); + netdev_info(netdev, "attached to %s channel %u (device 0x%08X)\n", + peak_usb_adapter->name, ctrl_idx, dev->can_channel_id); return 0; From 73019de17732ec2edde007930407912e491a1c0f Mon Sep 17 00:00:00 2001 From: Lukas Magel Date: Mon, 16 Jan 2023 20:09:32 +0000 Subject: [PATCH 8/8] can: peak_usb: Reorder include directives alphabetically The include directives in all source files are reordered alphabetically according to the names of the header files. Signed-off-by: Lukas Magel Link: https://lore.kernel.org/all/20230116200932.157769-9-lukas.magel@posteo.net [mkl: move header changes from Patch 3 here] Signed-off-by: Marc Kleine-Budde --- drivers/net/can/usb/peak_usb/pcan_usb.c | 5 +++-- drivers/net/can/usb/peak_usb/pcan_usb_core.c | 10 +++++----- drivers/net/can/usb/peak_usb/pcan_usb_fd.c | 4 ++-- drivers/net/can/usb/peak_usb/pcan_usb_pro.c | 4 ++-- 4 files changed, 12 insertions(+), 11 deletions(-) diff --git a/drivers/net/can/usb/peak_usb/pcan_usb.c b/drivers/net/can/usb/peak_usb/pcan_usb.c index bead4f4ba4726..b211b6e283a2c 100644 --- a/drivers/net/can/usb/peak_usb/pcan_usb.c +++ b/drivers/net/can/usb/peak_usb/pcan_usb.c @@ -9,10 +9,11 @@ * Many thanks to Klaus Hitschler */ #include + +#include +#include #include #include -#include -#include #include #include diff --git a/drivers/net/can/usb/peak_usb/pcan_usb_core.c b/drivers/net/can/usb/peak_usb/pcan_usb_core.c index 2bd62c8f2b253..d881e1d301832 100644 --- a/drivers/net/can/usb/peak_usb/pcan_usb_core.c +++ b/drivers/net/can/usb/peak_usb/pcan_usb_core.c @@ -8,15 +8,15 @@ * * Many thanks to Klaus Hitschler */ +#include +#include #include -#include -#include #include #include -#include -#include +#include +#include #include -#include +#include #include #include diff --git a/drivers/net/can/usb/peak_usb/pcan_usb_fd.c b/drivers/net/can/usb/peak_usb/pcan_usb_fd.c index fd925ae963313..4d85b29a17b78 100644 --- a/drivers/net/can/usb/peak_usb/pcan_usb_fd.c +++ b/drivers/net/can/usb/peak_usb/pcan_usb_fd.c @@ -4,10 +4,10 @@ * * Copyright (C) 2013-2014 Stephane Grosjean */ +#include +#include #include #include -#include -#include #include #include diff --git a/drivers/net/can/usb/peak_usb/pcan_usb_pro.c b/drivers/net/can/usb/peak_usb/pcan_usb_pro.c index 0c805d9672bf1..f736196383acf 100644 --- a/drivers/net/can/usb/peak_usb/pcan_usb_pro.c +++ b/drivers/net/can/usb/peak_usb/pcan_usb_pro.c @@ -6,10 +6,10 @@ * Copyright (C) 2003-2011 PEAK System-Technik GmbH * Copyright (C) 2011-2012 Stephane Grosjean */ +#include +#include #include #include -#include -#include #include #include