Skip to content

Instantly share code, notes, and snippets.

@marckleinebudde
Last active February 22, 2024 08:11
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save marckleinebudde/99f72d9db67accf08cc6efa367cfe54b to your computer and use it in GitHub Desktop.
Save marckleinebudde/99f72d9db67accf08cc6efa367cfe54b to your computer and use it in GitHub Desktop.
gs_usb protocol definition
enum gs_usb_breq {
    GS_USB_BREQ_HOST_FORMAT = 0,
    GS_USB_BREQ_BITTIMING,
    GS_USB_BREQ_MODE,
    GS_USB_BREQ_BERR,
    GS_USB_BREQ_BT_CONST,
    GS_USB_BREQ_DEVICE_CONFIG,
    GS_USB_BREQ_TIMESTAMP,
    GS_USB_BREQ_IDENTIFY,
    GS_USB_BREQ_GET_USER_ID,
    GS_USB_BREQ_QUIRK_CANTACT_PRO_DATA_BITTIMING = GS_USB_BREQ_GET_USER_ID,
    GS_USB_BREQ_SET_USER_ID,
    GS_USB_BREQ_DATA_BITTIMING,
    GS_USB_BREQ_BT_CONST_EXT,
    GS_USB_BREQ_SET_TERMINATION,
    GS_USB_BREQ_GET_TERMINATION,
    GS_USB_BREQ_GET_STATE,
};

enum gs_can_mode {
    /* reset a channel. turns it off */
    GS_CAN_MODE_RESET = 0,
    /* starts a channel */
    GS_CAN_MODE_START
};

enum gs_can_state {
    GS_CAN_STATE_ERROR_ACTIVE = 0,
    GS_CAN_STATE_ERROR_WARNING,
    GS_CAN_STATE_ERROR_PASSIVE,
    GS_CAN_STATE_BUS_OFF,
    GS_CAN_STATE_STOPPED,
    GS_CAN_STATE_SLEEPING
};

enum gs_can_identify_mode {
    GS_CAN_IDENTIFY_OFF = 0,
    GS_CAN_IDENTIFY_ON
};

enum gs_can_termination_state {
    GS_CAN_TERMINATION_STATE_OFF = 0,
    GS_CAN_TERMINATION_STATE_ON
};


/* data types passed between host and device */

/* The firmware on the original USB2CAN by Geschwister Schneider
 * Technologie Entwicklungs- und Vertriebs UG exchanges all data
 * between the host and the device in host byte order. This is done
 * with the struct gs_host_config::byte_order member, which is sent
 * first to indicate the desired byte order.
 *
 * The widely used open source firmware candleLight doesn't support
 * this feature and exchanges the data in little endian byte order.
 */
struct gs_host_config {
    __le32 byte_order;
} __packed;

/**
 * struct gs_device_config - Configuration describing the gs_usb compatible device
 * @icount: number of CAN interfaces - 1
 * @sw_version: software version - usually 2
 * @hw_version: hardware version - usually 1
 *
 */
struct gs_device_config {
    u8 reserved1;
    u8 reserved2;
    u8 reserved3;
    u8 icount;
    __le32 sw_version;
    __le32 hw_version;
} __packed;

#define GS_CAN_MODE_NORMAL 0
#define GS_CAN_MODE_LISTEN_ONLY BIT(0)
#define GS_CAN_MODE_LOOP_BACK BIT(1)
#define GS_CAN_MODE_TRIPLE_SAMPLE BIT(2)
#define GS_CAN_MODE_ONE_SHOT BIT(3)
#define GS_CAN_MODE_HW_TIMESTAMP BIT(4)
/* GS_CAN_FEATURE_IDENTIFY BIT(5) */
/* GS_CAN_FEATURE_USER_ID BIT(6) */
#define GS_CAN_MODE_PAD_PKTS_TO_MAX_PKT_SIZE BIT(7)
#define GS_CAN_MODE_FD BIT(8)
/* GS_CAN_FEATURE_REQ_USB_QUIRK_LPC546XX BIT(9) */
/* GS_CAN_FEATURE_BT_CONST_EXT BIT(10) */
/* GS_CAN_FEATURE_TERMINATION BIT(11) */
#define GS_CAN_MODE_BERR_REPORTING BIT(12)
/* GS_CAN_FEATURE_GET_STATE BIT(13) */

struct gs_device_mode {
    __le32 mode;
    __le32 flags;
} __packed;

struct gs_device_state {
    __le32 state;
    __le32 rxerr;
    __le32 txerr;
} __packed;

struct gs_device_bittiming {
    __le32 prop_seg;
    __le32 phase_seg1;
    __le32 phase_seg2;
    __le32 sjw;
    __le32 brp;
} __packed;

struct gs_identify_mode {
    __le32 mode;
} __packed;

struct gs_device_termination_state {
    __le32 state;
} __packed;

