+#define SERIAL_TIMEOUT_MS 1000
+
+#define ICSTATION_USBRELAY_CMD_ID 0x50
+#define ICSTATION_USBRELAY_CMD_START 0x51
+
+static int icstation_usbrelay_send_byte(struct sr_serial_dev_inst *serial,
+ uint8_t b)
+{
+ int ret;
+
+ ret = serial_write_blocking(serial, &b, sizeof(b), SERIAL_TIMEOUT_MS);
+ if (ret < SR_OK)
+ return SR_ERR_IO;
+ if ((size_t)ret != sizeof(b))
+ return SR_ERR_IO;
+
+ return SR_OK;
+}
+
+static int icstation_usbrelay_recv_byte(struct sr_serial_dev_inst *serial,
+ uint8_t *b)
+{
+ int ret;
+
+ ret = serial_read_blocking(serial, b, sizeof(*b), SERIAL_TIMEOUT_MS);
+ if (ret < SR_OK)
+ return SR_ERR_IO;
+ if ((size_t)ret != sizeof(*b))
+ return SR_ERR_IO;
+
+ return SR_OK;
+}
+
+SR_PRIV int icstation_usbrelay_identify(struct sr_serial_dev_inst *serial,
+ uint8_t *id)
+{
+ int ret;
+
+ if (!id)
+ return SR_ERR_ARG;
+
+ /*
+ * Send the identification request. Receive the device firmware's
+ * identification response.
+ *
+ * BEWARE!
+ * A vendor firmware implementation detail prevents the host from
+ * identifying the device again once command mode was entered.
+ * The UART protocol provides no means to leave command mode.
+ * The subsequent identification request is mistaken instead as
+ * another relay control request! Identifying the device will fail.
+ * The device must be power cycled before it identifies again.
+ */
+ ret = icstation_usbrelay_send_byte(serial, ICSTATION_USBRELAY_CMD_ID);
+ if (ret != SR_OK) {
+ sr_dbg("Could not send identification request.");
+ return SR_ERR_IO;
+ }
+ ret = icstation_usbrelay_recv_byte(serial, id);
+ if (ret != SR_OK) {
+ sr_dbg("Could not receive identification response.");
+ return SR_ERR_IO;
+ }
+ sr_dbg("Identification response 0x%02hhx.", *id);
+
+ return SR_OK;
+}
+
+SR_PRIV int icstation_usbrelay_start(const struct sr_dev_inst *sdi)
+{
+ struct sr_serial_dev_inst *serial;
+
+ if (!sdi)
+ return SR_ERR_ARG;
+ serial = sdi->conn;
+ if (!serial)
+ return SR_ERR_ARG;
+
+ return icstation_usbrelay_send_byte(serial,
+ ICSTATION_USBRELAY_CMD_START);
+}
+
+SR_PRIV int icstation_usbrelay_switch_cg(const struct sr_dev_inst *sdi,
+ const struct sr_channel_group *cg, gboolean on)