Linux CAN drivers development
 help / color / mirror / Atom feed
* [PATCH can] can: gs_usb: add workarounds for HScanT USB to CAN adapter
@ 2026-09-28 16:21 Marc Kleine-Budde
  2026-09-28 16:29 ` sashiko-bot
  0 siblings, 1 reply; 2+ messages in thread
From: Marc Kleine-Budde @ 2026-09-28 16:21 UTC (permalink / raw)
  To: Vincent Mailhol; +Cc: kernel, linux-can, linux-kernel, Marc Kleine-Budde

The HScanT [1] is a RISC-V based USB to 4 channels CAN-FD adapter, which is
compatible with the gs_usb protocol.

The device is shipped with firmware version 0x00010007 and needs several
quirks to work properly.

The HScanT FW announces 5 channels, but the hardware has only 4. Workaround
the problem by changing the struct gs_device_config::icount to 3, which
corresponds to 4 channels.

The HScanT FW always sends USB In URB with length 512 bytes. Add quirk
GS_CAN_FEATURE_QUIRK_HSCANT_URB_LENGTH to allocate URBs of that length.

This driver supports up to 256 channels per USB Interface. The HScanT
device has 4 channels, but the FW requires each channels to be bound to a
USB interface using the GS_USB_BREQ_HSCANT_SET_INTERFACENUMBER_ENDPOINT USB
request. Add quirk to GS_CAN_FEATURE_QUIRK_HSCANT_BIND_CHANNEL to bind the
CAN channel to the USB Interface 0 during gs_can_open()

Link: https://github.com/cherry-embedded/HSCanT-hardware
Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
---
 drivers/net/can/usb/gs_usb.c | 110 +++++++++++++++++++++++++++++++++++++++++--
 1 file changed, 106 insertions(+), 4 deletions(-)

diff --git a/drivers/net/can/usb/gs_usb.c b/drivers/net/can/usb/gs_usb.c
index 3b9b2f104d86..ec8256b46646 100644
--- a/drivers/net/can/usb/gs_usb.c
+++ b/drivers/net/can/usb/gs_usb.c
@@ -72,6 +72,7 @@ enum gs_usb_breq {
 	GS_USB_BREQ_SET_TERMINATION,
 	GS_USB_BREQ_GET_TERMINATION,
 	GS_USB_BREQ_GET_STATE,
+	GS_USB_BREQ_HSCANT_SET_INTERFACENUMBER_ENDPOINT = 17,
 };
 
 enum gs_can_mode {
@@ -188,6 +189,18 @@ struct gs_device_termination_state {
 
 /* internal quirks - keep in GS_CAN_FEATURE space for now */
 
+/* HScanT firmware version 0x00010007:
+ * - FW requires the binding of CAN channels to USB Interfaces
+ * - Route all CAN channels to USB Interface 0
+ */
+#define GS_CAN_FEATURE_QUIRK_HSCANT_BIND_CHANNEL BIT(29)
+
+/* HScanT firmware version 0x00010007:
+ * - FW requires bulk In URBs with >= 512 bytes.
+ * - Use struct quirk_hscant sized (512 bytes) In URBs as a workaround.
+ */
+#define GS_CAN_FEATURE_QUIRK_HSCANT_URB_LENGTH BIT(30)
+
 /* CANtact Pro original firmware:
  * BREQ DATA_BITTIMING overlaps with GET_USER_ID
  */
@@ -261,6 +274,10 @@ struct canfd_quirk {
 	u8 quirk;
 } __packed;
 
+struct quirk_hscant {
+	u8 quirk[512];
+} __packed;
+
 /* struct gs_host_frame::echo_id == GS_HOST_FRAME_ECHO_ID_RX indicates
  * a regular RX'ed CAN frame
  */
@@ -284,6 +301,7 @@ struct gs_host_frame {
 		DECLARE_FLEX_ARRAY(struct canfd, canfd);
 		DECLARE_FLEX_ARRAY(struct canfd_ts, canfd_ts);
 		DECLARE_FLEX_ARRAY(struct canfd_quirk, canfd_quirk);
+		DECLARE_FLEX_ARRAY(struct quirk_hscant, quirk_hscant);
 	};
 } __packed;
 /* The GS USB devices make use of the same flags and masks as in
@@ -812,6 +830,18 @@ static int gs_usb_set_data_bittiming(struct gs_can *dev)
 				    GFP_KERNEL);
 }
 
+static int gs_usb_hscant_bind_channel_to_interface(const struct gs_can *dev)
+{
+	const u16 interface_number = 0;
+
+	/* Bind dev->channel to interface_number */
+	return usb_control_msg_send(dev->udev, 0, GS_USB_BREQ_HSCANT_SET_INTERFACENUMBER_ENDPOINT,
+				    USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_INTERFACE,
+				    dev->channel, interface_number,
+				    NULL, 0, 1000,
+				    GFP_KERNEL);
+}
+
 static void gs_usb_xmit_callback(struct urb *urb)
 {
 	struct gs_tx_context *txc = urb->context;
@@ -1069,6 +1099,16 @@ static int gs_can_open(struct net_device *netdev)
 		}
 	}
 
+	if (dev->feature & GS_CAN_FEATURE_QUIRK_HSCANT_BIND_CHANNEL) {
+		rc = gs_usb_hscant_bind_channel_to_interface(dev);
+		if (rc) {
+			netdev_err(netdev,
+				   "failed to bind Channel to Interface: %pe\n",
+				   ERR_PTR(rc));
+			goto out_usb_kill_anchored_urbs;
+		}
+	}
+
 	/* finally start device */
 	dev->can.state = CAN_STATE_ERROR_ACTIVE;
 	dm.flags = cpu_to_le32(flags);
@@ -1314,6 +1354,49 @@ static const u16 gs_usb_termination_const[] = {
 	GS_USB_TERMINATION_ENABLED
 };
 
+static bool gs_usb_is_hscant(const struct usb_device *udev,
+			     const struct gs_device_config *dconf,
+			     const u32 sw_version)
+{
+	if (udev->descriptor.idVendor != cpu_to_le16(USB_GS_USB_1_VENDOR_ID) ||
+	    udev->descriptor.idProduct != cpu_to_le16(USB_GS_USB_1_PRODUCT_ID))
+		return false;
+
+	if (strcmp(udev->manufacturer, "HScanT") ||
+	    strcmp(udev->product, "HScanT USB to CAN adapter"))
+		return false;
+
+	if (dconf->sw_version != cpu_to_le32(sw_version))
+		return false;
+
+	return true;
+}
+
+static void
+gs_usb_make_candev_get_feature(struct gs_can *dev, const struct gs_device_config *dconf,
+			       const struct gs_device_bt_const *bt_const)
+{
+	const struct usb_device *udev = dev->udev;
+	const u32 feature = le32_to_cpu(bt_const->feature);
+
+	dev->feature = FIELD_GET(GS_CAN_FEATURE_MASK, feature);
+
+	if (!udev->manufacturer || !udev->product)
+		return;
+
+	/* HScanT firmware version 0x00010007:
+	 * - FW doesn't advertise GS_CAN_FEATURE_BT_CONST_EXT,
+	 *   but implements GS_USB_BREQ_BT_CONST_EXT, fixup.
+	 * - FW requires binding of CAN channel to USB Interface, add quirk.
+	 * - FW requires bulk In URBs with >= 512 bytes, add quirk.
+	 */
+	if (gs_usb_is_hscant(udev, dconf, 0x00010007)) {
+		dev->feature |= GS_CAN_FEATURE_BT_CONST_EXT |
+			GS_CAN_FEATURE_QUIRK_HSCANT_BIND_CHANNEL |
+			GS_CAN_FEATURE_QUIRK_HSCANT_URB_LENGTH;
+	}
+}
+
 static struct gs_can *gs_make_candev(unsigned int channel,
 				     struct usb_interface *intf,
 				     struct gs_device_config *dconf)
@@ -1385,8 +1468,9 @@ static struct gs_can *gs_make_candev(unsigned int channel,
 
 	dev->can.ctrlmode_supported = CAN_CTRLMODE_CC_LEN8_DLC;
 
-	feature = le32_to_cpu(bt_const.feature);
-	dev->feature = FIELD_GET(GS_CAN_FEATURE_MASK, feature);
+	gs_usb_make_candev_get_feature(dev, dconf, &bt_const);
+	feature = dev->feature;
+
 	if (feature & GS_CAN_FEATURE_LISTEN_ONLY)
 		dev->can.ctrlmode_supported |= CAN_CTRLMODE_LISTENONLY;
 
@@ -1514,6 +1598,20 @@ static void gs_destroy_candev(struct gs_can *dev)
 	free_candev(dev->netdev);
 }
 
+static void gs_usb_probe_quirks(const struct usb_device *udev, struct gs_device_config *dconf)
+{
+	if (!udev->manufacturer || !udev->product)
+		return;
+
+	/* HScanT firmware version 0x00010007:
+	 * - FW has an icount of 4, which corresponds to 5 CAN interfaces.
+	 *   The hardware has only 4 interfaces, fixup.
+	 */
+	if (gs_usb_is_hscant(udev, dconf, 0x00010007) &&
+	    dconf->icount == 4)
+		dconf->icount = 3;
+}
+
 static int gs_usb_probe(struct usb_interface *intf,
 			const struct usb_device_id *id)
 {
@@ -1560,6 +1658,8 @@ static int gs_usb_probe(struct usb_interface *intf,
 		return rc;
 	}
 
+	gs_usb_probe_quirks(udev, &dconf);
+
 	icount = dconf.icount + 1;
 	dev_info(&intf->dev, "Configuring for %u interfaces\n", icount);
 
@@ -1604,10 +1704,12 @@ static int gs_usb_probe(struct usb_interface *intf,
 		}
 		parent->canch[i]->parent = parent;
 
-		/* set RX packet size based on FD and if hardware
+		/* set RX packet size based on quirks, FD and if hardware
 		 * timestamps are supported.
 		 */
-		if (parent->canch[i]->can.ctrlmode_supported & CAN_CTRLMODE_FD) {
+		if (parent->canch[i]->feature & GS_CAN_FEATURE_QUIRK_HSCANT_URB_LENGTH) {
+			hf_size_rx = struct_size(hf, quirk_hscant, 1);
+		} else if (parent->canch[i]->can.ctrlmode_supported & CAN_CTRLMODE_FD) {
 			if (parent->canch[i]->feature & GS_CAN_FEATURE_HW_TIMESTAMP)
 				hf_size_rx = struct_size(hf, canfd_ts, 1);
 			else

---
base-commit: a7bfaba4823e3c165bb2004c74eff7c096672bc7
change-id: 20260924-gs_usb-hscant-bfe6987b97b2

Best regards,
--  
Marc Kleine-Budde <mkl@pengutronix.de>


^ permalink raw reply related	[flat|nested] 2+ messages in thread

* Re: [PATCH can] can: gs_usb: add workarounds for HScanT USB to CAN adapter
  2026-09-28 16:21 [PATCH can] can: gs_usb: add workarounds for HScanT USB to CAN adapter Marc Kleine-Budde
@ 2026-09-28 16:29 ` sashiko-bot
  0 siblings, 0 replies; 2+ messages in thread
