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 requires a USB High Speed Hub, bail out if device is connected to slower USB Hub. The HScanT FW always sends USB In URB with length 512 bytes and seems to have broken Zero Packet Length handling. Add quirk GS_CAN_FEATURE_QUIRK_HSCANT_URB_SIZE to allocate URBs of 513 bytes to work around these issues. 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 Link: https://patch.msgid.link/20260928-gs_usb-hscant-v2-1-a7c1c02460e9@pengutronix.de Cc: stable@vger.kernel.org Signed-off-by: Marc Kleine-Budde --- drivers/net/can/usb/gs_usb.c | 125 +++++++++++++++++++++++++++++++++-- 1 file changed, 121 insertions(+), 4 deletions(-) diff --git a/drivers/net/can/usb/gs_usb.c b/drivers/net/can/usb/gs_usb.c index f604358c8259..f7a349902c42 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,21 @@ 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 sends bulk In URBs with length of 512 bytes. + * - When using In URBs with 512 bytes it will send a second in URB with length 0 + * It seems the ZLP handling is broken. + * - Use In URBs of length GS_USB_QUIRK_HSCANT_IN_URB_SIZE as a workaround. + */ +#define GS_CAN_FEATURE_QUIRK_HSCANT_URB_SIZE BIT(30) +#define GS_USB_QUIRK_HSCANT_IN_URB_SIZE (513) + /* CANtact Pro original firmware: * BREQ DATA_BITTIMING overlaps with GET_USER_ID */ @@ -812,6 +828,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 +1097,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 +1352,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_SIZE; + } +} + static struct gs_can *gs_make_candev(unsigned int channel, struct usb_interface *intf, struct gs_device_config *dconf) @@ -1385,8 +1466,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 +1596,34 @@ static void gs_destroy_candev(struct gs_can *dev) free_candev(dev->netdev); } +static int gs_usb_probe_quirks(const struct usb_interface *intf, struct gs_device_config *dconf) +{ + const struct usb_device *udev = interface_to_usbdev(intf); + + if (!udev->manufacturer || !udev->product) + return 0; + + /* HScanT firmware version 0x00010007: + * - FW has an icount of 4, which corresponds to 5 CAN interfaces. + * The hardware has only 4 interfaces, fixup. + * - FW provides broken Endpoint Descriptors on USB Full Speed Hubs: + * config 1 interface 0 altsetting 0 endpoint 0x4 has invalid maxpacket 512, setting to 64 + * Probably related to GS_CAN_FEATURE_QUIRK_HSCANT_URB_SIZE, + * FW only works on USB High Speed Hubs, detect and bail out. + */ + if (gs_usb_is_hscant(udev, dconf, 0x00010007)) { + if (dconf->icount == 4) + dconf->icount = 3; + + if (udev->speed < USB_SPEED_HIGH) { + dev_err(&intf->dev, "Device only works with USB High Speed Hubs\n"); + return -ENODEV; + } + } + + return 0; +} + static int gs_usb_probe(struct usb_interface *intf, const struct usb_device_id *id) { @@ -1560,6 +1670,10 @@ static int gs_usb_probe(struct usb_interface *intf, return rc; } + rc = gs_usb_probe_quirks(intf, &dconf); + if (rc) + return rc; + icount = dconf.icount + 1; dev_info(&intf->dev, "Configuring for %u interfaces\n", icount); @@ -1604,10 +1718,13 @@ 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_SIZE) { + hf_size_rx = GS_USB_QUIRK_HSCANT_IN_URB_SIZE; + BUILD_BUG_ON(struct_size(hf, canfd, 1) > GS_USB_QUIRK_HSCANT_IN_URB_SIZE); + } 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 -- 2.53.0