+static int usb_read_while_ready(OsRoutine *ed,
+ void *buf_, unsigned int maxlen)
+{
+ u8 *buf = buf_;
+ unsigned int r = 0;
+
+ while (ed->usbRdReady() && r < maxlen)
+ buf[r++] = ed->usbReadByte();
+
+ return r;
+}
+
+static int usb_read(OsRoutine *ed, void *buf_, unsigned int maxlen)
+{
+ u8 *buf = buf_;
+ unsigned int r = 0;
+
+ while (r < maxlen)
+ buf[r++] = ed->usbReadByte();
+
+ return r;
+}
+
+static int usb_write(OsRoutine *ed, const void *buf_, unsigned int maxlen)
+{
+ const u8 *buf = buf_;
+ unsigned int r = 0;
+
+ while (r < maxlen)
+ ed->usbWriteByte(buf[r++]);
+
+ return r;
+}
+
+/*
+ * TH = 1 : ?1CBRLDU 3-button pad return value (not read)
+ * TH = 0 : ?0SA00DU 3-button pad return value
+ * TH = 1 : ?1CBRLDU 3-button pad return value
+ * TH = 0 : ?0SA0000 D3-0 are forced to '0'
+ * TH = 1 : ?1CBMXYZ Extra buttons returned in D3-0
+ * TH = 0 : ?0SA1111 D3-0 are forced to '1'
+ */
+static void test_joy_latency(int *min_out, int *max_out)
+{
+ u8 rbuf[8 * 6];
+ int min = 8;
+ int max = 0;
+ int i, v, b, e;
+
+ for (i = 0; i < 64; i++) {
+ read_joy_responses(rbuf);
+
+ for (b = 0; b < 8 * 4; b++) {
+ v = b & 7;
+ e = (b & 0x08) ? 0x0c : 0;
+ if ((rbuf[b] & 0x0c) == e) {
+ if (v < min)
+ min = v;
+ }
+ else if (v > max)
+ max = v;
+ }
+ }
+
+ /* print out the last test */
+ for (b = 0; b < 8 * 5; b++) {
+ printf(" %02x", rbuf[b]);
+ if ((b & 7) == 7)
+ printf("\n");
+ }
+ printf("\n");
+
+ *min_out = min;
+ *max_out = max;
+}
+
+static int do_test(OsRoutine *ed, u8 b3)
+{
+ int min = 0, max = 0;
+
+ switch (b3)
+ {
+ case 'j':
+ test_joy_latency(&min, &max);
+ printf("latency: %d - %d\n\n", min, max);
+ return 0;
+ default:
+ break;
+ }
+
+ return -1;
+}
+
+static int do_custom(OsRoutine *ed, u8 b3)
+{
+ struct {
+ unsigned int addr;
+ unsigned int size;
+ } d;
+
+ switch (b3)
+ {
+ case 'd':
+ usb_read(ed, &d, sizeof(d));
+ ed->usbWriteByte('k');
+ printf("sending %i bytes from %06x..\n", d.size, d.addr);
+ usb_write(ed, (void *)d.addr, d.size);
+ printf("done.\n");
+ return 1;
+ default:
+ break;
+ }
+
+ return -1;
+}
+
+#define MTYPE_OS 0
+#define MTYPE_MD 1
+#define MTYPE_SSF 2
+#define MTYPE_CD 3
+#define MTYPE_SMS 4
+#define MTYPE_10M 5
+#define MTYPE_32X 6
+
+static int do_run(OsRoutine *ed, u8 b3, int tas_sync)
+{
+ u8 mapper = 0;
+
+ switch (b3)
+ {
+ case 's':
+ mapper = MTYPE_SMS | (7 << 4);
+ break;
+ case 'm':
+ mapper = MTYPE_MD;
+ break;
+ case 'o':
+ mapper = MTYPE_OS;
+ break;
+ case 'c':
+ mapper = MTYPE_CD;
+ break;
+ case '3':
+ mapper = MTYPE_32X;
+ break;
+ case 'M':
+ mapper = MTYPE_10M;
+ break;
+ default:
+ return -1;
+ }
+
+ printf("starting mapper %x..\n", mapper);
+
+ while (read16(GFX_CTRL_PORT) & 2)
+ ;
+ ed->VDP_setReg(VDP_MODE1, 0x04);
+ ed->VDP_setReg(VDP_MODE2, 0x44);
+
+ ed->usbWriteByte('k');
+
+ run_game(mapper, tas_sync);
+ /* should not get here.. */
+
+ return -1;
+}
+