From: sashiko-bot @ 2026-09-28 16:29 UTC (permalink / raw)
  To: Marc Kleine-Budde
  Cc: Marc Kleine-Budde, Oliver Hartkopp, Vincent Mailhol, linux-can,
	Oleksij Rempel

Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [High] can: gs_usb: incorrect RX URB size calculation causes USB transfer hang
--

commit d72414dd12485ded5e69be85c30c0da0f32c460c
Author: Marc Kleine-Budde <mkl@pengutronix.de>
can: gs_usb: add workarounds for HScanT USB to CAN adapter

This commit adds workarounds for the HScanT RISC-V based USB to CAN adapter.
It corrects the channel count, binds channels to USB interface 0, and
implements a quirk to allocate 512-byte IN URBs for transfers.

Link: https://github.com/cherry-embedded/HSCanT-hardware

> diff --git a/drivers/net/can/usb/gs_usb.c b/drivers/net/can/usb/gs_usb.c
> index 3b9b2f104d868..ec8256b46646b 100644
> --- a/drivers/net/can/usb/gs_usb.c
> +++ b/drivers/net/can/usb/gs_usb.c

[ ... ]

> @@ -261,6 +274,10 @@ struct canfd_quirk {
>  	u8 quirk;
>  } __packed;
>  
> +struct quirk_hscant {
> +	u8 quirk[512];
> +} __packed;
> +

