freebsd-dev/sys/dev/usb/serial/uftdi.c
Ian Lepore 07a5254736 Use 2K buffers for IO to help achieve full device speed, rather than the
default wMaxPacketSize (64 or 512 bytes).  This actually helps older FTDI
devices (which were USB 1/full speed) more than the new H-series high
speed, but even for the new chips it helps cut the number of interrupts
when doing very high speed (3-12mbaud).
2014-04-02 01:58:54 +00:00

1624 lines
60 KiB
C

/* $NetBSD: uftdi.c,v 1.13 2002/09/23 05:51:23 simonb Exp $ */
/*-
* Copyright (c) 2000 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by Lennart Augustsson (lennart@augustsson.net).
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
/*
* NOTE: all function names beginning like "uftdi_cfg_" can only
* be called from within the config thread function !
*/
/*
* FTDI FT2232x, FT8U100AX and FT8U232AM serial adapter driver
*/
#include <sys/stdint.h>
#include <sys/stddef.h>
#include <sys/param.h>
#include <sys/queue.h>
#include <sys/types.h>
#include <sys/systm.h>
#include <sys/kernel.h>
#include <sys/bus.h>
#include <sys/module.h>
#include <sys/lock.h>
#include <sys/mutex.h>
#include <sys/condvar.h>
#include <sys/sysctl.h>
#include <sys/sx.h>
#include <sys/unistd.h>
#include <sys/callout.h>
#include <sys/malloc.h>
#include <sys/priv.h>
#include <dev/usb/usb.h>
#include <dev/usb/usbdi.h>
#include <dev/usb/usbdi_util.h>
#include <dev/usb/usb_core.h>
#include "usbdevs.h"
#define USB_DEBUG_VAR uftdi_debug
#include <dev/usb/usb_debug.h>
#include <dev/usb/usb_process.h>
#include <dev/usb/serial/usb_serial.h>
#include <dev/usb/serial/uftdi_reg.h>
#ifdef USB_DEBUG
static int uftdi_debug = 0;
static SYSCTL_NODE(_hw_usb, OID_AUTO, uftdi, CTLFLAG_RW, 0, "USB uftdi");
SYSCTL_INT(_hw_usb_uftdi, OID_AUTO, debug, CTLFLAG_RW,
&uftdi_debug, 0, "Debug level");
#endif
#define UFTDI_CONFIG_INDEX 0
#define UFTDI_IFACE_INDEX_JTAG 0
/*
* IO buffer sizes and FTDI device procotol sizes.
*
* Note that the output packet size in the following defines is not the usb
* protocol packet size based on bus speed, it is the size dictated by the FTDI
* device itself, and is used only on older chips.
*
* We allocate buffers bigger than the hardware's packet size, and process
* multiple packets within each buffer. This allows the controller to make
* optimal use of the usb bus by conducting multiple transfers with the device
* during a single bus timeslice to fill or drain the chip's fifos.
*
* The output data on newer chips has no packet header, and we are able to pack
* any number of output bytes into a buffer. On some older chips, each output
* packet contains a 1-byte header and up to 63 bytes of payload. The size is
* encoded in 6 bits of the header, hence the 64-byte limit on packet size. We
* loop to fill the buffer with many of these header+payload packets.
*
* The input data on all chips consists of packets which contain a 2-byte header
* followed by data payload. The total size of the packet is wMaxPacketSize
* which can change based on the bus speed (e.g., 64 for full speed, 512 for
* high speed). We loop to extract the headers and payloads from the packets
* packed into an input buffer.
*/
#define UFTDI_IBUFSIZE 2048
#define UFTDI_IHDRSIZE 2
#define UFTDI_OBUFSIZE 2048
#define UFTDI_OPKTSIZE 64
enum {
UFTDI_BULK_DT_WR,
UFTDI_BULK_DT_RD,
UFTDI_N_TRANSFER,
};
enum {
DEVT_SIO,
DEVT_232A,
DEVT_232B,
DEVT_2232D, /* Includes 2232C */
DEVT_232R,
DEVT_2232H,
DEVT_4232H,
DEVT_232H,
DEVT_230X,
};
#define DEVF_BAUDBITS_HINDEX 0x01 /* Baud bits in high byte of index. */
#define DEVF_BAUDCLK_12M 0X02 /* Base baud clock is 12MHz. */
struct uftdi_softc {
struct ucom_super_softc sc_super_ucom;
struct ucom_softc sc_ucom;
struct usb_device *sc_udev;
struct usb_xfer *sc_xfer[UFTDI_N_TRANSFER];
device_t sc_dev;
struct mtx sc_mtx;
uint32_t sc_unit;
uint16_t sc_last_lcr;
uint8_t sc_devtype;
uint8_t sc_devflags;
uint8_t sc_hdrlen;
uint8_t sc_msr;
uint8_t sc_lsr;
};
struct uftdi_param_config {
uint16_t baud_lobits;
uint16_t baud_hibits;
uint16_t lcr;
uint8_t v_start;
uint8_t v_stop;
uint8_t v_flow;
};
/* prototypes */
static device_probe_t uftdi_probe;
static device_attach_t uftdi_attach;
static device_detach_t uftdi_detach;
static void uftdi_free_softc(struct uftdi_softc *);
static usb_callback_t uftdi_write_callback;
static usb_callback_t uftdi_read_callback;
static void uftdi_free(struct ucom_softc *);
static void uftdi_cfg_open(struct ucom_softc *);
static void uftdi_cfg_set_dtr(struct ucom_softc *, uint8_t);
static void uftdi_cfg_set_rts(struct ucom_softc *, uint8_t);
static void uftdi_cfg_set_break(struct ucom_softc *, uint8_t);
static int uftdi_set_parm_soft(struct ucom_softc *, struct termios *,
struct uftdi_param_config *);
static int uftdi_pre_param(struct ucom_softc *, struct termios *);
static void uftdi_cfg_param(struct ucom_softc *, struct termios *);
static void uftdi_cfg_get_status(struct ucom_softc *, uint8_t *,
uint8_t *);
static void uftdi_start_read(struct ucom_softc *);
static void uftdi_stop_read(struct ucom_softc *);
static void uftdi_start_write(struct ucom_softc *);
static void uftdi_stop_write(struct ucom_softc *);
static void uftdi_poll(struct ucom_softc *ucom);
static const struct usb_config uftdi_config[UFTDI_N_TRANSFER] = {
[UFTDI_BULK_DT_WR] = {
.type = UE_BULK,
.endpoint = UE_ADDR_ANY,
.direction = UE_DIR_OUT,
.bufsize = UFTDI_OBUFSIZE,
.flags = {.pipe_bof = 1,},
.callback = &uftdi_write_callback,
},
[UFTDI_BULK_DT_RD] = {
.type = UE_BULK,
.endpoint = UE_ADDR_ANY,
.direction = UE_DIR_IN,
.bufsize = UFTDI_IBUFSIZE,
.flags = {.pipe_bof = 1,.short_xfer_ok = 1,},
.callback = &uftdi_read_callback,
},
};
static const struct ucom_callback uftdi_callback = {
.ucom_cfg_get_status = &uftdi_cfg_get_status,
.ucom_cfg_set_dtr = &uftdi_cfg_set_dtr,
.ucom_cfg_set_rts = &uftdi_cfg_set_rts,
.ucom_cfg_set_break = &uftdi_cfg_set_break,
.ucom_cfg_param = &uftdi_cfg_param,
.ucom_cfg_open = &uftdi_cfg_open,
.ucom_pre_param = &uftdi_pre_param,
.ucom_start_read = &uftdi_start_read,
.ucom_stop_read = &uftdi_stop_read,
.ucom_start_write = &uftdi_start_write,
.ucom_stop_write = &uftdi_stop_write,
.ucom_poll = &uftdi_poll,
.ucom_free = &uftdi_free,
};
static device_method_t uftdi_methods[] = {
/* Device interface */
DEVMETHOD(device_probe, uftdi_probe),
DEVMETHOD(device_attach, uftdi_attach),
DEVMETHOD(device_detach, uftdi_detach),
DEVMETHOD_END
};
static devclass_t uftdi_devclass;
static driver_t uftdi_driver = {
.name = "uftdi",
.methods = uftdi_methods,
.size = sizeof(struct uftdi_softc),
};
DRIVER_MODULE(uftdi, uhub, uftdi_driver, uftdi_devclass, NULL, NULL);
MODULE_DEPEND(uftdi, ucom, 1, 1, 1);
MODULE_DEPEND(uftdi, usb, 1, 1, 1);
MODULE_VERSION(uftdi, 1);
static const STRUCT_USB_HOST_ID uftdi_devs[] = {
#define UFTDI_DEV(v, p, i) \
{ USB_VPI(USB_VENDOR_##v, USB_PRODUCT_##v##_##p, i) }
UFTDI_DEV(ACTON, SPECTRAPRO, UFTDI_TYPE_AUTO),
UFTDI_DEV(ALTI2, N3, UFTDI_TYPE_AUTO),
UFTDI_DEV(ANALOGDEVICES, GNICE, UFTDI_TYPE_AUTO | UFTDI_FLAG_JTAG),
UFTDI_DEV(ANALOGDEVICES, GNICEPLUS, UFTDI_TYPE_AUTO | UFTDI_FLAG_JTAG),
UFTDI_DEV(ATMEL, STK541, UFTDI_TYPE_8U232AM),
UFTDI_DEV(BAYER, CONTOUR_CABLE, UFTDI_TYPE_AUTO),
UFTDI_DEV(BBELECTRONICS, 232USB9M, UFTDI_TYPE_AUTO),
UFTDI_DEV(BBELECTRONICS, 485USB9F_2W, UFTDI_TYPE_AUTO),
UFTDI_DEV(BBELECTRONICS, 485USB9F_4W, UFTDI_TYPE_AUTO),
UFTDI_DEV(BBELECTRONICS, 485USBTB_2W, UFTDI_TYPE_AUTO),
UFTDI_DEV(BBELECTRONICS, 485USBTB_4W, UFTDI_TYPE_AUTO),
UFTDI_DEV(BBELECTRONICS, TTL3USB9M, UFTDI_TYPE_AUTO),
UFTDI_DEV(BBELECTRONICS, TTL5USB9M, UFTDI_TYPE_AUTO),
UFTDI_DEV(BBELECTRONICS, USO9ML2, UFTDI_TYPE_AUTO),
UFTDI_DEV(BBELECTRONICS, USO9ML2DR, UFTDI_TYPE_AUTO),
UFTDI_DEV(BBELECTRONICS, USO9ML2DR_2, UFTDI_TYPE_AUTO),
UFTDI_DEV(BBELECTRONICS, USOPTL4, UFTDI_TYPE_AUTO),
UFTDI_DEV(BBELECTRONICS, USOPTL4DR, UFTDI_TYPE_AUTO),
UFTDI_DEV(BBELECTRONICS, USOPTL4DR2, UFTDI_TYPE_AUTO),
UFTDI_DEV(BBELECTRONICS, USOTL4, UFTDI_TYPE_8U232AM),
UFTDI_DEV(BBELECTRONICS, USPTL4, UFTDI_TYPE_AUTO),
UFTDI_DEV(BBELECTRONICS, USTL4, UFTDI_TYPE_AUTO),
UFTDI_DEV(BBELECTRONICS, ZZ_PROG1_USB, UFTDI_TYPE_AUTO),
UFTDI_DEV(CONTEC, COM1USBH, UFTDI_TYPE_AUTO),
UFTDI_DEV(DRESDENELEKTRONIK, SENSORTERMINALBOARD, UFTDI_TYPE_8U232AM),
UFTDI_DEV(DRESDENELEKTRONIK, WIRELESSHANDHELDTERMINAL, UFTDI_TYPE_8U232AM),
UFTDI_DEV(ELEKTOR, FT323R, UFTDI_TYPE_AUTO),
UFTDI_DEV(EVOLUTION, ER1, UFTDI_TYPE_AUTO),
UFTDI_DEV(EVOLUTION, HYBRID, UFTDI_TYPE_AUTO),
UFTDI_DEV(EVOLUTION, RCM4, UFTDI_TYPE_AUTO),
UFTDI_DEV(FALCOM, SAMBA, UFTDI_TYPE_AUTO),
UFTDI_DEV(FALCOM, TWIST, UFTDI_TYPE_8U232AM),
UFTDI_DEV(FIC, NEO1973_DEBUG, UFTDI_TYPE_AUTO | UFTDI_FLAG_JTAG),
UFTDI_DEV(FIC, NEO1973_DEBUG, UFTDI_TYPE_AUTO | UFTDI_FLAG_JTAG),
UFTDI_DEV(FTDI, 232EX, UFTDI_TYPE_AUTO),
UFTDI_DEV(FTDI, 232H, UFTDI_TYPE_AUTO),
UFTDI_DEV(FTDI, 232RL, UFTDI_TYPE_AUTO),
UFTDI_DEV(FTDI, 4N_GALAXY_DE_1, UFTDI_TYPE_AUTO),
UFTDI_DEV(FTDI, 4N_GALAXY_DE_2, UFTDI_TYPE_AUTO),
UFTDI_DEV(FTDI, 4N_GALAXY_DE_3, UFTDI_TYPE_AUTO),
UFTDI_DEV(FTDI, 8U232AM_ALT, UFTDI_TYPE_AUTO),
UFTDI_DEV(FTDI, ACCESSO, UFTDI_TYPE_AUTO),
UFTDI_DEV(FTDI, ACG_HFDUAL, UFTDI_TYPE_AUTO),
UFTDI_DEV(FTDI, ACTIVE_ROBOTS, UFTDI_TYPE_AUTO),
UFTDI_DEV(FTDI, ACTZWAVE, UFTDI_TYPE_AUTO),
UFTDI_DEV(FTDI, AMC232, UFTDI_TYPE_AUTO),
UFTDI_DEV(FTDI, ARTEMIS, UFTDI_TYPE_AUTO),
UFTDI_DEV(FTDI, ASK_RDR400, UFTDI_TYPE_AUTO),
UFTDI_DEV(FTDI, ATIK_ATK16, UFTDI_TYPE_AUTO),
UFTDI_DEV(FTDI, ATIK_ATK16C, UFTDI_TYPE_AUTO),
UFTDI_DEV(FTDI, ATIK_ATK16HR, UFTDI_TYPE_AUTO),
UFTDI_DEV(FTDI, ATIK_ATK16HRC, UFTDI_TYPE_AUTO),
UFTDI_DEV(FTDI, ATIK_ATK16IC, UFTDI_TYPE_AUTO),
UFTDI_DEV(FTDI, BCS_SE923, UFTDI_TYPE_AUTO),
UFTDI_DEV(FTDI, BEAGLEBONE, UFTDI_TYPE_8U232AM),
UFTDI_DEV(FTDI, CANDAPTER, UFTDI_TYPE_AUTO),
UFTDI_DEV(FTDI, CANUSB, UFTDI_TYPE_AUTO),
UFTDI_DEV(FTDI, CCSICDU20_0, UFTDI_TYPE_AUTO),
UFTDI_DEV(FTDI, CCSICDU40_1, UFTDI_TYPE_AUTO),
UFTDI_DEV(FTDI, CCSICDU64_4, UFTDI_TYPE_AUTO),
UFTDI_DEV(FTDI, CCSLOAD_N_GO_3, UFTDI_TYPE_AUTO),
UFTDI_DEV(FTDI, CCSMACHX_2, UFTDI_TYPE_AUTO),
UFTDI_DEV(FTDI, CCSPRIME8_5, UFTDI_TYPE_AUTO),
UFTDI_DEV(FTDI, CFA_631, UFTDI_TYPE_8U232AM),
UFTDI_DEV(FTDI, CFA_632, UFTDI_TYPE_8U232AM),
UFTDI_DEV(FTDI, CFA_633, UFTDI_TYPE_8U232AM),
UFTDI_DEV(FTDI, CFA_634, UFTDI_TYPE_8U232AM),
UFTDI_DEV(FTDI, CFA_635, UFTDI_TYPE_8U232AM),
UFTDI_DEV(FTDI, CHAMSYS_24_MASTER_WING, UFTDI_TYPE_AUTO),
UFTDI_DEV(FTDI, CHAMSYS_MAXI_WING, UFTDI_TYPE_AUTO),
UFTDI_DEV(FTDI, CHAMSYS_MEDIA_WING, UFTDI_TYPE_AUTO),
UFTDI_DEV(FTDI, CHAMSYS_MIDI_TIMECODE, UFTDI_TYPE_AUTO),
UFTDI_DEV(FTDI, CHAMSYS_MINI_WING, UFTDI_TYPE_AUTO),
UFTDI_DEV(FTDI, CHAMSYS_PC_WING, UFTDI_TYPE_AUTO),
UFTDI_DEV(FTDI, CHAMSYS_USB_DMX, UFTDI_TYPE_AUTO),
UFTDI_DEV(FTDI, CHAMSYS_WING, UFTDI_TYPE_AUTO),
UFTDI_DEV(FTDI, COM4SM, UFTDI_TYPE_AUTO),
UFTDI_DEV(FTDI, CONVERTER_0, UFTDI_TYPE_AUTO),
UFTDI_DEV(FTDI, CONVERTER_1, UFTDI_TYPE_AUTO),
UFTDI_DEV(FTDI, CONVERTER_2, UFTDI_TYPE_AUTO),
UFTDI_DEV(FTDI, CONVERTER_3, UFTDI_TYPE_AUTO),
UFTDI_DEV(FTDI, CONVERTER_4, UFTDI_TYPE_AUTO),
UFTDI_DEV(FTDI, CONVERTER_5, UFTDI_TYPE_AUTO),
UFTDI_DEV(FTDI, CONVERTER_6, UFTDI_TYPE_AUTO),
UFTDI_DEV(FTDI, CONVERTER_7, UFTDI_TYPE_AUTO),
UFTDI_DEV(FTDI, CTI_USB_MINI_485, UFTDI_TYPE_8U232AM),
UFTDI_DEV(FTDI, CTI_USB_NANO_485, UFTDI_TYPE_8U232AM),
UFTDI_DEV(FTDI, DMX4ALL, UFTDI_TYPE_AUTO),
UFTDI_DEV(FTDI, DOMINTELL_DGQG, UFTDI_TYPE_AUTO),
UFTDI_DEV(FTDI, DOMINTELL_DUSB, UFTDI_TYPE_AUTO),
UFTDI_DEV(FTDI, DOTEC, UFTDI_TYPE_AUTO),
UFTDI_DEV(FTDI, ECLO_COM_1WIRE, UFTDI_TYPE_AUTO),
UFTDI_DEV(FTDI, ECO_PRO_CDS, UFTDI_TYPE_AUTO),
UFTDI_DEV(FTDI, EISCOU, UFTDI_TYPE_8U232AM),
UFTDI_DEV(FTDI, ELSTER_UNICOM, UFTDI_TYPE_AUTO),
UFTDI_DEV(FTDI, ELV_ALC8500, UFTDI_TYPE_AUTO),
UFTDI_DEV(FTDI, ELV_CLI7000, UFTDI_TYPE_AUTO),
UFTDI_DEV(FTDI, ELV_CSI8, UFTDI_TYPE_AUTO),
UFTDI_DEV(FTDI, ELV_EC3000, UFTDI_TYPE_AUTO),
UFTDI_DEV(FTDI, ELV_EM1000DL, UFTDI_TYPE_AUTO),
UFTDI_DEV(FTDI, ELV_EM1010PC, UFTDI_TYPE_AUTO),
UFTDI_DEV(FTDI, ELV_FEM, UFTDI_TYPE_AUTO),
UFTDI_DEV(FTDI, ELV_FHZ1000PC, UFTDI_TYPE_AUTO),
UFTDI_DEV(FTDI, ELV_FHZ1300PC, UFTDI_TYPE_AUTO),
UFTDI_DEV(FTDI, ELV_FM3RX, UFTDI_TYPE_AUTO),
UFTDI_DEV(FTDI, ELV_FS20SIG, UFTDI_TYPE_AUTO),
UFTDI_DEV(FTDI, ELV_HS485, UFTDI_TYPE_AUTO),
UFTDI_DEV(FTDI, ELV_KL100, UFTDI_TYPE_AUTO),
UFTDI_DEV(FTDI, ELV_MSM1, UFTDI_TYPE_AUTO),
UFTDI_DEV(FTDI, ELV_PCD200, UFTDI_TYPE_AUTO),
UFTDI_DEV(FTDI, ELV_PCK100, UFTDI_TYPE_AUTO),
UFTDI_DEV(FTDI, ELV_PPS7330, UFTDI_TYPE_AUTO),
UFTDI_DEV(FTDI, ELV_RFP500, UFTDI_TYPE_AUTO),
UFTDI_DEV(FTDI, ELV_T1100, UFTDI_TYPE_AUTO),
UFTDI_DEV(FTDI, ELV_TFD128, UFTDI_TYPE_AUTO),
UFTDI_DEV(FTDI, ELV_TFM100, UFTDI_TYPE_AUTO),
UFTDI_DEV(FTDI, ELV_TWS550, UFTDI_TYPE_AUTO),
UFTDI_DEV(FTDI, ELV_UAD8, UFTDI_TYPE_AUTO),
UFTDI_DEV(FTDI, ELV_UDA7, UFTDI_TYPE_AUTO),
UFTDI_DEV(FTDI, ELV_UDF77, UFTDI_TYPE_AUTO),
UFTDI_DEV(FTDI, ELV_UIO88, UFTDI_TYPE_AUTO),
UFTDI_DEV(FTDI, ELV_ULA200, UFTDI_TYPE_AUTO),
UFTDI_DEV(FTDI, ELV_UM100, UFTDI_TYPE_AUTO),
UFTDI_DEV(FTDI, ELV_UMS100, UFTDI_TYPE_AUTO),
UFTDI_DEV(FTDI, ELV_UO100, UFTDI_TYPE_AUTO),
UFTDI_DEV(FTDI, ELV_UR100, UFTDI_TYPE_AUTO),
UFTDI_DEV(FTDI, ELV_USI2, UFTDI_TYPE_AUTO),
UFTDI_DEV(FTDI, ELV_USR, UFTDI_TYPE_AUTO),
UFTDI_DEV(FTDI, ELV_UTP8, UFTDI_TYPE_AUTO),
UFTDI_DEV(FTDI, ELV_WS300PC, UFTDI_TYPE_AUTO),
UFTDI_DEV(FTDI, ELV_WS444PC, UFTDI_TYPE_AUTO),
UFTDI_DEV(FTDI, ELV_WS500, UFTDI_TYPE_AUTO),
UFTDI_DEV(FTDI, ELV_WS550, UFTDI_TYPE_AUTO),
UFTDI_DEV(FTDI, ELV_WS777, UFTDI_TYPE_AUTO),
UFTDI_DEV(FTDI, ELV_WS888, UFTDI_TYPE_AUTO),
UFTDI_DEV(FTDI, EMCU2D, UFTDI_TYPE_8U232AM),
UFTDI_DEV(FTDI, EMCU2H, UFTDI_TYPE_8U232AM),
UFTDI_DEV(FTDI, FUTURE_0, UFTDI_TYPE_AUTO),
UFTDI_DEV(FTDI, FUTURE_1, UFTDI_TYPE_AUTO),
UFTDI_DEV(FTDI, FUTURE_2, UFTDI_TYPE_AUTO),
UFTDI_DEV(FTDI, GAMMASCOUT, UFTDI_TYPE_8U232AM),
UFTDI_DEV(FTDI, GENERIC, UFTDI_TYPE_AUTO),
UFTDI_DEV(FTDI, GUDEADS_E808, UFTDI_TYPE_AUTO),
UFTDI_DEV(FTDI, GUDEADS_E809, UFTDI_TYPE_AUTO),
UFTDI_DEV(FTDI, GUDEADS_E80A, UFTDI_TYPE_AUTO),
UFTDI_DEV(FTDI, GUDEADS_E80B, UFTDI_TYPE_AUTO),
UFTDI_DEV(FTDI, GUDEADS_E80C, UFTDI_TYPE_AUTO),
UFTDI_DEV(FTDI, GUDEADS_E80D, UFTDI_TYPE_AUTO),
UFTDI_DEV(FTDI, GUDEADS_E80E, UFTDI_TYPE_AUTO),
UFTDI_DEV(FTDI, GUDEADS_E80F, UFTDI_TYPE_AUTO),
UFTDI_DEV(FTDI, GUDEADS_E88D, UFTDI_TYPE_AUTO),
UFTDI_DEV(FTDI, GUDEADS_E88E, UFTDI_TYPE_AUTO),
UFTDI_DEV(FTDI, GUDEADS_E88F, UFTDI_TYPE_AUTO),
UFTDI_DEV(FTDI, HD_RADIO, UFTDI_TYPE_AUTO),
UFTDI_DEV(FTDI, HO720, UFTDI_TYPE_AUTO),
UFTDI_DEV(FTDI, HO730, UFTDI_TYPE_AUTO),
UFTDI_DEV(FTDI, HO820, UFTDI_TYPE_AUTO),
UFTDI_DEV(FTDI, HO870, UFTDI_TYPE_AUTO),
UFTDI_DEV(FTDI, IBS_APP70, UFTDI_TYPE_AUTO),
UFTDI_DEV(FTDI, IBS_PCMCIA, UFTDI_TYPE_AUTO),
UFTDI_DEV(FTDI, IBS_PEDO, UFTDI_TYPE_AUTO),
UFTDI_DEV(FTDI, IBS_PICPRO, UFTDI_TYPE_AUTO),
UFTDI_DEV(FTDI, IBS_PK1, UFTDI_TYPE_AUTO),
UFTDI_DEV(FTDI, IBS_PROD, UFTDI_TYPE_AUTO),
UFTDI_DEV(FTDI, IBS_RS232MON, UFTDI_TYPE_AUTO),
UFTDI_DEV(FTDI, IBS_US485, UFTDI_TYPE_AUTO),
UFTDI_DEV(FTDI, IPLUS, UFTDI_TYPE_AUTO),
UFTDI_DEV(FTDI, IPLUS2, UFTDI_TYPE_AUTO),
UFTDI_DEV(FTDI, IRTRANS, UFTDI_TYPE_AUTO),
UFTDI_DEV(FTDI, KBS, UFTDI_TYPE_8U232AM),
UFTDI_DEV(FTDI, KTLINK, UFTDI_TYPE_8U232AM),
UFTDI_DEV(FTDI, LENZ_LIUSB, UFTDI_TYPE_AUTO),
UFTDI_DEV(FTDI, LK202, UFTDI_TYPE_8U232AM),
UFTDI_DEV(FTDI, LK204, UFTDI_TYPE_8U232AM),
UFTDI_DEV(FTDI, LM3S_DEVEL_BOARD, UFTDI_TYPE_AUTO | UFTDI_FLAG_JTAG),
UFTDI_DEV(FTDI, LM3S_EVAL_BOARD, UFTDI_TYPE_AUTO | UFTDI_FLAG_JTAG),
UFTDI_DEV(FTDI, LM3S_ICDI_B_BOARD, UFTDI_TYPE_AUTO | UFTDI_FLAG_JTAG),
UFTDI_DEV(FTDI, MASTERDEVEL2, UFTDI_TYPE_AUTO),
UFTDI_DEV(FTDI, MAXSTREAM, UFTDI_TYPE_8U232AM),
UFTDI_DEV(FTDI, MHAM_DB9, UFTDI_TYPE_AUTO),
UFTDI_DEV(FTDI, MHAM_IC, UFTDI_TYPE_AUTO),
UFTDI_DEV(FTDI, MHAM_KW, UFTDI_TYPE_AUTO),
UFTDI_DEV(FTDI, MHAM_RS232, UFTDI_TYPE_AUTO),
UFTDI_DEV(FTDI, MHAM_Y6, UFTDI_TYPE_AUTO),
UFTDI_DEV(FTDI, MHAM_Y8, UFTDI_TYPE_AUTO),
UFTDI_DEV(FTDI, MHAM_Y9, UFTDI_TYPE_AUTO),
UFTDI_DEV(FTDI, MHAM_YS, UFTDI_TYPE_AUTO),
UFTDI_DEV(FTDI, MICRO_CHAMELEON, UFTDI_TYPE_AUTO),
UFTDI_DEV(FTDI, MTXORB_5, UFTDI_TYPE_AUTO),
UFTDI_DEV(FTDI, MTXORB_6, UFTDI_TYPE_AUTO),
UFTDI_DEV(FTDI, MX2_3, UFTDI_TYPE_8U232AM),
UFTDI_DEV(FTDI, MX4_5, UFTDI_TYPE_8U232AM),
UFTDI_DEV(FTDI, NXTCAM, UFTDI_TYPE_AUTO),
UFTDI_DEV(FTDI, OCEANIC, UFTDI_TYPE_AUTO),
UFTDI_DEV(FTDI, OOCDLINK, UFTDI_TYPE_AUTO | UFTDI_FLAG_JTAG),
UFTDI_DEV(FTDI, OPENDCC, UFTDI_TYPE_AUTO),
UFTDI_DEV(FTDI, OPENDCC_GATEWAY, UFTDI_TYPE_AUTO),
UFTDI_DEV(FTDI, OPENDCC_GBM, UFTDI_TYPE_AUTO),
UFTDI_DEV(FTDI, OPENDCC_SNIFFER, UFTDI_TYPE_AUTO),
UFTDI_DEV(FTDI, OPENDCC_THROTTLE, UFTDI_TYPE_AUTO),
UFTDI_DEV(FTDI, PCDJ_DAC2, UFTDI_TYPE_AUTO),
UFTDI_DEV(FTDI, PCMSFU, UFTDI_TYPE_8U232AM),
UFTDI_DEV(FTDI, PERLE_ULTRAPORT, UFTDI_TYPE_AUTO),
UFTDI_DEV(FTDI, PHI_FISCO, UFTDI_TYPE_AUTO),
UFTDI_DEV(FTDI, PIEGROUP, UFTDI_TYPE_AUTO),
UFTDI_DEV(FTDI, PROPOX_JTAGCABLEII, UFTDI_TYPE_AUTO),
UFTDI_DEV(FTDI, R2000KU_TRUE_RNG, UFTDI_TYPE_AUTO),
UFTDI_DEV(FTDI, R2X0, UFTDI_TYPE_AUTO),
UFTDI_DEV(FTDI, RELAIS, UFTDI_TYPE_AUTO),
UFTDI_DEV(FTDI, REU_TINY, UFTDI_TYPE_AUTO),
UFTDI_DEV(FTDI, RMP200, UFTDI_TYPE_AUTO),
UFTDI_DEV(FTDI, RM_CANVIEW, UFTDI_TYPE_AUTO),
UFTDI_DEV(FTDI, RRCIRKITS_LOCOBUFFER, UFTDI_TYPE_AUTO),
UFTDI_DEV(FTDI, SCIENCESCOPE_HS_LOGBOOK, UFTDI_TYPE_AUTO),
UFTDI_DEV(FTDI, SCIENCESCOPE_LOGBOOKML, UFTDI_TYPE_AUTO),
UFTDI_DEV(FTDI, SCIENCESCOPE_LS_LOGBOOK, UFTDI_TYPE_AUTO),
UFTDI_DEV(FTDI, SCS_DEVICE_0, UFTDI_TYPE_AUTO),
UFTDI_DEV(FTDI, SCS_DEVICE_1, UFTDI_TYPE_AUTO),
UFTDI_DEV(FTDI, SCS_DEVICE_2, UFTDI_TYPE_AUTO),
UFTDI_DEV(FTDI, SCS_DEVICE_3, UFTDI_TYPE_AUTO),
UFTDI_DEV(FTDI, SCS_DEVICE_4, UFTDI_TYPE_AUTO),
UFTDI_DEV(FTDI, SCS_DEVICE_5, UFTDI_TYPE_AUTO),
UFTDI_DEV(FTDI, SCS_DEVICE_6, UFTDI_TYPE_AUTO),
UFTDI_DEV(FTDI, SCS_DEVICE_7, UFTDI_TYPE_AUTO),
UFTDI_DEV(FTDI, SDMUSBQSS, UFTDI_TYPE_AUTO),
UFTDI_DEV(FTDI, SEMC_DSS20, UFTDI_TYPE_8U232AM),
UFTDI_DEV(FTDI, SERIAL_2232C, UFTDI_TYPE_8U232AM),
UFTDI_DEV(FTDI, SERIAL_2232D, UFTDI_TYPE_8U232AM),
UFTDI_DEV(FTDI, SERIAL_232RL, UFTDI_TYPE_AUTO),
UFTDI_DEV(FTDI, SERIAL_4232H, UFTDI_TYPE_8U232AM),
UFTDI_DEV(FTDI, SERIAL_8U100AX, UFTDI_TYPE_SIO),
UFTDI_DEV(FTDI, SERIAL_8U232AM, UFTDI_TYPE_8U232AM),
UFTDI_DEV(FTDI, SERIAL_8U232AM4, UFTDI_TYPE_8U232AM),
UFTDI_DEV(FTDI, SIGNALYZER_SH2, UFTDI_TYPE_AUTO | UFTDI_FLAG_JTAG),
UFTDI_DEV(FTDI, SIGNALYZER_SH4, UFTDI_TYPE_AUTO | UFTDI_FLAG_JTAG),
UFTDI_DEV(FTDI, SIGNALYZER_SLITE, UFTDI_TYPE_AUTO | UFTDI_FLAG_JTAG),
UFTDI_DEV(FTDI, SIGNALYZER_ST, UFTDI_TYPE_AUTO | UFTDI_FLAG_JTAG),
UFTDI_DEV(FTDI, SPECIAL_1, UFTDI_TYPE_AUTO),
UFTDI_DEV(FTDI, SPECIAL_3, UFTDI_TYPE_AUTO),
UFTDI_DEV(FTDI, SPECIAL_4, UFTDI_TYPE_AUTO),
UFTDI_DEV(FTDI, SPROG_II, UFTDI_TYPE_AUTO),
UFTDI_DEV(FTDI, SR_RADIO, UFTDI_TYPE_AUTO),
UFTDI_DEV(FTDI, SUUNTO_SPORTS, UFTDI_TYPE_AUTO),
UFTDI_DEV(FTDI, TACTRIX_OPENPORT_13M, UFTDI_TYPE_8U232AM),
UFTDI_DEV(FTDI, TACTRIX_OPENPORT_13S, UFTDI_TYPE_8U232AM),
UFTDI_DEV(FTDI, TACTRIX_OPENPORT_13U, UFTDI_TYPE_8U232AM),
UFTDI_DEV(FTDI, TAVIR_STK500, UFTDI_TYPE_AUTO),
UFTDI_DEV(FTDI, TERATRONIK_D2XX, UFTDI_TYPE_AUTO),
UFTDI_DEV(FTDI, TERATRONIK_VCP, UFTDI_TYPE_AUTO),
UFTDI_DEV(FTDI, THORLABS, UFTDI_TYPE_AUTO),
UFTDI_DEV(FTDI, TNC_X, UFTDI_TYPE_AUTO),
UFTDI_DEV(FTDI, TTUSB, UFTDI_TYPE_AUTO),
UFTDI_DEV(FTDI, TURTELIZER2, UFTDI_TYPE_8U232AM | UFTDI_FLAG_JTAG),
UFTDI_DEV(FTDI, UOPTBR, UFTDI_TYPE_8U232AM),
UFTDI_DEV(FTDI, USBSERIAL, UFTDI_TYPE_8U232AM),
UFTDI_DEV(FTDI, USBX_707, UFTDI_TYPE_AUTO),
UFTDI_DEV(FTDI, USB_UIRT, UFTDI_TYPE_8U232AM),
UFTDI_DEV(FTDI, USINT_CAT, UFTDI_TYPE_AUTO),
UFTDI_DEV(FTDI, USINT_RS232, UFTDI_TYPE_AUTO),
UFTDI_DEV(FTDI, USINT_WKEY, UFTDI_TYPE_AUTO),
UFTDI_DEV(FTDI, VARDAAN, UFTDI_TYPE_AUTO),
UFTDI_DEV(FTDI, VNHCPCUSB_D, UFTDI_TYPE_AUTO),
UFTDI_DEV(FTDI, WESTREX_MODEL_777, UFTDI_TYPE_AUTO),
UFTDI_DEV(FTDI, WESTREX_MODEL_8900F, UFTDI_TYPE_AUTO),
UFTDI_DEV(FTDI, XF_547, UFTDI_TYPE_AUTO),
UFTDI_DEV(FTDI, XF_640, UFTDI_TYPE_AUTO),
UFTDI_DEV(FTDI, XF_642, UFTDI_TYPE_AUTO),
UFTDI_DEV(FTDI, XM_RADIO, UFTDI_TYPE_AUTO),
UFTDI_DEV(FTDI, YEI_SERVOCENTER31, UFTDI_TYPE_AUTO),
UFTDI_DEV(GNOTOMETRICS, USB, UFTDI_TYPE_AUTO),
UFTDI_DEV(ICOM, SP1, UFTDI_TYPE_AUTO),
UFTDI_DEV(ICOM, OPC_U_UC, UFTDI_TYPE_AUTO),
UFTDI_DEV(ICOM, RP2C1, UFTDI_TYPE_AUTO),
UFTDI_DEV(ICOM, RP2C2, UFTDI_TYPE_AUTO),
UFTDI_DEV(ICOM, RP2D, UFTDI_TYPE_AUTO),
UFTDI_DEV(ICOM, RP2KVR, UFTDI_TYPE_AUTO),
UFTDI_DEV(ICOM, RP2KVT, UFTDI_TYPE_AUTO),
UFTDI_DEV(ICOM, RP2VR, UFTDI_TYPE_AUTO),
UFTDI_DEV(ICOM, RP2VT, UFTDI_TYPE_AUTO),
UFTDI_DEV(ICOM, RP4KVR, UFTDI_TYPE_AUTO),
UFTDI_DEV(ICOM, RP4KVT, UFTDI_TYPE_AUTO),
UFTDI_DEV(IDTECH, IDT1221U, UFTDI_TYPE_AUTO),
UFTDI_DEV(INTERBIOMETRICS, IOBOARD, UFTDI_TYPE_AUTO),
UFTDI_DEV(INTERBIOMETRICS, MINI_IOBOARD, UFTDI_TYPE_AUTO),
UFTDI_DEV(INTREPIDCS, NEOVI, UFTDI_TYPE_8U232AM),
UFTDI_DEV(INTREPIDCS, VALUECAN, UFTDI_TYPE_8U232AM),
UFTDI_DEV(IONICS, PLUGCOMPUTER, UFTDI_TYPE_AUTO | UFTDI_FLAG_JTAG),
UFTDI_DEV(JETI, SPC1201, UFTDI_TYPE_AUTO),
UFTDI_DEV(KOBIL, CONV_B1, UFTDI_TYPE_AUTO),
UFTDI_DEV(KOBIL, CONV_KAAN, UFTDI_TYPE_AUTO),
UFTDI_DEV(LARSENBRUSGAARD, ALTITRACK, UFTDI_TYPE_AUTO),
UFTDI_DEV(MARVELL, SHEEVAPLUG, UFTDI_TYPE_8U232AM),
UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_0100, UFTDI_TYPE_AUTO),
UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_0101, UFTDI_TYPE_AUTO),
UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_0102, UFTDI_TYPE_AUTO),
UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_0103, UFTDI_TYPE_AUTO),
UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_0104, UFTDI_TYPE_AUTO),
UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_0105, UFTDI_TYPE_AUTO),
UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_0106, UFTDI_TYPE_AUTO),
UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_0107, UFTDI_TYPE_AUTO),
UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_0108, UFTDI_TYPE_AUTO),
UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_0109, UFTDI_TYPE_AUTO),
UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_010A, UFTDI_TYPE_AUTO),
UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_010B, UFTDI_TYPE_AUTO),
UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_010C, UFTDI_TYPE_AUTO),
UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_010D, UFTDI_TYPE_AUTO),
UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_010E, UFTDI_TYPE_AUTO),
UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_010F, UFTDI_TYPE_AUTO),
UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_0110, UFTDI_TYPE_AUTO),
UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_0111, UFTDI_TYPE_AUTO),
UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_0112, UFTDI_TYPE_AUTO),
UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_0113, UFTDI_TYPE_AUTO),
UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_0114, UFTDI_TYPE_AUTO),
UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_0115, UFTDI_TYPE_AUTO),
UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_0116, UFTDI_TYPE_AUTO),
UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_0117, UFTDI_TYPE_AUTO),
UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_0118, UFTDI_TYPE_AUTO),
UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_0119, UFTDI_TYPE_AUTO),
UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_011A, UFTDI_TYPE_AUTO),
UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_011B, UFTDI_TYPE_AUTO),
UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_011C, UFTDI_TYPE_AUTO),
UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_011D, UFTDI_TYPE_AUTO),
UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_011E, UFTDI_TYPE_AUTO),
UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_011F, UFTDI_TYPE_AUTO),
UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_0120, UFTDI_TYPE_AUTO),
UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_0121, UFTDI_TYPE_AUTO),
UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_0122, UFTDI_TYPE_AUTO),
UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_0123, UFTDI_TYPE_AUTO),
UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_0124, UFTDI_TYPE_AUTO),
UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_0125, UFTDI_TYPE_AUTO),
UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_0126, UFTDI_TYPE_AUTO),
UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_0128, UFTDI_TYPE_AUTO),
UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_0129, UFTDI_TYPE_AUTO),
UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_012A, UFTDI_TYPE_AUTO),
UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_012B, UFTDI_TYPE_AUTO),
UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_012D, UFTDI_TYPE_AUTO),
UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_012E, UFTDI_TYPE_AUTO),
UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_012F, UFTDI_TYPE_AUTO),
UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_0130, UFTDI_TYPE_AUTO),
UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_0131, UFTDI_TYPE_AUTO),
UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_0132, UFTDI_TYPE_AUTO),
UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_0133, UFTDI_TYPE_AUTO),
UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_0134, UFTDI_TYPE_AUTO),
UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_0135, UFTDI_TYPE_AUTO),
UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_0136, UFTDI_TYPE_AUTO),
UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_0137, UFTDI_TYPE_AUTO),
UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_0138, UFTDI_TYPE_AUTO),
UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_0139, UFTDI_TYPE_AUTO),
UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_013A, UFTDI_TYPE_AUTO),
UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_013B, UFTDI_TYPE_AUTO),
UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_013C, UFTDI_TYPE_AUTO),
UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_013D, UFTDI_TYPE_AUTO),
UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_013E, UFTDI_TYPE_AUTO),
UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_013F, UFTDI_TYPE_AUTO),
UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_0140, UFTDI_TYPE_AUTO),
UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_0141, UFTDI_TYPE_AUTO),
UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_0142, UFTDI_TYPE_AUTO),
UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_0143, UFTDI_TYPE_AUTO),
UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_0144, UFTDI_TYPE_AUTO),
UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_0145, UFTDI_TYPE_AUTO),
UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_0146, UFTDI_TYPE_AUTO),
UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_0147, UFTDI_TYPE_AUTO),
UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_0148, UFTDI_TYPE_AUTO),
UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_0149, UFTDI_TYPE_AUTO),
UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_014A, UFTDI_TYPE_AUTO),
UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_014B, UFTDI_TYPE_AUTO),
UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_014C, UFTDI_TYPE_AUTO),
UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_014D, UFTDI_TYPE_AUTO),
UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_014E, UFTDI_TYPE_AUTO),
UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_014F, UFTDI_TYPE_AUTO),
UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_0150, UFTDI_TYPE_AUTO),
UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_0151, UFTDI_TYPE_AUTO),
UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_0152, UFTDI_TYPE_AUTO),
UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_0159, UFTDI_TYPE_AUTO),
UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_015A, UFTDI_TYPE_AUTO),
UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_015B, UFTDI_TYPE_AUTO),
UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_015C, UFTDI_TYPE_AUTO),
UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_015D, UFTDI_TYPE_AUTO),
UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_015E, UFTDI_TYPE_AUTO),
UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_015F, UFTDI_TYPE_AUTO),
UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_0160, UFTDI_TYPE_AUTO),
UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_0161, UFTDI_TYPE_AUTO),
UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_0162, UFTDI_TYPE_AUTO),
UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_0163, UFTDI_TYPE_AUTO),
UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_0164, UFTDI_TYPE_AUTO),
UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_0165, UFTDI_TYPE_AUTO),
UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_0166, UFTDI_TYPE_AUTO),
UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_0167, UFTDI_TYPE_AUTO),
UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_0168, UFTDI_TYPE_AUTO),
UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_0169, UFTDI_TYPE_AUTO),
UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_016A, UFTDI_TYPE_AUTO),
UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_016B, UFTDI_TYPE_AUTO),
UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_016C, UFTDI_TYPE_AUTO),
UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_016D, UFTDI_TYPE_AUTO),
UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_016E, UFTDI_TYPE_AUTO),
UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_016F, UFTDI_TYPE_AUTO),
UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_0170, UFTDI_TYPE_AUTO),
UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_0171, UFTDI_TYPE_AUTO),
UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_0172, UFTDI_TYPE_AUTO),
UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_0173, UFTDI_TYPE_AUTO),
UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_0174, UFTDI_TYPE_AUTO),
UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_0175, UFTDI_TYPE_AUTO),
UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_0176, UFTDI_TYPE_AUTO),
UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_0177, UFTDI_TYPE_AUTO),
UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_0178, UFTDI_TYPE_AUTO),
UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_0179, UFTDI_TYPE_AUTO),
UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_017A, UFTDI_TYPE_AUTO),
UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_017B, UFTDI_TYPE_AUTO),
UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_017C, UFTDI_TYPE_AUTO),
UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_017D, UFTDI_TYPE_AUTO),
UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_017E, UFTDI_TYPE_AUTO),
UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_017F, UFTDI_TYPE_AUTO),
UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_0180, UFTDI_TYPE_AUTO),
UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_0181, UFTDI_TYPE_AUTO),
UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_0182, UFTDI_TYPE_AUTO),
UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_0183, UFTDI_TYPE_AUTO),
UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_0184, UFTDI_TYPE_AUTO),
UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_0185, UFTDI_TYPE_AUTO),
UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_0186, UFTDI_TYPE_AUTO),
UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_0187, UFTDI_TYPE_AUTO),
UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_0188, UFTDI_TYPE_AUTO),
UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_0189, UFTDI_TYPE_AUTO),
UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_018A, UFTDI_TYPE_AUTO),
UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_018B, UFTDI_TYPE_AUTO),
UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_018C, UFTDI_TYPE_AUTO),
UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_018D, UFTDI_TYPE_AUTO),
UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_018E, UFTDI_TYPE_AUTO),
UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_018F, UFTDI_TYPE_AUTO),
UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_0190, UFTDI_TYPE_AUTO),
UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_0191, UFTDI_TYPE_AUTO),
UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_0192, UFTDI_TYPE_AUTO),
UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_0193, UFTDI_TYPE_AUTO),
UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_0194, UFTDI_TYPE_AUTO),
UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_0195, UFTDI_TYPE_AUTO),
UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_0196, UFTDI_TYPE_AUTO),
UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_0197, UFTDI_TYPE_AUTO),
UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_0198, UFTDI_TYPE_AUTO),
UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_0199, UFTDI_TYPE_AUTO),
UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_019A, UFTDI_TYPE_AUTO),
UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_019B, UFTDI_TYPE_AUTO),
UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_019C, UFTDI_TYPE_AUTO),
UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_019D, UFTDI_TYPE_AUTO),
UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_019E, UFTDI_TYPE_AUTO),
UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_019F, UFTDI_TYPE_AUTO),
UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_01A0, UFTDI_TYPE_AUTO),
UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_01A1, UFTDI_TYPE_AUTO),
UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_01A2, UFTDI_TYPE_AUTO),
UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_01A3, UFTDI_TYPE_AUTO),
UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_01A4, UFTDI_TYPE_AUTO),
UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_01A5, UFTDI_TYPE_AUTO),
UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_01A6, UFTDI_TYPE_AUTO),
UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_01A7, UFTDI_TYPE_AUTO),
UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_01A8, UFTDI_TYPE_AUTO),
UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_01A9, UFTDI_TYPE_AUTO),
UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_01AA, UFTDI_TYPE_AUTO),
UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_01AB, UFTDI_TYPE_AUTO),
UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_01AC, UFTDI_TYPE_AUTO),
UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_01AD, UFTDI_TYPE_AUTO),
UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_01AE, UFTDI_TYPE_AUTO),
UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_01AF, UFTDI_TYPE_AUTO),
UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_01B0, UFTDI_TYPE_AUTO),
UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_01B1, UFTDI_TYPE_AUTO),
UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_01B2, UFTDI_TYPE_AUTO),
UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_01B3, UFTDI_TYPE_AUTO),
UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_01B4, UFTDI_TYPE_AUTO),
UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_01B5, UFTDI_TYPE_AUTO),
UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_01B6, UFTDI_TYPE_AUTO),
UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_01B7, UFTDI_TYPE_AUTO),
UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_01B8, UFTDI_TYPE_AUTO),
UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_01B9, UFTDI_TYPE_AUTO),
UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_01BA, UFTDI_TYPE_AUTO),
UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_01BB, UFTDI_TYPE_AUTO),
UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_01BC, UFTDI_TYPE_AUTO),
UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_01BD, UFTDI_TYPE_AUTO),
UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_01BE, UFTDI_TYPE_AUTO),
UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_01BF, UFTDI_TYPE_AUTO),
UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_01C0, UFTDI_TYPE_AUTO),
UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_01C1, UFTDI_TYPE_AUTO),
UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_01C2, UFTDI_TYPE_AUTO),
UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_01C3, UFTDI_TYPE_AUTO),
UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_01C4, UFTDI_TYPE_AUTO),
UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_01C5, UFTDI_TYPE_AUTO),
UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_01C6, UFTDI_TYPE_AUTO),
UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_01C7, UFTDI_TYPE_AUTO),
UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_01C8, UFTDI_TYPE_AUTO),
UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_01C9, UFTDI_TYPE_AUTO),
UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_01CA, UFTDI_TYPE_AUTO),
UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_01CB, UFTDI_TYPE_AUTO),
UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_01CC, UFTDI_TYPE_AUTO),
UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_01CD, UFTDI_TYPE_AUTO),
UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_01CE, UFTDI_TYPE_AUTO),
UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_01CF, UFTDI_TYPE_AUTO),
UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_01D0, UFTDI_TYPE_AUTO),
UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_01D1, UFTDI_TYPE_AUTO),
UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_01D2, UFTDI_TYPE_AUTO),
UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_01D3, UFTDI_TYPE_AUTO),
UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_01D4, UFTDI_TYPE_AUTO),
UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_01D5, UFTDI_TYPE_AUTO),
UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_01D6, UFTDI_TYPE_AUTO),
UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_01D7, UFTDI_TYPE_AUTO),
UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_01D8, UFTDI_TYPE_AUTO),
UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_01D9, UFTDI_TYPE_AUTO),
UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_01DA, UFTDI_TYPE_AUTO),
UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_01DB, UFTDI_TYPE_AUTO),
UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_01DC, UFTDI_TYPE_AUTO),
UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_01DD, UFTDI_TYPE_AUTO),
UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_01DE, UFTDI_TYPE_AUTO),
UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_01DF, UFTDI_TYPE_AUTO),
UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_01E0, UFTDI_TYPE_AUTO),
UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_01E1, UFTDI_TYPE_AUTO),
UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_01E2, UFTDI_TYPE_AUTO),
UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_01E3, UFTDI_TYPE_AUTO),
UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_01E4, UFTDI_TYPE_AUTO),
UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_01E5, UFTDI_TYPE_AUTO),
UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_01E6, UFTDI_TYPE_AUTO),
UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_01E7, UFTDI_TYPE_AUTO),
UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_01E8, UFTDI_TYPE_AUTO),
UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_01E9, UFTDI_TYPE_AUTO),
UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_01EA, UFTDI_TYPE_AUTO),
UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_01EB, UFTDI_TYPE_AUTO),
UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_01EC, UFTDI_TYPE_AUTO),
UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_01ED, UFTDI_TYPE_AUTO),
UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_01EE, UFTDI_TYPE_AUTO),
UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_01EF, UFTDI_TYPE_AUTO),
UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_01F0, UFTDI_TYPE_AUTO),
UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_01F1, UFTDI_TYPE_AUTO),
UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_01F2, UFTDI_TYPE_AUTO),
UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_01F3, UFTDI_TYPE_AUTO),
UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_01F4, UFTDI_TYPE_AUTO),
UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_01F5, UFTDI_TYPE_AUTO),
UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_01F6, UFTDI_TYPE_AUTO),
UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_01F7, UFTDI_TYPE_AUTO),
UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_01F8, UFTDI_TYPE_AUTO),
UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_01F9, UFTDI_TYPE_AUTO),
UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_01FA, UFTDI_TYPE_AUTO),
UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_01FB, UFTDI_TYPE_AUTO),
UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_01FC, UFTDI_TYPE_AUTO),
UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_01FD, UFTDI_TYPE_AUTO),
UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_01FE, UFTDI_TYPE_AUTO),
UFTDI_DEV(MATRIXORBITAL, FTDI_RANGE_01FF, UFTDI_TYPE_AUTO),
UFTDI_DEV(MATRIXORBITAL, MOUA, UFTDI_TYPE_8U232AM),
UFTDI_DEV(MELCO, PCOPRS1, UFTDI_TYPE_8U232AM),
UFTDI_DEV(METAGEEK, TELLSTICK, UFTDI_TYPE_AUTO),
UFTDI_DEV(MOBILITY, USB_SERIAL, UFTDI_TYPE_AUTO),
UFTDI_DEV(OLIMEX, ARM_USB_OCD, UFTDI_TYPE_AUTO | UFTDI_FLAG_JTAG),
UFTDI_DEV(OLIMEX, ARM_USB_OCD_H, UFTDI_TYPE_AUTO | UFTDI_FLAG_JTAG),
UFTDI_DEV(OPTO, CRD7734, UFTDI_TYPE_AUTO),
UFTDI_DEV(OPTO, CRD7734_1, UFTDI_TYPE_AUTO),
UFTDI_DEV(PAPOUCH, AD4USB, UFTDI_TYPE_AUTO),
UFTDI_DEV(PAPOUCH, AP485, UFTDI_TYPE_AUTO),
UFTDI_DEV(PAPOUCH, AP485_2, UFTDI_TYPE_AUTO),
UFTDI_DEV(PAPOUCH, DRAK5, UFTDI_TYPE_AUTO),
UFTDI_DEV(PAPOUCH, DRAK6, UFTDI_TYPE_AUTO),
UFTDI_DEV(PAPOUCH, GMSR, UFTDI_TYPE_AUTO),
UFTDI_DEV(PAPOUCH, GMUX, UFTDI_TYPE_AUTO),
UFTDI_DEV(PAPOUCH, IRAMP, UFTDI_TYPE_AUTO),
UFTDI_DEV(PAPOUCH, LEC, UFTDI_TYPE_AUTO),
UFTDI_DEV(PAPOUCH, MU, UFTDI_TYPE_AUTO),
UFTDI_DEV(PAPOUCH, QUIDO10X1, UFTDI_TYPE_AUTO),
UFTDI_DEV(PAPOUCH, QUIDO2X16, UFTDI_TYPE_AUTO),
UFTDI_DEV(PAPOUCH, QUIDO2X2, UFTDI_TYPE_AUTO),
UFTDI_DEV(PAPOUCH, QUIDO30X3, UFTDI_TYPE_AUTO),
UFTDI_DEV(PAPOUCH, QUIDO3X32, UFTDI_TYPE_AUTO),
UFTDI_DEV(PAPOUCH, QUIDO4X4, UFTDI_TYPE_AUTO),
UFTDI_DEV(PAPOUCH, QUIDO60X3, UFTDI_TYPE_AUTO),
UFTDI_DEV(PAPOUCH, QUIDO8X8, UFTDI_TYPE_AUTO),
UFTDI_DEV(PAPOUCH, SB232, UFTDI_TYPE_AUTO),
UFTDI_DEV(PAPOUCH, SB422, UFTDI_TYPE_AUTO),
UFTDI_DEV(PAPOUCH, SB422_2, UFTDI_TYPE_AUTO),
UFTDI_DEV(PAPOUCH, SB485, UFTDI_TYPE_AUTO),
UFTDI_DEV(PAPOUCH, SB485C, UFTDI_TYPE_AUTO),
UFTDI_DEV(PAPOUCH, SB485S, UFTDI_TYPE_AUTO),
UFTDI_DEV(PAPOUCH, SB485_2, UFTDI_TYPE_AUTO),
UFTDI_DEV(PAPOUCH, SIMUKEY, UFTDI_TYPE_AUTO),
UFTDI_DEV(PAPOUCH, TMU, UFTDI_TYPE_AUTO),
UFTDI_DEV(PAPOUCH, UPSUSB, UFTDI_TYPE_AUTO),
UFTDI_DEV(POSIFLEX, PP7000, UFTDI_TYPE_AUTO),
UFTDI_DEV(QIHARDWARE, JTAGSERIAL, UFTDI_TYPE_AUTO | UFTDI_FLAG_JTAG),
UFTDI_DEV(RATOC, REXUSB60F, UFTDI_TYPE_8U232AM),
UFTDI_DEV(RTSYSTEMS, CT29B, UFTDI_TYPE_AUTO),
UFTDI_DEV(RTSYSTEMS, SERIAL_VX7, UFTDI_TYPE_AUTO),
UFTDI_DEV(SEALEVEL, 2101, UFTDI_TYPE_AUTO),
UFTDI_DEV(SEALEVEL, 2102, UFTDI_TYPE_AUTO),
UFTDI_DEV(SEALEVEL, 2103, UFTDI_TYPE_AUTO),
UFTDI_DEV(SEALEVEL, 2104, UFTDI_TYPE_AUTO),
UFTDI_DEV(SEALEVEL, 2106, UFTDI_TYPE_AUTO),
UFTDI_DEV(SEALEVEL, 2201_1, UFTDI_TYPE_AUTO),
UFTDI_DEV(SEALEVEL, 2201_2, UFTDI_TYPE_AUTO),
UFTDI_DEV(SEALEVEL, 2202_1, UFTDI_TYPE_AUTO),
UFTDI_DEV(SEALEVEL, 2202_2, UFTDI_TYPE_AUTO),
UFTDI_DEV(SEALEVEL, 2203_1, UFTDI_TYPE_AUTO),
UFTDI_DEV(SEALEVEL, 2203_2, UFTDI_TYPE_AUTO),
UFTDI_DEV(SEALEVEL, 2401_1, UFTDI_TYPE_AUTO),
UFTDI_DEV(SEALEVEL, 2401_2, UFTDI_TYPE_AUTO),
UFTDI_DEV(SEALEVEL, 2401_3, UFTDI_TYPE_AUTO),
UFTDI_DEV(SEALEVEL, 2401_4, UFTDI_TYPE_AUTO),
UFTDI_DEV(SEALEVEL, 2402_1, UFTDI_TYPE_AUTO),
UFTDI_DEV(SEALEVEL, 2402_2, UFTDI_TYPE_AUTO),
UFTDI_DEV(SEALEVEL, 2402_3, UFTDI_TYPE_AUTO),
UFTDI_DEV(SEALEVEL, 2402_4, UFTDI_TYPE_AUTO),
UFTDI_DEV(SEALEVEL, 2403_1, UFTDI_TYPE_AUTO),
UFTDI_DEV(SEALEVEL, 2403_2, UFTDI_TYPE_AUTO),
UFTDI_DEV(SEALEVEL, 2403_3, UFTDI_TYPE_AUTO),
UFTDI_DEV(SEALEVEL, 2403_4, UFTDI_TYPE_AUTO),
UFTDI_DEV(SEALEVEL, 2801_1, UFTDI_TYPE_AUTO),
UFTDI_DEV(SEALEVEL, 2801_2, UFTDI_TYPE_AUTO),
UFTDI_DEV(SEALEVEL, 2801_3, UFTDI_TYPE_AUTO),
UFTDI_DEV(SEALEVEL, 2801_4, UFTDI_TYPE_AUTO),
UFTDI_DEV(SEALEVEL, 2801_5, UFTDI_TYPE_AUTO),
UFTDI_DEV(SEALEVEL, 2801_6, UFTDI_TYPE_AUTO),
UFTDI_DEV(SEALEVEL, 2801_7, UFTDI_TYPE_AUTO),
UFTDI_DEV(SEALEVEL, 2801_8, UFTDI_TYPE_AUTO),
UFTDI_DEV(SEALEVEL, 2802_1, UFTDI_TYPE_AUTO),
UFTDI_DEV(SEALEVEL, 2802_2, UFTDI_TYPE_AUTO),
UFTDI_DEV(SEALEVEL, 2802_3, UFTDI_TYPE_AUTO),
UFTDI_DEV(SEALEVEL, 2802_4, UFTDI_TYPE_AUTO),
UFTDI_DEV(SEALEVEL, 2802_5, UFTDI_TYPE_AUTO),
UFTDI_DEV(SEALEVEL, 2802_6, UFTDI_TYPE_AUTO),
UFTDI_DEV(SEALEVEL, 2802_7, UFTDI_TYPE_AUTO),
UFTDI_DEV(SEALEVEL, 2802_8, UFTDI_TYPE_AUTO),
UFTDI_DEV(SEALEVEL, 2803_1, UFTDI_TYPE_AUTO),
UFTDI_DEV(SEALEVEL, 2803_2, UFTDI_TYPE_AUTO),
UFTDI_DEV(SEALEVEL, 2803_3, UFTDI_TYPE_AUTO),
UFTDI_DEV(SEALEVEL, 2803_4, UFTDI_TYPE_AUTO),
UFTDI_DEV(SEALEVEL, 2803_5, UFTDI_TYPE_AUTO),
UFTDI_DEV(SEALEVEL, 2803_6, UFTDI_TYPE_AUTO),
UFTDI_DEV(SEALEVEL, 2803_7, UFTDI_TYPE_AUTO),
UFTDI_DEV(SEALEVEL, 2803_8, UFTDI_TYPE_AUTO),
UFTDI_DEV(SIIG2, DK201, UFTDI_TYPE_AUTO),
UFTDI_DEV(SIIG2, US2308, UFTDI_TYPE_8U232AM),
UFTDI_DEV(TESTO, USB_INTERFACE, UFTDI_TYPE_AUTO),
UFTDI_DEV(TML, USB_SERIAL, UFTDI_TYPE_AUTO),
UFTDI_DEV(TTI, QL355P, UFTDI_TYPE_AUTO),
UFTDI_DEV(UNKNOWN4, NF_RIC, UFTDI_TYPE_AUTO),
#undef UFTDI_DEV
};
/*
* Set up softc fields whose value depends on the device type.
*
* Note that the 2232C and 2232D devices are the same for our purposes. In the
* silicon the difference is that the D series has CPU FIFO mode and C doesn't.
* I haven't found any way of determining the C/D difference from info provided
* by the chip other than trying to set CPU FIFO mode and having it work or not.
*
* Due to a hardware bug, a 232B chip without an eeprom reports itself as a
* 232A, but if the serial number is also zero we know it's really a 232B.
*/
static void
uftdi_devtype_setup(struct uftdi_softc *sc, struct usb_attach_arg *uaa)
{
struct usb_device_descriptor *dd;
switch (uaa->info.bcdDevice) {
case 0x200:
dd = usbd_get_device_descriptor(sc->sc_udev);
if (dd->iSerialNumber == 0) {
sc->sc_devtype = DEVT_232B;
} else {
sc->sc_devtype = DEVT_232A;
}
sc->sc_ucom.sc_portno = 0;
break;
case 0x400:
sc->sc_devtype = DEVT_232B;
sc->sc_ucom.sc_portno = 0;
break;
case 0x500:
sc->sc_devtype = DEVT_2232D;
sc->sc_devflags |= DEVF_BAUDBITS_HINDEX;
sc->sc_ucom.sc_portno = FTDI_PIT_SIOA + uaa->info.bIfaceNum;
break;
case 0x600:
sc->sc_devtype = DEVT_232R;
sc->sc_ucom.sc_portno = 0;
break;
case 0x700:
sc->sc_devtype = DEVT_2232H;
sc->sc_devflags |= DEVF_BAUDBITS_HINDEX | DEVF_BAUDCLK_12M;
sc->sc_ucom.sc_portno = FTDI_PIT_SIOA + uaa->info.bIfaceNum;
break;
case 0x800:
sc->sc_devtype = DEVT_4232H;
sc->sc_devflags |= DEVF_BAUDBITS_HINDEX | DEVF_BAUDCLK_12M;
sc->sc_ucom.sc_portno = FTDI_PIT_SIOA + uaa->info.bIfaceNum;
break;
case 0x900:
sc->sc_devtype = DEVT_232H;
sc->sc_devflags |= DEVF_BAUDBITS_HINDEX | DEVF_BAUDCLK_12M;
sc->sc_ucom.sc_portno = FTDI_PIT_SIOA + uaa->info.bIfaceNum;
break;
case 0x1000:
sc->sc_devtype = DEVT_230X;
sc->sc_devflags |= DEVF_BAUDBITS_HINDEX;
sc->sc_ucom.sc_portno = FTDI_PIT_SIOA + uaa->info.bIfaceNum;
break;
default:
if (uaa->info.bcdDevice < 0x200) {
sc->sc_devtype = DEVT_SIO;
sc->sc_hdrlen = 1;
} else {
sc->sc_devtype = DEVT_232R;
device_printf(sc->sc_dev, "Warning: unknown FTDI "
"device type, bcdDevice=0x%04x, assuming 232R",
uaa->info.bcdDevice);
}
sc->sc_ucom.sc_portno = 0;
break;
}
}
static int
uftdi_probe(device_t dev)
{
struct usb_attach_arg *uaa = device_get_ivars(dev);
const struct usb_device_id *id;
if (uaa->usb_mode != USB_MODE_HOST) {
return (ENXIO);
}
if (uaa->info.bConfigIndex != UFTDI_CONFIG_INDEX) {
return (ENXIO);
}
/*
* Attach to all present interfaces unless this is a JTAG one, which
* we leave for userland.
*/
id = usbd_lookup_id_by_info(uftdi_devs, sizeof(uftdi_devs),
&uaa->info);
if (id == NULL)
return (ENXIO);
if ((id->driver_info & UFTDI_FLAG_JTAG) != 0 &&
uaa->info.bIfaceIndex == UFTDI_IFACE_INDEX_JTAG) {
printf("%s: skipping JTAG interface at %u.%u\n",
device_get_name(dev), usbd_get_bus_index(uaa->device),
usbd_get_device_index(uaa->device));
return (ENXIO);
}
uaa->driver_info = id->driver_info;
return (BUS_PROBE_SPECIFIC);
}
static int
uftdi_attach(device_t dev)
{
struct usb_attach_arg *uaa = device_get_ivars(dev);
struct uftdi_softc *sc = device_get_softc(dev);
int error;
DPRINTF("\n");
sc->sc_udev = uaa->device;
sc->sc_dev = dev;
sc->sc_unit = device_get_unit(dev);
device_set_usb_desc(dev);
mtx_init(&sc->sc_mtx, "uftdi", NULL, MTX_DEF);
ucom_ref(&sc->sc_super_ucom);
uftdi_devtype_setup(sc, uaa);
error = usbd_transfer_setup(uaa->device,
&uaa->info.bIfaceIndex, sc->sc_xfer, uftdi_config,
UFTDI_N_TRANSFER, sc, &sc->sc_mtx);
if (error) {
device_printf(dev, "allocating USB "
"transfers failed\n");
goto detach;
}
/* clear stall at first run */
mtx_lock(&sc->sc_mtx);
usbd_xfer_set_stall(sc->sc_xfer[UFTDI_BULK_DT_WR]);
usbd_xfer_set_stall(sc->sc_xfer[UFTDI_BULK_DT_RD]);
mtx_unlock(&sc->sc_mtx);
/* set a valid "lcr" value */
sc->sc_last_lcr =
(FTDI_SIO_SET_DATA_STOP_BITS_2 |
FTDI_SIO_SET_DATA_PARITY_NONE |
FTDI_SIO_SET_DATA_BITS(8));
error = ucom_attach(&sc->sc_super_ucom, &sc->sc_ucom, 1, sc,
&uftdi_callback, &sc->sc_mtx);
if (error) {
goto detach;
}
ucom_set_pnpinfo_usb(&sc->sc_super_ucom, dev);
return (0); /* success */
detach:
uftdi_detach(dev);
return (ENXIO);
}
static int
uftdi_detach(device_t dev)
{
struct uftdi_softc *sc = device_get_softc(dev);
ucom_detach(&sc->sc_super_ucom, &sc->sc_ucom);
usbd_transfer_unsetup(sc->sc_xfer, UFTDI_N_TRANSFER);
device_claim_softc(dev);
uftdi_free_softc(sc);
return (0);
}
UCOM_UNLOAD_DRAIN(uftdi);
static void
uftdi_free_softc(struct uftdi_softc *sc)
{
if (ucom_unref(&sc->sc_super_ucom)) {
mtx_destroy(&sc->sc_mtx);
device_free_softc(sc);
}
}
static void
uftdi_free(struct ucom_softc *ucom)
{
uftdi_free_softc(ucom->sc_parent);
}
static void
uftdi_cfg_open(struct ucom_softc *ucom)
{
struct uftdi_softc *sc = ucom->sc_parent;
uint16_t wIndex = ucom->sc_portno;
struct usb_device_request req;
DPRINTF("");
/* perform a full reset on the device */
req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
req.bRequest = FTDI_SIO_RESET;
USETW(req.wValue, FTDI_SIO_RESET_SIO);
USETW(req.wIndex, wIndex);
USETW(req.wLength, 0);
ucom_cfg_do_request(sc->sc_udev, &sc->sc_ucom,
&req, NULL, 0, 1000);
/* turn on RTS/CTS flow control */
req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
req.bRequest = FTDI_SIO_SET_FLOW_CTRL;
USETW(req.wValue, 0);
USETW2(req.wIndex, FTDI_SIO_RTS_CTS_HS, wIndex);
USETW(req.wLength, 0);
ucom_cfg_do_request(sc->sc_udev, &sc->sc_ucom,
&req, NULL, 0, 1000);
/*
* NOTE: with the new UCOM layer there will always be a
* "uftdi_cfg_param()" call after "open()", so there is no need for
* "open()" to configure anything
*/
}
static void
uftdi_write_callback(struct usb_xfer *xfer, usb_error_t error)
{
struct uftdi_softc *sc = usbd_xfer_softc(xfer);
struct usb_page_cache *pc;
uint32_t pktlen;
uint32_t buflen;
uint8_t buf[1];
switch (USB_GET_STATE(xfer)) {
default: /* Error */
if (error != USB_ERR_CANCELLED) {
/* try to clear stall first */
usbd_xfer_set_stall(xfer);
}
/* FALLTHROUGH */
case USB_ST_SETUP:
case USB_ST_TRANSFERRED:
/*
* If output packets don't require headers (the common case) we
* can just load the buffer up with payload bytes all at once.
* Otherwise, loop to format packets into the buffer while there
* is data available, and room for a packet header and at least
* one byte of payload.
*/
pc = usbd_xfer_get_frame(xfer, 0);
if (sc->sc_hdrlen == 0) {
ucom_get_data(&sc->sc_ucom, pc, 0, UFTDI_OBUFSIZE,
&buflen);
} else {
buflen = 0;
while (buflen < UFTDI_OBUFSIZE - sc->sc_hdrlen - 1 &&
ucom_get_data(&sc->sc_ucom, pc, buflen +
sc->sc_hdrlen, UFTDI_OPKTSIZE - sc->sc_hdrlen,
&pktlen) != 0) {
buf[0] = FTDI_OUT_TAG(pktlen,
sc->sc_ucom.sc_portno);
usbd_copy_in(pc, buflen, buf, 1);
buflen += pktlen + sc->sc_hdrlen;
}
}
if (buflen != 0) {
usbd_xfer_set_frame_len(xfer, 0, buflen);
usbd_transfer_submit(xfer);
}
break;
}
}
static void
uftdi_read_callback(struct usb_xfer *xfer, usb_error_t error)
{
struct uftdi_softc *sc = usbd_xfer_softc(xfer);
struct usb_page_cache *pc;
uint8_t buf[2];
uint8_t ftdi_msr;
uint8_t msr;
uint8_t lsr;
int buflen;
int pktlen;
int pktmax;
int offset;
usbd_xfer_status(xfer, &buflen, NULL, NULL, NULL);
switch (USB_GET_STATE(xfer)) {
case USB_ST_TRANSFERRED:
if (buflen < UFTDI_IHDRSIZE)
goto tr_setup;
pc = usbd_xfer_get_frame(xfer, 0);
pktmax = xfer->max_packet_size - UFTDI_IHDRSIZE;
lsr = 0;
msr = 0;
offset = 0;
/*
* Extract packet headers and payload bytes from the buffer.
* Feed payload bytes to ucom/tty layer; OR-accumulate header
* status bits which are transient and could toggle with each
* packet. After processing all packets in the buffer, process
* the accumulated transient MSR and LSR values along with the
* non-transient bits from the last packet header.
*/
while (buflen >= UFTDI_IHDRSIZE) {
usbd_copy_out(pc, offset, buf, UFTDI_IHDRSIZE);
offset += UFTDI_IHDRSIZE;
buflen -= UFTDI_IHDRSIZE;
lsr |= FTDI_GET_LSR(buf);
if (FTDI_GET_MSR(buf) & FTDI_SIO_RI_MASK)
msr |= SER_RI;
pktlen = min(buflen, pktmax);
if (pktlen != 0) {
ucom_put_data(&sc->sc_ucom, pc, offset,
pktlen);
offset += pktlen;
buflen -= pktlen;
}
}
ftdi_msr = FTDI_GET_MSR(buf);
if (ftdi_msr & FTDI_SIO_CTS_MASK)
msr |= SER_CTS;
if (ftdi_msr & FTDI_SIO_DSR_MASK)
msr |= SER_DSR;
if (ftdi_msr & FTDI_SIO_RI_MASK)
msr |= SER_RI;
if (ftdi_msr & FTDI_SIO_RLSD_MASK)
msr |= SER_DCD;
if ((sc->sc_msr != msr) ||
((sc->sc_lsr & FTDI_LSR_MASK) != (lsr & FTDI_LSR_MASK))) {
DPRINTF("status change msr=0x%02x (0x%02x) "
"lsr=0x%02x (0x%02x)\n", msr, sc->sc_msr,
lsr, sc->sc_lsr);
sc->sc_msr = msr;
sc->sc_lsr = lsr;
ucom_status_change(&sc->sc_ucom);
}
/* FALLTHROUGH */
case USB_ST_SETUP:
tr_setup:
usbd_xfer_set_frame_len(xfer, 0, usbd_xfer_max_len(xfer));
usbd_transfer_submit(xfer);
return;
default: /* Error */
if (error != USB_ERR_CANCELLED) {
/* try to clear stall first */
usbd_xfer_set_stall(xfer);
goto tr_setup;
}
return;
}
}
static void
uftdi_cfg_set_dtr(struct ucom_softc *ucom, uint8_t onoff)
{
struct uftdi_softc *sc = ucom->sc_parent;
uint16_t wIndex = ucom->sc_portno;
uint16_t wValue;
struct usb_device_request req;
wValue = onoff ? FTDI_SIO_SET_DTR_HIGH : FTDI_SIO_SET_DTR_LOW;
req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
req.bRequest = FTDI_SIO_MODEM_CTRL;
USETW(req.wValue, wValue);
USETW(req.wIndex, wIndex);
USETW(req.wLength, 0);
ucom_cfg_do_request(sc->sc_udev, &sc->sc_ucom,
&req, NULL, 0, 1000);
}
static void
uftdi_cfg_set_rts(struct ucom_softc *ucom, uint8_t onoff)
{
struct uftdi_softc *sc = ucom->sc_parent;
uint16_t wIndex = ucom->sc_portno;
uint16_t wValue;
struct usb_device_request req;
wValue = onoff ? FTDI_SIO_SET_RTS_HIGH : FTDI_SIO_SET_RTS_LOW;
req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
req.bRequest = FTDI_SIO_MODEM_CTRL;
USETW(req.wValue, wValue);
USETW(req.wIndex, wIndex);
USETW(req.wLength, 0);
ucom_cfg_do_request(sc->sc_udev, &sc->sc_ucom,
&req, NULL, 0, 1000);
}
static void
uftdi_cfg_set_break(struct ucom_softc *ucom, uint8_t onoff)
{
struct uftdi_softc *sc = ucom->sc_parent;
uint16_t wIndex = ucom->sc_portno;
uint16_t wValue;
struct usb_device_request req;
if (onoff) {
sc->sc_last_lcr |= FTDI_SIO_SET_BREAK;
} else {
sc->sc_last_lcr &= ~FTDI_SIO_SET_BREAK;
}
wValue = sc->sc_last_lcr;
req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
req.bRequest = FTDI_SIO_SET_DATA;
USETW(req.wValue, wValue);
USETW(req.wIndex, wIndex);
USETW(req.wLength, 0);
ucom_cfg_do_request(sc->sc_udev, &sc->sc_ucom,
&req, NULL, 0, 1000);
}
/*
* Return true if the given speed is within operational tolerance of the target
* speed. FTDI recommends that the hardware speed be within 3% of nominal.
*/
static inline boolean_t
uftdi_baud_within_tolerance(uint64_t speed, uint64_t target)
{
return ((speed >= (target * 100) / 103) &&
(speed <= (target * 100) / 97));
}
static int
uftdi_sio_encode_baudrate(struct uftdi_softc *sc, speed_t speed,
struct uftdi_param_config *cfg)
{
u_int i;
const speed_t sio_speeds[] = {
300, 600, 1200, 2400, 4800, 9600, 19200, 38400, 57600, 115200
};
/*
* The original SIO chips were limited to a small choice of speeds
* listed in an internal table of speeds chosen by an index value.
*/
for (i = 0; i < nitems(sio_speeds); ++i) {
if (speed == sio_speeds[i]) {
cfg->baud_lobits = i;
cfg->baud_hibits = 0;
return (0);
}
}
return (ERANGE);
}
static int
uftdi_encode_baudrate(struct uftdi_softc *sc, speed_t speed,
struct uftdi_param_config *cfg)
{
static const uint8_t encoded_fraction[8] = {0, 3, 2, 4, 1, 5, 6, 7};
static const uint8_t roundoff_232a[16] = {
0, 1, 0, 1, 0, -1, 2, 1,
0, -1, -2, -3, 4, 3, 2, 1,
};
uint32_t clk, divisor, fastclk_flag, frac, hwspeed;
/*
* If this chip has the fast clock capability and the speed is within
* range, use the 12MHz clock, otherwise the standard clock is 3MHz.
*/
if ((sc->sc_devflags & DEVF_BAUDCLK_12M) && speed >= 1200) {
clk = 12000000;
fastclk_flag = (1 << 17);
} else {
clk = 3000000;
fastclk_flag = 0;
}
/*
* Make sure the requested speed is reachable with the available clock
* and a 14-bit divisor.
*/
if (speed < (clk >> 14) || speed > clk)
return (ERANGE);
/*
* Calculate the divisor, initially yielding a fixed point number with a
* 4-bit (1/16ths) fraction, then round it to the nearest fraction the
* hardware can handle. When the integral part of the divisor is
* greater than one, the fractional part is in 1/8ths of the base clock.
* The FT8U232AM chips can handle only 0.125, 0.250, and 0.5 fractions.
* Later chips can handle all 1/8th fractions.
*
* If the integral part of the divisor is 1, a special rule applies: the
* fractional part can only be .0 or .5 (this is a limitation of the
* hardware). We handle this by truncating the fraction rather than
* rounding, because this only applies to the two fastest speeds the
* chip can achieve and rounding doesn't matter, either you've asked for
* that exact speed or you've asked for something the chip can't do.
*
* For the FT8U232AM chips, use a roundoff table to adjust the result
* to the nearest 1/8th fraction that is supported by the hardware,
* leaving a fixed-point number with a 3-bit fraction which exactly
* represents the math the hardware divider will do. For later-series
* chips that support all 8 fractional divisors, just round 16ths to
* 8ths by adding 1 and dividing by 2.
*/
divisor = (clk << 4) / speed;
if ((divisor & 0xfffffff0) == 1)
divisor &= 0xfffffff8;
else if (sc->sc_devtype == DEVT_232A)
divisor += roundoff_232a[divisor & 0x0f];
else
divisor += 1; /* Rounds odd 16ths up to next 8th. */
divisor >>= 1;
/*
* Ensure the resulting hardware speed will be within operational
* tolerance (within 3% of nominal).
*/
hwspeed = (clk << 3) / divisor;
if (!uftdi_baud_within_tolerance(hwspeed, speed))
return (ERANGE);
/*
* Re-pack the divisor into hardware format. The lower 14-bits hold the
* integral part, while the upper bits specify the fraction by indexing
* a table of fractions within the hardware which is laid out as:
* {0.0, 0.5, 0.25, 0.125, 0.325, 0.625, 0.725, 0.875}
* The A-series chips only have the first four table entries; the
* roundoff table logic above ensures that the fractional part for those
* chips will be one of the first four values.
*
* When the divisor is 1 a special encoding applies: 1.0 is encoded as
* 0.0, and 1.5 is encoded as 1.0. The rounding logic above has already
* ensured that the fraction is either .0 or .5 if the integral is 1.
*/
frac = divisor & 0x07;
divisor >>= 3;
if (divisor == 1) {
if (frac == 0)
divisor = 0; /* 1.0 becomes 0.0 */
else
frac = 0; /* 1.5 becomes 1.0 */
}
divisor |= (encoded_fraction[frac] << 14) | fastclk_flag;
cfg->baud_lobits = (uint16_t)divisor;
cfg->baud_hibits = (uint16_t)(divisor >> 16);
/*
* If this chip requires the baud bits to be in the high byte of the
* index word, move the bits up to that location.
*/
if (sc->sc_devflags & DEVF_BAUDBITS_HINDEX) {
cfg->baud_hibits <<= 8;
}
return (0);
}
static int
uftdi_set_parm_soft(struct ucom_softc *ucom, struct termios *t,
struct uftdi_param_config *cfg)
{
struct uftdi_softc *sc = ucom->sc_parent;
int err;
memset(cfg, 0, sizeof(*cfg));
if (sc->sc_devtype == DEVT_SIO)
err = uftdi_sio_encode_baudrate(sc, t->c_ospeed, cfg);
else
err = uftdi_encode_baudrate(sc, t->c_ospeed, cfg);
if (err != 0)
return (err);
if (t->c_cflag & CSTOPB)
cfg->lcr = FTDI_SIO_SET_DATA_STOP_BITS_2;
else
cfg->lcr = FTDI_SIO_SET_DATA_STOP_BITS_1;
if (t->c_cflag & PARENB) {
if (t->c_cflag & PARODD) {
cfg->lcr |= FTDI_SIO_SET_DATA_PARITY_ODD;
} else {
cfg->lcr |= FTDI_SIO_SET_DATA_PARITY_EVEN;
}
} else {
cfg->lcr |= FTDI_SIO_SET_DATA_PARITY_NONE;
}
switch (t->c_cflag & CSIZE) {
case CS5:
cfg->lcr |= FTDI_SIO_SET_DATA_BITS(5);
break;
case CS6:
cfg->lcr |= FTDI_SIO_SET_DATA_BITS(6);
break;
case CS7:
cfg->lcr |= FTDI_SIO_SET_DATA_BITS(7);
break;
case CS8:
cfg->lcr |= FTDI_SIO_SET_DATA_BITS(8);
break;
}
if (t->c_cflag & CRTSCTS) {
cfg->v_flow = FTDI_SIO_RTS_CTS_HS;
} else if (t->c_iflag & (IXON | IXOFF)) {
cfg->v_flow = FTDI_SIO_XON_XOFF_HS;
cfg->v_start = t->c_cc[VSTART];
cfg->v_stop = t->c_cc[VSTOP];
} else {
cfg->v_flow = FTDI_SIO_DISABLE_FLOW_CTRL;
}
return (0);
}
static int
uftdi_pre_param(struct ucom_softc *ucom, struct termios *t)
{
struct uftdi_param_config cfg;
DPRINTF("\n");
return (uftdi_set_parm_soft(ucom, t, &cfg));
}
static void
uftdi_cfg_param(struct ucom_softc *ucom, struct termios *t)
{
struct uftdi_softc *sc = ucom->sc_parent;
uint16_t wIndex = ucom->sc_portno;
struct uftdi_param_config cfg;
struct usb_device_request req;
if (uftdi_set_parm_soft(ucom, t, &cfg)) {
/* should not happen */
return;
}
sc->sc_last_lcr = cfg.lcr;
DPRINTF("\n");
req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
req.bRequest = FTDI_SIO_SET_BAUD_RATE;
USETW(req.wValue, cfg.baud_lobits);
USETW(req.wIndex, cfg.baud_hibits | wIndex);
USETW(req.wLength, 0);
ucom_cfg_do_request(sc->sc_udev, &sc->sc_ucom,
&req, NULL, 0, 1000);
req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
req.bRequest = FTDI_SIO_SET_DATA;
USETW(req.wValue, cfg.lcr);
USETW(req.wIndex, wIndex);
USETW(req.wLength, 0);
ucom_cfg_do_request(sc->sc_udev, &sc->sc_ucom,
&req, NULL, 0, 1000);
req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
req.bRequest = FTDI_SIO_SET_FLOW_CTRL;
USETW2(req.wValue, cfg.v_stop, cfg.v_start);
USETW2(req.wIndex, cfg.v_flow, wIndex);
USETW(req.wLength, 0);
ucom_cfg_do_request(sc->sc_udev, &sc->sc_ucom,
&req, NULL, 0, 1000);
}
static void
uftdi_cfg_get_status(struct ucom_softc *ucom, uint8_t *lsr, uint8_t *msr)
{
struct uftdi_softc *sc = ucom->sc_parent;
DPRINTF("msr=0x%02x lsr=0x%02x\n",
sc->sc_msr, sc->sc_lsr);
*msr = sc->sc_msr;
*lsr = sc->sc_lsr;
}
static void
uftdi_start_read(struct ucom_softc *ucom)
{
struct uftdi_softc *sc = ucom->sc_parent;
usbd_transfer_start(sc->sc_xfer[UFTDI_BULK_DT_RD]);
}
static void
uftdi_stop_read(struct ucom_softc *ucom)
{
struct uftdi_softc *sc = ucom->sc_parent;
usbd_transfer_stop(sc->sc_xfer[UFTDI_BULK_DT_RD]);
}
static void
uftdi_start_write(struct ucom_softc *ucom)
{
struct uftdi_softc *sc = ucom->sc_parent;
usbd_transfer_start(sc->sc_xfer[UFTDI_BULK_DT_WR]);
}
static void
uftdi_stop_write(struct ucom_softc *ucom)
{
struct uftdi_softc *sc = ucom->sc_parent;
usbd_transfer_stop(sc->sc_xfer[UFTDI_BULK_DT_WR]);
}
static void
uftdi_poll(struct ucom_softc *ucom)
{
struct uftdi_softc *sc = ucom->sc_parent;
usbd_transfer_poll(sc->sc_xfer, UFTDI_N_TRANSFER);
}