#define GS_CAN_FEATURE_LISTEN_ONLY BIT(0)
#define GS_CAN_FEATURE_LOOP_BACK BIT(1)
#define GS_CAN_FEATURE_TRIPLE_SAMPLE BIT(2)
#define GS_CAN_FEATURE_ONE_SHOT BIT(3)
#define GS_CAN_FEATURE_HW_TIMESTAMP BIT(4)
#define GS_CAN_FEATURE_IDENTIFY BIT(5)
#define GS_CAN_FEATURE_USER_ID BIT(6)
#define GS_CAN_FEATURE_PAD_PKTS_TO_MAX_PKT_SIZE BIT(7)
#define GS_CAN_FEATURE_FD BIT(8)
#define GS_CAN_FEATURE_REQ_USB_QUIRK_LPC546XX BIT(9)
#define GS_CAN_FEATURE_BT_CONST_EXT BIT(10)
#define GS_CAN_FEATURE_TERMINATION BIT(11)
#define GS_CAN_FEATURE_BERR_REPORTING BIT(12)
#define GS_CAN_FEATURE_GET_STATE BIT(13)
#define GS_CAN_FEATURE_MASK GENMASK(13, 0)

struct gs_device_bt_const {
    __le32 feature;
    __le32 fclk_can;
    __le32 tseg1_min;
    __le32 tseg1_max;
    __le32 tseg2_min;
    __le32 tseg2_max;
    __le32 sjw_max;
    __le32 brp_min;
    __le32 brp_max;
    __le32 brp_inc;
} __packed;

struct gs_device_bt_const_extended {
    __le32 feature;
    __le32 fclk_can;
    __le32 tseg1_min;
    __le32 tseg1_max;
    __le32 tseg2_min;
    __le32 tseg2_max;
    __le32 sjw_max;
    __le32 brp_min;
    __le32 brp_max;
    __le32 brp_inc;

    __le32 dtseg1_min;
    __le32 dtseg1_max;
    __le32 dtseg2_min;
    __le32 dtseg2_max;
    __le32 dsjw_max;
    __le32 dbrp_min;
    __le32 dbrp_max;
    __le32 dbrp_inc;
} __packed;

#define GS_CAN_FLAG_OVERFLOW BIT(0)
#define GS_CAN_FLAG_FD BIT(1)
#define GS_CAN_FLAG_BRS BIT(2)
#define GS_CAN_FLAG_ESI BIT(3)

struct classic_can {
    u8 data[8];
} __packed;

struct classic_can_ts {
    u8 data[8];
    __le32 timestamp_us;
} __packed;

struct classic_can_quirk {
    u8 data[8];
    u8 quirk;
} __packed;

struct canfd {
    u8 data[64];
} __packed;

struct canfd_ts {
    u8 data[64];
    __le32 timestamp_us;
} __packed;

struct canfd_quirk {
    u8 data[64];
    u8 quirk;
} __packed;

/**
 * struct gs_host_frame - bulk data exchanged between host <-> device
 * @echo_id: cookie to identify frame, -1 means rx'ed frame, tx-complete otherwise
 * @can_id: the CAN-ID to send
 * @can_dlc: dlc value
 * @channel: the CAN channel to send to/received from
 */
struct gs_host_frame {
    u32 echo_id;
    __le32 can_id;

    u8 can_dlc;
    u8 channel;
    u8 flags;
    u8 reserved;

    union {
        DECLARE_FLEX_ARRAY(struct classic_can, classic_can);
        DECLARE_FLEX_ARRAY(struct classic_can_ts, classic_can_ts);
        DECLARE_FLEX_ARRAY(struct classic_can_quirk, classic_can_quirk);
        DECLARE_FLEX_ARRAY(struct canfd, canfd);
        DECLARE_FLEX_ARRAY(struct canfd_ts, canfd_ts);
        DECLARE_FLEX_ARRAY(struct canfd_quirk, canfd_quirk);
    };
} __packed;

USB messages

value is the CAN channel number, unless otherwise specified.

probe

Send a USB control message request = GS_USB_BREQ_HOST_FORMAT with struct struct gs_host_config with .byte_order = cpu_to_le32(0x0000beef), value is always 0.

Receive USB control message request = GS_USB_BREQ_DEVICE_CONFIG with struct gs_device_config, value is always 0.

Receive USB control message request = GS_USB_BREQ_BT_CONST with struct gs_device_bt_const, value is always 0.

Evaluate struct gs_device_bt_const::feature flags supported by device.

If struct gs_device_bt_const::feature contains GS_CAN_FEATURE_FD, receive USB control message request = GS_USB_BREQ_BT_CONST_EXT, value is always 0.

open

Setup struct gs_device_bittiming and send it with USB control message request = GS_USB_BREQ_BITTIMING to configure bit timing.

Setup struct gs_device_mode with mode = cpu_to_le32(GS_CAN_MODE_START), set features flags struct gs_device_mode::flags supported by driver. Send USB control message request = GS_USB_BREQ_MODE to open device.

close

Setup struct gs_device_mode with mode = cpu_to_le32(GS_CAN_MODE_RESET). Send USB control message request = GS_USB_BREQ_MODE to put device into reset mode.

TX

Setup struct gs_host_frame and send USB bulk transfer.

bulk receive

Receive struct gs_host_frame USB bulk transfer, evaluate struct gs_host_frame::echo_id.

TX complete

TX-completed CAN frames are echoed back to the host with struct gs_host_frame::echo_id equals the struct gs_host_frame::echo_id of the TX frame.

RX

A struct gs_host_frame::echo_id equals -1 identifies a RXed frame.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment