Add Toad, the USB micro dev companion.

This utility prefers to use the newer libftdi1 (not the 0.x version being
distributed currently), due to its (meagre) asynchronous transfer support.
This will still compile using libftdi 0.x, but console mode and the initialize
commands will be disabled.

The output of the Toad commands is designed to be very shell-script-friendly;
querying commands (status, getmode, etc) can be wrapped in "eval" to set a few
shell variables.

There is a hacky workaround to initialize the CBUS bit-bang mode when the
command is run on a Toad that has just been plugged in. The FTDI chip does not
seem to expose any better way to work around the issue, unfortunately.

When compiled with libftdi1, Toad includes a completely self-contained console
mode with some bonus keyboard escapes, so no ftdi_sio module or serial console
software is necessary.  Of course, on machines with ftdi_sio, this utility is
unnecessary for simple AP and EC console access. For machines with both,
libftdi1 will automatically disable the ftdi_sio module when you run the
utility.

Even libftdi1 does not fully support the FT230X in use, so the initialize
command has its own EEPROM modification and checksumming code.

BUG=chromium-os:36972
TEST=Play with the hardware:

1) Compile with the old libftdi 0.x; plug in one programmed Toad
Get the serial number: ./toad list
This should do the same thing: ./toad --serialname=$THE_SERIAL list
This should do the same thing, with more messages: ./toad --serialname= list
This should again do the same thing, with more messages: ./toad -s all list
Play with LEDs: ./toad ecap toggle
Spit out a file as boot code (don't do this plugged in): ./toad boot toad.c
Get the current mode: ./toad getmode
Turn the LEDs off: ./toad vbus off
Turn them back on: ./toad setmode boot
Go back to normal: ./toad boot off
Make sure the status is sane: ./toad status
This won't find any devices: ./toad initialize
This will find one, but won't work under the old libftdi: ./toad -f initialize
This still won't work under the old libftdi: ./toad initialize -f

2) Compile with the new libftdi 1.x; plug in one programmed Toad
Try everything in #1, up until the initialize commands.
This won't find any devices: ./toad initialize
This should work, though: ./toad -f initialize
But this shouldn't: ./toad -s $THE_SERIAL initialize
But this should: ./toad -s $THE_SERIAL initialize -f
Enter console mode: ./toad console
Switch between AP and EC in console mode: ^X^A, ^X^E
Forgot the escapes!: ^Xh
Cancel out: ^X^C. If you check the return code ($?) it should be non-zero.
Enter console mode again, this time start on the AP: ./toad ap
End console mode: ^X^D. The return code should be zero (success).
Enter console mode once more, on the EC: ./toad ec
Background console mode: ^X^Z. The terminal should be OK (not in raw mode).
Return using "fg". We should be in raw mode again.
If you can get something that echos (like a DUT or a loopback), see if you get
echos. Note that a straight loopback will not convert carriage returns (the
enter key) into linefeeds, so you won't get any newlines.
Unplug Toad. Console mode should error out.

3) Keep the new libftdi 1.x version; plug in a bunch of unprogrammed Toads
Program ALL the Toads!: ./toad -s all initialize
Make sure they're all programmed: ./toad -s all list
Unplug and plug them back in and make sure they're sane: ./toad -s all list

Change-Id: Ibf190dda8d45cb27e40dd19ef2fa21a87a1cd8b7
Reviewed-on: https://gerrit.chromium.org/gerrit/39106
Reviewed-by: Todd Broch <tbroch@chromium.org>
Commit-Ready: David Schneider <dnschneid@chromium.org>
Tested-by: David Schneider <dnschneid@chromium.org>
diff --git a/src/Makefile b/src/Makefile
index 75ac2ca..bef6701 100644
--- a/src/Makefile
+++ b/src/Makefile
@@ -3,7 +3,7 @@
 # found in the LICENSE file.
 include $(HDCTOOLS_DIR)/defs/definitions.mk
 
-SUBDIRS		= miniservod servod
+SUBDIRS		= miniservod servod toad
 SUBDIRS_INSTALL	= $(foreach var,$(SUBDIRS),$(var)-install)
 
 all:		$(SUBDIRS)