[Severity: High]
Because quirk is defined as a fixed 512-byte array rather than a flexible
array member (like u8 quirk[]), sizeof(struct quirk_hscant) evaluates to
512 bytes. Will this cause issues when used with struct_size() below?

>  /* struct gs_host_frame::echo_id == GS_HOST_FRAME_ECHO_ID_RX indicates
>   * a regular RX'ed CAN frame
>   */
> @@ -284,6 +301,7 @@ struct gs_host_frame {
>  		DECLARE_FLEX_ARRAY(struct canfd, canfd);
>  		DECLARE_FLEX_ARRAY(struct canfd_ts, canfd_ts);
>  		DECLARE_FLEX_ARRAY(struct canfd_quirk, canfd_quirk);
> +		DECLARE_FLEX_ARRAY(struct quirk_hscant, quirk_hscant);
>  	};
>  } __packed;

[ ... ]

> @@ -1604,10 +1704,12 @@ static int gs_usb_probe(struct usb_interface *intf,
>  		}
>  		parent->canch[i]->parent = parent;
>  
> -		/* set RX packet size based on FD and if hardware
> +		/* set RX packet size based on quirks, FD and if hardware
>  		 * timestamps are supported.
>  		 */
> -		if (parent->canch[i]->can.ctrlmode_supported & CAN_CTRLMODE_FD) {
> +		if (parent->canch[i]->feature & GS_CAN_FEATURE_QUIRK_HSCANT_URB_LENGTH) {
> +			hf_size_rx = struct_size(hf, quirk_hscant, 1);

[Severity: High]
Does this calculate the correct size for the RX URB? 

Because struct gs_host_frame has a 12-byte header, struct_size() computes
sizeof(*hf) + sizeof(struct quirk_hscant), which evaluates to 12 + 512 = 524
bytes instead of the intended 512 bytes.

If the host requests 524 bytes for a bulk IN transfer, but the device sends
exactly 512 bytes without a Zero-Length Packet, won't the host wait
indefinitely for the remaining 12 bytes and completely hang the RX path?

> +		} else if (parent->canch[i]->can.ctrlmode_supported & CAN_CTRLMODE_FD) {
>  			if (parent->canch[i]->feature & GS_CAN_FEATURE_HW_TIMESTAMP)
>  				hf_size_rx = struct_size(hf, canfd_ts, 1);
>  			else

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260928-gs_usb-hscant-v1-1-42638ca0f85f@pengutronix.de?part=1

^ permalink raw reply	[flat|nested] 2+ messages in thread

end of thread, other threads:[~2026-09-28 16:29 UTC | newest]

Thread overview: 2+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-09-28 16:21 [PATCH can] can: gs_usb: add workarounds for HScanT USB to CAN adapter Marc Kleine-Budde
2026-09-28 16:29 ` sashiko-bot

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox