+ ieee1284_write_control(port,
+ C1284_NSTROBE | C1284_NAUTOFD | C1284_NSELECTIN);
+ ieee1284_data_dir(port, 0);
+}
+
+SR_PRIV gboolean hung_chang_dso_2100_check_id(struct parport *port)
+{
+ gboolean ret = FALSE;
+
+ if (ieee1284_data_dir(port, 1) != E1284_OK)
+ goto fail;
+
+ ieee1284_write_control(port, C1284_NSTROBE | C1284_NAUTOFD | C1284_NSELECTIN);
+ ieee1284_write_control(port, C1284_NAUTOFD | C1284_NSELECTIN);
+
+ if (ieee1284_read_data(port) != 0x55)
+ goto fail;
+
+ ret = TRUE;
+fail:
+ hung_chang_dso_2100_reset_port(port);
+
+ return ret;
+}
+
+SR_PRIV void hung_chang_dso_2100_write_mbox(struct parport *port, uint8_t val)
+{
+ sr_dbg("mbox <= %X", val);
+ ieee1284_write_control(port,
+ C1284_NSTROBE | C1284_NINIT | C1284_NSELECTIN);
+ ieee1284_data_dir(port, 0);
+ ieee1284_write_data(port, val);
+ ieee1284_write_control(port, C1284_NINIT | C1284_NSELECTIN);
+ ieee1284_write_control(port,
+ C1284_NSTROBE | C1284_NINIT | C1284_NSELECTIN);
+ ieee1284_data_dir(port, 1);
+ ieee1284_write_control(port,
+ C1284_NSTROBE | C1284_NAUTOFD | C1284_NINIT | C1284_NSELECTIN);
+}
+
+SR_PRIV uint8_t hung_chang_dso_2100_read_mbox(struct parport *port, float timeout)
+{
+ GTimer *timer = NULL;
+ uint8_t val;
+
+ ieee1284_write_control(port, C1284_NSTROBE | C1284_NSELECTIN);
+ ieee1284_write_control(port, C1284_NSELECTIN);
+
+ for (;;) {
+ if (ieee1284_read_data(port)) {
+ /* Always read the value a second time.
+ * The first one may be unstable. */
+ val = ieee1284_read_data(port);
+ break;
+ }
+ if (!timer) {
+ timer = g_timer_new();
+ } else if (g_timer_elapsed(timer, NULL) > timeout) {
+ val = 0;
+ break;
+ }
+ }
+
+ ieee1284_write_control(port, C1284_NSTROBE | C1284_NSELECTIN);
+ ieee1284_write_control(port,
+ C1284_NSTROBE | C1284_NAUTOFD | C1284_NINIT | C1284_NSELECTIN);
+
+ if (timer)
+ g_timer_destroy(timer);
+ sr_dbg("mbox == %X", val);
+ return val;
+}
+
+SR_PRIV int hung_chang_dso_2100_move_to(const struct sr_dev_inst *sdi, uint8_t target)
+{
+ struct dev_context *devc = sdi->priv;
+ int timeout = 40;
+ uint8_t c;
+
+ while (timeout--) {
+ c = hung_chang_dso_2100_read_mbox(sdi->conn, 0.1);
+ if (c == target)
+ return SR_OK;
+
+ switch (c) {
+ case 0x00:
+ /* Can happen if someone wrote something into
+ * the mbox that was not expected by the uC.
+ * Alternating between 0xff and 4 helps in
+ * all states. */
+ c = (timeout & 1) ? 0xFF : 0x04;
+ break;
+ case 0x01:
+ switch (target) {
+ case 0x21: c = 2; break;
+ case 0x03: c = 3; break;
+ default: c = 4;
+ }
+ break;
+ case 0x03: c = 4; break;
+ case 0x05: c = devc->rate + 1; break;
+ case 0x06: c = devc->cctl[0]; break;
+ case 0x07: c = devc->cctl[1]; break;
+ case 0x08: c = 1 /* step 2 */ + 1 ; break;
+ case 0x09: c = readout_steps[devc->step].step1 + 1; break;
+ case 0x0A: c = readout_steps[devc->step].shift + 1; break;
+ case 0x0B: c = devc->edge + 1; break;
+ case 0x0C: c = devc->pos[0]; break;
+ case 0x0D: c = devc->pos[1]; break;
+ case 0x0E: c = devc->tlevel; break;
+ case 0x0F:
+ if (!devc->channel)
+ c = 1;
+ else if (readout_steps[devc->step].interleave)
+ c = devc->adc2 ? 2 : 1;
+ else
+ c = devc->channel;
+ break;
+ case 0x10: c = devc->offset[0]; break;
+ case 0x11: c = devc->gain[0]; break;
+ case 0x12: c = devc->offset[1]; break;
+ case 0x13: c = devc->gain[1]; break;
+ case 0x14:
+ case 0x21: c = 0xFF; break;
+ default:
+ return SR_ERR_DATA;
+ }
+ hung_chang_dso_2100_write_mbox(sdi->conn, c);
+ }
+ return SR_ERR_TIMEOUT;
+}
+
+static void skip_samples(struct parport *port, uint8_t ctrl, size_t num)
+{
+ while (num--) {
+ ieee1284_write_control(port, ctrl & ~C1284_NSTROBE);
+ ieee1284_write_control(port, ctrl);
+ }
+}
+
+static void read_samples(struct parport *port, uint8_t ctrl, uint8_t *buf, size_t num, size_t stride)
+{
+ while (num--) {
+ ieee1284_write_control(port, ctrl & ~C1284_NSTROBE);
+ *buf = ieee1284_read_data(port);
+ buf += stride;
+ ieee1284_write_control(port, ctrl);
+ }
+}
+
+static void push_samples(const struct sr_dev_inst *sdi, uint8_t *buf, size_t num)
+{
+ struct dev_context *devc = sdi->priv;
+ float *data = devc->samples;
+ struct sr_datafeed_analog_old analog = {
+ .channels = devc->enabled_channel,
+ .num_samples = num,
+ .mq = SR_MQ_VOLTAGE,
+ .unit = SR_UNIT_VOLT,
+ .mqflags = 0,
+ .data = data,
+ };
+ struct sr_datafeed_packet packet = {
+ .type = SR_DF_ANALOG_OLD,
+ .payload = &analog,
+ };
+ float factor = devc->factor;
+
+ while (num--)
+ data[num] = (buf[num] - 0x80) * factor;
+
+ sr_session_send(devc->cb_data, &packet);
+}
+
+static int read_subframe(const struct sr_dev_inst *sdi, uint8_t *buf)
+{
+ struct dev_context *devc = sdi->priv;
+ uint8_t sig[3], ctrl;
+ unsigned int num;
+ gboolean interleave;
+
+ interleave = readout_steps[devc->step].interleave;
+ ctrl = C1284_NSTROBE;
+ if ((interleave && devc->adc2) || (!interleave && devc->channel == 2))
+ ctrl |= C1284_NAUTOFD;
+
+ ieee1284_write_control(sdi->conn, ctrl);
+ num = readout_steps[devc->step].num;
+ if (num < 1000)
+ skip_samples(sdi->conn, ctrl, 1000 - num);
+ read_samples(sdi->conn, ctrl, buf + (devc->adc2 ? 1 : 0), num,
+ interleave ? 2 : 1);
+ read_samples(sdi->conn, ctrl, sig, 3, 1);
+ if (sig[0] != 0x01 || sig[1] != 0xfe || sig[2] != 0x80) {
+ if (--devc->retries) {
+ sr_dbg("Missing signature at end of buffer, %i tries remaining",
+ devc->retries);
+ return TRUE;
+ } else {
+ sr_err("Failed to read frame without transfer errors");
+ devc->step = 0;
+ }
+ } else {
+ if (interleave && !devc->adc2) {
+ devc->adc2 = TRUE;
+ devc->retries = MAX_RETRIES;
+ return TRUE;
+ } else {
+ if (interleave)
+ num *= 2;
+ if (!devc->step) {
+ struct sr_datafeed_packet packet = {
+ .type = SR_DF_TRIGGER
+ };
+
+ push_samples(sdi, buf, 6);
+ sr_session_send(devc->cb_data, &packet);
+ buf += 6;
+ num -= 6;
+ }
+ push_samples(sdi, buf, num);
+ if (++devc->step > devc->last_step)
+ devc->step = 0;
+ }
+ }
+
+ devc->adc2 = FALSE;
+ devc->retries = MAX_RETRIES;
+
+ return devc->step > 0;
+}
+
+SR_PRIV int hung_chang_dso_2100_poll(int fd, int revents, void *cb_data)
+{
+ struct sr_datafeed_packet packet = { .type = SR_DF_FRAME_BEGIN };