diff --git a/src/toad/50-toad.rules b/src/toad/50-toad.rules
new file mode 100644
index 0000000..ecef30d
--- /dev/null
+++ b/src/toad/50-toad.rules
@@ -0,0 +1,2 @@
+# Allow all plugdev members to access Toad (and other generic FT230X devices).
+SUBSYSTEM=="usb", ACTION=="add", ATTRS{idVendor}=="0403", ATTRS{idProduct}=="6015", GROUP="plugdev"
diff --git a/src/toad/Makefile b/src/toad/Makefile
new file mode 100644
index 0000000..c72b81d
--- /dev/null
+++ b/src/toad/Makefile
@@ -0,0 +1,37 @@
+# Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+include $(HDCTOOLS_DIR)/defs/definitions.mk
+
+BINDIR		= /usr/bin
+BIN_DEST	= $(DESTDIR)$(BINDIR)
+
+ETCDIR		= /etc
+ETC_DEST	= $(DESTDIR)$(ETCDIR)
+UDEV_DEST	= $(ETC_DEST)/udev/rules.d
+
+CFLAGS  	+= -Wno-cast-qual $(LIBFTDI_CFLAGS)
+LDLIBS		+= $(LIBFTDI_LDLIBS)
+
+FTDI_COMMON	= $(HDCTOOLS_BUILD_DIR)/lib/ftdicommon.o
+
+TARGETS		= toad
+UDEV_RULE	= $(HDCTOOLS_DIR)/$${REL_DIR}/50-toad.rules
+
+all: $(TARGETS)
+
+%.o : %.c Makefile
+	$(COMPILE.c)
+
+toad: toad.o $(FTDI_COMMON)
+	$(LINK.c)
+
+install:
+	$(MESSAGE) "Installing '$(TARGETS)' to $(BIN_DEST)"
+	$(MKDIR) -p $(BIN_DEST)
+	$(CP) $(TARGETS) "$(BIN_DEST)"
+	$(MESSAGE) "Installing '$(notdir $(UDEV_RULE))' to $(UDEV_DEST)"
+	$(MKDIR) -p $(UDEV_DEST)
+	$(CP) $(UDEV_RULE) $(UDEV_DEST)
+
+-include *.d
diff --git a/src/toad/toad.c b/src/toad/toad.c
new file mode 100644
index 0000000..ae09728
--- /dev/null
+++ b/src/toad/toad.c
@@ -0,0 +1,1166 @@
+// Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+/*    Toad Utility -- The USB micro dev companion.
+ *
+ * If you just want an EC or AP serial console, you do not need this tool.
+ * The ftdi_sio module will expose the serial device which you can use normally.
+ * Press the button on the device to switch between EC and AP consoles.
+ *
+ * This utility lets you control the additional capabilites of Toad.
+ * You can:
+ *   > Switch the console endpoint (EC or AP) via software and/or monitor it
+ *   > Enable the EC boot mode and upload code (unless the RO screw is present)
+ *   > Toggle the VBUS to the DUT to simulate connect/disconnect
+ *   > Initialize Toad when it's fresh out of the factory
+ *
+ * Building is easy, just run "make", and optionally "sudo make install".
+ * i386, x86_64, and 32-bit ARM architectures should all work with this tool.
+ */
+
+static const char *USAGE =
+"command [options]\n"
+"\n"
+"Options:\n"
+"    -s SN              - Specifies the Toad you want to communicate with, by\n"
+"    --serialname=SN      serial. If unspecified, the tool will use the first\n"
+"                         Toad found. If SN is left empty (long form only) or\n"
+"                         set to \"all\", all connected Toads will be used in\n"
+"                         batch operations.\n"
+"    -f                 - Forces a command. Specify multiple times to apply\n"
+"                         more force. Currently only used with initialize.\n"
+"\n"
+"Commands:\n"
+"    list               - Prints out the serial.\n"
+"    initialize         - Initializes the Toad EEPROM.\n"
+"                         Use -f to re-program programmed Toad devices.\n"
+"                         Use -f twice to re-program devices that are not\n"
+"                         recognized as a Toad. (Use with -s; dangerous.)\n"
+"    status             - Prints the full state: VBUS, EC/AP, boot states.\n"
+"    setvbus STATE      - Sets or toggles VBUS, where STATE can be one of\n"
+"                         on, off, or toggle.\n"
+"    setecap STATE      - Sets the EC/AP target mode, where STATE can be one\n"
+"                         of ec, ap, or toggle.\n"
+"    setboot STATE      - Sets the boot override mode, where STATE can be one\n"
+"                         of on, off, or toggle.\n"
+"    getmode            - Gets the current effective mode: off, ec, ap, boot.\n"
+"    setmode MODE       - Sets the effective mode, where MODE can be one of\n"
+"                         off, ec, ap, or boot.\n"
+"    boot [FILE]        - Boots the EC using the specified binary.\n"
+"                         Uses stdin if FILE is left unspecified.\n";
+static const char *CONSOLE =
+"    console            - Opens a console to the DUT without switching modes.\n"
+"    ec                 - Switches to EC mode and opens a console.\n"
+"    ap                 - Switches to AP mode and opens a console.\n";
+static const char *ESCAPES =
+"Console escapes: prefix with ^X (Ctrl-X)\n"
+"    h, H, ^H  (Ctrl-H) - Print out supported escapes (this message).\n"
+"    ^X  (Ctrl-X)       - Send a literal ^X\n"
+"    ^C  (Ctrl-C)       - Close the console. Returns a failure exit code.\n"
+"    ^D  (Ctrl-D)       - Close the console.\n"
+"    ^Z  (Ctrl-Z)       - Suspend the console into the background.\n"
+"    e, E, ^E  (Ctrl-E) - Switch to monitoring the EC output.\n"
+"    a, A, ^A  (Ctrl-A) - Switch to monitoring the AP output.\n"
+"    p, P, ^P  (Ctrl-P) - Switch to monitoring the AP output.\n";
+
+
+#include <errno.h>
+#include <getopt.h>
+#include <poll.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <termios.h>
+#include <unistd.h>
+
+#include "toad.h"
+
+
+/* Options for passing into getopt_long */
+static const char *SHORT_OPTS = "s:f";
+static const struct option LONG_OPTS[] = {
+    { "serialname", required_argument, NULL, 's' },
+    { NULL, 0, NULL, 0 }  // end-of-list sentinel
+};
+
+/* Commands and their dispatch functions */
+static const struct cmd COMMAND_LIST[] = {
+    { "list", cmdList },
+    { "init", cmdInitialize },
+    { "initialize", cmdInitialize },
+    { "st", cmdStatus },
+    { "status", cmdStatus },
+    { "vbus", cmdSetVbus },
+    { "setvbus", cmdSetVbus },
+    { "ecap", cmdSetEcAp },
+    { "setecap", cmdSetEcAp },
+    { "setboot", cmdSetBoot },
+    { "getmode", cmdGetMode },
+    { "setmode", cmdSetMode },
+    { "mode", cmdMode },
+    { "boot", cmdBoot },
+#if ENABLE_CONSOLE
+    { "console", cmdConsole },
+    { "ec", cmdEc },
+    { "ap", cmdAp },
+#endif
+    { NULL, NULL }  // end-of-list sentinel
+};
+
+
+/* Config data at start of FT230X EEPROM for programming */
+static const unsigned char TOAD_EEPROM_00[] = {
+    /* 00 */ 0x00, 0x00,  // First two bytes must be zero
+    /* 02 */ TOAD_VID & 0xFF, TOAD_VID >> 8,
+    /* 04 */ TOAD_PID & 0xFF, TOAD_PID >> 8,
+    /* 06 */ 0x00, 0x10,  // bcdDevice
+    /* 08 */ 0x80,  // bus powered
+    /* 09 */ 0xFA,  // 500 mA (2mA increments)
+    /* 0A */ 0x08,  // Max packet size
+    /* 0B */ 0x00, 0x00, 0x00,  // bDeviceClass/bDeviceSubClass/bDeviceProtocol
+    /* 0E */ TOAD_EEPROM_MANUFACTURER_START, sizeof(TOAD_MANUFACTURER) * 2,
+    /* 10 */ TOAD_EEPROM_DESC_START, sizeof(TOAD_DESC) * 2,
+    /* 12 */ TOAD_EEPROM_SERIAL_START, 0,  // we don't know the size yet
+    /* 14 */ 0x00, 0x00, 0x00,  // AC are normal skew, no schmitt, 4mA drive
+    /* 17 */ 0x00, 0x00, 0x00,  // AD are normal skew, no schmitt, 4mA drive
+    /* 20 */ CBUSH_IOMODE, CBUSH_IOMODE, CBUSH_IOMODE, CBUSH_IOMODE,  // Cbus0-3
+    /* 24 */ CBUSH_TRISTATE, CBUSH_TRISTATE, CBUSH_TRISTATE,  // Cbus4-6
+    /* 27 */ 0, 0, 0, 0,  // Do not invert TXD, RXD, RTS, CTS
+    /* 2B */ 0, 0, 0, 0,  // Do not invert DTR, DSR, DCD, RI
+    /* 2F */ 0, 0, 0,  // No battery charge detect, disable BCD pin, keep awake
+    /* 32 */ 0, 0, 0,  // No I2C address, no device ID, no schmitt trigger
+    /* 35 */ 0, 0, 0,  // Not an FT1248 (clock polarity, data endianness, flow)
+    /* 38 */ 0, 0, 0,  // No RS485 echo suppression, no power save, D2XX driver
+};
+
+
+/* Entry-point.
+ * Processes global options, determines the command, and hands off to the
+ * command dispatcher (runCmd).
+ *
+ * returns: zero on success, non-zero on error.
+ */
+int main(int argc, char **argv) {
+    const char *device = NULL, *command = NULL, *option = NULL;
+    const struct cmd *curCmd = NULL;
+    int force = 0;
+    int c;
+
+    if (argc == 1) {
+        // Print usage and quit if there are no arguments.
+        if (ENABLE_CONSOLE) {
+            fprintf(stderr, "Usage: %s %s%s\n%s",
+                    argv[0], USAGE, CONSOLE, ESCAPES);
+        } else {
+            fprintf(stderr, "Usage: %s %s", argv[0], USAGE);
+        }
+        return 1;
+    }
+
+    while ((c = getopt_long(argc, argv, SHORT_OPTS, LONG_OPTS, NULL)) != -1) {
+        if (c == 's') {
+            if (device) {
+                ERR(1, "Only one serial may be specified at a time.");
+            }
+            // "all" is equivalent to an empty string.
+            device = strcmp("all", optarg) ? optarg : "";
+        } else if (c == 'f') {
+            force++;
+        } else {
+            return 1;
+        }
+    }
+
+    // Grab command
+    if (optind < argc) {
+        command = argv[optind++];
+    } else {
+        ERR(1, "Please specify a command.");
+    }
+
+    // Grab option
+    if (optind < argc) {
+        option = argv[optind++];
+    }
+
+    if (optind < argc) {
+        ERR(1, "Too many parameters.");
+    }
+
+    // Hand off to the proper function.
+    for (curCmd = COMMAND_LIST; curCmd->name; ++curCmd) {
+        if (!strcmp(command, curCmd->name)) {
+            return runCmd(curCmd->func, device, option, force);
+        }
+    }
+    ERR(1, "Unrecognized command.");
+}
+
+
+/* Switches the TTY into raw mode and back (if it's a TTY)
+ * In raw mode, characters are passed through as they are typed (instead of
+ * line-based editing), and are not automatically echoed back out on the TTY.
+ *
+ * enable: non-zero to enable, zero to disable.
+ * returns: zero on success, non-zero on error, or if stdin is not a TTY.
+ */
+int ttyRawMode(int enable) {
+    static int rawmode = 0;
+    static struct termios orig;
+    if (!isatty(STDIN_FILENO)) {
+        return -1;
+    }
+
+    if (enable == rawmode) {
+        return 0;
+    }
+
+    if (enable) {
+        struct termios raw;
+        if (tcgetattr(STDIN_FILENO, &orig) < 0) {
+            return -1;
+        }
+        raw = orig;
+        cfmakeraw(&raw);
+        raw.c_cc[VMIN] = 0;
+        raw.c_cc[VTIME] = 0;
+        if (tcsetattr(STDIN_FILENO, TCSAFLUSH, &raw) < 0) {
+            return -1;
+        }
+    } else {
+        if (tcsetattr(STDIN_FILENO, TCSAFLUSH, &orig) < 0) {
+            return -1;
+        }
+        // Ensure that the cursor is at a new line.
+        fputc('\n', stderr);
+    }
+    rawmode = enable;
+    return 0;
+}
+
+
+/* Configures UART settings, using the constants specified above.
+ *
+ * returns: zero on success; non-zero on error. */
+int ftdiConfigure(struct ftdi_context *ftdi) {
+    unsigned char latency;
+
+    FTORDIE(ftdi_set_baudrate(ftdi, TOAD_BAUD));
+    FTORDIE(ftdi_set_line_property(ftdi, TOAD_LINE_PROPERTY));
+    FTORDIE(ftdi_setflowctrl(ftdi, TOAD_FLOW_CONTROL));
+
+    /* HACK: After the FTDI chip comes out of reset, ftdi_read_pins doesn't
+     * return sensible results until ftdi_set_bitmode has been called to set the
+     * mode to bit-bang. Since we don't want to wipe the boot/vbus state every
+     * time we run the tool, we store some state on the FT230X to see if we've
+     * initialized it or not.  Unfortunately, the only volatile state accessible
+     * is the latency timer, which is initially 16ms. Thus we check the latency
+     * timer and call ftdi_set_bitmode if it is not our custom value. The custom
+     * value can be anything (we don't care too much about the buffer timeout
+     * latency), as long as it's not 16.
+     */
+    FTORDIE(ftdi_get_latency_timer(ftdi, &latency));
+    if (latency != TOAD_LATENCY_TIMER) {
+        FTORDIE(ftdi_set_bitmode(ftdi, 0x00, BITMODE_CBUS));
+        FTORDIE(ftdi_set_latency_timer(ftdi, TOAD_LATENCY_TIMER));
+    }
+    return 0;
+}
+
+
+/* Opens FT230X devices and runs the specified command.
+ *
+ * If no device is specified, opens the first device with the correct
+ * description; this is either the generic FT230X description (in the case of
+ * the initialize command), or Toad's unique description.
+ *
+ * If device is specified but blank, operates on all devices that match the
+ * appropriate description.
+ *
+ * If device is specified and non-empty, opens the first device with the
+ * matching serial.
+ *
+ * cmd: the function to call on each device opened.
+ * device: the device specified as a command line flag, or NULL if --device was
+ *         not provided.
+ * option: an additional parameter if provided by the user.
+ * returns: zero on success, non-zero on error.
+ */
+int runCmd(cmd_func cmd, const char *device, const char *option, int force) {
+    int ret = 0;
+    struct ftdi_context *ftdi = ftdi_new();
+    const char *desc = TOAD_DESC;
+    struct ftdi_device_list *list, *cur;
+    unsigned int i, count, num_valid = 0, num_failed_to_open = 0;
+    int all = 0, check_desc = 1;
+
+    // If we're initializing (and there's no force), look for generic parts.
+    // If we are 2x forcing, don't even bother checking desc.
+    if (cmd == cmdInitialize) {
+        if (!force) {
+            desc = FTDI_DESC;
+        } else if (force >= 2) {
+            check_desc = 0;
+        }
+    }
+
+    // If device is provided but blank, process all devices.
+    if (device && !*device) {
+        all = 1;
+    }
+
+    // Get the list of devices
+    FTORDIE(count = ftdi_usb_find_all(ftdi, &list, TOAD_VID, TOAD_PID));
+
+    // Go through each one and operate on them individually.
+    for (i = 0, cur = list; i < count && cur; ++i, cur = cur->next) {
+        char cur_desc[64], cur_serial[64];
+        int result;
+        // If we've specified a device, make sure it matches that.
+        // If the device doesn't match and we're operating on all, explain why.
+        if (ftdi_usb_get_strings(ftdi, cur->dev, NULL, 0,
+                                 cur_desc, sizeof(cur_desc),
+                                 cur_serial, sizeof(cur_serial)) < 0) {
+            if (all) {
+                prn_error("%u: unable to query device.", i);
+            }
+        } else if (check_desc && strcmp(cur_desc, desc)) {
+            if (all) {
+                if (!strcmp(cur_desc, FTDI_DESC)) {
+                    prn_error("%u (%s): unprogrammed, or generic part.",
+                              i, cur_serial);
+                } else if (!strcmp(cur_desc, TOAD_DESC)) {
+                    prn_error("%u (%s): already programmed.", i, cur_serial);
+                } else {
+                    prn_error("%u: incorrect description (\"%s\").",
+                              i, cur_desc);
+                }
+            }
+        } else if (!all && device && strcmp(cur_serial, device)) {
+            // Didn't match the specified device serial.
+        } else if ((result = ftdi_usb_open_dev(ftdi, cur->dev)) < 0) {
+            num_failed_to_open++;
+            if (all) {
+                prn_error("%u (%s): %s",
+                          i, cur_serial, ftdi_get_error_string(ftdi));
+            }
+        } else {
+            // Matched! Do the proccessing.
+            num_valid++;
+            if (all) {
+                prn_info("%u (%s): processing...", i, cur_serial);
+            }
+            result = ftdiConfigure(ftdi);
+            if (!result) result = (*cmd)(ftdi, option, force);
+            ftdi_usb_close(ftdi);
+            if (all && !result) {
+                prn_info("%u (%s): success.", i, cur_serial);
+            } else if (!ret) {
+                ret = result;
+            }
+            if (!all) {
+                break;
+            }
+        }
+    }
+    // Clean up, and notify the user if there were no devices
+    ftdi_list_free(&list);
+    ftdi_free(ftdi);
+    if (!num_valid) {
+        if (!ret) ret = 2;
+        if (num_failed_to_open) {
+            prn_error("Failed to open %u devices.", num_failed_to_open);
+        } else {
+            prn_error("No valid devices found.");
+        }
+    } else if (all) {
+        prn_info("Processed %u devices.", num_valid);
+    }
+
+    return ret;
+}
+
+
+/* Sets the CBUS pins to the specified values, keeping others the same.
+ *
+ * For boot_mode and vbus_en, the special value SET_CBUS_KEEP can be specified
+ * to keep the value at the same state that it presently is.
+ * WARNING: passing SET_CBUS_KEEP to mode_sw is unsafe (since the user may be
+ *          pressing the button), so this is not allowed.
+ *
+ * boot_mode: set to 1 to enable EC boot mode. This has higher precedence than
+ *            EC/AP mode, but lower precedence than disabling VBUS.
+ * vbus_en: set to 1 to enable VBUS to the DUT. If VBUS is disabled, all modes
+ *          are overridden with "off".
+ * mode_sw: set to 1 to assert the mode switch button, toggling the EC/AP mode.
+ *          This is the same line that the user uses (via a physical button), so
+ *          be sure to de-assert it once the mode switches.
+ * returns: zero on success, non-zero on error.
+ */
+int setCbus(struct ftdi_context *ftdi, int boot_mode,
+            int vbus_en, int mode_sw) {
+    unsigned char mode, mask;
+    FTORDIE(ftdi_read_pins(ftdi, &mode));
+    if (vbus_en == SET_CBUS_KEEP) {
+        vbus_en = ((mode & BIT_VBUS_EN_MASK) != 0);
+    }
+    if (boot_mode == SET_CBUS_KEEP) {
+        boot_mode = !(mode & BIT_BOOT_MODE_L_MASK);
+    }
+    if (mode_sw == SET_CBUS_KEEP) {
+        ERR(254, "mode_sw should never be set to SET_CBUS_KEEP in setCbus");
+    }
+    mask = (vbus_en ? BIT_VBUS_EN_ASSERT : BIT_VBUS_EN_DEASSERT)
+         | (boot_mode ? BIT_BOOT_MODE_L_ASSERT : BIT_BOOT_MODE_L_DEASSERT)
+         | (mode_sw ? BIT_MODE_SW_L_ASSERT : BIT_MODE_SW_L_DEASSERT)
+         | BIT_AP_MODE_EC_MODE_L_INPUT;
+    FTORDIE(ftdi_set_bitmode(ftdi, mask, BITMODE_CBUS));
+    return 0;
+}
+
+
+/* Sets the ec/ap mode by pressing the button and checking the result.
+ * Does not affect boot or vbus states.
+ *
+ * ec: set to 1 to change to EC mode, 0 to change to AP mode, or
+ *     SET_EC_AP_TOGGLE to toggle the current mode.
+ * returns: zero on success, non-zero on error.
+ */
+int setEcAp(struct ftdi_context *ftdi, int ec) {
+    int ret;
+    unsigned char mode;
+    FTORDIE(ftdi_read_pins(ftdi, &mode));
+    // Check if the button is held down. If so, make sure we're not the ones
+    // holding it down, then alert the user and wait for it to be released.
+    if (!(mode & BIT_MODE_SW_L_MASK)) {
+        ret = setCbus(ftdi, SET_CBUS_KEEP, SET_CBUS_KEEP, 0);
+        if (ret) return ret;
+        FTORDIE(ftdi_read_pins(ftdi, &mode));
+        if (!(mode & BIT_MODE_SW_L_MASK)) {
+            prn_warn("The mode button is pressed. Please release it.");
+            while (!(mode & BIT_MODE_SW_L_MASK)) {
+                FTORDIE(ftdi_read_pins(ftdi, &mode));
+            }
+            prn_info("The mode button has been released. Thank you.");
+        }
+    }
+    // If we requested a toggle, update ec to our target value.
+    if (ec == SET_EC_AP_TOGGLE) {
+        ec = ((mode & BIT_AP_MODE_EC_MODE_L_MASK) != 0);
+    }
+    // See if the mode even needs to be toggled.
+    if (!(mode & BIT_AP_MODE_EC_MODE_L_MASK) != ec) {
+        // Press the button and wait for the mode to switch.
+        ret = setCbus(ftdi, SET_CBUS_KEEP, SET_CBUS_KEEP, 1);
+        if (ret) return ret;
+        // Wait for mode to change.
+        while (!(mode & BIT_AP_MODE_EC_MODE_L_MASK) != ec) {
+            FTORDIE(ftdi_read_pins(ftdi, &mode));
+        }
+        // Release the button.  All done!
+        return setCbus(ftdi, SET_CBUS_KEEP, SET_CBUS_KEEP, 0);
+    } else {
+        // We're already in the right state.
+        return 0;
+    }
+}
+
+
+/* Rewrites the EEPROM of the FT230X with the settings for Toad.
+ *
+ * option: no options allowed.
+ * force: the user-specified force; non-zero forces operation by ignoring some
+ *        sanity checks. >=1 allows rewriting an already-programmed Toad, and
+ *        >=2 allows rewriting something totally unrecognized.
+ * returns: zero on success, non-zero on error.
+ */
+int cmdInitialize(struct ftdi_context *ftdi UNUSED_ON_OLD_LIBFTDI,
+                  const char *option UNUSED_ON_OLD_LIBFTDI,
+                  int force UNUSED_ON_OLD_LIBFTDI) {
+#if NEW_LIBFTDI
+    struct libusb_device_descriptor desc;
+    int detected;
+    unsigned char serial[16];
+    int serial_size;
+    unsigned char data[TOAD_EEPROM_SIZE];
+    size_t i;
+    uint16_t checksum;
+
+    NO_OPTIONS(option);
+
+    // Determine device type; assume the device doesn't match
+    detected = 2;
+    FTORDIE(libusb_get_device_descriptor(
+                libusb_get_device(ftdi->usb_dev), &desc));
+    if (desc.idVendor == TOAD_VID && desc.idProduct == TOAD_PID) {
+        unsigned char product[64];
+        FTORDIE(libusb_get_string_descriptor_ascii(
+                    ftdi->usb_dev, desc.iProduct, product, sizeof(product)));
+        if (!strcmp((char*)product, FTDI_DESC)) {
+            detected = 0;
+        } else if (!strcmp((char*)product, TOAD_DESC)) {
+            detected = 1;
+        }
+    }
+
+    // Stop if we have insufficient force.
+    if (detected > force) {
+        if (detected == 1) {
+            ERR(2, "Avoiding re-programming part; specify -f to force.");
+        } else {
+            ERR(2, "Avoiding programming random device; specify -ff to force.");
+        }
+    }
+
+    // Get serial and print it out
+    FTORDIE(serial_size = libusb_get_string_descriptor_ascii(
+                ftdi->usb_dev, desc.iSerialNumber, serial, sizeof(serial)));
+    // Make sure that our serial_size counts the null byte, like sizeof
+    if (serial[serial_size - 1])
+        serial_size++;
+    // Update the manufacturer ID
+    serial[0] = TOAD_MANUFACTURER_ID[0];
+    serial[1] = TOAD_MANUFACTURER_ID[1];
+    prn_info("Initializing device %s", serial);
+
+    // Initialize the EEPROM part of libftdi. We don't actually use the stuff it
+    // initializes, but without this initialization, ftdi_eeprom_write will not
+    // function.
+    FTORDIE(ftdi_eeprom_initdefaults(ftdi, "", "", ""));
+
+    // Grab the EEPROM data
+    FTORDIE(ftdi_read_eeprom(ftdi));
+    FTORDIE(ftdi_get_eeprom_buf(ftdi, data, sizeof(data)));
+
+    // Overwrite the header information
+    memcpy(data, TOAD_EEPROM_00, sizeof(TOAD_EEPROM_00));
+
+    // Fix up the serial size
+    data[TOAD_EEPROM_00_SERIAL_SIZE_OFFSET] = serial_size * 2;
+
+    // Rewrite the manufacturer descriptor
+    data[TOAD_EEPROM_MANUFACTURER_START + 0] = sizeof(TOAD_MANUFACTURER) * 2;
+    data[TOAD_EEPROM_MANUFACTURER_START + 1] = TOAD_EEPROM_STRING_DESCRIPTOR;
+    for (i = 1; i < sizeof(TOAD_MANUFACTURER); ++i) {
+        data[TOAD_EEPROM_MANUFACTURER_START + i*2 + 0] = TOAD_MANUFACTURER[i-1];
+        data[TOAD_EEPROM_MANUFACTURER_START + i*2 + 1] = 0;
+    }
+
+    // Rewrite the description descriptor
+    data[TOAD_EEPROM_DESC_START + 0] = sizeof(TOAD_DESC) * 2;
+    data[TOAD_EEPROM_DESC_START + 1] = TOAD_EEPROM_STRING_DESCRIPTOR;
+    for (i = 1; i < sizeof(TOAD_DESC); ++i) {
+        data[TOAD_EEPROM_DESC_START + i*2 + 0] = TOAD_DESC[i-1];
+        data[TOAD_EEPROM_DESC_START + i*2 + 1] = 0;
+    }
+
+    // Rewrite the serial descriptor
+    data[TOAD_EEPROM_SERIAL_START + 0] = serial_size * 2;
+    data[TOAD_EEPROM_SERIAL_START + 1] = TOAD_EEPROM_STRING_DESCRIPTOR;
+    for (i = 1; i < (size_t)serial_size; ++i) {
+        data[TOAD_EEPROM_SERIAL_START + i*2 + 0] = serial[i-1];
+        data[TOAD_EEPROM_SERIAL_START + i*2 + 1] = 0;
+    }
+
+    // Zero out everything afterwards
+    i = TOAD_EEPROM_SERIAL_START + serial_size * 2;
+    memset(&data[i], 0, sizeof(data) - i);
+
+    // Calculate and fill in the checksum (algorithm from libftdi's ftdi.c)
+    checksum = TOAD_EEPROM_CHECKSUM_SEED;
+    for (i = 0; i < TOAD_EEPROM_CHECKSUM_OFFSET; i+=2) {
+        checksum = (data[i] | (data[i+1] << 8)) ^ checksum;
+        checksum = (checksum << 1) | (checksum >> 15);
+    }
+    data[TOAD_EEPROM_CHECKSUM_OFFSET + 0] = checksum & 0xFF;
+    data[TOAD_EEPROM_CHECKSUM_OFFSET + 1] = checksum >> 8;
+
+    // Write back to the device
+    FTORDIE(ftdi_set_eeprom_buf(ftdi, data, sizeof(data)));
+    FTORDIE(ftdi_write_eeprom(ftdi));
+
+    // Reset the port to reload the configuration
+    libusb_reset_device(ftdi->usb_dev);
+
+    return 0;
+#else  // if NEW_LIBFTDI
+    ERR(1, "initialize command is not supported with libftdi 0.x");
+#endif  // if NEW_LIBFTDI
+}
+
+
+/* Prints out the serial on stdout, in a format compatible with "eval".
+ *
+ * option: no options allowed.
+ * force: not applicable.
+ * returns: zero on success, non-zero on error.
+ */
+int cmdList(struct ftdi_context *ftdi, const char *option, int force UNUSED) {
+    unsigned char serial[16];
+    struct libusb_device_descriptor desc;
+
+    NO_OPTIONS(option);
+
+    FTORDIE(libusb_get_device_descriptor(
+                libusb_get_device(ftdi->usb_dev), &desc));
+    FTORDIE(libusb_get_string_descriptor_ascii(
+                ftdi->usb_dev, desc.iSerialNumber, serial, sizeof(serial)));
+    fprintf(stdout, "serial='%s'\n", serial);
+    return 0;
+}
+
+
+/* Prints full device state, in a format compatible with "eval".
+ *
+ * option: no options allowed.
+ * force: not applicable.
+ * returns: zero on success, non-zero on error.
+ * */
+int cmdStatus(struct ftdi_context *ftdi, const char *option, int force UNUSED) {
+    unsigned char mode;
+
+    NO_OPTIONS(option);
+
+    FTORDIE(ftdi_read_pins(ftdi, &mode));
+    fprintf(stdout, "vbus='%s'\necap='%s'\nboot='%s'\nmodesw='%s'\n",
+            (mode & BIT_VBUS_EN_MASK) ? "on" : "off",
+            (mode & BIT_AP_MODE_EC_MODE_L_MASK) ? "ap" : "ec",
+            (mode & BIT_BOOT_MODE_L_MASK) ? "off" : "on",
+            (mode & BIT_MODE_SW_L_MASK) ? "off" : "pushed");
+    return 0;
+}
+
+
+/* Processes option parameter string for "on"/"off"/"toggle".
+ * Returns whether the new state should be asserted or deasserted.
+ * Properly handles inversion of the active-low inputs in toggle mode.
+ *
+ * option: the user-supplied option string, either "on", "off", or "toggle".
+ * mask: a single BIT_*_MASK value that denotes the option to be set.
+ * enable: returns the new value for the output.
+ * returns: zero on success, non-zero on error.
+ */
+int parseOnOffToggle(struct ftdi_context *ftdi, const char *option,
+                     unsigned char mask, int *enable) {
+    NEEDS_OPTION(option);
+    if (!strcmp(option, "on")) {
+        *enable = 1;
+    } else if (!strcmp(option, "off")) {
+        *enable = 0;
+    } else if (!strcmp(option, "toggle")) {
+        unsigned char mode;
+        FTORDIE(ftdi_read_pins(ftdi, &mode));
+        *enable = !(mode & mask);
+        // The other masks are active low, so invert.
+        if (mask != BIT_VBUS_EN_MASK) {
+            *enable = !*enable;
+        }
+    } else {
+        ERR(1, "Unrecognized option.");
+    }
+    return 0;
+}
+
+
+/* Sets or toggles vbus.
+ *
+ * option: the user-supplied option string, either "on", "off", or "toggle".
+ * force: not applicable.
+ * returns: zero on success, non-zero on error.
+ */
+int cmdSetVbus(struct ftdi_context *ftdi, const char *option,
+               int force UNUSED) {
+    int enable;
+    int ret = parseOnOffToggle(ftdi, option, BIT_VBUS_EN_MASK, &enable);
+    return ret ? ret : setCbus(ftdi, SET_CBUS_KEEP, enable, 0);
+}
+
+
+/* Sets or toggles the ec/ap mode.
+ *
+ * option: the user-supplied option string, either "ec", "ap", or "toggle".
+ * force: not applicable.
+ * returns: zero on success, non-zero on error.
+ */
+int cmdSetEcAp(struct ftdi_context *ftdi, const char *option,
+               int force UNUSED) {
+    NEEDS_OPTION(option);
+    if (!strcmp(option, "ec")) {
+        return setEcAp(ftdi, 1);
+    } else if (!strcmp(option, "ap")) {
+        return setEcAp(ftdi, 0);
+    } else if (!strcmp(option, "toggle")) {
+        return setEcAp(ftdi, SET_EC_AP_TOGGLE);
+    } else {
+        ERR(1, "Unrecognized option.");
+    }
+}
+
+
+/* Sets or toggles boot mode.
+ *
+ * option: the user-supplied option string, either "on", "off", or "toggle".
+ * force: not applicable.
+ * returns: zero on success, non-zero on error.
+ */
+int cmdSetBoot(struct ftdi_context *ftdi, const char *option,
+               int force UNUSED) {
+    int enable;
+    int ret = parseOnOffToggle(ftdi, option, BIT_BOOT_MODE_L_MASK, &enable);
+    return ret ? ret : setCbus(ftdi, enable, SET_CBUS_KEEP, 0);
+}
+
+
+/* Sets or gets the effective mode.
+ *
+ * option: if empty, outputs the current mode on stdout. Otherwise, it is the
+ *         mode to change to; see cmdSetMode.
+ * force: passed to cmdSetMode/cmdGetMode.
+ * returns: zero on success, non-zero on error.
+ */
+int cmdMode(struct ftdi_context *ftdi, const char *option, int force) {
+    if (option && *option) {
+        return cmdSetMode(ftdi, option, force);
+    } else {
+        return cmdGetMode(ftdi, option, force);
+    }
+}
+
+
+/* Prints the effective mode to stdout, in a format compatible with "eval".
+ *
+ * option: no options allowed.
+ * force: not applicable.
+ * returns: zero on success, non-zero on error.
+ */
+int cmdGetMode(struct ftdi_context *ftdi, const char *option,
+               int force UNUSED) {
+    unsigned char mode;
+    const char *name;
+
+    NO_OPTIONS(option);
+
+    FTORDIE(ftdi_read_pins(ftdi, &mode));
+    if (!(mode & BIT_VBUS_EN_MASK)) {
+        name = "off";
+    } else if (!(mode & BIT_BOOT_MODE_L_MASK)) {
+        name = "boot";
+    } else if (!(mode & BIT_AP_MODE_EC_MODE_L_MASK)) {
+        name = "ec";
+    } else {
+        name = "ap";
+    }
+    fprintf(stdout, "mode='%s'\n", name);
+    return 0;
+}
+
+
+/* Sets the effective mode explicitly.
+ * Changes VBUS_EN, BOOT_MODE, and toggles the MODE_SW as appropriate.
+ *
+ * option: the user-supplied option string, either "off", "boot", "ec", or "ap".
+ * force: not applicable.
+ * returns: zero on success, non-zero on error.
+ */
+int cmdSetMode(struct ftdi_context *ftdi, const char *option,
+               int force UNUSED) {
+    NEEDS_OPTION(option);
+    if (!strcmp(option, "off")) {
+        return setCbus(ftdi, SET_CBUS_KEEP, 0, 0);
+    } else if (!strcmp(option, "boot")) {
+        return setCbus(ftdi, 1, 1, 0);
+    } else if (!strcmp(option, "ec")) {
+        int ret = setCbus(ftdi, 0, 1, 0);
+        return ret ? ret : setEcAp(ftdi, 1);
+    } else if (!strcmp(option, "ap")) {
+        int ret = setCbus(ftdi, 0, 1, 0);
+        return ret ? ret : setEcAp(ftdi, 0);
+    } else {
+        ERR(1, "Unrecognized option.");
+    }
+}
+
+
+#if NEW_LIBFTDI
+/* Grabs all available input from FTDI and outputs on stdout without blocking.
+ * We start a one-byte asynchronous transfer. libftdi's chunking system will
+ * make this efficient. If data's already there, completed will be set to 1, and
+ * we can immediately print it out and loop. Otherwise, it will start an
+ * asynchronous request that we can then wait on using poll elsewhere, or
+ * revisit when we want to.
+ *
+ * read_tc: a state pointer that gets updated with the current read transaction.
+ * returns: zero on success, non-zero on error.
+ */
+int printAvailableFtdiOutput(struct ftdi_context *ftdi,
+                             struct ftdi_transfer_control **read_tc) {
+    unsigned char *buffer = NULL;
+    struct timeval zero = { 0, 0 };
+    int written = 0;
+    // Make sure libusb has a chance to process events
+    libusb_handle_events_timeout(ftdi->usb_ctx, &zero);
+    // Loop until there's no data available and we've initiated a read
+    while (!*read_tc || (*read_tc)->completed) {
+        // There's data available if we've looped and there's a read
+        if (*read_tc) {
+            // Grab the buffer pointer, since ftdi_transfer_data_done frees
+            // the structure
+            buffer = (*read_tc)->buf;
+            if (ftdi_transfer_data_done(*read_tc) > 0) {
+                // Output our byte
+                if (fputc(*buffer, stdout) == EOF) {
+                    free(buffer);
+                    ttyRawMode(0);
+                    ERR(2, "Failed write to stdout");
+                }
+                written++;
+            }
+            *read_tc = NULL;
+            // We don't have to free buffer since we can immediately reuse it.
+        }
+        // If we didn't just finish a read, then we won't have a buffer.
+        // This will only happen once per ftdi_transfer_control* variable.
+        if (!buffer) {
+            buffer = malloc(1);
+        }
+        // Initialize the read
+        if (!(*read_tc = ftdi_read_data_submit(ftdi, buffer, 1))) {
+            free(buffer);
+            ttyRawMode(0);
+            ERR(2, "Failed to communicate with Toad");
+        }
+    }
+    if (written) {
+        fflush(stdout);
+    }
+    return 0;
+}
+#else  // NEW_LIBFTDI
+/* We can't check how much data is available on the old libftdi, so no-op.
+ */
+int printAvailableFtdiOutput(struct ftdi_context *ftdi,
+                             struct ftdi_transfer_control **read_tc) {
+    if (ftdi || read_tc) {}
+    return 0;
+}
+#endif  // NEW_LIBFTDI
+
+
+/* Writes the buffer to the FTDI, receiving FTDI output at each step.
+ *
+ * buffer: data to write to the FTDI.
+ * length: length of the data pointed to by buffer.
+ * read_tc: a state pointer that gets updated with the current read transaction.
+ * returns: zero on success, non-zero on error.
+ */
+int ftdiWrite(struct ftdi_context *ftdi, unsigned char *buffer, size_t length,
+              struct ftdi_transfer_control **read_tc) {
+    while (length) {
+        int written = ftdi_write_data(ftdi, buffer, length);
+        if (written < 0) {
+            ttyRawMode(0);
+            ERR(2, "Failed writing to Toad\n");
+        }
+        buffer += written;
+        length -= written;
+        if (printAvailableFtdiOutput(ftdi, read_tc)) {
+            return 2;
+        }
+    }
+    return 0;
+}
+
+
+/* Sets the system to boot mode, dumps code, and resets the mode.
+ * Will also print any messages that appear over UART out to stdout.
+ *
+ * option: if NULL, reads from stdin. Otherwise, a path to the file to write.
+ * force: not applicable.
+ * returns: zero on success, non-zero on error.
+ */
+int cmdBoot(struct ftdi_context *ftdi, const char *option, int force UNUSED) {
+    struct ftdi_transfer_control *read_tc = NULL;
+    unsigned char mode;
+    FILE *file;
+    int ret;
+    unsigned char buffer[1024];
+    size_t received;
+
+    // Save the VBUS state
+    FTORDIE(ftdi_read_pins(ftdi, &mode));
+    // Open the file
+    file = option ? fopen(option, "rb") : stdin;
+    if (!file) {
+        ERR(2, "Unable to open file for reading.");
+    }
+    // Set boot mode
+    ret = setCbus(ftdi, 1, 1, 0);
+    // Wait a second for EC to be ready
+    if (!ret) sleep(1);
+    // Dump the file
+    while (!ret) {
+        received = fread(buffer, 1, sizeof(buffer), file);
+        if (!received) break;
+        ret = ftdiWrite(ftdi, buffer, received, &read_tc);
+    }
+    // Return to non-boot mode
+    if (!ret) ret = setCbus(ftdi, 0, (mode & BIT_VBUS_EN_MASK) != 0, 0);
+    // Close the file.
+    if (option) fclose(file);
+    return ret;
+}
+
+
+/* Processes stdin input for console mode. Assumes there is input available.
+ *
+ * escaped: state variable for escapes, both read and written.
+ *          Set to NULL if escapes are disabled (e.g. not a TTY).
+ * returns: zero if the user quit, 1 upon EOF, and anything else on error.
+ */
+int processConsoleInput(struct ftdi_context *ftdi, int *escaped,
+                        struct ftdi_transfer_control **read_tc) {
+    // stdin input is available. Grab what's there
+    unsigned char buffer[1024];
+    size_t available = read(STDIN_FILENO, buffer, sizeof(buffer));
+    size_t start = 0, current;
+    if (available == 0) {
+        // EOF
+        return 1;
+    } else if (escaped != NULL) {
+        // Search for and process escape characters.
+        for (current = 0; current < available; ++current) {
+            if (*escaped) {
+                *escaped = 0;
+                start = current + 1;
+                switch (buffer[current]) {
+                    case TOAD_CONSOLE_HELP1:
+                    case TOAD_CONSOLE_HELP2:
+                    case TOAD_CONSOLE_HELP3:
+                        // Print out console help.
+                        ttyRawMode(0);
+                        fputs(ESCAPES, stderr);
+                        ttyRawMode(1);
+                        break;
+                    case TOAD_CONSOLE_ESCAPE:
+                        // Send the escape character.
+                        start = current;
+                        break;
+                    case TOAD_CONSOLE_BREAK:
+                        // Exit out, return failure.
+                        return 2;
+                    case TOAD_CONSOLE_EOF:
+                        // Exit out, return success.
+                        return 1;
+                    case TOAD_CONSOLE_SUSPEND:
+                        // Suspend by calling SIGTSTP on ourselves.
+                        ttyRawMode(0);
+                        kill(0, SIGTSTP);
+                        ttyRawMode(1);
+                        break;
+                    case TOAD_CONSOLE_EC_SWITCH1:
+                    case TOAD_CONSOLE_EC_SWITCH2:
+                    case TOAD_CONSOLE_EC_SWITCH3:
+                        // Switch to EC console
+                        ttyRawMode(0);
+                        if (cmdSetMode(ftdi, "ec", 0) == 0) {
+                            puts("*** Switched to EC console ***");
+                        } else {
+                            puts("*** FAILED to switch to EC console ***");
+                        }
+                        ttyRawMode(1);
+                        break;
+                    case TOAD_CONSOLE_AP_SWITCH1:
+                    case TOAD_CONSOLE_AP_SWITCH2:
+                    case TOAD_CONSOLE_AP_SWITCH3:
+                    case TOAD_CONSOLE_AP_SWITCH4:
+                    case TOAD_CONSOLE_AP_SWITCH5:
+                    case TOAD_CONSOLE_AP_SWITCH6:
+                        // Switch to AP console
+                        ttyRawMode(0);
+                        if (cmdSetMode(ftdi, "ap", 0) == 0) {
+                            puts("*** Switched to AP console ***");
+                        } else {
+                            puts("*** FAILED to switch to AP console ***");
+                        }
+                        ttyRawMode(1);
+                        break;
+                    default:
+                        // Consume it
+                        break;
+                }
+            } else if (buffer[current] == TOAD_CONSOLE_ESCAPE) {
+                *escaped = 1;
+                // Print out what we have so far
+                if (start < current) {
+                    int ret = ftdiWrite(ftdi, &buffer[start], current - start,
+                                        read_tc);
+                    if (ret) return ret;
+                }
+                // Don't spit out this and the next character
+                start = current + 2;
+            }
+        }
+    } else {
+        // Request to out everything
+        current = available;
+    }
+    // Print out what we have left
+    if (start < current) {
+        int ret = ftdiWrite(ftdi, &buffer[start], current - start, read_tc);
+        if (ret) return ret;
+    }
+    return 0;
+}
+
+
+#if ENABLE_CONSOLE
+/* Monitors the current UART console.
+ * If stdin is a TTY, changes it to raw mode and provides an interactive
+ * console with escapes.
+ *
+ * option: no options allowed.
+ * force: not applicable.
+ * returns: zero on success, non-zero on error.
+ */
+int cmdConsole(struct ftdi_context *ftdi, const char *option,
+               int force UNUSED) {
+    int escaped = 0;
+    int *pescaped = NULL;
+
+    // Monitor for STDIN input and USB events
+    int ret = 0;
+    const char *poll_err = NULL;
+    struct pollfd *fds = NULL;
+    int num_fds = 0;
+    struct ftdi_transfer_control *read_tc = NULL;
+    struct timeval tv;
+
+    NO_OPTIONS(option);
+
+    // Switch to raw mode, and set pescaped if we should handle escapes
+    if (!ttyRawMode(1)) {
+        pescaped = &escaped;
+    }
+
+    // Main IO loop
+    while (1) {
+        const struct libusb_pollfd** libusb_fds;
+        int cur_fds, i;
+
+        // Print any available FTDI output, and start input monitoring.
+        // NOTE: calls libusb_handle_events_timout for async stuff.
+        if ((ret = printAvailableFtdiOutput(ftdi, &read_tc)))
+            break;
+
+        // Prepare the poll; lock libusb events
+        libusb_lock_events(ftdi->usb_ctx);
+
+        // Make sure a transfer completion didn't sneak in on us
+        if (read_tc && read_tc->completed) {
+            // Whoops! Loop around so that the events are handled.
+            libusb_unlock_events(ftdi->usb_ctx);
+            continue;
+        }
+
+        // Make a list of all the fds we should poll on
+        if (!(libusb_fds = libusb_get_pollfds(ftdi->usb_ctx))) {
+            poll_err = "Unable to query libusb file descriptors.";
+            break;
+        }
+        // Count the libusb fds
+        for (cur_fds = 0; libusb_fds[cur_fds]; ++cur_fds) {
+        }
+        // Add one for stdin
+        cur_fds += 1;
+
+        // Make sure our structure is big enough for all the fds
+        if (cur_fds > num_fds) {
+            num_fds = cur_fds;
+            if (!(fds = realloc(fds, sizeof(struct pollfd) * num_fds))) {
+                poll_err = "Realloc failed when polling %d file descriptors.";
+                break;
+            }
+        }
+
+        // Fill the structure with fds, starting with stdin
+        fds[0].fd = STDIN_FILENO;
+        fds[0].events = POLLIN;
+        // Poll all of the libusb fds
+        for (i = 1; i < cur_fds; ++i) {
+            fds[i].fd = libusb_fds[i-1]->fd;
+            fds[i].events = libusb_fds[i-1]->events;
+        }
+
+        // We're done with the list
+        free(libusb_fds);
+
+        // libusb might want a timeout, so query it
+        if (!libusb_get_next_timeout(ftdi->usb_ctx, &tv)) {
+            // No timeouts. Specifying a negative timeout waits forever.
+            tv.tv_sec = -1;
+        }
+
+        // Poll
+        ret = poll(fds, cur_fds, tv.tv_usec / 1000 + tv.tv_sec * 1000);
+        if (ret < 0 && errno != EINTR) {
+            poll_err = "Call to poll() failed.";
+            break;
+        }
+
+        // Allow for other threads to do event handling
+        libusb_unlock_events(ftdi->usb_ctx);
+
+        // Handle user input if there is some available
+        if (fds[0].revents) {
+            if ((ret = processConsoleInput(ftdi, pescaped, &read_tc))) {
+                // ret == 1 means EOF, which is not an error.
+                if (ret == 1)
+                    ret = 0;
+                break;
+            }
+        }
+    }
+
+    // Clean up
+    ttyRawMode(0);
+    free(fds);
+
+    // Print poll-related error messages AFTER ttyRawMode has been deactivated.
+    if (poll_err) {
+        ret = 2;
+        prn_error(poll_err, num_fds);
+    }
+
+    return ret;
+}
+#endif  // if ENABLE_CONSOLE
+
+
+#if ENABLE_CONSOLE
+/* Sets EC mode and monitors the UART console.
+ *
+ * option: no options allowed.
+ * force: passed to cmdSetMode and cmdConsole.
+ * returns: zero on success, non-zero on error.
+ */
+int cmdEc(struct ftdi_context *ftdi, const char *option, int force) {
+    int ret = cmdSetMode(ftdi, "ec", force);
+    return ret ? ret : cmdConsole(ftdi, option, force);
+}
+#endif  // if ENABLE_CONSOLE
+
+
+#if ENABLE_CONSOLE
+/* Sets AP mode and monitors the UART console
+ *
+ * option: no options allowed.
+ * force: passed to cmdSetMode and cmdConsole.
+ * returns: zero on success, non-zero on error.
+ */
+int cmdAp(struct ftdi_context *ftdi, const char *option, int force) {
+    int ret = cmdSetMode(ftdi, "ap", force);
+    return ret ? ret : cmdConsole(ftdi, option, force);
+}
+#endif  // if ENABLE_CONSOLE
diff --git a/src/toad/toad.h b/src/toad/toad.h
new file mode 100644
index 0000000..fe402b4
--- /dev/null
+++ b/src/toad/toad.h
@@ -0,0 +1,190 @@
+// Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef __TOAD_H__
+#define __TOAD_H__
+
+#include "ftdi_common.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+/* libftdi version handling:
+ * We need the 1.x version of libftdi for its asynchronous read interface.
+ * If we don't have it, disable the features that depend on it.
+ * There is no official method to detect the old version, but the 1.x version
+ * makes the EEPROM structure opaque; thus, we can detect 0.x by checking for
+ * the FTDI_DEFAULT_EEPROM_SIZE define.
+ */
+#ifndef FTDI_DEFAULT_EEPROM_SIZE
+#   define NEW_LIBFTDI 1
+#   ifndef ENABLE_CONSOLE
+#       define ENABLE_CONSOLE 1
+#   endif
+#else
+#   define NEW_LIBFTDI 0
+#   undef ENABLE_CONSOLE
+#   define ENABLE_CONSOLE 0
+
+    // Some defines are missing in the old libftdi
+#   define CBUSH_IOMODE 0x08
+#   define CBUSH_TRISTATE 0x00
+
+    // We don't use this if console mode is disabled, but predeclare it for
+    // code simplicity.
+    struct ftdi_transfer_control;
+
+    // This version doesn't use libusb, but we don't use many libusb functions,
+    // so we can define equivalents easily.
+#   define libusb_device_descriptor usb_device_descriptor
+#   define libusb_get_device_descriptor(usb_dev, desc) \
+            usb_get_descriptor(usb_dev, USB_DT_DEVICE, 0, desc, sizeof(*desc))
+#   define libusb_get_string_descriptor_ascii(usb_dev, index, buf, buflen) \
+            usb_get_string_simple(usb_dev, index, (char*)buf, buflen)
+#   define libusb_get_device(usb_dev) usb_dev
+#endif
+
+
+/* Types */
+typedef int (*cmd_func)(struct ftdi_context *, const char *, int);
+struct cmd {
+    const char *name;
+    cmd_func func;
+};
+
+
+/* Constants */
+#define FTDI_DESC "FT230X Basic UART"
+#define TOAD_DESC "Toad UART Adapter"
+#define TOAD_MANUFACTURER "Google Inc"
+#define TOAD_MANUFACTURER_ID "GG"  // Must be two characters
+#define TOAD_VID 0x0403
+#define TOAD_PID 0x6015
+#define TOAD_BAUD 115200
+#define TOAD_FLOW_CONTROL SIO_DISABLE_FLOW_CTRL
+#define TOAD_LINE_PROPERTY BITS_8, STOP_BIT_1, NONE
+#define TOAD_LATENCY_TIMER 17  // Cannot be 16; see ftdiConfigure in toad.c
+
+/* Programming data for the FT230X */
+#define TOAD_EEPROM_SIZE 0x100
+#define TOAD_EEPROM_CHECKSUM_OFFSET (TOAD_EEPROM_SIZE - 2)
+/* Each string descriptor is 2 bytes (size, type) plus the text in UTF16, sans
+ * null terminator. This means the string descriptor size is equal to
+ * sizeof(stringbuffer) * 2, since sizeof includes the null character, which we
+ * count as the two header bytes.
+ */
+#define TOAD_EEPROM_STRING_DESCRIPTOR 0x03
+#define TOAD_EEPROM_STRING_START 0xA0
+#define TOAD_EEPROM_MANUFACTURER_START (TOAD_EEPROM_STRING_START)
+#define TOAD_EEPROM_DESC_START \
+    (TOAD_EEPROM_MANUFACTURER_START + sizeof(TOAD_MANUFACTURER) * 2)
+#define TOAD_EEPROM_SERIAL_START \
+    (TOAD_EEPROM_DESC_START + sizeof(TOAD_DESC) * 2)
+// Offset of the length of the serial in the header
+#define TOAD_EEPROM_00_SERIAL_SIZE_OFFSET 0x13
+// Initial value for the FT230X checksum. Used to be 0xAAAA on older devices.
+#define TOAD_EEPROM_CHECKSUM_SEED 0x7557
+
+/* Console escapes */
+#define TOAD_CONSOLE_HELP1      'h'
+#define TOAD_CONSOLE_HELP2      'H'
+#define TOAD_CONSOLE_HELP3       8  // ^H
+#define TOAD_CONSOLE_ESCAPE     24  // ^X
+#define TOAD_CONSOLE_BREAK       3  // ^C
+#define TOAD_CONSOLE_EOF         4  // ^D
+#define TOAD_CONSOLE_SUSPEND    26  // ^Z
+#define TOAD_CONSOLE_EC_SWITCH1 'e'
+#define TOAD_CONSOLE_EC_SWITCH2 'E'
+#define TOAD_CONSOLE_EC_SWITCH3  5  // ^E
+#define TOAD_CONSOLE_AP_SWITCH1 'a'
+#define TOAD_CONSOLE_AP_SWITCH2 'A'
+#define TOAD_CONSOLE_AP_SWITCH3  1  // ^A -- might be used by screen/tmux
+#define TOAD_CONSOLE_AP_SWITCH4 'p'
+#define TOAD_CONSOLE_AP_SWITCH5 'P'
+#define TOAD_CONSOLE_AP_SWITCH6 16  // ^P
+
+/* For parsing the ftdi_read_pins response */
+#define BIT_MODE_SW_L_MASK 0x01
+#define BIT_AP_MODE_EC_MODE_L_MASK 0x02
+#define BIT_BOOT_MODE_L_MASK 0x04
+#define BIT_VBUS_EN_MASK 0x08
+
+/* For setting mask for ftdi_set_bitmode */
+#define BIT_MODE_SW_L_ASSERT 0x10
+#define BIT_MODE_SW_L_DEASSERT 0x00
+#define BIT_AP_MODE_EC_MODE_L_INPUT 0x00
+#define BIT_BOOT_MODE_L_ASSERT 0x40
+#define BIT_BOOT_MODE_L_DEASSERT 0x00
+#define BIT_VBUS_EN_ASSERT 0x00
+#define BIT_VBUS_EN_DEASSERT 0x80
+
+/* Special parameters */
+#define SET_CBUS_KEEP 2
+#define SET_EC_AP_TOGGLE 2
+
+/* Parameter declaration modifiers */
+#define UNUSED __attribute__((unused))
+#if NEW_LIBFTDI
+#    define UNUSED_ON_OLD_LIBFTDI
+#else
+#    define UNUSED_ON_OLD_LIBFTDI UNUSED
+#endif
+
+
+/* Function declarations */
+#define ERR(n, s) \
+    do { \
+        prn_error(s); \
+        return (n); \
+    } while (0)
+#define FTORDIE(x) \
+    do { \
+        int __ret; \
+        if ((__ret = (x)) < 0) \
+            ERR(__ret, #x " failed"); \
+    } while (0)
+#define NO_OPTIONS(x) \
+    do { \
+        if (x && *x) \
+            ERR(1, "Unrecognized option."); \
+    } while (0)
+#define NEEDS_OPTION(x) \
+    do { \
+        if (!x || !*x) \
+            ERR(1, "Option required."); \
+    } while (0)
+int ttyRawMode(int enable);
+int runCmd(cmd_func cmd, const char *device, const char *option, int force);
+int ftdiConfigure(struct ftdi_context *ftdi);
+int ftdiWrite(struct ftdi_context *ftdi, unsigned char *buffer, size_t length,
+              struct ftdi_transfer_control **read_tc);
+int setCbus(struct ftdi_context *ftdi, int boot_mode, int vbus_en, int mode_sw);
+int setEcAp(struct ftdi_context *ftdi, int ec);
+int parseOnOffToggle(struct ftdi_context *ftdi, const char *option,
+                     unsigned char mask, int *enable);
+int printAvailableFtdiOutput(struct ftdi_context *ftdi,
+                             struct ftdi_transfer_control **read_tc);
+int processConsoleInput(struct ftdi_context *ftdi, int *escaped,
+                        struct ftdi_transfer_control **read_tc);
+int cmdList(struct ftdi_context *ftdi, const char *option, int force);
+int cmdInitialize(struct ftdi_context *ftdi, const char *option, int force);
+int cmdStatus(struct ftdi_context *ftdi, const char *option, int force);
+int cmdSetVbus(struct ftdi_context *ftdi, const char *option, int force);
+int cmdSetEcAp(struct ftdi_context *ftdi, const char *option, int force);
+int cmdSetBoot(struct ftdi_context *ftdi, const char *option, int force);
+int cmdMode(struct ftdi_context *ftdi, const char *option, int force);
+int cmdGetMode(struct ftdi_context *ftdi, const char *option, int force);
+int cmdSetMode(struct ftdi_context *ftdi, const char *option, int force);
+int cmdBoot(struct ftdi_context *ftdi, const char *option, int force);
+int cmdConsole(struct ftdi_context *ftdi, const char *option, int force);
+int cmdEc(struct ftdi_context *ftdi, const char *option, int force);
+int cmdAp(struct ftdi_context *ftdi, const char *option, int force);
+
+
+#ifdef __cplusplus
+}
+#endif
+#endif  // __TOAD_H__