xref: /openbmc/linux/drivers/usb/serial/ftdi_sio.c (revision 58bb229d)
15fd54aceSGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0+
21da177e4SLinus Torvalds /*
31da177e4SLinus Torvalds  * USB FTDI SIO driver
41da177e4SLinus Torvalds  *
5659597b7SJohan Hovold  *	Copyright (C) 2009 - 2013
6d3901a06SJohan Hovold  *	    Johan Hovold (jhovold@gmail.com)
71da177e4SLinus Torvalds  *	Copyright (C) 1999 - 2001
81da177e4SLinus Torvalds  *	    Greg Kroah-Hartman (greg@kroah.com)
91da177e4SLinus Torvalds  *          Bill Ryder (bryder@sgi.com)
101da177e4SLinus Torvalds  *	Copyright (C) 2002
111da177e4SLinus Torvalds  *	    Kuba Ober (kuba@mareimbrium.org)
121da177e4SLinus Torvalds  *
13ecefae6dSMauro Carvalho Chehab  * See Documentation/usb/usb-serial.rst for more information on using this
14464cbb24SAlan Cox  * driver
151da177e4SLinus Torvalds  *
161da177e4SLinus Torvalds  * See http://ftdi-usb-sio.sourceforge.net for up to date testing info
171da177e4SLinus Torvalds  *	and extra documentation
181da177e4SLinus Torvalds  *
19504b55ccSGreg Kroah-Hartman  * Change entries from 2004 and earlier can be found in versions of this
20504b55ccSGreg Kroah-Hartman  * file in kernel versions prior to the 2.6.24 release.
211da177e4SLinus Torvalds  *
221da177e4SLinus Torvalds  */
231da177e4SLinus Torvalds 
241da177e4SLinus Torvalds /* Bill Ryder - bryder@sgi.com - wrote the FTDI_SIO implementation */
251da177e4SLinus Torvalds /* Thanx to FTDI for so kindly providing details of the protocol required */
261da177e4SLinus Torvalds /*   to talk to the device */
27464cbb24SAlan Cox /* Thanx to gkh and the rest of the usb dev group for all code I have
28464cbb24SAlan Cox    assimilated :-) */
291da177e4SLinus Torvalds 
301da177e4SLinus Torvalds #include <linux/kernel.h>
311da177e4SLinus Torvalds #include <linux/errno.h>
321da177e4SLinus Torvalds #include <linux/slab.h>
331da177e4SLinus Torvalds #include <linux/tty.h>
341da177e4SLinus Torvalds #include <linux/tty_driver.h>
351da177e4SLinus Torvalds #include <linux/tty_flip.h>
361da177e4SLinus Torvalds #include <linux/module.h>
371da177e4SLinus Torvalds #include <linux/spinlock.h>
38bd09a9f5SAlessio Igor Bogani #include <linux/mutex.h>
39464cbb24SAlan Cox #include <linux/uaccess.h>
401da177e4SLinus Torvalds #include <linux/usb.h>
411da177e4SLinus Torvalds #include <linux/serial.h>
42ba93cc7dSKaroly Pados #include <linux/gpio/driver.h>
43a969888cSGreg Kroah-Hartman #include <linux/usb/serial.h>
441da177e4SLinus Torvalds #include "ftdi_sio.h"
4531844d55SAndreas Mohr #include "ftdi_sio_ids.h"
461da177e4SLinus Torvalds 
47d3901a06SJohan Hovold #define DRIVER_AUTHOR "Greg Kroah-Hartman <greg@kroah.com>, Bill Ryder <bryder@sgi.com>, Kuba Ober <kuba@mareimbrium.org>, Andreas Mohr, Johan Hovold <jhovold@gmail.com>"
481da177e4SLinus Torvalds #define DRIVER_DESC "USB FTDI Serial Converters Driver"
491da177e4SLinus Torvalds 
50366e89aaSJohan Hovold enum ftdi_chip_type {
51366e89aaSJohan Hovold 	SIO,
5201aeb31fSJohan Hovold 	FT232A,
5301aeb31fSJohan Hovold 	FT232B,
54366e89aaSJohan Hovold 	FT2232C,
5501aeb31fSJohan Hovold 	FT232R,
5601aeb31fSJohan Hovold 	FT232H,
57366e89aaSJohan Hovold 	FT2232H,
58366e89aaSJohan Hovold 	FT4232H,
59cfebcd53SAmireddy mallikarjuna reddy 	FT4232HA,
60cfebcd53SAmireddy mallikarjuna reddy 	FT232HP,
61cfebcd53SAmireddy mallikarjuna reddy 	FT233HP,
62cfebcd53SAmireddy mallikarjuna reddy 	FT2232HP,
63cfebcd53SAmireddy mallikarjuna reddy 	FT2233HP,
64cfebcd53SAmireddy mallikarjuna reddy 	FT4232HP,
65cfebcd53SAmireddy mallikarjuna reddy 	FT4233HP,
66366e89aaSJohan Hovold 	FTX,
67366e89aaSJohan Hovold };
681da177e4SLinus Torvalds 
690ffbbe25SOliver Neukum struct ftdi_private {
703bb36aa2SGreg Kroah-Hartman 	enum ftdi_chip_type chip_type;
710ffbbe25SOliver Neukum 	int baud_base;		/* baud base clock for divisor setting */
72464cbb24SAlan Cox 	int custom_divisor;	/* custom_divisor kludge, this is for
73464cbb24SAlan Cox 				   baud_base (different from what goes to the
74464cbb24SAlan Cox 				   chip!) */
7516410115SJohan Hovold 	u16 last_set_data_value; /* the last data state set - needed for doing
76464cbb24SAlan Cox 				  * a break
77464cbb24SAlan Cox 				  */
780ffbbe25SOliver Neukum 	int flags;		/* some ASYNC_xxxx flags are supported */
790ffbbe25SOliver Neukum 	unsigned long last_dtr_rts;	/* saved modem control outputs */
80fca5430dSSimon Arlott 	char prev_status;        /* Used for TIOCMIWAIT */
81c466cd2bSGreg Kroah-Hartman 	char transmit_empty;	/* If transmitter is empty or not */
82027bf37dSJohan Hovold 	u16 channel;		/* channel index, or 0 for legacy types */
830ffbbe25SOliver Neukum 
84464cbb24SAlan Cox 	speed_t force_baud;	/* if non-zero, force the baud rate to
85464cbb24SAlan Cox 				   this value */
86464cbb24SAlan Cox 	int force_rtscts;	/* if non-zero, force RTS-CTS to always
87464cbb24SAlan Cox 				   be enabled */
880ffbbe25SOliver Neukum 
89557aaa7fSAlan Cox 	unsigned int latency;		/* latency setting in use */
90895f28baSMark Adamson 	unsigned short max_packet_size;
919c67d28eSAlessio Igor Bogani 	struct mutex cfg_lock; /* Avoid mess by parallel calls of config ioctl() and change_speed() */
92ba93cc7dSKaroly Pados #ifdef CONFIG_GPIOLIB
93ba93cc7dSKaroly Pados 	struct gpio_chip gc;
94ba93cc7dSKaroly Pados 	struct mutex gpio_lock;	/* protects GPIO state */
95ba93cc7dSKaroly Pados 	bool gpio_registered;	/* is the gpiochip in kernel registered */
96ba93cc7dSKaroly Pados 	bool gpio_used;		/* true if the user requested a gpio */
97ba93cc7dSKaroly Pados 	u8 gpio_altfunc;	/* which pins are in gpio mode */
98ba93cc7dSKaroly Pados 	u8 gpio_output;		/* pin directions cache */
99ba93cc7dSKaroly Pados 	u8 gpio_value;		/* pin value for outputs */
100ba93cc7dSKaroly Pados #endif
1010ffbbe25SOliver Neukum };
1020ffbbe25SOliver Neukum 
1036b2fe3dfSJohan Hovold struct ftdi_quirk {
104fa91d43bSTony Lindgren 	int (*probe)(struct usb_serial *);
105464cbb24SAlan Cox 	/* Special settings for probed ports. */
106464cbb24SAlan Cox 	void (*port_probe)(struct ftdi_private *);
1078f977e42SIan Abbott };
1088f977e42SIan Abbott 
10920734345SHarald Welte static int   ftdi_jtag_probe(struct usb_serial *serial);
110b760dac2SMartin Geleynse static int   ftdi_NDI_device_setup(struct usb_serial *serial);
1116ec2f46cSJean-Christophe PLAGNIOL-VILLARD static int   ftdi_stmclite_probe(struct usb_serial *serial);
112c96fbdd0SJean-Christophe PLAGNIOL-VILLARD static int   ftdi_8u2232c_probe(struct usb_serial *serial);
1130ffbbe25SOliver Neukum static void  ftdi_USB_UIRT_setup(struct ftdi_private *priv);
1140ffbbe25SOliver Neukum static void  ftdi_HE_TIRA1_setup(struct ftdi_private *priv);
1158f977e42SIan Abbott 
1166b2fe3dfSJohan Hovold static const struct ftdi_quirk ftdi_jtag_quirk = {
11720734345SHarald Welte 	.probe	= ftdi_jtag_probe,
118fa91d43bSTony Lindgren };
119fa91d43bSTony Lindgren 
1206b2fe3dfSJohan Hovold static const struct ftdi_quirk ftdi_NDI_device_quirk = {
121b760dac2SMartin Geleynse 	.probe	= ftdi_NDI_device_setup,
122b760dac2SMartin Geleynse };
123b760dac2SMartin Geleynse 
1246b2fe3dfSJohan Hovold static const struct ftdi_quirk ftdi_USB_UIRT_quirk = {
1250ffbbe25SOliver Neukum 	.port_probe = ftdi_USB_UIRT_setup,
1268f977e42SIan Abbott };
1278f977e42SIan Abbott 
1286b2fe3dfSJohan Hovold static const struct ftdi_quirk ftdi_HE_TIRA1_quirk = {
1290ffbbe25SOliver Neukum 	.port_probe = ftdi_HE_TIRA1_setup,
1301da177e4SLinus Torvalds };
1311da177e4SLinus Torvalds 
1326b2fe3dfSJohan Hovold static const struct ftdi_quirk ftdi_stmclite_quirk = {
1336ec2f46cSJean-Christophe PLAGNIOL-VILLARD 	.probe	= ftdi_stmclite_probe,
1346ec2f46cSJean-Christophe PLAGNIOL-VILLARD };
1356ec2f46cSJean-Christophe PLAGNIOL-VILLARD 
1366b2fe3dfSJohan Hovold static const struct ftdi_quirk ftdi_8u2232c_quirk = {
137c96fbdd0SJean-Christophe PLAGNIOL-VILLARD 	.probe	= ftdi_8u2232c_probe,
138c96fbdd0SJean-Christophe PLAGNIOL-VILLARD };
139c96fbdd0SJean-Christophe PLAGNIOL-VILLARD 
1401da177e4SLinus Torvalds /*
1411da177e4SLinus Torvalds  * The 8U232AM has the same API as the sio except for:
1421da177e4SLinus Torvalds  * - it can support MUCH higher baudrates; up to:
1431da177e4SLinus Torvalds  *   o 921600 for RS232 and 2000000 for RS422/485 at 48MHz
1441da177e4SLinus Torvalds  *   o 230400 at 12MHz
1451da177e4SLinus Torvalds  *   so .. 8U232AM's baudrate setting codes are different
1461da177e4SLinus Torvalds  * - it has a two byte status code.
1471da177e4SLinus Torvalds  * - it returns characters every 16ms (the FTDI does it every 40ms)
1481da177e4SLinus Torvalds  *
1491da177e4SLinus Torvalds  * the bcdDevice value is used to differentiate FT232BM and FT245BM from
1501da177e4SLinus Torvalds  * the earlier FT8U232AM and FT8U232BM.  For now, include all known VID/PID
1511da177e4SLinus Torvalds  * combinations in both tables.
1528f977e42SIan Abbott  * FIXME: perhaps bcdDevice can also identify 12MHz FT8U232AM devices,
1538f977e42SIan Abbott  * but I don't know if those ever went into mass production. [Ian Abbott]
1541da177e4SLinus Torvalds  */
1551da177e4SLinus Torvalds 
1561da177e4SLinus Torvalds 
1571da177e4SLinus Torvalds 
15865e1ec67SAndreas Mohr /*
159e17c1aa2SJohan Hovold  * Device ID not listed? Test it using
160e17c1aa2SJohan Hovold  * /sys/bus/usb-serial/drivers/ftdi_sio/new_id and send a patch or report.
16165e1ec67SAndreas Mohr  */
1625c6b98ddSJohan Hovold static const struct usb_device_id id_table_combined[] = {
1637f2719f0SPerry Hung 	{ USB_DEVICE(FTDI_VID, FTDI_BRICK_PID) },
164ce7e9065SArtur Zimmer 	{ USB_DEVICE(FTDI_VID, FTDI_ZEITCONTROL_TAGTRACE_MIFARE_PID) },
1655a9443f0SChristian Simon 	{ USB_DEVICE(FTDI_VID, FTDI_CTI_MINI_PID) },
1665a9443f0SChristian Simon 	{ USB_DEVICE(FTDI_VID, FTDI_CTI_NANO_PID) },
1672011e924SJonathan Davies 	{ USB_DEVICE(FTDI_VID, FTDI_AMC232_PID) },
1682011e924SJonathan Davies 	{ USB_DEVICE(FTDI_VID, FTDI_CANUSB_PID) },
16901ba0856SAndrew Ewert 	{ USB_DEVICE(FTDI_VID, FTDI_CANDAPTER_PID) },
1706552cc7fSJohan Hovold 	{ USB_DEVICE(FTDI_VID, FTDI_BM_ATOM_NANO_PID) },
17165e1ec67SAndreas Mohr 	{ USB_DEVICE(FTDI_VID, FTDI_NXTCAM_PID) },
17267847baeSBjørn Mork 	{ USB_DEVICE(FTDI_VID, FTDI_EV3CON_PID) },
1736e1ab3edSPeter Mack 	{ USB_DEVICE(FTDI_VID, FTDI_SCS_DEVICE_0_PID) },
1746e1ab3edSPeter Mack 	{ USB_DEVICE(FTDI_VID, FTDI_SCS_DEVICE_1_PID) },
1756e1ab3edSPeter Mack 	{ USB_DEVICE(FTDI_VID, FTDI_SCS_DEVICE_2_PID) },
1766e1ab3edSPeter Mack 	{ USB_DEVICE(FTDI_VID, FTDI_SCS_DEVICE_3_PID) },
1776e1ab3edSPeter Mack 	{ USB_DEVICE(FTDI_VID, FTDI_SCS_DEVICE_4_PID) },
1786e1ab3edSPeter Mack 	{ USB_DEVICE(FTDI_VID, FTDI_SCS_DEVICE_5_PID) },
1796e1ab3edSPeter Mack 	{ USB_DEVICE(FTDI_VID, FTDI_SCS_DEVICE_6_PID) },
1806e1ab3edSPeter Mack 	{ USB_DEVICE(FTDI_VID, FTDI_SCS_DEVICE_7_PID) },
181b6180ef7Sdranch@trinnet.net 	{ USB_DEVICE(FTDI_VID, FTDI_USINT_CAT_PID) },
182b6180ef7Sdranch@trinnet.net 	{ USB_DEVICE(FTDI_VID, FTDI_USINT_WKEY_PID) },
183b6180ef7Sdranch@trinnet.net 	{ USB_DEVICE(FTDI_VID, FTDI_USINT_RS232_PID) },
18472a9f958SRazvan Gavril 	{ USB_DEVICE(FTDI_VID, FTDI_ACTZWAVE_PID) },
1851da177e4SLinus Torvalds 	{ USB_DEVICE(FTDI_VID, FTDI_IRTRANS_PID) },
18669737dfaSLuiz Fernando N. Capitulino 	{ USB_DEVICE(FTDI_VID, FTDI_IPLUS_PID) },
187d099321bSLuiz Fernando N. Capitulino 	{ USB_DEVICE(FTDI_VID, FTDI_IPLUS2_PID) },
188fad14a0dSFrank Sievertsen 	{ USB_DEVICE(FTDI_VID, FTDI_DMX4ALL) },
1891da177e4SLinus Torvalds 	{ USB_DEVICE(FTDI_VID, FTDI_SIO_PID) },
1901da177e4SLinus Torvalds 	{ USB_DEVICE(FTDI_VID, FTDI_8U232AM_PID) },
1911da177e4SLinus Torvalds 	{ USB_DEVICE(FTDI_VID, FTDI_8U232AM_ALT_PID) },
192d8b21606SGard Spreemann 	{ USB_DEVICE(FTDI_VID, FTDI_232RL_PID) },
193c96fbdd0SJean-Christophe PLAGNIOL-VILLARD 	{ USB_DEVICE(FTDI_VID, FTDI_8U2232C_PID) ,
194c96fbdd0SJean-Christophe PLAGNIOL-VILLARD 		.driver_info = (kernel_ulong_t)&ftdi_8u2232c_quirk },
195094c2e6dSMark Adamson 	{ USB_DEVICE(FTDI_VID, FTDI_4232H_PID) },
196309427b6SUwe Bonnes 	{ USB_DEVICE(FTDI_VID, FTDI_232H_PID) },
197dc0827c1SJim Paris 	{ USB_DEVICE(FTDI_VID, FTDI_FTX_PID) },
198cfebcd53SAmireddy mallikarjuna reddy 	{ USB_DEVICE(FTDI_VID, FTDI_FT2233HP_PID) },
199cfebcd53SAmireddy mallikarjuna reddy 	{ USB_DEVICE(FTDI_VID, FTDI_FT4233HP_PID) },
200cfebcd53SAmireddy mallikarjuna reddy 	{ USB_DEVICE(FTDI_VID, FTDI_FT2232HP_PID) },
201cfebcd53SAmireddy mallikarjuna reddy 	{ USB_DEVICE(FTDI_VID, FTDI_FT4232HP_PID) },
202cfebcd53SAmireddy mallikarjuna reddy 	{ USB_DEVICE(FTDI_VID, FTDI_FT233HP_PID) },
203cfebcd53SAmireddy mallikarjuna reddy 	{ USB_DEVICE(FTDI_VID, FTDI_FT232HP_PID) },
204cfebcd53SAmireddy mallikarjuna reddy 	{ USB_DEVICE(FTDI_VID, FTDI_FT4232HA_PID) },
205c0f8d561SChristophe Mariac 	{ USB_DEVICE(FTDI_VID, FTDI_MICRO_CHAMELEON_PID) },
2061da177e4SLinus Torvalds 	{ USB_DEVICE(FTDI_VID, FTDI_RELAIS_PID) },
2072adb80e9SGuido Scholz 	{ USB_DEVICE(FTDI_VID, FTDI_OPENDCC_PID) },
208ec3815c3Smail@rainerkeller.de 	{ USB_DEVICE(FTDI_VID, FTDI_OPENDCC_SNIFFER_PID) },
209ec3815c3Smail@rainerkeller.de 	{ USB_DEVICE(FTDI_VID, FTDI_OPENDCC_THROTTLE_PID) },
210ec3815c3Smail@rainerkeller.de 	{ USB_DEVICE(FTDI_VID, FTDI_OPENDCC_GATEWAY_PID) },
21199c1e4f8SRainer Keller 	{ USB_DEVICE(FTDI_VID, FTDI_OPENDCC_GBM_PID) },
21258f8b6c4SStefani Seibold 	{ USB_DEVICE(FTDI_VID, FTDI_OPENDCC_GBM_BOOST_PID) },
213d7e14b37SMartin Teichmann 	{ USB_DEVICE(NEWPORT_VID, NEWPORT_AGILIS_PID) },
21471381439SGomella, Andrew (NIH/NHLBI) [F] 	{ USB_DEVICE(NEWPORT_VID, NEWPORT_CONEX_CC_PID) },
21571381439SGomella, Andrew (NIH/NHLBI) [F] 	{ USB_DEVICE(NEWPORT_VID, NEWPORT_CONEX_AGP_PID) },
2161da177e4SLinus Torvalds 	{ USB_DEVICE(INTERBIOMETRICS_VID, INTERBIOMETRICS_IOBOARD_PID) },
2171da177e4SLinus Torvalds 	{ USB_DEVICE(INTERBIOMETRICS_VID, INTERBIOMETRICS_MINI_IOBOARD_PID) },
218f2ee6955SAlan Cox 	{ USB_DEVICE(FTDI_VID, FTDI_SPROG_II) },
21976f24e3fSUlrich Hahn 	{ USB_DEVICE(FTDI_VID, FTDI_TAGSYS_LP101_PID) },
22076f24e3fSUlrich Hahn 	{ USB_DEVICE(FTDI_VID, FTDI_TAGSYS_P200X_PID) },
221ea233f80SGalen Seitz 	{ USB_DEVICE(FTDI_VID, FTDI_LENZ_LIUSB_PID) },
2221da177e4SLinus Torvalds 	{ USB_DEVICE(FTDI_VID, FTDI_XF_632_PID) },
2231da177e4SLinus Torvalds 	{ USB_DEVICE(FTDI_VID, FTDI_XF_634_PID) },
2241da177e4SLinus Torvalds 	{ USB_DEVICE(FTDI_VID, FTDI_XF_547_PID) },
2251da177e4SLinus Torvalds 	{ USB_DEVICE(FTDI_VID, FTDI_XF_633_PID) },
2261da177e4SLinus Torvalds 	{ USB_DEVICE(FTDI_VID, FTDI_XF_631_PID) },
2271da177e4SLinus Torvalds 	{ USB_DEVICE(FTDI_VID, FTDI_XF_635_PID) },
2281da177e4SLinus Torvalds 	{ USB_DEVICE(FTDI_VID, FTDI_XF_640_PID) },
2291da177e4SLinus Torvalds 	{ USB_DEVICE(FTDI_VID, FTDI_XF_642_PID) },
2301da177e4SLinus Torvalds 	{ USB_DEVICE(FTDI_VID, FTDI_DSS20_PID) },
23174bdf22bSHakan Kvist 	{ USB_DEVICE(FTDI_VID, FTDI_URBAN_0_PID) },
23274bdf22bSHakan Kvist 	{ USB_DEVICE(FTDI_VID, FTDI_URBAN_1_PID) },
2331da177e4SLinus Torvalds 	{ USB_DEVICE(FTDI_NF_RIC_VID, FTDI_NF_RIC_PID) },
2341da177e4SLinus Torvalds 	{ USB_DEVICE(FTDI_VID, FTDI_VNHCPCUSB_D_PID) },
2358f977e42SIan Abbott 	{ USB_DEVICE(FTDI_VID, FTDI_MTXORB_0_PID) },
2368f977e42SIan Abbott 	{ USB_DEVICE(FTDI_VID, FTDI_MTXORB_1_PID) },
2378f977e42SIan Abbott 	{ USB_DEVICE(FTDI_VID, FTDI_MTXORB_2_PID) },
2388f977e42SIan Abbott 	{ USB_DEVICE(FTDI_VID, FTDI_MTXORB_3_PID) },
2398f977e42SIan Abbott 	{ USB_DEVICE(FTDI_VID, FTDI_MTXORB_4_PID) },
2408f977e42SIan Abbott 	{ USB_DEVICE(FTDI_VID, FTDI_MTXORB_5_PID) },
2418f977e42SIan Abbott 	{ USB_DEVICE(FTDI_VID, FTDI_MTXORB_6_PID) },
242b34efeeaSFolkert van Heusden 	{ USB_DEVICE(FTDI_VID, FTDI_R2000KU_TRUE_RNG) },
2436fdbad80SJacques Viviers 	{ USB_DEVICE(FTDI_VID, FTDI_VARDAAN_PID) },
2448da0e55cSDavid Bauer 	{ USB_DEVICE(FTDI_VID, FTDI_AUTO_M3_OP_COM_V2_PID) },
245ebb3770cSRay Molenkamp 	{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0100_PID) },
246ebb3770cSRay Molenkamp 	{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0101_PID) },
247ebb3770cSRay Molenkamp 	{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0102_PID) },
248ebb3770cSRay Molenkamp 	{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0103_PID) },
249ebb3770cSRay Molenkamp 	{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0104_PID) },
250ebb3770cSRay Molenkamp 	{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0105_PID) },
251ebb3770cSRay Molenkamp 	{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0106_PID) },
252ebb3770cSRay Molenkamp 	{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0107_PID) },
253ebb3770cSRay Molenkamp 	{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0108_PID) },
254ebb3770cSRay Molenkamp 	{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0109_PID) },
255ebb3770cSRay Molenkamp 	{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_010A_PID) },
256ebb3770cSRay Molenkamp 	{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_010B_PID) },
257ebb3770cSRay Molenkamp 	{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_010C_PID) },
258ebb3770cSRay Molenkamp 	{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_010D_PID) },
259ebb3770cSRay Molenkamp 	{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_010E_PID) },
260ebb3770cSRay Molenkamp 	{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_010F_PID) },
261ebb3770cSRay Molenkamp 	{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0110_PID) },
262ebb3770cSRay Molenkamp 	{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0111_PID) },
263ebb3770cSRay Molenkamp 	{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0112_PID) },
264ebb3770cSRay Molenkamp 	{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0113_PID) },
265ebb3770cSRay Molenkamp 	{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0114_PID) },
266ebb3770cSRay Molenkamp 	{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0115_PID) },
267ebb3770cSRay Molenkamp 	{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0116_PID) },
268ebb3770cSRay Molenkamp 	{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0117_PID) },
269ebb3770cSRay Molenkamp 	{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0118_PID) },
270ebb3770cSRay Molenkamp 	{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0119_PID) },
271ebb3770cSRay Molenkamp 	{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_011A_PID) },
272ebb3770cSRay Molenkamp 	{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_011B_PID) },
273ebb3770cSRay Molenkamp 	{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_011C_PID) },
274ebb3770cSRay Molenkamp 	{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_011D_PID) },
275ebb3770cSRay Molenkamp 	{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_011E_PID) },
276ebb3770cSRay Molenkamp 	{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_011F_PID) },
277ebb3770cSRay Molenkamp 	{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0120_PID) },
278ebb3770cSRay Molenkamp 	{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0121_PID) },
279ebb3770cSRay Molenkamp 	{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0122_PID) },
280ebb3770cSRay Molenkamp 	{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0123_PID) },
281ebb3770cSRay Molenkamp 	{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0124_PID) },
282ebb3770cSRay Molenkamp 	{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0125_PID) },
283ebb3770cSRay Molenkamp 	{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0126_PID) },
28419de4278SJohan Hovold 	{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0127_PID) },
285ebb3770cSRay Molenkamp 	{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0128_PID) },
286ebb3770cSRay Molenkamp 	{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0129_PID) },
287ebb3770cSRay Molenkamp 	{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_012A_PID) },
288ebb3770cSRay Molenkamp 	{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_012B_PID) },
28919de4278SJohan Hovold 	{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_012C_PID) },
290ebb3770cSRay Molenkamp 	{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_012D_PID) },
291ebb3770cSRay Molenkamp 	{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_012E_PID) },
292ebb3770cSRay Molenkamp 	{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_012F_PID) },
293ebb3770cSRay Molenkamp 	{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0130_PID) },
294ebb3770cSRay Molenkamp 	{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0131_PID) },
295ebb3770cSRay Molenkamp 	{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0132_PID) },
296ebb3770cSRay Molenkamp 	{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0133_PID) },
297ebb3770cSRay Molenkamp 	{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0134_PID) },
298ebb3770cSRay Molenkamp 	{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0135_PID) },
299ebb3770cSRay Molenkamp 	{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0136_PID) },
300ebb3770cSRay Molenkamp 	{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0137_PID) },
301ebb3770cSRay Molenkamp 	{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0138_PID) },
302ebb3770cSRay Molenkamp 	{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0139_PID) },
303ebb3770cSRay Molenkamp 	{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_013A_PID) },
304ebb3770cSRay Molenkamp 	{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_013B_PID) },
305ebb3770cSRay Molenkamp 	{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_013C_PID) },
306ebb3770cSRay Molenkamp 	{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_013D_PID) },
307ebb3770cSRay Molenkamp 	{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_013E_PID) },
308ebb3770cSRay Molenkamp 	{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_013F_PID) },
309ebb3770cSRay Molenkamp 	{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0140_PID) },
310ebb3770cSRay Molenkamp 	{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0141_PID) },
311ebb3770cSRay Molenkamp 	{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0142_PID) },
312ebb3770cSRay Molenkamp 	{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0143_PID) },
313ebb3770cSRay Molenkamp 	{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0144_PID) },
314ebb3770cSRay Molenkamp 	{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0145_PID) },
315ebb3770cSRay Molenkamp 	{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0146_PID) },
316ebb3770cSRay Molenkamp 	{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0147_PID) },
317ebb3770cSRay Molenkamp 	{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0148_PID) },
318ebb3770cSRay Molenkamp 	{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0149_PID) },
319ebb3770cSRay Molenkamp 	{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_014A_PID) },
320ebb3770cSRay Molenkamp 	{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_014B_PID) },
321ebb3770cSRay Molenkamp 	{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_014C_PID) },
322ebb3770cSRay Molenkamp 	{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_014D_PID) },
323ebb3770cSRay Molenkamp 	{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_014E_PID) },
324ebb3770cSRay Molenkamp 	{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_014F_PID) },
325ebb3770cSRay Molenkamp 	{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0150_PID) },
326ebb3770cSRay Molenkamp 	{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0151_PID) },
327ebb3770cSRay Molenkamp 	{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0152_PID) },
32819de4278SJohan Hovold 	{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0153_PID) },
32919de4278SJohan Hovold 	{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0154_PID) },
33019de4278SJohan Hovold 	{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0155_PID) },
33119de4278SJohan Hovold 	{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0156_PID) },
33219de4278SJohan Hovold 	{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0157_PID) },
33319de4278SJohan Hovold 	{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0158_PID) },
334ebb3770cSRay Molenkamp 	{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0159_PID) },
335ebb3770cSRay Molenkamp 	{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_015A_PID) },
336ebb3770cSRay Molenkamp 	{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_015B_PID) },
337ebb3770cSRay Molenkamp 	{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_015C_PID) },
338ebb3770cSRay Molenkamp 	{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_015D_PID) },
339ebb3770cSRay Molenkamp 	{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_015E_PID) },
340ebb3770cSRay Molenkamp 	{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_015F_PID) },
341ebb3770cSRay Molenkamp 	{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0160_PID) },
342ebb3770cSRay Molenkamp 	{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0161_PID) },
343ebb3770cSRay Molenkamp 	{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0162_PID) },
344ebb3770cSRay Molenkamp 	{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0163_PID) },
345ebb3770cSRay Molenkamp 	{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0164_PID) },
346ebb3770cSRay Molenkamp 	{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0165_PID) },
347ebb3770cSRay Molenkamp 	{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0166_PID) },
348ebb3770cSRay Molenkamp 	{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0167_PID) },
349ebb3770cSRay Molenkamp 	{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0168_PID) },
350ebb3770cSRay Molenkamp 	{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0169_PID) },
351ebb3770cSRay Molenkamp 	{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_016A_PID) },
352ebb3770cSRay Molenkamp 	{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_016B_PID) },
353ebb3770cSRay Molenkamp 	{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_016C_PID) },
354ebb3770cSRay Molenkamp 	{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_016D_PID) },
355ebb3770cSRay Molenkamp 	{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_016E_PID) },
356ebb3770cSRay Molenkamp 	{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_016F_PID) },
357ebb3770cSRay Molenkamp 	{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0170_PID) },
358ebb3770cSRay Molenkamp 	{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0171_PID) },
359ebb3770cSRay Molenkamp 	{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0172_PID) },
360ebb3770cSRay Molenkamp 	{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0173_PID) },
361ebb3770cSRay Molenkamp 	{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0174_PID) },
362ebb3770cSRay Molenkamp 	{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0175_PID) },
363ebb3770cSRay Molenkamp 	{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0176_PID) },
364ebb3770cSRay Molenkamp 	{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0177_PID) },
365ebb3770cSRay Molenkamp 	{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0178_PID) },
366ebb3770cSRay Molenkamp 	{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0179_PID) },
367ebb3770cSRay Molenkamp 	{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_017A_PID) },
368ebb3770cSRay Molenkamp 	{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_017B_PID) },
369ebb3770cSRay Molenkamp 	{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_017C_PID) },
370ebb3770cSRay Molenkamp 	{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_017D_PID) },
371ebb3770cSRay Molenkamp 	{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_017E_PID) },
372ebb3770cSRay Molenkamp 	{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_017F_PID) },
373ebb3770cSRay Molenkamp 	{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0180_PID) },
374ebb3770cSRay Molenkamp 	{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0181_PID) },
375ebb3770cSRay Molenkamp 	{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0182_PID) },
376ebb3770cSRay Molenkamp 	{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0183_PID) },
377ebb3770cSRay Molenkamp 	{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0184_PID) },
378ebb3770cSRay Molenkamp 	{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0185_PID) },
379ebb3770cSRay Molenkamp 	{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0186_PID) },
380ebb3770cSRay Molenkamp 	{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0187_PID) },
381ebb3770cSRay Molenkamp 	{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0188_PID) },
382ebb3770cSRay Molenkamp 	{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0189_PID) },
383ebb3770cSRay Molenkamp 	{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_018A_PID) },
384ebb3770cSRay Molenkamp 	{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_018B_PID) },
385ebb3770cSRay Molenkamp 	{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_018C_PID) },
386ebb3770cSRay Molenkamp 	{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_018D_PID) },
387ebb3770cSRay Molenkamp 	{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_018E_PID) },
388ebb3770cSRay Molenkamp 	{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_018F_PID) },
389ebb3770cSRay Molenkamp 	{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0190_PID) },
390ebb3770cSRay Molenkamp 	{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0191_PID) },
391ebb3770cSRay Molenkamp 	{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0192_PID) },
392ebb3770cSRay Molenkamp 	{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0193_PID) },
393ebb3770cSRay Molenkamp 	{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0194_PID) },
394ebb3770cSRay Molenkamp 	{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0195_PID) },
395ebb3770cSRay Molenkamp 	{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0196_PID) },
396ebb3770cSRay Molenkamp 	{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0197_PID) },
397ebb3770cSRay Molenkamp 	{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0198_PID) },
398ebb3770cSRay Molenkamp 	{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0199_PID) },
399ebb3770cSRay Molenkamp 	{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_019A_PID) },
400ebb3770cSRay Molenkamp 	{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_019B_PID) },
401ebb3770cSRay Molenkamp 	{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_019C_PID) },
402ebb3770cSRay Molenkamp 	{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_019D_PID) },
403ebb3770cSRay Molenkamp 	{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_019E_PID) },
404ebb3770cSRay Molenkamp 	{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_019F_PID) },
405ebb3770cSRay Molenkamp 	{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01A0_PID) },
406ebb3770cSRay Molenkamp 	{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01A1_PID) },
407ebb3770cSRay Molenkamp 	{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01A2_PID) },
408ebb3770cSRay Molenkamp 	{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01A3_PID) },
409ebb3770cSRay Molenkamp 	{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01A4_PID) },
410ebb3770cSRay Molenkamp 	{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01A5_PID) },
411ebb3770cSRay Molenkamp 	{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01A6_PID) },
412ebb3770cSRay Molenkamp 	{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01A7_PID) },
413ebb3770cSRay Molenkamp 	{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01A8_PID) },
414ebb3770cSRay Molenkamp 	{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01A9_PID) },
415ebb3770cSRay Molenkamp 	{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01AA_PID) },
416ebb3770cSRay Molenkamp 	{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01AB_PID) },
417ebb3770cSRay Molenkamp 	{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01AC_PID) },
418ebb3770cSRay Molenkamp 	{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01AD_PID) },
419ebb3770cSRay Molenkamp 	{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01AE_PID) },
420ebb3770cSRay Molenkamp 	{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01AF_PID) },
421ebb3770cSRay Molenkamp 	{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01B0_PID) },
422ebb3770cSRay Molenkamp 	{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01B1_PID) },
423ebb3770cSRay Molenkamp 	{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01B2_PID) },
424ebb3770cSRay Molenkamp 	{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01B3_PID) },
425ebb3770cSRay Molenkamp 	{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01B4_PID) },
426ebb3770cSRay Molenkamp 	{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01B5_PID) },
427ebb3770cSRay Molenkamp 	{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01B6_PID) },
428ebb3770cSRay Molenkamp 	{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01B7_PID) },
429ebb3770cSRay Molenkamp 	{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01B8_PID) },
430ebb3770cSRay Molenkamp 	{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01B9_PID) },
431ebb3770cSRay Molenkamp 	{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01BA_PID) },
432ebb3770cSRay Molenkamp 	{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01BB_PID) },
433ebb3770cSRay Molenkamp 	{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01BC_PID) },
434ebb3770cSRay Molenkamp 	{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01BD_PID) },
435ebb3770cSRay Molenkamp 	{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01BE_PID) },
436ebb3770cSRay Molenkamp 	{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01BF_PID) },
437ebb3770cSRay Molenkamp 	{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01C0_PID) },
438ebb3770cSRay Molenkamp 	{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01C1_PID) },
439ebb3770cSRay Molenkamp 	{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01C2_PID) },
440ebb3770cSRay Molenkamp 	{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01C3_PID) },
441ebb3770cSRay Molenkamp 	{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01C4_PID) },
442ebb3770cSRay Molenkamp 	{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01C5_PID) },
443ebb3770cSRay Molenkamp 	{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01C6_PID) },
444ebb3770cSRay Molenkamp 	{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01C7_PID) },
445ebb3770cSRay Molenkamp 	{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01C8_PID) },
446ebb3770cSRay Molenkamp 	{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01C9_PID) },
447ebb3770cSRay Molenkamp 	{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01CA_PID) },
448ebb3770cSRay Molenkamp 	{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01CB_PID) },
449ebb3770cSRay Molenkamp 	{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01CC_PID) },
450ebb3770cSRay Molenkamp 	{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01CD_PID) },
451ebb3770cSRay Molenkamp 	{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01CE_PID) },
452ebb3770cSRay Molenkamp 	{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01CF_PID) },
453ebb3770cSRay Molenkamp 	{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01D0_PID) },
454ebb3770cSRay Molenkamp 	{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01D1_PID) },
455ebb3770cSRay Molenkamp 	{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01D2_PID) },
456ebb3770cSRay Molenkamp 	{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01D3_PID) },
457ebb3770cSRay Molenkamp 	{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01D4_PID) },
458ebb3770cSRay Molenkamp 	{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01D5_PID) },
459ebb3770cSRay Molenkamp 	{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01D6_PID) },
460ebb3770cSRay Molenkamp 	{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01D7_PID) },
461ebb3770cSRay Molenkamp 	{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01D8_PID) },
462ebb3770cSRay Molenkamp 	{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01D9_PID) },
463ebb3770cSRay Molenkamp 	{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01DA_PID) },
464ebb3770cSRay Molenkamp 	{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01DB_PID) },
465ebb3770cSRay Molenkamp 	{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01DC_PID) },
466ebb3770cSRay Molenkamp 	{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01DD_PID) },
467ebb3770cSRay Molenkamp 	{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01DE_PID) },
468ebb3770cSRay Molenkamp 	{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01DF_PID) },
469ebb3770cSRay Molenkamp 	{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01E0_PID) },
470ebb3770cSRay Molenkamp 	{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01E1_PID) },
471ebb3770cSRay Molenkamp 	{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01E2_PID) },
472ebb3770cSRay Molenkamp 	{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01E3_PID) },
473ebb3770cSRay Molenkamp 	{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01E4_PID) },
474ebb3770cSRay Molenkamp 	{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01E5_PID) },
475ebb3770cSRay Molenkamp 	{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01E6_PID) },
476ebb3770cSRay Molenkamp 	{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01E7_PID) },
477ebb3770cSRay Molenkamp 	{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01E8_PID) },
478ebb3770cSRay Molenkamp 	{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01E9_PID) },
479ebb3770cSRay Molenkamp 	{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01EA_PID) },
480ebb3770cSRay Molenkamp 	{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01EB_PID) },
481ebb3770cSRay Molenkamp 	{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01EC_PID) },
482ebb3770cSRay Molenkamp 	{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01ED_PID) },
483ebb3770cSRay Molenkamp 	{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01EE_PID) },
484ebb3770cSRay Molenkamp 	{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01EF_PID) },
485ebb3770cSRay Molenkamp 	{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01F0_PID) },
486ebb3770cSRay Molenkamp 	{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01F1_PID) },
487ebb3770cSRay Molenkamp 	{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01F2_PID) },
488ebb3770cSRay Molenkamp 	{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01F3_PID) },
489ebb3770cSRay Molenkamp 	{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01F4_PID) },
490ebb3770cSRay Molenkamp 	{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01F5_PID) },
491ebb3770cSRay Molenkamp 	{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01F6_PID) },
492ebb3770cSRay Molenkamp 	{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01F7_PID) },
493ebb3770cSRay Molenkamp 	{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01F8_PID) },
494ebb3770cSRay Molenkamp 	{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01F9_PID) },
495ebb3770cSRay Molenkamp 	{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01FA_PID) },
496ebb3770cSRay Molenkamp 	{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01FB_PID) },
497ebb3770cSRay Molenkamp 	{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01FC_PID) },
498ebb3770cSRay Molenkamp 	{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01FD_PID) },
499ebb3770cSRay Molenkamp 	{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01FE_PID) },
500ebb3770cSRay Molenkamp 	{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01FF_PID) },
501204ec6e0STroy Clark 	{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_4701_PID) },
502204ec6e0STroy Clark 	{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_9300_PID) },
503204ec6e0STroy Clark 	{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_9301_PID) },
504204ec6e0STroy Clark 	{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_9302_PID) },
505204ec6e0STroy Clark 	{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_9303_PID) },
506204ec6e0STroy Clark 	{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_9304_PID) },
507204ec6e0STroy Clark 	{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_9305_PID) },
508204ec6e0STroy Clark 	{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_9306_PID) },
509204ec6e0STroy Clark 	{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_9307_PID) },
510204ec6e0STroy Clark 	{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_9308_PID) },
511204ec6e0STroy Clark 	{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_9309_PID) },
512204ec6e0STroy Clark 	{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_930A_PID) },
513204ec6e0STroy Clark 	{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_930B_PID) },
514204ec6e0STroy Clark 	{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_930C_PID) },
515204ec6e0STroy Clark 	{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_930D_PID) },
516204ec6e0STroy Clark 	{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_930E_PID) },
517204ec6e0STroy Clark 	{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_930F_PID) },
518204ec6e0STroy Clark 	{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_9310_PID) },
519204ec6e0STroy Clark 	{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_9311_PID) },
520204ec6e0STroy Clark 	{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_9312_PID) },
521204ec6e0STroy Clark 	{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_9313_PID) },
522204ec6e0STroy Clark 	{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_9314_PID) },
523204ec6e0STroy Clark 	{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_9315_PID) },
524204ec6e0STroy Clark 	{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_9316_PID) },
525204ec6e0STroy Clark 	{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_9317_PID) },
526204ec6e0STroy Clark 	{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_9318_PID) },
527204ec6e0STroy Clark 	{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_9319_PID) },
528204ec6e0STroy Clark 	{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_931A_PID) },
529204ec6e0STroy Clark 	{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_931B_PID) },
530204ec6e0STroy Clark 	{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_931C_PID) },
531204ec6e0STroy Clark 	{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_931D_PID) },
532204ec6e0STroy Clark 	{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_931E_PID) },
533204ec6e0STroy Clark 	{ USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_931F_PID) },
5348f977e42SIan Abbott 	{ USB_DEVICE(FTDI_VID, FTDI_PERLE_ULTRAPORT_PID) },
5351da177e4SLinus Torvalds 	{ USB_DEVICE(FTDI_VID, FTDI_PIEGROUP_PID) },
536274a4bbcSDave Platt 	{ USB_DEVICE(FTDI_VID, FTDI_TNC_X_PID) },
537868e440dSJelle Foks 	{ USB_DEVICE(FTDI_VID, FTDI_USBX_707_PID) },
5381da177e4SLinus Torvalds 	{ USB_DEVICE(SEALEVEL_VID, SEALEVEL_2101_PID) },
5391da177e4SLinus Torvalds 	{ USB_DEVICE(SEALEVEL_VID, SEALEVEL_2102_PID) },
5401da177e4SLinus Torvalds 	{ USB_DEVICE(SEALEVEL_VID, SEALEVEL_2103_PID) },
5411da177e4SLinus Torvalds 	{ USB_DEVICE(SEALEVEL_VID, SEALEVEL_2104_PID) },
542a1484827SJustin Carlson 	{ USB_DEVICE(SEALEVEL_VID, SEALEVEL_2106_PID) },
5431da177e4SLinus Torvalds 	{ USB_DEVICE(SEALEVEL_VID, SEALEVEL_2201_1_PID) },
5441da177e4SLinus Torvalds 	{ USB_DEVICE(SEALEVEL_VID, SEALEVEL_2201_2_PID) },
5451da177e4SLinus Torvalds 	{ USB_DEVICE(SEALEVEL_VID, SEALEVEL_2202_1_PID) },
5461da177e4SLinus Torvalds 	{ USB_DEVICE(SEALEVEL_VID, SEALEVEL_2202_2_PID) },
5471da177e4SLinus Torvalds 	{ USB_DEVICE(SEALEVEL_VID, SEALEVEL_2203_1_PID) },
5481da177e4SLinus Torvalds 	{ USB_DEVICE(SEALEVEL_VID, SEALEVEL_2203_2_PID) },
5491da177e4SLinus Torvalds 	{ USB_DEVICE(SEALEVEL_VID, SEALEVEL_2401_1_PID) },
5501da177e4SLinus Torvalds 	{ USB_DEVICE(SEALEVEL_VID, SEALEVEL_2401_2_PID) },
5511da177e4SLinus Torvalds 	{ USB_DEVICE(SEALEVEL_VID, SEALEVEL_2401_3_PID) },
5521da177e4SLinus Torvalds 	{ USB_DEVICE(SEALEVEL_VID, SEALEVEL_2401_4_PID) },
5531da177e4SLinus Torvalds 	{ USB_DEVICE(SEALEVEL_VID, SEALEVEL_2402_1_PID) },
5541da177e4SLinus Torvalds 	{ USB_DEVICE(SEALEVEL_VID, SEALEVEL_2402_2_PID) },
5551da177e4SLinus Torvalds 	{ USB_DEVICE(SEALEVEL_VID, SEALEVEL_2402_3_PID) },
5561da177e4SLinus Torvalds 	{ USB_DEVICE(SEALEVEL_VID, SEALEVEL_2402_4_PID) },
5571da177e4SLinus Torvalds 	{ USB_DEVICE(SEALEVEL_VID, SEALEVEL_2403_1_PID) },
5581da177e4SLinus Torvalds 	{ USB_DEVICE(SEALEVEL_VID, SEALEVEL_2403_2_PID) },
5591da177e4SLinus Torvalds 	{ USB_DEVICE(SEALEVEL_VID, SEALEVEL_2403_3_PID) },
5601da177e4SLinus Torvalds 	{ USB_DEVICE(SEALEVEL_VID, SEALEVEL_2403_4_PID) },
5611da177e4SLinus Torvalds 	{ USB_DEVICE(SEALEVEL_VID, SEALEVEL_2801_1_PID) },
5621da177e4SLinus Torvalds 	{ USB_DEVICE(SEALEVEL_VID, SEALEVEL_2801_2_PID) },
5631da177e4SLinus Torvalds 	{ USB_DEVICE(SEALEVEL_VID, SEALEVEL_2801_3_PID) },
5641da177e4SLinus Torvalds 	{ USB_DEVICE(SEALEVEL_VID, SEALEVEL_2801_4_PID) },
5651da177e4SLinus Torvalds 	{ USB_DEVICE(SEALEVEL_VID, SEALEVEL_2801_5_PID) },
5661da177e4SLinus Torvalds 	{ USB_DEVICE(SEALEVEL_VID, SEALEVEL_2801_6_PID) },
5671da177e4SLinus Torvalds 	{ USB_DEVICE(SEALEVEL_VID, SEALEVEL_2801_7_PID) },
5681da177e4SLinus Torvalds 	{ USB_DEVICE(SEALEVEL_VID, SEALEVEL_2801_8_PID) },
5691da177e4SLinus Torvalds 	{ USB_DEVICE(SEALEVEL_VID, SEALEVEL_2802_1_PID) },
5701da177e4SLinus Torvalds 	{ USB_DEVICE(SEALEVEL_VID, SEALEVEL_2802_2_PID) },
5711da177e4SLinus Torvalds 	{ USB_DEVICE(SEALEVEL_VID, SEALEVEL_2802_3_PID) },
5721da177e4SLinus Torvalds 	{ USB_DEVICE(SEALEVEL_VID, SEALEVEL_2802_4_PID) },
5731da177e4SLinus Torvalds 	{ USB_DEVICE(SEALEVEL_VID, SEALEVEL_2802_5_PID) },
5741da177e4SLinus Torvalds 	{ USB_DEVICE(SEALEVEL_VID, SEALEVEL_2802_6_PID) },
5751da177e4SLinus Torvalds 	{ USB_DEVICE(SEALEVEL_VID, SEALEVEL_2802_7_PID) },
5761da177e4SLinus Torvalds 	{ USB_DEVICE(SEALEVEL_VID, SEALEVEL_2802_8_PID) },
5771da177e4SLinus Torvalds 	{ USB_DEVICE(SEALEVEL_VID, SEALEVEL_2803_1_PID) },
5781da177e4SLinus Torvalds 	{ USB_DEVICE(SEALEVEL_VID, SEALEVEL_2803_2_PID) },
5791da177e4SLinus Torvalds 	{ USB_DEVICE(SEALEVEL_VID, SEALEVEL_2803_3_PID) },
5801da177e4SLinus Torvalds 	{ USB_DEVICE(SEALEVEL_VID, SEALEVEL_2803_4_PID) },
5811da177e4SLinus Torvalds 	{ USB_DEVICE(SEALEVEL_VID, SEALEVEL_2803_5_PID) },
5821da177e4SLinus Torvalds 	{ USB_DEVICE(SEALEVEL_VID, SEALEVEL_2803_6_PID) },
5831da177e4SLinus Torvalds 	{ USB_DEVICE(SEALEVEL_VID, SEALEVEL_2803_7_PID) },
5841da177e4SLinus Torvalds 	{ USB_DEVICE(SEALEVEL_VID, SEALEVEL_2803_8_PID) },
5856d161b99SScott Dial 	{ USB_DEVICE(SEALEVEL_VID, SEALEVEL_2803R_1_PID) },
5866d161b99SScott Dial 	{ USB_DEVICE(SEALEVEL_VID, SEALEVEL_2803R_2_PID) },
5876d161b99SScott Dial 	{ USB_DEVICE(SEALEVEL_VID, SEALEVEL_2803R_3_PID) },
5886d161b99SScott Dial 	{ USB_DEVICE(SEALEVEL_VID, SEALEVEL_2803R_4_PID) },
5891da177e4SLinus Torvalds 	{ USB_DEVICE(IDTECH_VID, IDTECH_IDT1221U_PID) },
5901da177e4SLinus Torvalds 	{ USB_DEVICE(OCT_VID, OCT_US101_PID) },
59111a31d84SJohan Hovold 	{ USB_DEVICE(OCT_VID, OCT_DK201_PID) },
5928f977e42SIan Abbott 	{ USB_DEVICE(FTDI_VID, FTDI_HE_TIRA1_PID),
5938f977e42SIan Abbott 		.driver_info = (kernel_ulong_t)&ftdi_HE_TIRA1_quirk },
5948f977e42SIan Abbott 	{ USB_DEVICE(FTDI_VID, FTDI_USB_UIRT_PID),
5958f977e42SIan Abbott 		.driver_info = (kernel_ulong_t)&ftdi_USB_UIRT_quirk },
5961da177e4SLinus Torvalds 	{ USB_DEVICE(FTDI_VID, PROTEGO_SPECIAL_1) },
5971da177e4SLinus Torvalds 	{ USB_DEVICE(FTDI_VID, PROTEGO_R2X0) },
5981da177e4SLinus Torvalds 	{ USB_DEVICE(FTDI_VID, PROTEGO_SPECIAL_3) },
5991da177e4SLinus Torvalds 	{ USB_DEVICE(FTDI_VID, PROTEGO_SPECIAL_4) },
6008f977e42SIan Abbott 	{ USB_DEVICE(FTDI_VID, FTDI_GUDEADS_E808_PID) },
6018f977e42SIan Abbott 	{ USB_DEVICE(FTDI_VID, FTDI_GUDEADS_E809_PID) },
6028f977e42SIan Abbott 	{ USB_DEVICE(FTDI_VID, FTDI_GUDEADS_E80A_PID) },
6038f977e42SIan Abbott 	{ USB_DEVICE(FTDI_VID, FTDI_GUDEADS_E80B_PID) },
6048f977e42SIan Abbott 	{ USB_DEVICE(FTDI_VID, FTDI_GUDEADS_E80C_PID) },
6058f977e42SIan Abbott 	{ USB_DEVICE(FTDI_VID, FTDI_GUDEADS_E80D_PID) },
6068f977e42SIan Abbott 	{ USB_DEVICE(FTDI_VID, FTDI_GUDEADS_E80E_PID) },
6078f977e42SIan Abbott 	{ USB_DEVICE(FTDI_VID, FTDI_GUDEADS_E80F_PID) },
6088f977e42SIan Abbott 	{ USB_DEVICE(FTDI_VID, FTDI_GUDEADS_E888_PID) },
6098f977e42SIan Abbott 	{ USB_DEVICE(FTDI_VID, FTDI_GUDEADS_E889_PID) },
6108f977e42SIan Abbott 	{ USB_DEVICE(FTDI_VID, FTDI_GUDEADS_E88A_PID) },
6118f977e42SIan Abbott 	{ USB_DEVICE(FTDI_VID, FTDI_GUDEADS_E88B_PID) },
6128f977e42SIan Abbott 	{ USB_DEVICE(FTDI_VID, FTDI_GUDEADS_E88C_PID) },
6138f977e42SIan Abbott 	{ USB_DEVICE(FTDI_VID, FTDI_GUDEADS_E88D_PID) },
6148f977e42SIan Abbott 	{ USB_DEVICE(FTDI_VID, FTDI_GUDEADS_E88E_PID) },
6158f977e42SIan Abbott 	{ USB_DEVICE(FTDI_VID, FTDI_GUDEADS_E88F_PID) },
6161da177e4SLinus Torvalds 	{ USB_DEVICE(FTDI_VID, FTDI_ELV_UO100_PID) },
61747900743SIan Abbott 	{ USB_DEVICE(FTDI_VID, FTDI_ELV_UM100_PID) },
618e6ac4a40SIan Abbott 	{ USB_DEVICE(FTDI_VID, FTDI_ELV_UR100_PID) },
619e6ac4a40SIan Abbott 	{ USB_DEVICE(FTDI_VID, FTDI_ELV_ALC8500_PID) },
620207c47e1SThomas Riewe 	{ USB_DEVICE(FTDI_VID, FTDI_PYRAMID_PID) },
621bde62185SMartin Hagelin 	{ USB_DEVICE(FTDI_VID, FTDI_ELV_FHZ1000PC_PID) },
6224eaf60e0SThomas Schleusener 	{ USB_DEVICE(FTDI_VID, FTDI_IBS_US485_PID) },
6234eaf60e0SThomas Schleusener 	{ USB_DEVICE(FTDI_VID, FTDI_IBS_PICPRO_PID) },
6244eaf60e0SThomas Schleusener 	{ USB_DEVICE(FTDI_VID, FTDI_IBS_PCMCIA_PID) },
6254eaf60e0SThomas Schleusener 	{ USB_DEVICE(FTDI_VID, FTDI_IBS_PK1_PID) },
6264eaf60e0SThomas Schleusener 	{ USB_DEVICE(FTDI_VID, FTDI_IBS_RS232MON_PID) },
6274eaf60e0SThomas Schleusener 	{ USB_DEVICE(FTDI_VID, FTDI_IBS_APP70_PID) },
6284eaf60e0SThomas Schleusener 	{ USB_DEVICE(FTDI_VID, FTDI_IBS_PEDO_PID) },
6294eaf60e0SThomas Schleusener 	{ USB_DEVICE(FTDI_VID, FTDI_IBS_PROD_PID) },
63037909fe5SBenedek László 	{ USB_DEVICE(FTDI_VID, FTDI_TAVIR_STK500_PID) },
63154575b05SAntonio Ospite 	{ USB_DEVICE(FTDI_VID, FTDI_TIAO_UMPA_PID),
63254575b05SAntonio Ospite 		.driver_info = (kernel_ulong_t)&ftdi_jtag_quirk },
633d0839d75SGeorge McCollister 	{ USB_DEVICE(FTDI_VID, FTDI_NT_ORIONLXM_PID),
634d0839d75SGeorge McCollister 		.driver_info = (kernel_ulong_t)&ftdi_jtag_quirk },
635422c2537SGeorge McCollister 	{ USB_DEVICE(FTDI_VID, FTDI_NT_ORIONLX_PLUS_PID) },
636422c2537SGeorge McCollister 	{ USB_DEVICE(FTDI_VID, FTDI_NT_ORION_IO_PID) },
637bc96c72dSGeorge McCollister 	{ USB_DEVICE(FTDI_VID, FTDI_NT_ORIONMX_PID) },
6384899c054SDoug Goldstein 	{ USB_DEVICE(FTDI_VID, FTDI_SYNAPSE_SS200_PID) },
6391fb8dc36SMatthijs Kooijman 	{ USB_DEVICE(FTDI_VID, FTDI_CUSTOMWARE_MINIPLEX_PID) },
6401fb8dc36SMatthijs Kooijman 	{ USB_DEVICE(FTDI_VID, FTDI_CUSTOMWARE_MINIPLEX2_PID) },
6411fb8dc36SMatthijs Kooijman 	{ USB_DEVICE(FTDI_VID, FTDI_CUSTOMWARE_MINIPLEX2WI_PID) },
6421fb8dc36SMatthijs Kooijman 	{ USB_DEVICE(FTDI_VID, FTDI_CUSTOMWARE_MINIPLEX3_PID) },
643e6ac4a40SIan Abbott 	/*
64465e1ec67SAndreas Mohr 	 * ELV devices:
645e6ac4a40SIan Abbott 	 */
646c249f911SSven Killig 	{ USB_DEVICE(FTDI_ELV_VID, FTDI_ELV_WS300_PID) },
64765e1ec67SAndreas Mohr 	{ USB_DEVICE(FTDI_VID, FTDI_ELV_USR_PID) },
64865e1ec67SAndreas Mohr 	{ USB_DEVICE(FTDI_VID, FTDI_ELV_MSM1_PID) },
64965e1ec67SAndreas Mohr 	{ USB_DEVICE(FTDI_VID, FTDI_ELV_KL100_PID) },
65065e1ec67SAndreas Mohr 	{ USB_DEVICE(FTDI_VID, FTDI_ELV_WS550_PID) },
65165e1ec67SAndreas Mohr 	{ USB_DEVICE(FTDI_VID, FTDI_ELV_EC3000_PID) },
65265e1ec67SAndreas Mohr 	{ USB_DEVICE(FTDI_VID, FTDI_ELV_WS888_PID) },
65365e1ec67SAndreas Mohr 	{ USB_DEVICE(FTDI_VID, FTDI_ELV_TWS550_PID) },
65465e1ec67SAndreas Mohr 	{ USB_DEVICE(FTDI_VID, FTDI_ELV_FEM_PID) },
65542f8aa94SPeter Stark 	{ USB_DEVICE(FTDI_VID, FTDI_ELV_CLI7000_PID) },
65642f8aa94SPeter Stark 	{ USB_DEVICE(FTDI_VID, FTDI_ELV_PPS7330_PID) },
65742f8aa94SPeter Stark 	{ USB_DEVICE(FTDI_VID, FTDI_ELV_TFM100_PID) },
65842f8aa94SPeter Stark 	{ USB_DEVICE(FTDI_VID, FTDI_ELV_UDF77_PID) },
65942f8aa94SPeter Stark 	{ USB_DEVICE(FTDI_VID, FTDI_ELV_UIO88_PID) },
66042f8aa94SPeter Stark 	{ USB_DEVICE(FTDI_VID, FTDI_ELV_UAD8_PID) },
66142f8aa94SPeter Stark 	{ USB_DEVICE(FTDI_VID, FTDI_ELV_UDA7_PID) },
66242f8aa94SPeter Stark 	{ USB_DEVICE(FTDI_VID, FTDI_ELV_USI2_PID) },
66342f8aa94SPeter Stark 	{ USB_DEVICE(FTDI_VID, FTDI_ELV_T1100_PID) },
66442f8aa94SPeter Stark 	{ USB_DEVICE(FTDI_VID, FTDI_ELV_PCD200_PID) },
66542f8aa94SPeter Stark 	{ USB_DEVICE(FTDI_VID, FTDI_ELV_ULA200_PID) },
66642f8aa94SPeter Stark 	{ USB_DEVICE(FTDI_VID, FTDI_ELV_CSI8_PID) },
66742f8aa94SPeter Stark 	{ USB_DEVICE(FTDI_VID, FTDI_ELV_EM1000DL_PID) },
66842f8aa94SPeter Stark 	{ USB_DEVICE(FTDI_VID, FTDI_ELV_PCK100_PID) },
66942f8aa94SPeter Stark 	{ USB_DEVICE(FTDI_VID, FTDI_ELV_RFP500_PID) },
67042f8aa94SPeter Stark 	{ USB_DEVICE(FTDI_VID, FTDI_ELV_FS20SIG_PID) },
67165e1ec67SAndreas Mohr 	{ USB_DEVICE(FTDI_VID, FTDI_ELV_UTP8_PID) },
67242f8aa94SPeter Stark 	{ USB_DEVICE(FTDI_VID, FTDI_ELV_WS300PC_PID) },
67365e1ec67SAndreas Mohr 	{ USB_DEVICE(FTDI_VID, FTDI_ELV_WS444PC_PID) },
67442f8aa94SPeter Stark 	{ USB_DEVICE(FTDI_VID, FTDI_ELV_FHZ1300PC_PID) },
6754ae897dfSSven Andersen 	{ USB_DEVICE(FTDI_VID, FTDI_ELV_EM1010PC_PID) },
67642f8aa94SPeter Stark 	{ USB_DEVICE(FTDI_VID, FTDI_ELV_WS500_PID) },
677b5894a50SAndré Schenk 	{ USB_DEVICE(FTDI_VID, FTDI_ELV_HS485_PID) },
67865e1ec67SAndreas Mohr 	{ USB_DEVICE(FTDI_VID, FTDI_ELV_UMS100_PID) },
67965e1ec67SAndreas Mohr 	{ USB_DEVICE(FTDI_VID, FTDI_ELV_TFD128_PID) },
68065e1ec67SAndreas Mohr 	{ USB_DEVICE(FTDI_VID, FTDI_ELV_FM3RX_PID) },
68165e1ec67SAndreas Mohr 	{ USB_DEVICE(FTDI_VID, FTDI_ELV_WS777_PID) },
6826977495cSRobert Deliën 	{ USB_DEVICE(FTDI_VID, FTDI_PALMSENS_PID) },
6836977495cSRobert Deliën 	{ USB_DEVICE(FTDI_VID, FTDI_IVIUM_XSTAT_PID) },
6848f977e42SIan Abbott 	{ USB_DEVICE(FTDI_VID, LINX_SDMUSBQSS_PID) },
6858f977e42SIan Abbott 	{ USB_DEVICE(FTDI_VID, LINX_MASTERDEVEL2_PID) },
6868f977e42SIan Abbott 	{ USB_DEVICE(FTDI_VID, LINX_FUTURE_0_PID) },
6878f977e42SIan Abbott 	{ USB_DEVICE(FTDI_VID, LINX_FUTURE_1_PID) },
6888f977e42SIan Abbott 	{ USB_DEVICE(FTDI_VID, LINX_FUTURE_2_PID) },
6891da177e4SLinus Torvalds 	{ USB_DEVICE(FTDI_VID, FTDI_CCSICDU20_0_PID) },
6901da177e4SLinus Torvalds 	{ USB_DEVICE(FTDI_VID, FTDI_CCSICDU40_1_PID) },
691ec434e9bSJan Capek 	{ USB_DEVICE(FTDI_VID, FTDI_CCSMACHX_2_PID) },
6929d37ff64SJan Capek 	{ USB_DEVICE(FTDI_VID, FTDI_CCSLOAD_N_GO_3_PID) },
6939d37ff64SJan Capek 	{ USB_DEVICE(FTDI_VID, FTDI_CCSICDU64_4_PID) },
6949d37ff64SJan Capek 	{ USB_DEVICE(FTDI_VID, FTDI_CCSPRIME8_5_PID) },
6951da177e4SLinus Torvalds 	{ USB_DEVICE(FTDI_VID, INSIDE_ACCESSO) },
6961da177e4SLinus Torvalds 	{ USB_DEVICE(INTREPID_VID, INTREPID_VALUECAN_PID) },
6971da177e4SLinus Torvalds 	{ USB_DEVICE(INTREPID_VID, INTREPID_NEOVI_PID) },
6981da177e4SLinus Torvalds 	{ USB_DEVICE(FALCOM_VID, FALCOM_TWIST_PID) },
699e6ac4a40SIan Abbott 	{ USB_DEVICE(FALCOM_VID, FALCOM_SAMBA_PID) },
7001da177e4SLinus Torvalds 	{ USB_DEVICE(FTDI_VID, FTDI_SUUNTO_SPORTS_PID) },
701c3d36c45SVladimir Vukicevic 	{ USB_DEVICE(FTDI_VID, FTDI_OCEANIC_PID) },
702ef31fec0SMichael Olberg 	{ USB_DEVICE(TTI_VID, TTI_QL355P_PID) },
7036f92872cSIan Abbott 	{ USB_DEVICE(FTDI_VID, FTDI_RM_CANVIEW_PID) },
70428fe2eb0SMichael Williamson 	{ USB_DEVICE(ACTON_VID, ACTON_SPECTRAPRO_PID) },
70546b72d78SDaniel Sangorrin 	{ USB_DEVICE(CONTEC_VID, CONTEC_COM1USBH_PID) },
706482b0b5dSKonstantin Holoborodko 	{ USB_DEVICE(MITSUBISHI_VID, MITSUBISHI_FXUSB_PID) },
7071da177e4SLinus Torvalds 	{ USB_DEVICE(BANDB_VID, BANDB_USOTL4_PID) },
7081da177e4SLinus Torvalds 	{ USB_DEVICE(BANDB_VID, BANDB_USTL4_PID) },
7091da177e4SLinus Torvalds 	{ USB_DEVICE(BANDB_VID, BANDB_USO9ML2_PID) },
710a8cbd90aSCliff Brake 	{ USB_DEVICE(BANDB_VID, BANDB_USOPTL4_PID) },
711a8cbd90aSCliff Brake 	{ USB_DEVICE(BANDB_VID, BANDB_USPTL4_PID) },
712a8cbd90aSCliff Brake 	{ USB_DEVICE(BANDB_VID, BANDB_USO9ML2DR_2_PID) },
713a8cbd90aSCliff Brake 	{ USB_DEVICE(BANDB_VID, BANDB_USO9ML2DR_PID) },
714a8cbd90aSCliff Brake 	{ USB_DEVICE(BANDB_VID, BANDB_USOPTL4DR2_PID) },
715a8cbd90aSCliff Brake 	{ USB_DEVICE(BANDB_VID, BANDB_USOPTL4DR_PID) },
716a8cbd90aSCliff Brake 	{ USB_DEVICE(BANDB_VID, BANDB_485USB9F_2W_PID) },
717a8cbd90aSCliff Brake 	{ USB_DEVICE(BANDB_VID, BANDB_485USB9F_4W_PID) },
718a8cbd90aSCliff Brake 	{ USB_DEVICE(BANDB_VID, BANDB_232USB9M_PID) },
719a8cbd90aSCliff Brake 	{ USB_DEVICE(BANDB_VID, BANDB_485USBTB_2W_PID) },
720a8cbd90aSCliff Brake 	{ USB_DEVICE(BANDB_VID, BANDB_485USBTB_4W_PID) },
721a8cbd90aSCliff Brake 	{ USB_DEVICE(BANDB_VID, BANDB_TTL5USB9M_PID) },
722a8cbd90aSCliff Brake 	{ USB_DEVICE(BANDB_VID, BANDB_TTL3USB9M_PID) },
723a8cbd90aSCliff Brake 	{ USB_DEVICE(BANDB_VID, BANDB_ZZ_PROG1_USB_PID) },
7241da177e4SLinus Torvalds 	{ USB_DEVICE(FTDI_VID, EVER_ECO_PRO_CDS) },
7256f92872cSIan Abbott 	{ USB_DEVICE(FTDI_VID, FTDI_4N_GALAXY_DE_1_PID) },
7266f92872cSIan Abbott 	{ USB_DEVICE(FTDI_VID, FTDI_4N_GALAXY_DE_2_PID) },
727a26d31ceSSteffen Sledz 	{ USB_DEVICE(FTDI_VID, FTDI_4N_GALAXY_DE_3_PID) },
728e6ac4a40SIan Abbott 	{ USB_DEVICE(FTDI_VID, XSENS_CONVERTER_0_PID) },
729e6ac4a40SIan Abbott 	{ USB_DEVICE(FTDI_VID, XSENS_CONVERTER_1_PID) },
730e6ac4a40SIan Abbott 	{ USB_DEVICE(FTDI_VID, XSENS_CONVERTER_2_PID) },
731e6ac4a40SIan Abbott 	{ USB_DEVICE(FTDI_VID, XSENS_CONVERTER_3_PID) },
732e6ac4a40SIan Abbott 	{ USB_DEVICE(FTDI_VID, XSENS_CONVERTER_4_PID) },
733e6ac4a40SIan Abbott 	{ USB_DEVICE(FTDI_VID, XSENS_CONVERTER_5_PID) },
734e6ac4a40SIan Abbott 	{ USB_DEVICE(FTDI_VID, XSENS_CONVERTER_6_PID) },
735e6ac4a40SIan Abbott 	{ USB_DEVICE(FTDI_VID, XSENS_CONVERTER_7_PID) },
736edd74ffaSFrans Klaver 	{ USB_DEVICE(XSENS_VID, XSENS_AWINDA_DONGLE_PID) },
737edd74ffaSFrans Klaver 	{ USB_DEVICE(XSENS_VID, XSENS_AWINDA_STATION_PID) },
7384bdcde35SPatrick Riphagen 	{ USB_DEVICE(XSENS_VID, XSENS_CONVERTER_PID) },
7391df5b888SPatrick Riphagen 	{ USB_DEVICE(XSENS_VID, XSENS_MTDEVBOARD_PID) },
7406ccc48e0SPatrick Riphagen 	{ USB_DEVICE(XSENS_VID, XSENS_MTIUSBCONVERTER_PID) },
7414bdcde35SPatrick Riphagen 	{ USB_DEVICE(XSENS_VID, XSENS_MTW_PID) },
7420ba3b2ccSPetr Kubánek 	{ USB_DEVICE(FTDI_VID, FTDI_OMNI1509) },
7436f92872cSIan Abbott 	{ USB_DEVICE(MOBILITY_VID, MOBILITY_USB_SERIAL_PID) },
7448f977e42SIan Abbott 	{ USB_DEVICE(FTDI_VID, FTDI_ACTIVE_ROBOTS_PID) },
74534d1a8aaSIan Abbott 	{ USB_DEVICE(FTDI_VID, FTDI_MHAM_KW_PID) },
74634d1a8aaSIan Abbott 	{ USB_DEVICE(FTDI_VID, FTDI_MHAM_YS_PID) },
7479b1513d9SIan Abbott 	{ USB_DEVICE(FTDI_VID, FTDI_MHAM_Y6_PID) },
7489b1513d9SIan Abbott 	{ USB_DEVICE(FTDI_VID, FTDI_MHAM_Y8_PID) },
74934d1a8aaSIan Abbott 	{ USB_DEVICE(FTDI_VID, FTDI_MHAM_IC_PID) },
75034d1a8aaSIan Abbott 	{ USB_DEVICE(FTDI_VID, FTDI_MHAM_DB9_PID) },
75134d1a8aaSIan Abbott 	{ USB_DEVICE(FTDI_VID, FTDI_MHAM_RS232_PID) },
75234d1a8aaSIan Abbott 	{ USB_DEVICE(FTDI_VID, FTDI_MHAM_Y9_PID) },
753740a4282SIan Abbott 	{ USB_DEVICE(FTDI_VID, FTDI_TERATRONIK_VCP_PID) },
754740a4282SIan Abbott 	{ USB_DEVICE(FTDI_VID, FTDI_TERATRONIK_D2XX_PID) },
7559b1513d9SIan Abbott 	{ USB_DEVICE(EVOLUTION_VID, EVOLUTION_ER1_PID) },
756c1f8ea7dSSøren Hauberg 	{ USB_DEVICE(EVOLUTION_VID, EVO_HYBRID_PID) },
757c1f8ea7dSSøren Hauberg 	{ USB_DEVICE(EVOLUTION_VID, EVO_RCM4_PID) },
758c9c7746dSRui Santos 	{ USB_DEVICE(FTDI_VID, FTDI_ARTEMIS_PID) },
759c9c7746dSRui Santos 	{ USB_DEVICE(FTDI_VID, FTDI_ATIK_ATK16_PID) },
76009c280a2SRui Santos 	{ USB_DEVICE(FTDI_VID, FTDI_ATIK_ATK16C_PID) },
761c9c7746dSRui Santos 	{ USB_DEVICE(FTDI_VID, FTDI_ATIK_ATK16HR_PID) },
76209c280a2SRui Santos 	{ USB_DEVICE(FTDI_VID, FTDI_ATIK_ATK16HRC_PID) },
76334910434SFranco Lanza 	{ USB_DEVICE(FTDI_VID, FTDI_ATIK_ATK16IC_PID) },
764b4723ae3SIan Abbott 	{ USB_DEVICE(KOBIL_VID, KOBIL_CONV_B1_PID) },
765b4723ae3SIan Abbott 	{ USB_DEVICE(KOBIL_VID, KOBIL_CONV_KAAN_PID) },
766effac8beSPavel Fedin 	{ USB_DEVICE(POSIFLEX_VID, POSIFLEX_PP7000_PID) },
767641adaaeSLouis Nyffenegger 	{ USB_DEVICE(FTDI_VID, FTDI_TTUSB_PID) },
7687e1c0b86SIan Abbott 	{ USB_DEVICE(FTDI_VID, FTDI_ECLO_COM_1WIRE_PID) },
769a94b52acSIan Abbott 	{ USB_DEVICE(FTDI_VID, FTDI_WESTREX_MODEL_777_PID) },
770a94b52acSIan Abbott 	{ USB_DEVICE(FTDI_VID, FTDI_WESTREX_MODEL_8900F_PID) },
771ce40d290SWouter Paesen 	{ USB_DEVICE(FTDI_VID, FTDI_PCDJ_DAC2_PID) },
772cdd3b156SNathan Bronson 	{ USB_DEVICE(FTDI_VID, FTDI_RRCIRKITS_LOCOBUFFER_PID) },
7737e0258fdSIan Abbott 	{ USB_DEVICE(FTDI_VID, FTDI_ASK_RDR400_PID) },
77426a538b9SHorst Schirmeier 	{ USB_DEVICE(FTDI_VID, FTDI_NZR_SEM_USB_PID) },
775a9d61bc4SPieter Maes 	{ USB_DEVICE(ICOM_VID, ICOM_ID_1_PID) },
776a9d61bc4SPieter Maes 	{ USB_DEVICE(ICOM_VID, ICOM_OPC_U_UC_PID) },
777a9d61bc4SPieter Maes 	{ USB_DEVICE(ICOM_VID, ICOM_ID_RP2C1_PID) },
778a9d61bc4SPieter Maes 	{ USB_DEVICE(ICOM_VID, ICOM_ID_RP2C2_PID) },
779a9d61bc4SPieter Maes 	{ USB_DEVICE(ICOM_VID, ICOM_ID_RP2D_PID) },
780a9d61bc4SPieter Maes 	{ USB_DEVICE(ICOM_VID, ICOM_ID_RP2VT_PID) },
781a9d61bc4SPieter Maes 	{ USB_DEVICE(ICOM_VID, ICOM_ID_RP2VR_PID) },
782a9d61bc4SPieter Maes 	{ USB_DEVICE(ICOM_VID, ICOM_ID_RP4KVT_PID) },
783a9d61bc4SPieter Maes 	{ USB_DEVICE(ICOM_VID, ICOM_ID_RP4KVR_PID) },
784a9d61bc4SPieter Maes 	{ USB_DEVICE(ICOM_VID, ICOM_ID_RP2KVT_PID) },
785a9d61bc4SPieter Maes 	{ USB_DEVICE(ICOM_VID, ICOM_ID_RP2KVR_PID) },
78620a0f47eSIan Abbott 	{ USB_DEVICE(FTDI_VID, FTDI_ACG_HFDUAL_PID) },
787eb79b4fdSIan Abbott 	{ USB_DEVICE(FTDI_VID, FTDI_YEI_SERVOCENTER31_PID) },
78848437486SD. Peter Siddons 	{ USB_DEVICE(FTDI_VID, FTDI_THORLABS_PID) },
7895a7fbe7eSBert Vermeulen 	{ USB_DEVICE(TESTO_VID, TESTO_1_PID) },
7905a7fbe7eSBert Vermeulen 	{ USB_DEVICE(TESTO_VID, TESTO_3_PID) },
791eaede2cbSRalf Schlatterbeck 	{ USB_DEVICE(FTDI_VID, FTDI_GAMMA_SCOUT_PID) },
7929978f9e1SIan Abbott 	{ USB_DEVICE(FTDI_VID, FTDI_TACTRIX_OPENPORT_13M_PID) },
7939978f9e1SIan Abbott 	{ USB_DEVICE(FTDI_VID, FTDI_TACTRIX_OPENPORT_13S_PID) },
7949978f9e1SIan Abbott 	{ USB_DEVICE(FTDI_VID, FTDI_TACTRIX_OPENPORT_13U_PID) },
79540c36092SKjell Myksvoll 	{ USB_DEVICE(ELEKTOR_VID, ELEKTOR_FT323R_PID) },
796b760dac2SMartin Geleynse 	{ USB_DEVICE(FTDI_VID, FTDI_NDI_HUC_PID),
797b760dac2SMartin Geleynse 		.driver_info = (kernel_ulong_t)&ftdi_NDI_device_quirk },
798b760dac2SMartin Geleynse 	{ USB_DEVICE(FTDI_VID, FTDI_NDI_SPECTRA_SCU_PID),
799b760dac2SMartin Geleynse 		.driver_info = (kernel_ulong_t)&ftdi_NDI_device_quirk },
800b760dac2SMartin Geleynse 	{ USB_DEVICE(FTDI_VID, FTDI_NDI_FUTURE_2_PID),
801b760dac2SMartin Geleynse 		.driver_info = (kernel_ulong_t)&ftdi_NDI_device_quirk },
802b760dac2SMartin Geleynse 	{ USB_DEVICE(FTDI_VID, FTDI_NDI_FUTURE_3_PID),
803b760dac2SMartin Geleynse 		.driver_info = (kernel_ulong_t)&ftdi_NDI_device_quirk },
804b760dac2SMartin Geleynse 	{ USB_DEVICE(FTDI_VID, FTDI_NDI_AURORA_SCU_PID),
805b760dac2SMartin Geleynse 		.driver_info = (kernel_ulong_t)&ftdi_NDI_device_quirk },
806822c7ef4SMicke Prag 	{ USB_DEVICE(TELLDUS_VID, TELLDUS_TELLSTICK_PID) },
807ee444609SJohan Hovold 	{ USB_DEVICE(NOVITUS_VID, NOVITUS_BONO_E_PID) },
8089608e5c0SMajor Hayden 	{ USB_DEVICE(FTDI_VID, RTSYSTEMS_USB_VX8_PID) },
809fed1f1edSRick Farina (Zero_Chaos) 	{ USB_DEVICE(RTSYSTEMS_VID, RTSYSTEMS_USB_S03_PID) },
810fed1f1edSRick Farina (Zero_Chaos) 	{ USB_DEVICE(RTSYSTEMS_VID, RTSYSTEMS_USB_59_PID) },
811fed1f1edSRick Farina (Zero_Chaos) 	{ USB_DEVICE(RTSYSTEMS_VID, RTSYSTEMS_USB_57A_PID) },
812fed1f1edSRick Farina (Zero_Chaos) 	{ USB_DEVICE(RTSYSTEMS_VID, RTSYSTEMS_USB_57B_PID) },
813fed1f1edSRick Farina (Zero_Chaos) 	{ USB_DEVICE(RTSYSTEMS_VID, RTSYSTEMS_USB_29A_PID) },
814fed1f1edSRick Farina (Zero_Chaos) 	{ USB_DEVICE(RTSYSTEMS_VID, RTSYSTEMS_USB_29B_PID) },
815fed1f1edSRick Farina (Zero_Chaos) 	{ USB_DEVICE(RTSYSTEMS_VID, RTSYSTEMS_USB_29F_PID) },
816fed1f1edSRick Farina (Zero_Chaos) 	{ USB_DEVICE(RTSYSTEMS_VID, RTSYSTEMS_USB_62B_PID) },
817fed1f1edSRick Farina (Zero_Chaos) 	{ USB_DEVICE(RTSYSTEMS_VID, RTSYSTEMS_USB_S01_PID) },
818fed1f1edSRick Farina (Zero_Chaos) 	{ USB_DEVICE(RTSYSTEMS_VID, RTSYSTEMS_USB_63_PID) },
819fed1f1edSRick Farina (Zero_Chaos) 	{ USB_DEVICE(RTSYSTEMS_VID, RTSYSTEMS_USB_29C_PID) },
820fed1f1edSRick Farina (Zero_Chaos) 	{ USB_DEVICE(RTSYSTEMS_VID, RTSYSTEMS_USB_81B_PID) },
821fed1f1edSRick Farina (Zero_Chaos) 	{ USB_DEVICE(RTSYSTEMS_VID, RTSYSTEMS_USB_82B_PID) },
822fed1f1edSRick Farina (Zero_Chaos) 	{ USB_DEVICE(RTSYSTEMS_VID, RTSYSTEMS_USB_K5D_PID) },
823fed1f1edSRick Farina (Zero_Chaos) 	{ USB_DEVICE(RTSYSTEMS_VID, RTSYSTEMS_USB_K4Y_PID) },
824fed1f1edSRick Farina (Zero_Chaos) 	{ USB_DEVICE(RTSYSTEMS_VID, RTSYSTEMS_USB_K5G_PID) },
825fed1f1edSRick Farina (Zero_Chaos) 	{ USB_DEVICE(RTSYSTEMS_VID, RTSYSTEMS_USB_S05_PID) },
826fed1f1edSRick Farina (Zero_Chaos) 	{ USB_DEVICE(RTSYSTEMS_VID, RTSYSTEMS_USB_60_PID) },
827fed1f1edSRick Farina (Zero_Chaos) 	{ USB_DEVICE(RTSYSTEMS_VID, RTSYSTEMS_USB_61_PID) },
828fed1f1edSRick Farina (Zero_Chaos) 	{ USB_DEVICE(RTSYSTEMS_VID, RTSYSTEMS_USB_62_PID) },
829fed1f1edSRick Farina (Zero_Chaos) 	{ USB_DEVICE(RTSYSTEMS_VID, RTSYSTEMS_USB_63B_PID) },
830fed1f1edSRick Farina (Zero_Chaos) 	{ USB_DEVICE(RTSYSTEMS_VID, RTSYSTEMS_USB_64_PID) },
831fed1f1edSRick Farina (Zero_Chaos) 	{ USB_DEVICE(RTSYSTEMS_VID, RTSYSTEMS_USB_65_PID) },
832fed1f1edSRick Farina (Zero_Chaos) 	{ USB_DEVICE(RTSYSTEMS_VID, RTSYSTEMS_USB_92_PID) },
833fed1f1edSRick Farina (Zero_Chaos) 	{ USB_DEVICE(RTSYSTEMS_VID, RTSYSTEMS_USB_92D_PID) },
834fed1f1edSRick Farina (Zero_Chaos) 	{ USB_DEVICE(RTSYSTEMS_VID, RTSYSTEMS_USB_W5R_PID) },
835fed1f1edSRick Farina (Zero_Chaos) 	{ USB_DEVICE(RTSYSTEMS_VID, RTSYSTEMS_USB_A5R_PID) },
836fed1f1edSRick Farina (Zero_Chaos) 	{ USB_DEVICE(RTSYSTEMS_VID, RTSYSTEMS_USB_PW1_PID) },
837762e92faSNeil \"Superna\" ARMSTRONG 	{ USB_DEVICE(FTDI_VID, FTDI_MAXSTREAM_PID) },
838a5f62399SLex Ross 	{ USB_DEVICE(FTDI_VID, FTDI_PHI_FISCO_PID) },
839d7fde2d6SPierre Castella 	{ USB_DEVICE(TML_VID, TML_USB_SERIAL_PID) },
8404bb0ef19SEd Beroset 	{ USB_DEVICE(FTDI_VID, FTDI_ELSTER_UNICOM_PID) },
84111171d1bSMirko Bordignon 	{ USB_DEVICE(FTDI_VID, FTDI_PROPOX_JTAGCABLEII_PID) },
842307369b0SMarcin Kościelnicki 	{ USB_DEVICE(FTDI_VID, FTDI_PROPOX_ISPCABLEIII_PID) },
843c7d373c3SMax Mansfield 	{ USB_DEVICE(FTDI_VID, CYBER_CORTEX_AV_PID),
844c7d373c3SMax Mansfield 		.driver_info = (kernel_ulong_t)&ftdi_jtag_quirk },
8455f63424aSAndrey Korolyov 	{ USB_DEVICE_INTERFACE_NUMBER(OLIMEX_VID, OLIMEX_ARM_USB_OCD_PID, 1) },
8465f63424aSAndrey Korolyov 	{ USB_DEVICE_INTERFACE_NUMBER(OLIMEX_VID, OLIMEX_ARM_USB_OCD_H_PID, 1) },
8475f63424aSAndrey Korolyov 	{ USB_DEVICE_INTERFACE_NUMBER(OLIMEX_VID, OLIMEX_ARM_USB_TINY_PID, 1) },
8485f63424aSAndrey Korolyov 	{ USB_DEVICE_INTERFACE_NUMBER(OLIMEX_VID, OLIMEX_ARM_USB_TINY_H_PID, 1) },
84920734345SHarald Welte 	{ USB_DEVICE(FIC_VID, FIC_NEO1973_DEBUG_PID),
85020734345SHarald Welte 		.driver_info = (kernel_ulong_t)&ftdi_jtag_quirk },
85120734345SHarald Welte 	{ USB_DEVICE(FTDI_VID, FTDI_OOCDLINK_PID),
85220734345SHarald Welte 		.driver_info = (kernel_ulong_t)&ftdi_jtag_quirk },
853a00c3cadSFrederik Kriewitz 	{ USB_DEVICE(FTDI_VID, LMI_LM3S_DEVEL_BOARD_PID),
854a00c3cadSFrederik Kriewitz 		.driver_info = (kernel_ulong_t)&ftdi_jtag_quirk },
855a00c3cadSFrederik Kriewitz 	{ USB_DEVICE(FTDI_VID, LMI_LM3S_EVAL_BOARD_PID),
856a00c3cadSFrederik Kriewitz 		.driver_info = (kernel_ulong_t)&ftdi_jtag_quirk },
8573687f641SPeter Stuge 	{ USB_DEVICE(FTDI_VID, LMI_LM3S_ICDI_BOARD_PID),
8583687f641SPeter Stuge 		.driver_info = (kernel_ulong_t)&ftdi_jtag_quirk },
85914511412SKrzysztof Halasa 	{ USB_DEVICE(FTDI_VID, FTDI_TURTELIZER_PID),
86014511412SKrzysztof Halasa 		.driver_info = (kernel_ulong_t)&ftdi_jtag_quirk },
86126ab7053SAtsushi Nemoto 	{ USB_DEVICE(RATOC_VENDOR_ID, RATOC_PRODUCT_ID_USB60F) },
862e03cdf22SGreg Kroah-Hartman 	{ USB_DEVICE(RATOC_VENDOR_ID, RATOC_PRODUCT_ID_SCU18) },
8632542335cSJon K Hellan 	{ USB_DEVICE(FTDI_VID, FTDI_REU_TINY_PID) },
86459c6ccd9SDaniel Suchy 
86559c6ccd9SDaniel Suchy 	/* Papouch devices based on FTDI chip */
86659c6ccd9SDaniel Suchy 	{ USB_DEVICE(PAPOUCH_VID, PAPOUCH_SB485_PID) },
86759c6ccd9SDaniel Suchy 	{ USB_DEVICE(PAPOUCH_VID, PAPOUCH_AP485_PID) },
86859c6ccd9SDaniel Suchy 	{ USB_DEVICE(PAPOUCH_VID, PAPOUCH_SB422_PID) },
86959c6ccd9SDaniel Suchy 	{ USB_DEVICE(PAPOUCH_VID, PAPOUCH_SB485_2_PID) },
87059c6ccd9SDaniel Suchy 	{ USB_DEVICE(PAPOUCH_VID, PAPOUCH_AP485_2_PID) },
87159c6ccd9SDaniel Suchy 	{ USB_DEVICE(PAPOUCH_VID, PAPOUCH_SB422_2_PID) },
87259c6ccd9SDaniel Suchy 	{ USB_DEVICE(PAPOUCH_VID, PAPOUCH_SB485S_PID) },
87359c6ccd9SDaniel Suchy 	{ USB_DEVICE(PAPOUCH_VID, PAPOUCH_SB485C_PID) },
87459c6ccd9SDaniel Suchy 	{ USB_DEVICE(PAPOUCH_VID, PAPOUCH_LEC_PID) },
87559c6ccd9SDaniel Suchy 	{ USB_DEVICE(PAPOUCH_VID, PAPOUCH_SB232_PID) },
87659c6ccd9SDaniel Suchy 	{ USB_DEVICE(PAPOUCH_VID, PAPOUCH_TMU_PID) },
87759c6ccd9SDaniel Suchy 	{ USB_DEVICE(PAPOUCH_VID, PAPOUCH_IRAMP_PID) },
87859c6ccd9SDaniel Suchy 	{ USB_DEVICE(PAPOUCH_VID, PAPOUCH_DRAK5_PID) },
87959c6ccd9SDaniel Suchy 	{ USB_DEVICE(PAPOUCH_VID, PAPOUCH_QUIDO8x8_PID) },
880a18f80b4SJaroslav Kysela 	{ USB_DEVICE(PAPOUCH_VID, PAPOUCH_QUIDO4x4_PID) },
88159c6ccd9SDaniel Suchy 	{ USB_DEVICE(PAPOUCH_VID, PAPOUCH_QUIDO2x2_PID) },
88259c6ccd9SDaniel Suchy 	{ USB_DEVICE(PAPOUCH_VID, PAPOUCH_QUIDO10x1_PID) },
88359c6ccd9SDaniel Suchy 	{ USB_DEVICE(PAPOUCH_VID, PAPOUCH_QUIDO30x3_PID) },
88459c6ccd9SDaniel Suchy 	{ USB_DEVICE(PAPOUCH_VID, PAPOUCH_QUIDO60x3_PID) },
88559c6ccd9SDaniel Suchy 	{ USB_DEVICE(PAPOUCH_VID, PAPOUCH_QUIDO2x16_PID) },
88659c6ccd9SDaniel Suchy 	{ USB_DEVICE(PAPOUCH_VID, PAPOUCH_QUIDO3x32_PID) },
88759c6ccd9SDaniel Suchy 	{ USB_DEVICE(PAPOUCH_VID, PAPOUCH_DRAK6_PID) },
88859c6ccd9SDaniel Suchy 	{ USB_DEVICE(PAPOUCH_VID, PAPOUCH_UPSUSB_PID) },
88959c6ccd9SDaniel Suchy 	{ USB_DEVICE(PAPOUCH_VID, PAPOUCH_MU_PID) },
89059c6ccd9SDaniel Suchy 	{ USB_DEVICE(PAPOUCH_VID, PAPOUCH_SIMUKEY_PID) },
891a7787e50SRadek Liboska 	{ USB_DEVICE(PAPOUCH_VID, PAPOUCH_AD4USB_PID) },
89259c6ccd9SDaniel Suchy 	{ USB_DEVICE(PAPOUCH_VID, PAPOUCH_GMUX_PID) },
89359c6ccd9SDaniel Suchy 	{ USB_DEVICE(PAPOUCH_VID, PAPOUCH_GMSR_PID) },
89459c6ccd9SDaniel Suchy 
89596285cb8SGaetan Carlier 	{ USB_DEVICE(FTDI_VID, FTDI_DOMINTELL_DGQG_PID) },
89696285cb8SGaetan Carlier 	{ USB_DEVICE(FTDI_VID, FTDI_DOMINTELL_DUSB_PID) },
89745eeff84SRobie Basak 	{ USB_DEVICE(ALTI2_VID, ALTI2_N3_PID) },
898ca80801bSMhayk Whandson 	{ USB_DEVICE(FTDI_VID, DIEBOLD_BCS_SE923_PID) },
8997f82b6ddSAxel Wachtler 	{ USB_DEVICE(ATMEL_VID, STK541_PID) },
9007f82b6ddSAxel Wachtler 	{ USB_DEVICE(DE_VID, STB_PID) },
9017f82b6ddSAxel Wachtler 	{ USB_DEVICE(DE_VID, WHT_PID) },
902b0d65900SMichael Hennerich 	{ USB_DEVICE(ADI_VID, ADI_GNICE_PID),
903b0d65900SMichael Hennerich 		.driver_info = (kernel_ulong_t)&ftdi_jtag_quirk },
90411eaf170SMichael Hennerich 	{ USB_DEVICE(ADI_VID, ADI_GNICEPLUS_PID),
90511eaf170SMichael Hennerich 		.driver_info = (kernel_ulong_t)&ftdi_jtag_quirk },
906f08dea73SBjørn Mork 	{ USB_DEVICE_AND_INTERFACE_INFO(MICROCHIP_VID, MICROCHIP_USB_BOARD_PID,
907f08dea73SBjørn Mork 					USB_CLASS_VENDOR_SPEC,
908f08dea73SBjørn Mork 					USB_SUBCLASS_VENDOR_SPEC, 0x00) },
90931c5d192SMarek Vasut 	{ USB_DEVICE_INTERFACE_NUMBER(ACTEL_VID, MICROSEMI_ARROW_SF2PLUS_BOARD_PID, 2) },
910ae27d843SPeter Korsgaard 	{ USB_DEVICE(JETI_VID, JETI_SPC1201_PID) },
9111002bb77SNicolas Pitre 	{ USB_DEVICE(MARVELL_VID, MARVELL_SHEEVAPLUG_PID),
9121002bb77SNicolas Pitre 		.driver_info = (kernel_ulong_t)&ftdi_jtag_quirk },
913d46130abSDaniel Suchy 	{ USB_DEVICE(LARSENBRUSGAARD_VID, LB_ALTITRACK_PID) },
914fca4404cSVille Sundberg 	{ USB_DEVICE(GN_OTOMETRICS_VID, AURICAL_USB_PID) },
915dafc4f7bSÉric Piel 	{ USB_DEVICE(FTDI_VID, PI_C865_PID) },
916dafc4f7bSÉric Piel 	{ USB_DEVICE(FTDI_VID, PI_C857_PID) },
917dafc4f7bSÉric Piel 	{ USB_DEVICE(PI_VID, PI_C866_PID) },
918dafc4f7bSÉric Piel 	{ USB_DEVICE(PI_VID, PI_C663_PID) },
919dafc4f7bSÉric Piel 	{ USB_DEVICE(PI_VID, PI_C725_PID) },
920dafc4f7bSÉric Piel 	{ USB_DEVICE(PI_VID, PI_E517_PID) },
921dafc4f7bSÉric Piel 	{ USB_DEVICE(PI_VID, PI_C863_PID) },
922b69cc672SÉric Piel 	{ USB_DEVICE(PI_VID, PI_E861_PID) },
923dafc4f7bSÉric Piel 	{ USB_DEVICE(PI_VID, PI_C867_PID) },
924dafc4f7bSÉric Piel 	{ USB_DEVICE(PI_VID, PI_E609_PID) },
925dafc4f7bSÉric Piel 	{ USB_DEVICE(PI_VID, PI_E709_PID) },
926dafc4f7bSÉric Piel 	{ USB_DEVICE(PI_VID, PI_100F_PID) },
927dafc4f7bSÉric Piel 	{ USB_DEVICE(PI_VID, PI_1011_PID) },
928dafc4f7bSÉric Piel 	{ USB_DEVICE(PI_VID, PI_1012_PID) },
929dafc4f7bSÉric Piel 	{ USB_DEVICE(PI_VID, PI_1013_PID) },
930dafc4f7bSÉric Piel 	{ USB_DEVICE(PI_VID, PI_1014_PID) },
931dafc4f7bSÉric Piel 	{ USB_DEVICE(PI_VID, PI_1015_PID) },
932dafc4f7bSÉric Piel 	{ USB_DEVICE(PI_VID, PI_1016_PID) },
9337724a1edSOzan Çağlayan 	{ USB_DEVICE(KONDO_VID, KONDO_USB_SERIAL_PID) },
934c47aacc6SMarko Hänninen 	{ USB_DEVICE(BAYER_VID, BAYER_CONTOUR_CABLE_PID) },
93550d0678eSDhaval Vasa 	{ USB_DEVICE(FTDI_VID, MARVELL_OPENRD_PID),
93650d0678eSDhaval Vasa 		.driver_info = (kernel_ulong_t)&ftdi_jtag_quirk },
93755f13aeaSPeter Korsgaard 	{ USB_DEVICE(FTDI_VID, TI_XDS100V2_PID),
93855f13aeaSPeter Korsgaard 		.driver_info = (kernel_ulong_t)&ftdi_jtag_quirk },
939e7d7fcc0SPawel Ludwikow 	{ USB_DEVICE(FTDI_VID, HAMEG_HO820_PID) },
940c53c2fabSPaul Friedrich 	{ USB_DEVICE(FTDI_VID, HAMEG_HO720_PID) },
941c53c2fabSPaul Friedrich 	{ USB_DEVICE(FTDI_VID, HAMEG_HO730_PID) },
942e7d7fcc0SPawel Ludwikow 	{ USB_DEVICE(FTDI_VID, HAMEG_HO870_PID) },
9439714080dSMitchell Solomon 	{ USB_DEVICE(FTDI_VID, MJSG_GENERIC_PID) },
9449714080dSMitchell Solomon 	{ USB_DEVICE(FTDI_VID, MJSG_SR_RADIO_PID) },
9459714080dSMitchell Solomon 	{ USB_DEVICE(FTDI_VID, MJSG_HD_RADIO_PID) },
9469714080dSMitchell Solomon 	{ USB_DEVICE(FTDI_VID, MJSG_XM_RADIO_PID) },
94777dbd74eSColin Leitner 	{ USB_DEVICE(FTDI_VID, XVERVE_SIGNALYZER_ST_PID),
94877dbd74eSColin Leitner 		.driver_info = (kernel_ulong_t)&ftdi_jtag_quirk },
94977dbd74eSColin Leitner 	{ USB_DEVICE(FTDI_VID, XVERVE_SIGNALYZER_SLITE_PID),
95077dbd74eSColin Leitner 		.driver_info = (kernel_ulong_t)&ftdi_jtag_quirk },
95177dbd74eSColin Leitner 	{ USB_DEVICE(FTDI_VID, XVERVE_SIGNALYZER_SH2_PID),
95277dbd74eSColin Leitner 		.driver_info = (kernel_ulong_t)&ftdi_jtag_quirk },
95377dbd74eSColin Leitner 	{ USB_DEVICE(FTDI_VID, XVERVE_SIGNALYZER_SH4_PID),
95477dbd74eSColin Leitner 		.driver_info = (kernel_ulong_t)&ftdi_jtag_quirk },
955afad1964SJohn G. Rogers 	{ USB_DEVICE(FTDI_VID, SEGWAY_RMP200_PID) },
9563126d823SRich Mattes 	{ USB_DEVICE(FTDI_VID, ACCESIO_COM4SM_PID) },
957666cc076SMartin Michlmayr 	{ USB_DEVICE(IONICS_VID, IONICS_PLUGCOMPUTER_PID),
958666cc076SMartin Michlmayr 		.driver_info = (kernel_ulong_t)&ftdi_jtag_quirk },
95965737388SLuke Lowrey 	{ USB_DEVICE(FTDI_VID, FTDI_CHAMSYS_24_MASTER_WING_PID) },
96065737388SLuke Lowrey 	{ USB_DEVICE(FTDI_VID, FTDI_CHAMSYS_PC_WING_PID) },
96165737388SLuke Lowrey 	{ USB_DEVICE(FTDI_VID, FTDI_CHAMSYS_USB_DMX_PID) },
96265737388SLuke Lowrey 	{ USB_DEVICE(FTDI_VID, FTDI_CHAMSYS_MIDI_TIMECODE_PID) },
96365737388SLuke Lowrey 	{ USB_DEVICE(FTDI_VID, FTDI_CHAMSYS_MINI_WING_PID) },
96465737388SLuke Lowrey 	{ USB_DEVICE(FTDI_VID, FTDI_CHAMSYS_MAXI_WING_PID) },
96565737388SLuke Lowrey 	{ USB_DEVICE(FTDI_VID, FTDI_CHAMSYS_MEDIA_WING_PID) },
96665737388SLuke Lowrey 	{ USB_DEVICE(FTDI_VID, FTDI_CHAMSYS_WING_PID) },
9670f266abdSGreg Kroah-Hartman 	{ USB_DEVICE(FTDI_VID, FTDI_SCIENCESCOPE_LOGBOOKML_PID) },
9680f266abdSGreg Kroah-Hartman 	{ USB_DEVICE(FTDI_VID, FTDI_SCIENCESCOPE_LS_LOGBOOK_PID) },
9690f266abdSGreg Kroah-Hartman 	{ USB_DEVICE(FTDI_VID, FTDI_SCIENCESCOPE_HS_LOGBOOK_PID) },
97090451e69SMilan Kocian 	{ USB_DEVICE(FTDI_VID, FTDI_CINTERION_MC55I_PID) },
9716555ad13SClemens Werther 	{ USB_DEVICE(FTDI_VID, FTDI_FHE_PID) },
9725363cdc3SFlorian Faber 	{ USB_DEVICE(FTDI_VID, FTDI_DOTEC_PID) },
9737fea0f71SSebastien Bourdeauducq 	{ USB_DEVICE(QIHARDWARE_VID, MILKYMISTONE_JTAGSERIAL_PID),
9747fea0f71SSebastien Bourdeauducq 		.driver_info = (kernel_ulong_t)&ftdi_jtag_quirk },
9759f06d15fSAdrian Thomasset 	{ USB_DEVICE(ST_VID, ST_STMCLT_2232_PID),
9769f06d15fSAdrian Thomasset 		.driver_info = (kernel_ulong_t)&ftdi_jtag_quirk },
9779f06d15fSAdrian Thomasset 	{ USB_DEVICE(ST_VID, ST_STMCLT_4232_PID),
9786ec2f46cSJean-Christophe PLAGNIOL-VILLARD 		.driver_info = (kernel_ulong_t)&ftdi_stmclite_quirk },
979fc216ec3SPeter Naulls 	{ USB_DEVICE(FTDI_VID, FTDI_RF_R106) },
98047594d55SMichał Wróbel 	{ USB_DEVICE(FTDI_VID, FTDI_DISTORTEC_JTAG_LOCK_PICK_PID),
98147594d55SMichał Wróbel 		.driver_info = (kernel_ulong_t)&ftdi_jtag_quirk },
98257e596f3SMichał Wróbel 	{ USB_DEVICE(FTDI_VID, FTDI_LUMEL_PD12_PID) },
9838cf65dc3STomasz Mloduchowski 	/* Crucible Devices */
9848cf65dc3STomasz Mloduchowski 	{ USB_DEVICE(FTDI_VID, FTDI_CT_COMET_PID) },
985e1466ad5SАлексей Крамаренко 	{ USB_DEVICE(FTDI_VID, FTDI_Z3X_PID) },
9866dbd46c8SJoerg Dorchain 	/* Cressi Devices */
9876dbd46c8SJoerg Dorchain 	{ USB_DEVICE(FTDI_VID, FTDI_CRESSI_PID) },
988efe26e16SMichele Baldessari 	/* Brainboxes Devices */
989efe26e16SMichele Baldessari 	{ USB_DEVICE(BRAINBOXES_VID, BRAINBOXES_VX_001_PID) },
990efe26e16SMichele Baldessari 	{ USB_DEVICE(BRAINBOXES_VID, BRAINBOXES_VX_012_PID) },
991efe26e16SMichele Baldessari 	{ USB_DEVICE(BRAINBOXES_VID, BRAINBOXES_VX_023_PID) },
992efe26e16SMichele Baldessari 	{ USB_DEVICE(BRAINBOXES_VID, BRAINBOXES_VX_034_PID) },
993efe26e16SMichele Baldessari 	{ USB_DEVICE(BRAINBOXES_VID, BRAINBOXES_US_101_PID) },
994fbb9b194SCameron Williams 	{ USB_DEVICE(BRAINBOXES_VID, BRAINBOXES_US_159_PID) },
995efe26e16SMichele Baldessari 	{ USB_DEVICE(BRAINBOXES_VID, BRAINBOXES_US_160_1_PID) },
996efe26e16SMichele Baldessari 	{ USB_DEVICE(BRAINBOXES_VID, BRAINBOXES_US_160_2_PID) },
997efe26e16SMichele Baldessari 	{ USB_DEVICE(BRAINBOXES_VID, BRAINBOXES_US_160_3_PID) },
998efe26e16SMichele Baldessari 	{ USB_DEVICE(BRAINBOXES_VID, BRAINBOXES_US_160_4_PID) },
999efe26e16SMichele Baldessari 	{ USB_DEVICE(BRAINBOXES_VID, BRAINBOXES_US_160_5_PID) },
1000efe26e16SMichele Baldessari 	{ USB_DEVICE(BRAINBOXES_VID, BRAINBOXES_US_160_6_PID) },
1001efe26e16SMichele Baldessari 	{ USB_DEVICE(BRAINBOXES_VID, BRAINBOXES_US_160_7_PID) },
1002efe26e16SMichele Baldessari 	{ USB_DEVICE(BRAINBOXES_VID, BRAINBOXES_US_160_8_PID) },
1003fbb9b194SCameron Williams 	{ USB_DEVICE(BRAINBOXES_VID, BRAINBOXES_US_235_PID) },
1004efe26e16SMichele Baldessari 	{ USB_DEVICE(BRAINBOXES_VID, BRAINBOXES_US_257_PID) },
1005efe26e16SMichele Baldessari 	{ USB_DEVICE(BRAINBOXES_VID, BRAINBOXES_US_279_1_PID) },
1006efe26e16SMichele Baldessari 	{ USB_DEVICE(BRAINBOXES_VID, BRAINBOXES_US_279_2_PID) },
1007efe26e16SMichele Baldessari 	{ USB_DEVICE(BRAINBOXES_VID, BRAINBOXES_US_279_3_PID) },
1008efe26e16SMichele Baldessari 	{ USB_DEVICE(BRAINBOXES_VID, BRAINBOXES_US_279_4_PID) },
1009efe26e16SMichele Baldessari 	{ USB_DEVICE(BRAINBOXES_VID, BRAINBOXES_US_313_PID) },
1010fbb9b194SCameron Williams 	{ USB_DEVICE(BRAINBOXES_VID, BRAINBOXES_US_320_PID) },
1011efe26e16SMichele Baldessari 	{ USB_DEVICE(BRAINBOXES_VID, BRAINBOXES_US_324_PID) },
1012efe26e16SMichele Baldessari 	{ USB_DEVICE(BRAINBOXES_VID, BRAINBOXES_US_346_1_PID) },
1013efe26e16SMichele Baldessari 	{ USB_DEVICE(BRAINBOXES_VID, BRAINBOXES_US_346_2_PID) },
1014efe26e16SMichele Baldessari 	{ USB_DEVICE(BRAINBOXES_VID, BRAINBOXES_US_357_PID) },
1015efe26e16SMichele Baldessari 	{ USB_DEVICE(BRAINBOXES_VID, BRAINBOXES_US_606_1_PID) },
1016efe26e16SMichele Baldessari 	{ USB_DEVICE(BRAINBOXES_VID, BRAINBOXES_US_606_2_PID) },
1017efe26e16SMichele Baldessari 	{ USB_DEVICE(BRAINBOXES_VID, BRAINBOXES_US_606_3_PID) },
1018efe26e16SMichele Baldessari 	{ USB_DEVICE(BRAINBOXES_VID, BRAINBOXES_US_701_1_PID) },
1019efe26e16SMichele Baldessari 	{ USB_DEVICE(BRAINBOXES_VID, BRAINBOXES_US_701_2_PID) },
1020efe26e16SMichele Baldessari 	{ USB_DEVICE(BRAINBOXES_VID, BRAINBOXES_US_842_1_PID) },
1021efe26e16SMichele Baldessari 	{ USB_DEVICE(BRAINBOXES_VID, BRAINBOXES_US_842_2_PID) },
1022efe26e16SMichele Baldessari 	{ USB_DEVICE(BRAINBOXES_VID, BRAINBOXES_US_842_3_PID) },
1023efe26e16SMichele Baldessari 	{ USB_DEVICE(BRAINBOXES_VID, BRAINBOXES_US_842_4_PID) },
1024646907f5SJaša Bartelj 	/* ekey Devices */
1025646907f5SJaša Bartelj 	{ USB_DEVICE(FTDI_VID, FTDI_EKEY_CONV_USB_PID) },
1026d8279a40SMichal Sojka 	/* Infineon Devices */
1027ca006f78SStefan Tauner 	{ USB_DEVICE_INTERFACE_NUMBER(INFINEON_VID, INFINEON_TRIBOARD_TC1798_PID, 1) },
1028ca006f78SStefan Tauner 	{ USB_DEVICE_INTERFACE_NUMBER(INFINEON_VID, INFINEON_TRIBOARD_TC2X7_PID, 1) },
10299c491c37STaylor Braun-Jones 	/* GE Healthcare devices */
10309c491c37STaylor Braun-Jones 	{ USB_DEVICE(GE_HEALTHCARE_VID, GE_HEALTHCARE_NEMO_TRACKER_PID) },
1031f6950344SMark Glover 	/* Active Research (Actisense) devices */
1032f6950344SMark Glover 	{ USB_DEVICE(FTDI_VID, ACTISENSE_NDC_PID) },
1033f6950344SMark Glover 	{ USB_DEVICE(FTDI_VID, ACTISENSE_USG_PID) },
1034f6950344SMark Glover 	{ USB_DEVICE(FTDI_VID, ACTISENSE_NGT_PID) },
1035f6950344SMark Glover 	{ USB_DEVICE(FTDI_VID, ACTISENSE_NGW_PID) },
103666c13151SMark Glover 	{ USB_DEVICE(FTDI_VID, ACTISENSE_UID_PID) },
103766c13151SMark Glover 	{ USB_DEVICE(FTDI_VID, ACTISENSE_USA_PID) },
103866c13151SMark Glover 	{ USB_DEVICE(FTDI_VID, ACTISENSE_NGX_PID) },
1039f6950344SMark Glover 	{ USB_DEVICE(FTDI_VID, ACTISENSE_D9AF_PID) },
1040f6950344SMark Glover 	{ USB_DEVICE(FTDI_VID, CHETCO_SEAGAUGE_PID) },
1041f6950344SMark Glover 	{ USB_DEVICE(FTDI_VID, CHETCO_SEASWITCH_PID) },
1042f6950344SMark Glover 	{ USB_DEVICE(FTDI_VID, CHETCO_SEASMART_NMEA2000_PID) },
1043f6950344SMark Glover 	{ USB_DEVICE(FTDI_VID, CHETCO_SEASMART_ETHERNET_PID) },
1044f6950344SMark Glover 	{ USB_DEVICE(FTDI_VID, CHETCO_SEASMART_WIFI_PID) },
1045f6950344SMark Glover 	{ USB_DEVICE(FTDI_VID, CHETCO_SEASMART_DISPLAY_PID) },
1046f6950344SMark Glover 	{ USB_DEVICE(FTDI_VID, CHETCO_SEASMART_LITE_PID) },
1047f6950344SMark Glover 	{ USB_DEVICE(FTDI_VID, CHETCO_SEASMART_ANALOG_PID) },
10487c239a07SLucien Buchmann 	/* Belimo Automation devices */
10497c239a07SLucien Buchmann 	{ USB_DEVICE(FTDI_VID, BELIMO_ZTH_PID) },
10507c239a07SLucien Buchmann 	{ USB_DEVICE(FTDI_VID, BELIMO_ZIP_PID) },
1051ea6db90eSJosh Boyer 	/* ICP DAS I-756xU devices */
1052ea6db90eSJosh Boyer 	{ USB_DEVICE(ICPDAS_VID, ICPDAS_I7560U_PID) },
1053ea6db90eSJosh Boyer 	{ USB_DEVICE(ICPDAS_VID, ICPDAS_I7561U_PID) },
1054ea6db90eSJosh Boyer 	{ USB_DEVICE(ICPDAS_VID, ICPDAS_I7563U_PID) },
1055ae34d12cSSheng-Hui J. Chu 	{ USB_DEVICE(WICED_VID, WICED_USB20706V2_PID) },
10569bfef729SDoug Brown 	{ USB_DEVICE(TI_VID, TI_CC3200_LAUNCHPAD_PID),
10579bfef729SDoug Brown 		.driver_info = (kernel_ulong_t)&ftdi_jtag_quirk },
1058a6c215e2SJeffrey Chu 	{ USB_DEVICE(CYPRESS_VID, CYPRESS_WICED_BT_USB_PID) },
1059a6c215e2SJeffrey Chu 	{ USB_DEVICE(CYPRESS_VID, CYPRESS_WICED_WL_USB_PID) },
1060c6a36ad3SMax Schulze 	{ USB_DEVICE(AIRBUS_DS_VID, AIRBUS_DS_P8GR) },
10618d7fa3d4SMans Rullgard 	/* EZPrototypes devices */
10628d7fa3d4SMans Rullgard 	{ USB_DEVICE(EZPROTOTYPES_VID, HJELMSLUND_USB485_ISO_PID) },
1063f8377effSAndreas Fritiofson 	{ USB_DEVICE_INTERFACE_NUMBER(UNJO_VID, UNJO_ISODEBUG_V1_PID, 1) },
1064357f16d9SBeni Mahler 	/* Sienna devices */
1065357f16d9SBeni Mahler 	{ USB_DEVICE(FTDI_VID, FTDI_SIENNA_PID) },
1066357f16d9SBeni Mahler 	{ USB_DEVICE(ECHELON_VID, ECHELON_U20_PID) },
1067c5a80540SDominik Andreas Schorpp 	/* IDS GmbH devices */
1068c5a80540SDominik Andreas Schorpp 	{ USB_DEVICE(IDS_VID, IDS_SI31A_PID) },
1069c5a80540SDominik Andreas Schorpp 	{ USB_DEVICE(IDS_VID, IDS_CM31A_PID) },
1070001047eaSNiek Nooijens 	/* Omron devices */
1071001047eaSNiek Nooijens 	{ USB_DEVICE(OMRON_VID, OMRON_CS1W_CIF31_PID) },
1072c1a1f273SFabio D'Urso 	/* U-Blox devices */
1073c1a1f273SFabio D'Urso 	{ USB_DEVICE(UBLOX_VID, UBLOX_C099F9P_ZED_PID) },
1074c1a1f273SFabio D'Urso 	{ USB_DEVICE(UBLOX_VID, UBLOX_C099F9P_ODIN_PID) },
10756cf87e5eSMychaela N. Falconia 	/* FreeCalypso USB adapters */
10766cf87e5eSMychaela N. Falconia 	{ USB_DEVICE(FTDI_VID, FTDI_FALCONIA_JTAG_BUF_PID),
10776cf87e5eSMychaela N. Falconia 		.driver_info = (kernel_ulong_t)&ftdi_jtag_quirk },
10786cf87e5eSMychaela N. Falconia 	{ USB_DEVICE(FTDI_VID, FTDI_FALCONIA_JTAG_UNBUF_PID),
10796cf87e5eSMychaela N. Falconia 		.driver_info = (kernel_ulong_t)&ftdi_jtag_quirk },
108058bb229dSDaniel Vogelbacher 	/* GMC devices */
108158bb229dSDaniel Vogelbacher 	{ USB_DEVICE(GMC_VID, GMC_Z216C_PID) },
10821da177e4SLinus Torvalds 	{ }					/* Terminating entry */
10831da177e4SLinus Torvalds };
10841da177e4SLinus Torvalds 
10851da177e4SLinus Torvalds MODULE_DEVICE_TABLE(usb, id_table_combined);
10861da177e4SLinus Torvalds 
10874c4c9432SArjan van de Ven static const char *ftdi_chip_name[] = {
10881da177e4SLinus Torvalds 	[SIO]		= "SIO",	/* the serial part of FT8U100AX */
108901aeb31fSJohan Hovold 	[FT232A]	= "FT232A",
109001aeb31fSJohan Hovold 	[FT232B]	= "FT232B",
109164b12fdaSJohan Hovold 	[FT2232C]	= "FT2232C/D",
109201aeb31fSJohan Hovold 	[FT232R]	= "FT232R",
109301aeb31fSJohan Hovold 	[FT232H]	= "FT232H",
1094094c2e6dSMark Adamson 	[FT2232H]	= "FT2232H",
1095309427b6SUwe Bonnes 	[FT4232H]	= "FT4232H",
1096cfebcd53SAmireddy mallikarjuna reddy 	[FT4232HA]	= "FT4232HA",
1097cfebcd53SAmireddy mallikarjuna reddy 	[FT232HP]	= "FT232HP",
1098cfebcd53SAmireddy mallikarjuna reddy 	[FT233HP]	= "FT233HP",
1099cfebcd53SAmireddy mallikarjuna reddy 	[FT2232HP]	= "FT2232HP",
1100cfebcd53SAmireddy mallikarjuna reddy 	[FT2233HP]	= "FT2233HP",
1101cfebcd53SAmireddy mallikarjuna reddy 	[FT4232HP]	= "FT4232HP",
1102cfebcd53SAmireddy mallikarjuna reddy 	[FT4233HP]	= "FT4233HP",
110301aeb31fSJohan Hovold 	[FTX]		= "FT-X",
11041da177e4SLinus Torvalds };
11051da177e4SLinus Torvalds 
11061da177e4SLinus Torvalds 
11071da177e4SLinus Torvalds /* Used for TIOCMIWAIT */
11081da177e4SLinus Torvalds #define FTDI_STATUS_B0_MASK	(FTDI_RS0_CTS | FTDI_RS0_DSR | FTDI_RS0_RI | FTDI_RS0_RLSD)
11091da177e4SLinus Torvalds #define FTDI_STATUS_B1_MASK	(FTDI_RS_BI)
11101da177e4SLinus Torvalds /* End TIOCMIWAIT */
11111da177e4SLinus Torvalds 
1112464cbb24SAlan Cox static void ftdi_set_termios(struct tty_struct *tty,
1113f6d47fe5SIlpo Järvinen 			     struct usb_serial_port *port,
1114f6d47fe5SIlpo Järvinen 			     const struct ktermios *old_termios);
1115c4133648SJohan Hovold static int ftdi_get_modem_status(struct usb_serial_port *port,
11165fb0432eSJohan Hovold 						unsigned char status[2]);
11171da177e4SLinus Torvalds 
11181da177e4SLinus Torvalds #define WDR_TIMEOUT 5000 /* default urb timeout */
1119279e1545SIan Abbott #define WDR_SHORT_TIMEOUT 1000	/* shorter urb timeout */
11201da177e4SLinus Torvalds 
11211da177e4SLinus Torvalds /*
11221da177e4SLinus Torvalds  * ***************************************************************************
1123fa91d43bSTony Lindgren  * Utility functions
11241da177e4SLinus Torvalds  * ***************************************************************************
11251da177e4SLinus Torvalds  */
11261da177e4SLinus Torvalds 
ftdi_232am_baud_base_to_divisor(int baud,int base)11271da177e4SLinus Torvalds static unsigned short int ftdi_232am_baud_base_to_divisor(int baud, int base)
11281da177e4SLinus Torvalds {
11291da177e4SLinus Torvalds 	unsigned short int divisor;
1130464cbb24SAlan Cox 	/* divisor shifted 3 bits to the left */
11316abd8371SNikolaj Fogh 	int divisor3 = DIV_ROUND_CLOSEST(base, 2 * baud);
1132464cbb24SAlan Cox 	if ((divisor3 & 0x7) == 7)
1133464cbb24SAlan Cox 		divisor3++; /* round x.7/8 up to x+1 */
11341da177e4SLinus Torvalds 	divisor = divisor3 >> 3;
11351da177e4SLinus Torvalds 	divisor3 &= 0x7;
1136464cbb24SAlan Cox 	if (divisor3 == 1)
11371ef26803SJohan Hovold 		divisor |= 0xc000;	/* +0.125 */
1138464cbb24SAlan Cox 	else if (divisor3 >= 4)
11391ef26803SJohan Hovold 		divisor |= 0x4000;	/* +0.5 */
1140464cbb24SAlan Cox 	else if (divisor3 != 0)
11411ef26803SJohan Hovold 		divisor |= 0x8000;	/* +0.25 */
1142464cbb24SAlan Cox 	else if (divisor == 1)
1143464cbb24SAlan Cox 		divisor = 0;		/* special case for maximum baud rate */
11441da177e4SLinus Torvalds 	return divisor;
11451da177e4SLinus Torvalds }
11461da177e4SLinus Torvalds 
ftdi_232am_baud_to_divisor(int baud)11471da177e4SLinus Torvalds static unsigned short int ftdi_232am_baud_to_divisor(int baud)
11481da177e4SLinus Torvalds {
1149464cbb24SAlan Cox 	 return ftdi_232am_baud_base_to_divisor(baud, 48000000);
11501da177e4SLinus Torvalds }
11511da177e4SLinus Torvalds 
ftdi_232bm_baud_base_to_divisor(int baud,int base)1152fd54a99aSJohan Hovold static u32 ftdi_232bm_baud_base_to_divisor(int baud, int base)
11531da177e4SLinus Torvalds {
11541da177e4SLinus Torvalds 	static const unsigned char divfrac[8] = { 0, 3, 2, 4, 1, 5, 6, 7 };
1155fd54a99aSJohan Hovold 	u32 divisor;
1156464cbb24SAlan Cox 	/* divisor shifted 3 bits to the left */
11576abd8371SNikolaj Fogh 	int divisor3 = DIV_ROUND_CLOSEST(base, 2 * baud);
11581da177e4SLinus Torvalds 	divisor = divisor3 >> 3;
1159fd54a99aSJohan Hovold 	divisor |= (u32)divfrac[divisor3 & 0x7] << 14;
11601da177e4SLinus Torvalds 	/* Deal with special cases for highest baud rates. */
11611ef26803SJohan Hovold 	if (divisor == 1)		/* 1.0 */
1162464cbb24SAlan Cox 		divisor = 0;
11631ef26803SJohan Hovold 	else if (divisor == 0x4001)	/* 1.5 */
1164464cbb24SAlan Cox 		divisor = 1;
11651da177e4SLinus Torvalds 	return divisor;
11661da177e4SLinus Torvalds }
11671da177e4SLinus Torvalds 
ftdi_232bm_baud_to_divisor(int baud)1168fd54a99aSJohan Hovold static u32 ftdi_232bm_baud_to_divisor(int baud)
11691da177e4SLinus Torvalds {
1170464cbb24SAlan Cox 	 return ftdi_232bm_baud_base_to_divisor(baud, 48000000);
11711da177e4SLinus Torvalds }
11721da177e4SLinus Torvalds 
ftdi_2232h_baud_base_to_divisor(int baud,int base)1173fd54a99aSJohan Hovold static u32 ftdi_2232h_baud_base_to_divisor(int baud, int base)
1174094c2e6dSMark Adamson {
1175094c2e6dSMark Adamson 	static const unsigned char divfrac[8] = { 0, 3, 2, 4, 1, 5, 6, 7 };
1176fd54a99aSJohan Hovold 	u32 divisor;
1177094c2e6dSMark Adamson 	int divisor3;
1178094c2e6dSMark Adamson 
1179094c2e6dSMark Adamson 	/* hi-speed baud rate is 10-bit sampling instead of 16-bit */
11806abd8371SNikolaj Fogh 	divisor3 = DIV_ROUND_CLOSEST(8 * base, 10 * baud);
1181094c2e6dSMark Adamson 
1182094c2e6dSMark Adamson 	divisor = divisor3 >> 3;
1183fd54a99aSJohan Hovold 	divisor |= (u32)divfrac[divisor3 & 0x7] << 14;
1184094c2e6dSMark Adamson 	/* Deal with special cases for highest baud rates. */
11851ef26803SJohan Hovold 	if (divisor == 1)		/* 1.0 */
1186094c2e6dSMark Adamson 		divisor = 0;
11871ef26803SJohan Hovold 	else if (divisor == 0x4001)	/* 1.5 */
1188094c2e6dSMark Adamson 		divisor = 1;
1189094c2e6dSMark Adamson 	/*
1190094c2e6dSMark Adamson 	 * Set this bit to turn off a divide by 2.5 on baud rate generator
1191094c2e6dSMark Adamson 	 * This enables baud rates up to 12Mbaud but cannot reach below 1200
1192094c2e6dSMark Adamson 	 * baud with this bit set
1193094c2e6dSMark Adamson 	 */
1194094c2e6dSMark Adamson 	divisor |= 0x00020000;
1195094c2e6dSMark Adamson 	return divisor;
1196094c2e6dSMark Adamson }
1197094c2e6dSMark Adamson 
ftdi_2232h_baud_to_divisor(int baud)1198fd54a99aSJohan Hovold static u32 ftdi_2232h_baud_to_divisor(int baud)
1199094c2e6dSMark Adamson {
1200094c2e6dSMark Adamson 	 return ftdi_2232h_baud_base_to_divisor(baud, 120000000);
1201094c2e6dSMark Adamson }
1202094c2e6dSMark Adamson 
120374ede0ffSIan Abbott #define set_mctrl(port, set)		update_mctrl((port), (set), 0)
120474ede0ffSIan Abbott #define clear_mctrl(port, clear)	update_mctrl((port), 0, (clear))
120574ede0ffSIan Abbott 
update_mctrl(struct usb_serial_port * port,unsigned int set,unsigned int clear)1206464cbb24SAlan Cox static int update_mctrl(struct usb_serial_port *port, unsigned int set,
1207464cbb24SAlan Cox 							unsigned int clear)
12081da177e4SLinus Torvalds {
12091da177e4SLinus Torvalds 	struct ftdi_private *priv = usb_get_serial_port_data(port);
1210bfc51614SGreg Kroah-Hartman 	struct device *dev = &port->dev;
121116410115SJohan Hovold 	unsigned value;
12121da177e4SLinus Torvalds 	int rv;
12131da177e4SLinus Torvalds 
121474ede0ffSIan Abbott 	if (((set | clear) & (TIOCM_DTR | TIOCM_RTS)) == 0) {
1215bfc51614SGreg Kroah-Hartman 		dev_dbg(dev, "%s - DTR|RTS not being set|cleared\n", __func__);
121674ede0ffSIan Abbott 		return 0;	/* no change */
12171da177e4SLinus Torvalds 	}
121874ede0ffSIan Abbott 
121974ede0ffSIan Abbott 	clear &= ~set;	/* 'set' takes precedence over 'clear' */
122016410115SJohan Hovold 	value = 0;
122174ede0ffSIan Abbott 	if (clear & TIOCM_DTR)
122216410115SJohan Hovold 		value |= FTDI_SIO_SET_DTR_LOW;
122374ede0ffSIan Abbott 	if (clear & TIOCM_RTS)
122416410115SJohan Hovold 		value |= FTDI_SIO_SET_RTS_LOW;
122574ede0ffSIan Abbott 	if (set & TIOCM_DTR)
122616410115SJohan Hovold 		value |= FTDI_SIO_SET_DTR_HIGH;
122774ede0ffSIan Abbott 	if (set & TIOCM_RTS)
122816410115SJohan Hovold 		value |= FTDI_SIO_SET_RTS_HIGH;
12291da177e4SLinus Torvalds 	rv = usb_control_msg(port->serial->dev,
12301da177e4SLinus Torvalds 			       usb_sndctrlpipe(port->serial->dev, 0),
12311da177e4SLinus Torvalds 			       FTDI_SIO_SET_MODEM_CTRL_REQUEST,
12321da177e4SLinus Torvalds 			       FTDI_SIO_SET_MODEM_CTRL_REQUEST_TYPE,
1233027bf37dSJohan Hovold 			       value, priv->channel,
123466e47e60SJohan Hovold 			       NULL, 0, WDR_TIMEOUT);
123574ede0ffSIan Abbott 	if (rv < 0) {
1236bfc51614SGreg Kroah-Hartman 		dev_dbg(dev, "%s Error from MODEM_CTRL urb: DTR %s, RTS %s\n",
1237441b62c1SHarvey Harrison 			__func__,
1238bfc51614SGreg Kroah-Hartman 			(set & TIOCM_DTR) ? "HIGH" : (clear & TIOCM_DTR) ? "LOW" : "unchanged",
1239bfc51614SGreg Kroah-Hartman 			(set & TIOCM_RTS) ? "HIGH" : (clear & TIOCM_RTS) ? "LOW" : "unchanged");
12402c2ee545SJohan Hovold 		rv = usb_translate_errors(rv);
12411da177e4SLinus Torvalds 	} else {
1242bfc51614SGreg Kroah-Hartman 		dev_dbg(dev, "%s - DTR %s, RTS %s\n", __func__,
1243bfc51614SGreg Kroah-Hartman 			(set & TIOCM_DTR) ? "HIGH" : (clear & TIOCM_DTR) ? "LOW" : "unchanged",
1244bfc51614SGreg Kroah-Hartman 			(set & TIOCM_RTS) ? "HIGH" : (clear & TIOCM_RTS) ? "LOW" : "unchanged");
12459b0f2582SAlan Cox 		/* FIXME: locking on last_dtr_rts */
124674ede0ffSIan Abbott 		priv->last_dtr_rts = (priv->last_dtr_rts & ~clear) | set;
12471da177e4SLinus Torvalds 	}
12481da177e4SLinus Torvalds 	return rv;
12491da177e4SLinus Torvalds }
12501da177e4SLinus Torvalds 
12511da177e4SLinus Torvalds 
get_ftdi_divisor(struct tty_struct * tty,struct usb_serial_port * port)1252fd54a99aSJohan Hovold static u32 get_ftdi_divisor(struct tty_struct *tty,
1253464cbb24SAlan Cox 						struct usb_serial_port *port)
1254e49bbce1SJohan Hovold {
12551da177e4SLinus Torvalds 	struct ftdi_private *priv = usb_get_serial_port_data(port);
1256bfc51614SGreg Kroah-Hartman 	struct device *dev = &port->dev;
1257fd54a99aSJohan Hovold 	u32 div_value = 0;
12581da177e4SLinus Torvalds 	int div_okay = 1;
12591da177e4SLinus Torvalds 	int baud;
12601da177e4SLinus Torvalds 
126195da310eSAlan Cox 	baud = tty_get_baud_rate(tty);
1262bfc51614SGreg Kroah-Hartman 	dev_dbg(dev, "%s - tty_get_baud_rate reports speed %d\n", __func__, baud);
12631da177e4SLinus Torvalds 
126483c9a2d1SJohan Hovold 	/*
126583c9a2d1SJohan Hovold 	 * Observe deprecated async-compatible custom_divisor hack, update
126683c9a2d1SJohan Hovold 	 * baudrate if needed.
126783c9a2d1SJohan Hovold 	 */
12681da177e4SLinus Torvalds 	if (baud == 38400 &&
12691da177e4SLinus Torvalds 	    ((priv->flags & ASYNC_SPD_MASK) == ASYNC_SPD_CUST) &&
12701da177e4SLinus Torvalds 	     (priv->custom_divisor)) {
12711da177e4SLinus Torvalds 		baud = priv->baud_base / priv->custom_divisor;
1272bfc51614SGreg Kroah-Hartman 		dev_dbg(dev, "%s - custom divisor %d sets baud rate to %d\n",
1273464cbb24SAlan Cox 			__func__, priv->custom_divisor, baud);
12741da177e4SLinus Torvalds 	}
12751da177e4SLinus Torvalds 
1276464cbb24SAlan Cox 	if (!baud)
1277464cbb24SAlan Cox 		baud = 9600;
12781da177e4SLinus Torvalds 	switch (priv->chip_type) {
127925eb9486SJohan Hovold 	case SIO:
12801da177e4SLinus Torvalds 		switch (baud) {
12811da177e4SLinus Torvalds 		case 300: div_value = ftdi_sio_b300; break;
12821da177e4SLinus Torvalds 		case 600: div_value = ftdi_sio_b600; break;
12831da177e4SLinus Torvalds 		case 1200: div_value = ftdi_sio_b1200; break;
12841da177e4SLinus Torvalds 		case 2400: div_value = ftdi_sio_b2400; break;
12851da177e4SLinus Torvalds 		case 4800: div_value = ftdi_sio_b4800; break;
12861da177e4SLinus Torvalds 		case 9600: div_value = ftdi_sio_b9600; break;
12871da177e4SLinus Torvalds 		case 19200: div_value = ftdi_sio_b19200; break;
12881da177e4SLinus Torvalds 		case 38400: div_value = ftdi_sio_b38400; break;
12891da177e4SLinus Torvalds 		case 57600: div_value = ftdi_sio_b57600;  break;
12901da177e4SLinus Torvalds 		case 115200: div_value = ftdi_sio_b115200; break;
12917bd7ad3cSJohan Hovold 		default:
1292bfc51614SGreg Kroah-Hartman 			dev_dbg(dev, "%s - Baudrate (%d) requested is not supported\n",
1293464cbb24SAlan Cox 				__func__,  baud);
12941da177e4SLinus Torvalds 			div_value = ftdi_sio_b9600;
1295669a6db1SAlan Cox 			baud = 9600;
12961da177e4SLinus Torvalds 			div_okay = 0;
12971da177e4SLinus Torvalds 		}
12981da177e4SLinus Torvalds 		break;
129901aeb31fSJohan Hovold 	case FT232A:
13001da177e4SLinus Torvalds 		if (baud <= 3000000) {
13011da177e4SLinus Torvalds 			div_value = ftdi_232am_baud_to_divisor(baud);
13021da177e4SLinus Torvalds 		} else {
1303bfc51614SGreg Kroah-Hartman 			dev_dbg(dev, "%s - Baud rate too high!\n", __func__);
1304669a6db1SAlan Cox 			baud = 9600;
13051da177e4SLinus Torvalds 			div_value = ftdi_232am_baud_to_divisor(9600);
13061da177e4SLinus Torvalds 			div_okay = 0;
13071da177e4SLinus Torvalds 		}
13081da177e4SLinus Torvalds 		break;
130901aeb31fSJohan Hovold 	case FT232B:
131025eb9486SJohan Hovold 	case FT2232C:
131101aeb31fSJohan Hovold 	case FT232R:
131225eb9486SJohan Hovold 	case FTX:
13131da177e4SLinus Torvalds 		if (baud <= 3000000) {
1314fd54a99aSJohan Hovold 			u16 product_id = le16_to_cpu(
1315b760dac2SMartin Geleynse 				port->serial->dev->descriptor.idProduct);
1316fb571101SMathieu OTHACEHE 			if (((product_id == FTDI_NDI_HUC_PID)		||
1317fb571101SMathieu OTHACEHE 			     (product_id == FTDI_NDI_SPECTRA_SCU_PID)	||
1318fb571101SMathieu OTHACEHE 			     (product_id == FTDI_NDI_FUTURE_2_PID)	||
1319fb571101SMathieu OTHACEHE 			     (product_id == FTDI_NDI_FUTURE_3_PID)	||
1320fb571101SMathieu OTHACEHE 			     (product_id == FTDI_NDI_AURORA_SCU_PID))	&&
1321b760dac2SMartin Geleynse 			    (baud == 19200)) {
1322b760dac2SMartin Geleynse 				baud = 1200000;
1323b760dac2SMartin Geleynse 			}
13241da177e4SLinus Torvalds 			div_value = ftdi_232bm_baud_to_divisor(baud);
13251da177e4SLinus Torvalds 		} else {
1326bfc51614SGreg Kroah-Hartman 			dev_dbg(dev, "%s - Baud rate too high!\n", __func__);
13271da177e4SLinus Torvalds 			div_value = ftdi_232bm_baud_to_divisor(9600);
13281da177e4SLinus Torvalds 			div_okay = 0;
1329669a6db1SAlan Cox 			baud = 9600;
13301da177e4SLinus Torvalds 		}
13311da177e4SLinus Torvalds 		break;
13321a039891SJohan Hovold 	default:
13331862cdd5SIonut Nicu 		if ((baud <= 12000000) && (baud >= 1200)) {
1334094c2e6dSMark Adamson 			div_value = ftdi_2232h_baud_to_divisor(baud);
1335094c2e6dSMark Adamson 		} else if (baud < 1200) {
1336094c2e6dSMark Adamson 			div_value = ftdi_232bm_baud_to_divisor(baud);
1337094c2e6dSMark Adamson 		} else {
1338bfc51614SGreg Kroah-Hartman 			dev_dbg(dev, "%s - Baud rate too high!\n", __func__);
1339094c2e6dSMark Adamson 			div_value = ftdi_232bm_baud_to_divisor(9600);
1340094c2e6dSMark Adamson 			div_okay = 0;
1341094c2e6dSMark Adamson 			baud = 9600;
1342094c2e6dSMark Adamson 		}
1343094c2e6dSMark Adamson 		break;
134425eb9486SJohan Hovold 	}
13451da177e4SLinus Torvalds 
13461da177e4SLinus Torvalds 	if (div_okay) {
1347bfc51614SGreg Kroah-Hartman 		dev_dbg(dev, "%s - Baud rate set to %d (divisor 0x%lX) on chip %s\n",
1348441b62c1SHarvey Harrison 			__func__, baud, (unsigned long)div_value,
13491da177e4SLinus Torvalds 			ftdi_chip_name[priv->chip_type]);
13501da177e4SLinus Torvalds 	}
13511da177e4SLinus Torvalds 
135295da310eSAlan Cox 	tty_encode_baud_rate(tty, baud, baud);
1353464cbb24SAlan Cox 	return div_value;
13541da177e4SLinus Torvalds }
13551da177e4SLinus Torvalds 
change_speed(struct tty_struct * tty,struct usb_serial_port * port)135695da310eSAlan Cox static int change_speed(struct tty_struct *tty, struct usb_serial_port *port)
135795da310eSAlan Cox {
135895da310eSAlan Cox 	struct ftdi_private *priv = usb_get_serial_port_data(port);
135916410115SJohan Hovold 	u16 value;
136016410115SJohan Hovold 	u16 index;
136116410115SJohan Hovold 	u32 index_value;
136295da310eSAlan Cox 	int rv;
136395da310eSAlan Cox 
136416410115SJohan Hovold 	index_value = get_ftdi_divisor(tty, port);
136516410115SJohan Hovold 	value = (u16)index_value;
136616410115SJohan Hovold 	index = (u16)(index_value >> 16);
1367a146cc4dSJohan Hovold 	if (priv->channel)
1368027bf37dSJohan Hovold 		index = (u16)((index << 8) | priv->channel);
136995da310eSAlan Cox 
137095da310eSAlan Cox 	rv = usb_control_msg(port->serial->dev,
137195da310eSAlan Cox 			    usb_sndctrlpipe(port->serial->dev, 0),
137295da310eSAlan Cox 			    FTDI_SIO_SET_BAUDRATE_REQUEST,
137395da310eSAlan Cox 			    FTDI_SIO_SET_BAUDRATE_REQUEST_TYPE,
137416410115SJohan Hovold 			    value, index,
137566e47e60SJohan Hovold 			    NULL, 0, WDR_SHORT_TIMEOUT);
137695da310eSAlan Cox 	return rv;
137795da310eSAlan Cox }
137895da310eSAlan Cox 
write_latency_timer(struct usb_serial_port * port)1379557aaa7fSAlan Cox static int write_latency_timer(struct usb_serial_port *port)
1380557aaa7fSAlan Cox {
1381557aaa7fSAlan Cox 	struct ftdi_private *priv = usb_get_serial_port_data(port);
1382557aaa7fSAlan Cox 	struct usb_device *udev = port->serial->dev;
1383c1284d77SJohan Hovold 	int rv;
1384557aaa7fSAlan Cox 	int l = priv->latency;
138595da310eSAlan Cox 
138601aeb31fSJohan Hovold 	if (priv->chip_type == SIO || priv->chip_type == FT232A)
13872dea7cd7SIan Abbott 		return -EINVAL;
13882dea7cd7SIan Abbott 
1389557aaa7fSAlan Cox 	if (priv->flags & ASYNC_LOW_LATENCY)
1390557aaa7fSAlan Cox 		l = 1;
1391557aaa7fSAlan Cox 
1392bfc51614SGreg Kroah-Hartman 	dev_dbg(&port->dev, "%s: setting latency timer = %i\n", __func__, l);
1393557aaa7fSAlan Cox 
1394557aaa7fSAlan Cox 	rv = usb_control_msg(udev,
1395557aaa7fSAlan Cox 			     usb_sndctrlpipe(udev, 0),
1396557aaa7fSAlan Cox 			     FTDI_SIO_SET_LATENCY_TIMER_REQUEST,
1397557aaa7fSAlan Cox 			     FTDI_SIO_SET_LATENCY_TIMER_REQUEST_TYPE,
1398027bf37dSJohan Hovold 			     l, priv->channel,
139966e47e60SJohan Hovold 			     NULL, 0, WDR_TIMEOUT);
1400557aaa7fSAlan Cox 	if (rv < 0)
1401557aaa7fSAlan Cox 		dev_err(&port->dev, "Unable to write latency timer: %i\n", rv);
1402557aaa7fSAlan Cox 	return rv;
1403557aaa7fSAlan Cox }
1404557aaa7fSAlan Cox 
_read_latency_timer(struct usb_serial_port * port)14057e1e6cedSIan Abbott static int _read_latency_timer(struct usb_serial_port *port)
1406557aaa7fSAlan Cox {
1407557aaa7fSAlan Cox 	struct ftdi_private *priv = usb_get_serial_port_data(port);
1408557aaa7fSAlan Cox 	struct usb_device *udev = port->serial->dev;
1409a7388592SHimadri Pandya 	u8 buf;
1410c1284d77SJohan Hovold 	int rv;
1411557aaa7fSAlan Cox 
1412a7388592SHimadri Pandya 	rv = usb_control_msg_recv(udev, 0, FTDI_SIO_GET_LATENCY_TIMER_REQUEST,
1413a7388592SHimadri Pandya 				  FTDI_SIO_GET_LATENCY_TIMER_REQUEST_TYPE, 0,
1414027bf37dSJohan Hovold 				  priv->channel, &buf, 1, WDR_TIMEOUT,
1415a7388592SHimadri Pandya 				  GFP_KERNEL);
1416a7388592SHimadri Pandya 	if (rv == 0)
1417a7388592SHimadri Pandya 		rv = buf;
141854f328d0SJohan Hovold 
14198c4f99cdSJohan Hovold 	return rv;
1420557aaa7fSAlan Cox }
14211da177e4SLinus Torvalds 
read_latency_timer(struct usb_serial_port * port)14227e1e6cedSIan Abbott static int read_latency_timer(struct usb_serial_port *port)
14237e1e6cedSIan Abbott {
14247e1e6cedSIan Abbott 	struct ftdi_private *priv = usb_get_serial_port_data(port);
14257e1e6cedSIan Abbott 	int rv;
14267e1e6cedSIan Abbott 
142701aeb31fSJohan Hovold 	if (priv->chip_type == SIO || priv->chip_type == FT232A)
14287e1e6cedSIan Abbott 		return -EINVAL;
14297e1e6cedSIan Abbott 
14307e1e6cedSIan Abbott 	rv = _read_latency_timer(port);
14317e1e6cedSIan Abbott 	if (rv < 0) {
14327e1e6cedSIan Abbott 		dev_err(&port->dev, "Unable to read latency timer: %i\n", rv);
14337e1e6cedSIan Abbott 		return rv;
14347e1e6cedSIan Abbott 	}
14357e1e6cedSIan Abbott 
14367e1e6cedSIan Abbott 	priv->latency = rv;
14377e1e6cedSIan Abbott 
14387e1e6cedSIan Abbott 	return 0;
14397e1e6cedSIan Abbott }
14407e1e6cedSIan Abbott 
get_serial_info(struct tty_struct * tty,struct serial_struct * ss)144101fd45f6SJohan Hovold static void get_serial_info(struct tty_struct *tty, struct serial_struct *ss)
14421da177e4SLinus Torvalds {
14433ae36bedSAl Viro 	struct usb_serial_port *port = tty->driver_data;
14441da177e4SLinus Torvalds 	struct ftdi_private *priv = usb_get_serial_port_data(port);
14451da177e4SLinus Torvalds 
14463ae36bedSAl Viro 	ss->flags = priv->flags;
14473ae36bedSAl Viro 	ss->baud_base = priv->baud_base;
14483ae36bedSAl Viro 	ss->custom_divisor = priv->custom_divisor;
1449e49bbce1SJohan Hovold }
14501da177e4SLinus Torvalds 
set_serial_info(struct tty_struct * tty,struct serial_struct * ss)14510428bf68SJohan Hovold static int set_serial_info(struct tty_struct *tty, struct serial_struct *ss)
1452e49bbce1SJohan Hovold {
14533ae36bedSAl Viro 	struct usb_serial_port *port = tty->driver_data;
14541da177e4SLinus Torvalds 	struct ftdi_private *priv = usb_get_serial_port_data(port);
14550428bf68SJohan Hovold 	int old_flags, old_divisor;
14561da177e4SLinus Torvalds 
1457bd09a9f5SAlessio Igor Bogani 	mutex_lock(&priv->cfg_lock);
14581da177e4SLinus Torvalds 
14591da177e4SLinus Torvalds 	if (!capable(CAP_SYS_ADMIN)) {
14603ae36bedSAl Viro 		if ((ss->flags ^ priv->flags) & ~ASYNC_USR_MASK) {
1461bd09a9f5SAlessio Igor Bogani 			mutex_unlock(&priv->cfg_lock);
14621da177e4SLinus Torvalds 			return -EPERM;
146364905b48SDan Carpenter 		}
14641da177e4SLinus Torvalds 	}
14651da177e4SLinus Torvalds 
14660428bf68SJohan Hovold 	old_flags = priv->flags;
14670428bf68SJohan Hovold 	old_divisor = priv->custom_divisor;
14680428bf68SJohan Hovold 
1469c12860c0SJohan Hovold 	priv->flags = ss->flags & ASYNC_FLAGS;
14703ae36bedSAl Viro 	priv->custom_divisor = ss->custom_divisor;
14711da177e4SLinus Torvalds 
1472557aaa7fSAlan Cox 	write_latency_timer(port);
14731da177e4SLinus Torvalds 
14740428bf68SJohan Hovold 	if ((priv->flags ^ old_flags) & ASYNC_SPD_MASK ||
1475f3e8ae65SJohan Hovold 			((priv->flags & ASYNC_SPD_MASK) == ASYNC_SPD_CUST &&
14760428bf68SJohan Hovold 			 priv->custom_divisor != old_divisor)) {
147783c9a2d1SJohan Hovold 
147883c9a2d1SJohan Hovold 		/* warn about deprecation unless clearing */
147983c9a2d1SJohan Hovold 		if (priv->flags & ASYNC_SPD_MASK)
148083c9a2d1SJohan Hovold 			dev_warn_ratelimited(&port->dev, "use of SPD flags is deprecated\n");
148183c9a2d1SJohan Hovold 
148295da310eSAlan Cox 		change_speed(tty, port);
14831da177e4SLinus Torvalds 	}
1484bd09a9f5SAlessio Igor Bogani 	mutex_unlock(&priv->cfg_lock);
148595da310eSAlan Cox 	return 0;
1486e49bbce1SJohan Hovold }
14871da177e4SLinus Torvalds 
get_lsr_info(struct usb_serial_port * port,unsigned int __user * retinfo)1488c466cd2bSGreg Kroah-Hartman static int get_lsr_info(struct usb_serial_port *port,
148959556608SJohan Hovold 			unsigned int __user *retinfo)
1490c466cd2bSGreg Kroah-Hartman {
1491c466cd2bSGreg Kroah-Hartman 	struct ftdi_private *priv = usb_get_serial_port_data(port);
1492c466cd2bSGreg Kroah-Hartman 	unsigned int result = 0;
1493c466cd2bSGreg Kroah-Hartman 
1494c466cd2bSGreg Kroah-Hartman 	if (priv->transmit_empty)
1495c466cd2bSGreg Kroah-Hartman 		result = TIOCSER_TEMT;
1496c466cd2bSGreg Kroah-Hartman 
1497c466cd2bSGreg Kroah-Hartman 	if (copy_to_user(retinfo, &result, sizeof(unsigned int)))
1498c466cd2bSGreg Kroah-Hartman 		return -EFAULT;
1499c466cd2bSGreg Kroah-Hartman 	return 0;
1500c466cd2bSGreg Kroah-Hartman }
1501c466cd2bSGreg Kroah-Hartman 
ftdi_determine_type(struct usb_serial_port * port)1502f353c0d4SJohan Hovold static int ftdi_determine_type(struct usb_serial_port *port)
15038f977e42SIan Abbott {
15048f977e42SIan Abbott 	struct ftdi_private *priv = usb_get_serial_port_data(port);
15058f977e42SIan Abbott 	struct usb_serial *serial = port->serial;
15068f977e42SIan Abbott 	struct usb_device *udev = serial->dev;
1507f353c0d4SJohan Hovold 	unsigned int version, ifnum;
15088f977e42SIan Abbott 
15098f977e42SIan Abbott 	version = le16_to_cpu(udev->descriptor.bcdDevice);
1510f353c0d4SJohan Hovold 	ifnum = serial->interface->cur_altsetting->desc.bInterfaceNumber;
15118f977e42SIan Abbott 
15124d50f4fcSJohan Hovold 	/* Assume Hi-Speed type */
1513094c2e6dSMark Adamson 	priv->baud_base = 120000000 / 2;
15144d50f4fcSJohan Hovold 	priv->channel = CHANNEL_A + ifnum;
1515094c2e6dSMark Adamson 
1516f353c0d4SJohan Hovold 	switch (version) {
1517f353c0d4SJohan Hovold 	case 0x200:
151801aeb31fSJohan Hovold 		priv->chip_type = FT232A;
15194d50f4fcSJohan Hovold 		priv->baud_base = 48000000 / 2;
15204d50f4fcSJohan Hovold 		priv->channel = 0;
15217e1e6cedSIan Abbott 		/*
1522f353c0d4SJohan Hovold 		 * FT232B devices have a bug where bcdDevice gets set to 0x200
1523f353c0d4SJohan Hovold 		 * when iSerialNumber is 0. Assume it is an FT232B in case the
1524f353c0d4SJohan Hovold 		 * latency timer is readable.
15257e1e6cedSIan Abbott 		 */
15267e1e6cedSIan Abbott 		if (udev->descriptor.iSerialNumber == 0 &&
15277e1e6cedSIan Abbott 				_read_latency_timer(port) >= 0) {
152801aeb31fSJohan Hovold 			priv->chip_type = FT232B;
15297e1e6cedSIan Abbott 		}
1530f353c0d4SJohan Hovold 		break;
1531f353c0d4SJohan Hovold 	case 0x400:
153201aeb31fSJohan Hovold 		priv->chip_type = FT232B;
15334d50f4fcSJohan Hovold 		priv->baud_base = 48000000 / 2;
15344d50f4fcSJohan Hovold 		priv->channel = 0;
1535f353c0d4SJohan Hovold 		break;
1536f353c0d4SJohan Hovold 	case 0x500:
1537f353c0d4SJohan Hovold 		priv->chip_type = FT2232C;
15384d50f4fcSJohan Hovold 		priv->baud_base = 48000000 / 2;
1539f353c0d4SJohan Hovold 		break;
1540f353c0d4SJohan Hovold 	case 0x600:
154101aeb31fSJohan Hovold 		priv->chip_type = FT232R;
15424d50f4fcSJohan Hovold 		priv->baud_base = 48000000 / 2;
15434d50f4fcSJohan Hovold 		priv->channel = 0;
1544f353c0d4SJohan Hovold 		break;
1545f353c0d4SJohan Hovold 	case 0x700:
1546f353c0d4SJohan Hovold 		priv->chip_type = FT2232H;
1547f353c0d4SJohan Hovold 		break;
1548f353c0d4SJohan Hovold 	case 0x800:
1549f353c0d4SJohan Hovold 		priv->chip_type = FT4232H;
1550f353c0d4SJohan Hovold 		break;
1551f353c0d4SJohan Hovold 	case 0x900:
1552309427b6SUwe Bonnes 		priv->chip_type = FT232H;
1553f353c0d4SJohan Hovold 		break;
1554f353c0d4SJohan Hovold 	case 0x1000:
1555dc0827c1SJim Paris 		priv->chip_type = FTX;
15564d50f4fcSJohan Hovold 		priv->baud_base = 48000000 / 2;
1557f353c0d4SJohan Hovold 		break;
1558cfebcd53SAmireddy mallikarjuna reddy 	case 0x2800:
1559cfebcd53SAmireddy mallikarjuna reddy 		priv->chip_type = FT2233HP;
1560cfebcd53SAmireddy mallikarjuna reddy 		break;
1561cfebcd53SAmireddy mallikarjuna reddy 	case 0x2900:
1562cfebcd53SAmireddy mallikarjuna reddy 		priv->chip_type = FT4233HP;
1563cfebcd53SAmireddy mallikarjuna reddy 		break;
1564cfebcd53SAmireddy mallikarjuna reddy 	case 0x3000:
1565cfebcd53SAmireddy mallikarjuna reddy 		priv->chip_type = FT2232HP;
1566cfebcd53SAmireddy mallikarjuna reddy 		break;
1567cfebcd53SAmireddy mallikarjuna reddy 	case 0x3100:
1568cfebcd53SAmireddy mallikarjuna reddy 		priv->chip_type = FT4232HP;
1569cfebcd53SAmireddy mallikarjuna reddy 		break;
1570cfebcd53SAmireddy mallikarjuna reddy 	case 0x3200:
1571cfebcd53SAmireddy mallikarjuna reddy 		priv->chip_type = FT233HP;
1572cfebcd53SAmireddy mallikarjuna reddy 		break;
1573cfebcd53SAmireddy mallikarjuna reddy 	case 0x3300:
1574cfebcd53SAmireddy mallikarjuna reddy 		priv->chip_type = FT232HP;
1575cfebcd53SAmireddy mallikarjuna reddy 		break;
1576cfebcd53SAmireddy mallikarjuna reddy 	case 0x3600:
1577cfebcd53SAmireddy mallikarjuna reddy 		priv->chip_type = FT4232HA;
1578cfebcd53SAmireddy mallikarjuna reddy 		break;
1579f353c0d4SJohan Hovold 	default:
1580f353c0d4SJohan Hovold 		if (version < 0x200) {
1581f353c0d4SJohan Hovold 			priv->chip_type = SIO;
1582f353c0d4SJohan Hovold 			priv->baud_base = 12000000 / 16;
15834d50f4fcSJohan Hovold 			priv->channel = 0;
1584f353c0d4SJohan Hovold 		} else {
1585f353c0d4SJohan Hovold 			dev_err(&port->dev, "unknown device type: 0x%02x\n", version);
1586f353c0d4SJohan Hovold 			return -ENODEV;
1587f353c0d4SJohan Hovold 		}
15888f977e42SIan Abbott 	}
1589dc0827c1SJim Paris 
1590c197a8dbSGreg Kroah-Hartman 	dev_info(&udev->dev, "Detected %s\n", ftdi_chip_name[priv->chip_type]);
1591f353c0d4SJohan Hovold 
1592f353c0d4SJohan Hovold 	return 0;
15938f977e42SIan Abbott }
15948f977e42SIan Abbott 
15958f977e42SIan Abbott 
159647e57595SJohan Hovold /*
159747e57595SJohan Hovold  * Determine the maximum packet size for the device. This depends on the chip
1598895f28baSMark Adamson  * type and the USB host capabilities. The value should be obtained from the
159947e57595SJohan Hovold  * device descriptor as the chip will use the appropriate values for the host.
160047e57595SJohan Hovold  */
ftdi_set_max_packet_size(struct usb_serial_port * port)1601895f28baSMark Adamson static void ftdi_set_max_packet_size(struct usb_serial_port *port)
1602895f28baSMark Adamson {
1603895f28baSMark Adamson 	struct ftdi_private *priv = usb_get_serial_port_data(port);
160447e57595SJohan Hovold 	struct usb_interface *interface = port->serial->interface;
1605aea1ae87SJohan Hovold 	struct usb_endpoint_descriptor *ep_desc;
1606895f28baSMark Adamson 	unsigned num_endpoints;
1607aea1ae87SJohan Hovold 	unsigned i;
1608895f28baSMark Adamson 
1609895f28baSMark Adamson 	num_endpoints = interface->cur_altsetting->desc.bNumEndpoints;
1610aea1ae87SJohan Hovold 	if (!num_endpoints)
1611aea1ae87SJohan Hovold 		return;
1612aea1ae87SJohan Hovold 
161347e57595SJohan Hovold 	/*
161447e57595SJohan Hovold 	 * NOTE: Some customers have programmed FT232R/FT245R devices
1615895f28baSMark Adamson 	 * with an endpoint size of 0 - not good. In this case, we
1616895f28baSMark Adamson 	 * want to override the endpoint descriptor setting and use a
161747e57595SJohan Hovold 	 * value of 64 for wMaxPacketSize.
161847e57595SJohan Hovold 	 */
1619895f28baSMark Adamson 	for (i = 0; i < num_endpoints; i++) {
1620895f28baSMark Adamson 		ep_desc = &interface->cur_altsetting->endpoint[i].desc;
162147e57595SJohan Hovold 		if (!ep_desc->wMaxPacketSize) {
1622895f28baSMark Adamson 			ep_desc->wMaxPacketSize = cpu_to_le16(0x40);
1623a90d84adSJohan Hovold 			dev_warn(&port->dev, "Overriding wMaxPacketSize on endpoint %d\n",
1624a90d84adSJohan Hovold 					usb_endpoint_num(ep_desc));
1625895f28baSMark Adamson 		}
1626895f28baSMark Adamson 	}
1627895f28baSMark Adamson 
162847e57595SJohan Hovold 	/* Set max packet size based on last descriptor. */
162929cc8897SKuninori Morimoto 	priv->max_packet_size = usb_endpoint_maxp(ep_desc);
1630895f28baSMark Adamson }
1631895f28baSMark Adamson 
1632895f28baSMark Adamson 
16331da177e4SLinus Torvalds /*
16341da177e4SLinus Torvalds  * ***************************************************************************
16351da177e4SLinus Torvalds  * Sysfs Attribute
16361da177e4SLinus Torvalds  * ***************************************************************************
16371da177e4SLinus Torvalds  */
16381da177e4SLinus Torvalds 
latency_timer_show(struct device * dev,struct device_attribute * attr,char * buf)1639154547c4SGreg Kroah-Hartman static ssize_t latency_timer_show(struct device *dev,
1640464cbb24SAlan Cox 				  struct device_attribute *attr, char *buf)
16411da177e4SLinus Torvalds {
16421da177e4SLinus Torvalds 	struct usb_serial_port *port = to_usb_serial_port(dev);
16431da177e4SLinus Torvalds 	struct ftdi_private *priv = usb_get_serial_port_data(port);
1644557aaa7fSAlan Cox 	if (priv->flags & ASYNC_LOW_LATENCY)
1645557aaa7fSAlan Cox 		return sprintf(buf, "1\n");
1646557aaa7fSAlan Cox 	else
16471b30499aSDaniels Umanovskis 		return sprintf(buf, "%u\n", priv->latency);
16481da177e4SLinus Torvalds }
1649557aaa7fSAlan Cox 
16501da177e4SLinus Torvalds /* Write a new value of the latency timer, in units of milliseconds. */
latency_timer_store(struct device * dev,struct device_attribute * attr,const char * valbuf,size_t count)1651154547c4SGreg Kroah-Hartman static ssize_t latency_timer_store(struct device *dev,
1652154547c4SGreg Kroah-Hartman 				   struct device_attribute *attr,
1653154547c4SGreg Kroah-Hartman 				   const char *valbuf, size_t count)
16541da177e4SLinus Torvalds {
16551da177e4SLinus Torvalds 	struct usb_serial_port *port = to_usb_serial_port(dev);
16561da177e4SLinus Torvalds 	struct ftdi_private *priv = usb_get_serial_port_data(port);
1657db924066SIan Abbott 	u8 v;
1658c1284d77SJohan Hovold 	int rv;
16591da177e4SLinus Torvalds 
1660db924066SIan Abbott 	if (kstrtou8(valbuf, 10, &v))
1661db924066SIan Abbott 		return -EINVAL;
1662db924066SIan Abbott 
1663557aaa7fSAlan Cox 	priv->latency = v;
1664557aaa7fSAlan Cox 	rv = write_latency_timer(port);
1665557aaa7fSAlan Cox 	if (rv < 0)
16661da177e4SLinus Torvalds 		return -EIO;
16671da177e4SLinus Torvalds 	return count;
16681da177e4SLinus Torvalds }
1669154547c4SGreg Kroah-Hartman static DEVICE_ATTR_RW(latency_timer);
16701da177e4SLinus Torvalds 
16711da177e4SLinus Torvalds /* Write an event character directly to the FTDI register.  The ASCII
16721da177e4SLinus Torvalds    value is in the low 8 bits, with the enable bit in the 9th bit. */
event_char_store(struct device * dev,struct device_attribute * attr,const char * valbuf,size_t count)1673ca35910aSGreg Kroah-Hartman static ssize_t event_char_store(struct device *dev,
1674464cbb24SAlan Cox 	struct device_attribute *attr, const char *valbuf, size_t count)
16751da177e4SLinus Torvalds {
16761da177e4SLinus Torvalds 	struct usb_serial_port *port = to_usb_serial_port(dev);
16771da177e4SLinus Torvalds 	struct ftdi_private *priv = usb_get_serial_port_data(port);
167812bdbe03SJim Radford 	struct usb_device *udev = port->serial->dev;
1679d0559a2fSIan Abbott 	unsigned int v;
1680c1284d77SJohan Hovold 	int rv;
16811da177e4SLinus Torvalds 
1682f1ce25f2SIan Abbott 	if (kstrtouint(valbuf, 0, &v) || v >= 0x200)
1683d0559a2fSIan Abbott 		return -EINVAL;
1684d0559a2fSIan Abbott 
1685f1ce25f2SIan Abbott 	dev_dbg(&port->dev, "%s: setting event char = 0x%03x\n", __func__, v);
16861da177e4SLinus Torvalds 
16871da177e4SLinus Torvalds 	rv = usb_control_msg(udev,
16881da177e4SLinus Torvalds 			     usb_sndctrlpipe(udev, 0),
16891da177e4SLinus Torvalds 			     FTDI_SIO_SET_EVENT_CHAR_REQUEST,
16901da177e4SLinus Torvalds 			     FTDI_SIO_SET_EVENT_CHAR_REQUEST_TYPE,
1691027bf37dSJohan Hovold 			     v, priv->channel,
169266e47e60SJohan Hovold 			     NULL, 0, WDR_TIMEOUT);
16931da177e4SLinus Torvalds 	if (rv < 0) {
1694bfc51614SGreg Kroah-Hartman 		dev_dbg(&port->dev, "Unable to write event character: %i\n", rv);
16951da177e4SLinus Torvalds 		return -EIO;
16961da177e4SLinus Torvalds 	}
16971da177e4SLinus Torvalds 
16981da177e4SLinus Torvalds 	return count;
16991da177e4SLinus Torvalds }
1700ca35910aSGreg Kroah-Hartman static DEVICE_ATTR_WO(event_char);
17011da177e4SLinus Torvalds 
17020f6632e2SJiasheng Jiang static struct attribute *ftdi_attrs[] = {
17030f6632e2SJiasheng Jiang 	&dev_attr_event_char.attr,
17040f6632e2SJiasheng Jiang 	&dev_attr_latency_timer.attr,
17050f6632e2SJiasheng Jiang 	NULL
17060f6632e2SJiasheng Jiang };
17070f6632e2SJiasheng Jiang 
ftdi_is_visible(struct kobject * kobj,struct attribute * attr,int idx)17080f6632e2SJiasheng Jiang static umode_t ftdi_is_visible(struct kobject *kobj, struct attribute *attr, int idx)
17091da177e4SLinus Torvalds {
17100f6632e2SJiasheng Jiang 	struct device *dev = kobj_to_dev(kobj);
17110f6632e2SJiasheng Jiang 	struct usb_serial_port *port = to_usb_serial_port(dev);
171212bdbe03SJim Radford 	struct ftdi_private *priv = usb_get_serial_port_data(port);
17134d045b98SJohan Hovold 	enum ftdi_chip_type type = priv->chip_type;
17141da177e4SLinus Torvalds 
1715c142bdc5SJohan Hovold 	if (attr == &dev_attr_event_char.attr) {
1716c142bdc5SJohan Hovold 		if (type == SIO)
17170f6632e2SJiasheng Jiang 			return 0;
17181da177e4SLinus Torvalds 	}
17191da177e4SLinus Torvalds 
1720c142bdc5SJohan Hovold 	if (attr == &dev_attr_latency_timer.attr) {
1721c142bdc5SJohan Hovold 		if (type == SIO || type == FT232A)
1722c142bdc5SJohan Hovold 			return 0;
17231da177e4SLinus Torvalds 	}
17241da177e4SLinus Torvalds 
1725c142bdc5SJohan Hovold 	return attr->mode;
17261da177e4SLinus Torvalds }
17271da177e4SLinus Torvalds 
17280f6632e2SJiasheng Jiang static const struct attribute_group ftdi_group = {
17290f6632e2SJiasheng Jiang 	.attrs		= ftdi_attrs,
17300f6632e2SJiasheng Jiang 	.is_visible	= ftdi_is_visible,
17310f6632e2SJiasheng Jiang };
17320f6632e2SJiasheng Jiang 
17330f6632e2SJiasheng Jiang static const struct attribute_group *ftdi_groups[] = {
17340f6632e2SJiasheng Jiang 	&ftdi_group,
17350f6632e2SJiasheng Jiang 	NULL
17360f6632e2SJiasheng Jiang };
17370f6632e2SJiasheng Jiang 
1738ba93cc7dSKaroly Pados #ifdef CONFIG_GPIOLIB
1739ba93cc7dSKaroly Pados 
ftdi_set_bitmode(struct usb_serial_port * port,u8 mode)1740ba93cc7dSKaroly Pados static int ftdi_set_bitmode(struct usb_serial_port *port, u8 mode)
1741ba93cc7dSKaroly Pados {
1742ba93cc7dSKaroly Pados 	struct ftdi_private *priv = usb_get_serial_port_data(port);
1743ba93cc7dSKaroly Pados 	struct usb_serial *serial = port->serial;
1744ba93cc7dSKaroly Pados 	int result;
1745ba93cc7dSKaroly Pados 	u16 val;
1746ba93cc7dSKaroly Pados 
1747a8eda9faSKaroly Pados 	result = usb_autopm_get_interface(serial->interface);
1748a8eda9faSKaroly Pados 	if (result)
1749a8eda9faSKaroly Pados 		return result;
1750a8eda9faSKaroly Pados 
1751ba93cc7dSKaroly Pados 	val = (mode << 8) | (priv->gpio_output << 4) | priv->gpio_value;
1752ba93cc7dSKaroly Pados 	result = usb_control_msg(serial->dev,
1753ba93cc7dSKaroly Pados 				 usb_sndctrlpipe(serial->dev, 0),
1754ba93cc7dSKaroly Pados 				 FTDI_SIO_SET_BITMODE_REQUEST,
1755ba93cc7dSKaroly Pados 				 FTDI_SIO_SET_BITMODE_REQUEST_TYPE, val,
1756027bf37dSJohan Hovold 				 priv->channel, NULL, 0, WDR_TIMEOUT);
1757ba93cc7dSKaroly Pados 	if (result < 0) {
1758ba93cc7dSKaroly Pados 		dev_err(&serial->interface->dev,
1759ba93cc7dSKaroly Pados 			"bitmode request failed for value 0x%04x: %d\n",
1760ba93cc7dSKaroly Pados 			val, result);
1761ba93cc7dSKaroly Pados 	}
1762ba93cc7dSKaroly Pados 
1763a8eda9faSKaroly Pados 	usb_autopm_put_interface(serial->interface);
1764a8eda9faSKaroly Pados 
1765ba93cc7dSKaroly Pados 	return result;
1766ba93cc7dSKaroly Pados }
1767ba93cc7dSKaroly Pados 
ftdi_set_cbus_pins(struct usb_serial_port * port)1768ba93cc7dSKaroly Pados static int ftdi_set_cbus_pins(struct usb_serial_port *port)
1769ba93cc7dSKaroly Pados {
1770ba93cc7dSKaroly Pados 	return ftdi_set_bitmode(port, FTDI_SIO_BITMODE_CBUS);
1771ba93cc7dSKaroly Pados }
1772ba93cc7dSKaroly Pados 
ftdi_exit_cbus_mode(struct usb_serial_port * port)1773ba93cc7dSKaroly Pados static int ftdi_exit_cbus_mode(struct usb_serial_port *port)
1774ba93cc7dSKaroly Pados {
1775ba93cc7dSKaroly Pados 	struct ftdi_private *priv = usb_get_serial_port_data(port);
1776ba93cc7dSKaroly Pados 
1777ba93cc7dSKaroly Pados 	priv->gpio_output = 0;
1778ba93cc7dSKaroly Pados 	priv->gpio_value = 0;
1779ba93cc7dSKaroly Pados 	return ftdi_set_bitmode(port, FTDI_SIO_BITMODE_RESET);
1780ba93cc7dSKaroly Pados }
1781ba93cc7dSKaroly Pados 
ftdi_gpio_request(struct gpio_chip * gc,unsigned int offset)1782ba93cc7dSKaroly Pados static int ftdi_gpio_request(struct gpio_chip *gc, unsigned int offset)
1783ba93cc7dSKaroly Pados {
1784ba93cc7dSKaroly Pados 	struct usb_serial_port *port = gpiochip_get_data(gc);
1785ba93cc7dSKaroly Pados 	struct ftdi_private *priv = usb_get_serial_port_data(port);
1786ba93cc7dSKaroly Pados 	int result;
1787ba93cc7dSKaroly Pados 
1788ba93cc7dSKaroly Pados 	mutex_lock(&priv->gpio_lock);
1789ba93cc7dSKaroly Pados 	if (!priv->gpio_used) {
1790ba93cc7dSKaroly Pados 		/* Set default pin states, as we cannot get them from device */
1791ba93cc7dSKaroly Pados 		priv->gpio_output = 0x00;
1792ba93cc7dSKaroly Pados 		priv->gpio_value = 0x00;
1793ba93cc7dSKaroly Pados 		result = ftdi_set_cbus_pins(port);
1794ba93cc7dSKaroly Pados 		if (result) {
1795ba93cc7dSKaroly Pados 			mutex_unlock(&priv->gpio_lock);
1796ba93cc7dSKaroly Pados 			return result;
1797ba93cc7dSKaroly Pados 		}
1798ba93cc7dSKaroly Pados 
1799ba93cc7dSKaroly Pados 		priv->gpio_used = true;
1800ba93cc7dSKaroly Pados 	}
1801ba93cc7dSKaroly Pados 	mutex_unlock(&priv->gpio_lock);
1802ba93cc7dSKaroly Pados 
1803ba93cc7dSKaroly Pados 	return 0;
1804ba93cc7dSKaroly Pados }
1805ba93cc7dSKaroly Pados 
ftdi_read_cbus_pins(struct usb_serial_port * port)1806ba93cc7dSKaroly Pados static int ftdi_read_cbus_pins(struct usb_serial_port *port)
1807ba93cc7dSKaroly Pados {
1808ba93cc7dSKaroly Pados 	struct ftdi_private *priv = usb_get_serial_port_data(port);
1809ba93cc7dSKaroly Pados 	struct usb_serial *serial = port->serial;
1810a7388592SHimadri Pandya 	u8 buf;
1811ba93cc7dSKaroly Pados 	int result;
1812ba93cc7dSKaroly Pados 
1813a8eda9faSKaroly Pados 	result = usb_autopm_get_interface(serial->interface);
1814a8eda9faSKaroly Pados 	if (result)
1815a8eda9faSKaroly Pados 		return result;
1816a8eda9faSKaroly Pados 
1817a7388592SHimadri Pandya 	result = usb_control_msg_recv(serial->dev, 0,
1818ba93cc7dSKaroly Pados 				      FTDI_SIO_READ_PINS_REQUEST,
1819ba93cc7dSKaroly Pados 				      FTDI_SIO_READ_PINS_REQUEST_TYPE, 0,
1820027bf37dSJohan Hovold 				      priv->channel, &buf, 1, WDR_TIMEOUT,
1821a7388592SHimadri Pandya 				      GFP_KERNEL);
1822a7388592SHimadri Pandya 	if (result == 0)
1823a7388592SHimadri Pandya 		result = buf;
1824ba93cc7dSKaroly Pados 
1825a8eda9faSKaroly Pados 	usb_autopm_put_interface(serial->interface);
1826ba93cc7dSKaroly Pados 
1827ba93cc7dSKaroly Pados 	return result;
1828ba93cc7dSKaroly Pados }
1829ba93cc7dSKaroly Pados 
ftdi_gpio_get(struct gpio_chip * gc,unsigned int gpio)1830ba93cc7dSKaroly Pados static int ftdi_gpio_get(struct gpio_chip *gc, unsigned int gpio)
1831ba93cc7dSKaroly Pados {
1832ba93cc7dSKaroly Pados 	struct usb_serial_port *port = gpiochip_get_data(gc);
1833ba93cc7dSKaroly Pados 	int result;
1834ba93cc7dSKaroly Pados 
1835ba93cc7dSKaroly Pados 	result = ftdi_read_cbus_pins(port);
1836ba93cc7dSKaroly Pados 	if (result < 0)
1837ba93cc7dSKaroly Pados 		return result;
1838ba93cc7dSKaroly Pados 
1839ba93cc7dSKaroly Pados 	return !!(result & BIT(gpio));
1840ba93cc7dSKaroly Pados }
1841ba93cc7dSKaroly Pados 
ftdi_gpio_set(struct gpio_chip * gc,unsigned int gpio,int value)1842ba93cc7dSKaroly Pados static void ftdi_gpio_set(struct gpio_chip *gc, unsigned int gpio, int value)
1843ba93cc7dSKaroly Pados {
1844ba93cc7dSKaroly Pados 	struct usb_serial_port *port = gpiochip_get_data(gc);
1845ba93cc7dSKaroly Pados 	struct ftdi_private *priv = usb_get_serial_port_data(port);
1846ba93cc7dSKaroly Pados 
1847ba93cc7dSKaroly Pados 	mutex_lock(&priv->gpio_lock);
1848ba93cc7dSKaroly Pados 
1849ba93cc7dSKaroly Pados 	if (value)
1850ba93cc7dSKaroly Pados 		priv->gpio_value |= BIT(gpio);
1851ba93cc7dSKaroly Pados 	else
1852ba93cc7dSKaroly Pados 		priv->gpio_value &= ~BIT(gpio);
1853ba93cc7dSKaroly Pados 
1854ba93cc7dSKaroly Pados 	ftdi_set_cbus_pins(port);
1855ba93cc7dSKaroly Pados 
1856ba93cc7dSKaroly Pados 	mutex_unlock(&priv->gpio_lock);
1857ba93cc7dSKaroly Pados }
1858ba93cc7dSKaroly Pados 
ftdi_gpio_get_multiple(struct gpio_chip * gc,unsigned long * mask,unsigned long * bits)1859ba93cc7dSKaroly Pados static int ftdi_gpio_get_multiple(struct gpio_chip *gc, unsigned long *mask,
1860ba93cc7dSKaroly Pados 					unsigned long *bits)
1861ba93cc7dSKaroly Pados {
1862ba93cc7dSKaroly Pados 	struct usb_serial_port *port = gpiochip_get_data(gc);
1863ba93cc7dSKaroly Pados 	int result;
1864ba93cc7dSKaroly Pados 
1865ba93cc7dSKaroly Pados 	result = ftdi_read_cbus_pins(port);
1866ba93cc7dSKaroly Pados 	if (result < 0)
1867ba93cc7dSKaroly Pados 		return result;
1868ba93cc7dSKaroly Pados 
1869ba93cc7dSKaroly Pados 	*bits = result & *mask;
1870ba93cc7dSKaroly Pados 
1871ba93cc7dSKaroly Pados 	return 0;
1872ba93cc7dSKaroly Pados }
1873ba93cc7dSKaroly Pados 
ftdi_gpio_set_multiple(struct gpio_chip * gc,unsigned long * mask,unsigned long * bits)1874ba93cc7dSKaroly Pados static void ftdi_gpio_set_multiple(struct gpio_chip *gc, unsigned long *mask,
1875ba93cc7dSKaroly Pados 					unsigned long *bits)
1876ba93cc7dSKaroly Pados {
1877ba93cc7dSKaroly Pados 	struct usb_serial_port *port = gpiochip_get_data(gc);
1878ba93cc7dSKaroly Pados 	struct ftdi_private *priv = usb_get_serial_port_data(port);
1879ba93cc7dSKaroly Pados 
1880ba93cc7dSKaroly Pados 	mutex_lock(&priv->gpio_lock);
1881ba93cc7dSKaroly Pados 
1882ba93cc7dSKaroly Pados 	priv->gpio_value &= ~(*mask);
1883ba93cc7dSKaroly Pados 	priv->gpio_value |= *bits & *mask;
1884ba93cc7dSKaroly Pados 	ftdi_set_cbus_pins(port);
1885ba93cc7dSKaroly Pados 
1886ba93cc7dSKaroly Pados 	mutex_unlock(&priv->gpio_lock);
1887ba93cc7dSKaroly Pados }
1888ba93cc7dSKaroly Pados 
ftdi_gpio_direction_get(struct gpio_chip * gc,unsigned int gpio)1889ba93cc7dSKaroly Pados static int ftdi_gpio_direction_get(struct gpio_chip *gc, unsigned int gpio)
1890ba93cc7dSKaroly Pados {
1891ba93cc7dSKaroly Pados 	struct usb_serial_port *port = gpiochip_get_data(gc);
1892ba93cc7dSKaroly Pados 	struct ftdi_private *priv = usb_get_serial_port_data(port);
1893ba93cc7dSKaroly Pados 
1894ba93cc7dSKaroly Pados 	return !(priv->gpio_output & BIT(gpio));
1895ba93cc7dSKaroly Pados }
1896ba93cc7dSKaroly Pados 
ftdi_gpio_direction_input(struct gpio_chip * gc,unsigned int gpio)1897ba93cc7dSKaroly Pados static int ftdi_gpio_direction_input(struct gpio_chip *gc, unsigned int gpio)
1898ba93cc7dSKaroly Pados {
1899ba93cc7dSKaroly Pados 	struct usb_serial_port *port = gpiochip_get_data(gc);
1900ba93cc7dSKaroly Pados 	struct ftdi_private *priv = usb_get_serial_port_data(port);
1901ba93cc7dSKaroly Pados 	int result;
1902ba93cc7dSKaroly Pados 
1903ba93cc7dSKaroly Pados 	mutex_lock(&priv->gpio_lock);
1904ba93cc7dSKaroly Pados 
1905ba93cc7dSKaroly Pados 	priv->gpio_output &= ~BIT(gpio);
1906ba93cc7dSKaroly Pados 	result = ftdi_set_cbus_pins(port);
1907ba93cc7dSKaroly Pados 
1908ba93cc7dSKaroly Pados 	mutex_unlock(&priv->gpio_lock);
1909ba93cc7dSKaroly Pados 
1910ba93cc7dSKaroly Pados 	return result;
1911ba93cc7dSKaroly Pados }
1912ba93cc7dSKaroly Pados 
ftdi_gpio_direction_output(struct gpio_chip * gc,unsigned int gpio,int value)1913ba93cc7dSKaroly Pados static int ftdi_gpio_direction_output(struct gpio_chip *gc, unsigned int gpio,
1914ba93cc7dSKaroly Pados 					int value)
1915ba93cc7dSKaroly Pados {
1916ba93cc7dSKaroly Pados 	struct usb_serial_port *port = gpiochip_get_data(gc);
1917ba93cc7dSKaroly Pados 	struct ftdi_private *priv = usb_get_serial_port_data(port);
1918ba93cc7dSKaroly Pados 	int result;
1919ba93cc7dSKaroly Pados 
1920ba93cc7dSKaroly Pados 	mutex_lock(&priv->gpio_lock);
1921ba93cc7dSKaroly Pados 
1922ba93cc7dSKaroly Pados 	priv->gpio_output |= BIT(gpio);
1923ba93cc7dSKaroly Pados 	if (value)
1924ba93cc7dSKaroly Pados 		priv->gpio_value |= BIT(gpio);
1925ba93cc7dSKaroly Pados 	else
1926ba93cc7dSKaroly Pados 		priv->gpio_value &= ~BIT(gpio);
1927ba93cc7dSKaroly Pados 
1928ba93cc7dSKaroly Pados 	result = ftdi_set_cbus_pins(port);
1929ba93cc7dSKaroly Pados 
1930ba93cc7dSKaroly Pados 	mutex_unlock(&priv->gpio_lock);
1931ba93cc7dSKaroly Pados 
1932ba93cc7dSKaroly Pados 	return result;
1933ba93cc7dSKaroly Pados }
1934ba93cc7dSKaroly Pados 
ftdi_gpio_init_valid_mask(struct gpio_chip * gc,unsigned long * valid_mask,unsigned int ngpios)193511fb08cfSMarc Zyngier static int ftdi_gpio_init_valid_mask(struct gpio_chip *gc,
193611fb08cfSMarc Zyngier 				     unsigned long *valid_mask,
193711fb08cfSMarc Zyngier 				     unsigned int ngpios)
193811fb08cfSMarc Zyngier {
193911fb08cfSMarc Zyngier 	struct usb_serial_port *port = gpiochip_get_data(gc);
194011fb08cfSMarc Zyngier 	struct ftdi_private *priv = usb_get_serial_port_data(port);
194111fb08cfSMarc Zyngier 	unsigned long map = priv->gpio_altfunc;
194211fb08cfSMarc Zyngier 
194311fb08cfSMarc Zyngier 	bitmap_complement(valid_mask, &map, ngpios);
194411fb08cfSMarc Zyngier 
1945fddd408aSMarc Zyngier 	if (bitmap_empty(valid_mask, ngpios))
1946fddd408aSMarc Zyngier 		dev_dbg(&port->dev, "no CBUS pin configured for GPIO\n");
1947fddd408aSMarc Zyngier 	else
1948fddd408aSMarc Zyngier 		dev_dbg(&port->dev, "CBUS%*pbl configured for GPIO\n", ngpios,
1949fddd408aSMarc Zyngier 			valid_mask);
1950fddd408aSMarc Zyngier 
195111fb08cfSMarc Zyngier 	return 0;
195211fb08cfSMarc Zyngier }
195311fb08cfSMarc Zyngier 
ftdi_read_eeprom(struct usb_serial * serial,void * dst,u16 addr,u16 nbytes)1954ba93cc7dSKaroly Pados static int ftdi_read_eeprom(struct usb_serial *serial, void *dst, u16 addr,
1955ba93cc7dSKaroly Pados 				u16 nbytes)
1956ba93cc7dSKaroly Pados {
1957ba93cc7dSKaroly Pados 	int read = 0;
1958ba93cc7dSKaroly Pados 
1959ba93cc7dSKaroly Pados 	if (addr % 2 != 0)
1960ba93cc7dSKaroly Pados 		return -EINVAL;
1961ba93cc7dSKaroly Pados 	if (nbytes % 2 != 0)
1962ba93cc7dSKaroly Pados 		return -EINVAL;
1963ba93cc7dSKaroly Pados 
1964ba93cc7dSKaroly Pados 	/* Read EEPROM two bytes at a time */
1965ba93cc7dSKaroly Pados 	while (read < nbytes) {
1966ba93cc7dSKaroly Pados 		int rv;
1967ba93cc7dSKaroly Pados 
1968ba93cc7dSKaroly Pados 		rv = usb_control_msg(serial->dev,
1969ba93cc7dSKaroly Pados 				     usb_rcvctrlpipe(serial->dev, 0),
1970ba93cc7dSKaroly Pados 				     FTDI_SIO_READ_EEPROM_REQUEST,
1971ba93cc7dSKaroly Pados 				     FTDI_SIO_READ_EEPROM_REQUEST_TYPE,
1972ba93cc7dSKaroly Pados 				     0, (addr + read) / 2, dst + read, 2,
1973ba93cc7dSKaroly Pados 				     WDR_TIMEOUT);
1974ba93cc7dSKaroly Pados 		if (rv < 2) {
1975ba93cc7dSKaroly Pados 			if (rv >= 0)
1976ba93cc7dSKaroly Pados 				return -EIO;
1977ba93cc7dSKaroly Pados 			else
1978ba93cc7dSKaroly Pados 				return rv;
1979ba93cc7dSKaroly Pados 		}
1980ba93cc7dSKaroly Pados 
1981ba93cc7dSKaroly Pados 		read += rv;
1982ba93cc7dSKaroly Pados 	}
1983ba93cc7dSKaroly Pados 
1984ba93cc7dSKaroly Pados 	return 0;
1985ba93cc7dSKaroly Pados }
1986ba93cc7dSKaroly Pados 
ftdi_gpio_init_ft232h(struct usb_serial_port * port)19877a786b84SMatthew Michilot static int ftdi_gpio_init_ft232h(struct usb_serial_port *port)
19887a786b84SMatthew Michilot {
19897a786b84SMatthew Michilot 	struct ftdi_private *priv = usb_get_serial_port_data(port);
19907a786b84SMatthew Michilot 	u16 cbus_config;
19917a786b84SMatthew Michilot 	u8 *buf;
19927a786b84SMatthew Michilot 	int ret;
19937a786b84SMatthew Michilot 	int i;
19947a786b84SMatthew Michilot 
19957a786b84SMatthew Michilot 	buf = kmalloc(4, GFP_KERNEL);
19967a786b84SMatthew Michilot 	if (!buf)
19977a786b84SMatthew Michilot 		return -ENOMEM;
19987a786b84SMatthew Michilot 
19997a786b84SMatthew Michilot 	ret = ftdi_read_eeprom(port->serial, buf, 0x1a, 4);
20007a786b84SMatthew Michilot 	if (ret < 0)
20017a786b84SMatthew Michilot 		goto out_free;
20027a786b84SMatthew Michilot 
20037a786b84SMatthew Michilot 	/*
20047a786b84SMatthew Michilot 	 * FT232H CBUS Memory Map
20057a786b84SMatthew Michilot 	 *
20067a786b84SMatthew Michilot 	 * 0x1a: X- (upper nibble -> AC5)
20077a786b84SMatthew Michilot 	 * 0x1b: -X (lower nibble -> AC6)
20087a786b84SMatthew Michilot 	 * 0x1c: XX (upper nibble -> AC9 | lower nibble -> AC8)
20097a786b84SMatthew Michilot 	 */
20107a786b84SMatthew Michilot 	cbus_config = buf[2] << 8 | (buf[1] & 0xf) << 4 | (buf[0] & 0xf0) >> 4;
20117a786b84SMatthew Michilot 
20127a786b84SMatthew Michilot 	priv->gc.ngpio = 4;
20137a786b84SMatthew Michilot 	priv->gpio_altfunc = 0xff;
20147a786b84SMatthew Michilot 
20157a786b84SMatthew Michilot 	for (i = 0; i < priv->gc.ngpio; ++i) {
20167a786b84SMatthew Michilot 		if ((cbus_config & 0xf) == FTDI_FTX_CBUS_MUX_GPIO)
20177a786b84SMatthew Michilot 			priv->gpio_altfunc &= ~BIT(i);
20187a786b84SMatthew Michilot 		cbus_config >>= 4;
20197a786b84SMatthew Michilot 	}
20207a786b84SMatthew Michilot 
20217a786b84SMatthew Michilot out_free:
20227a786b84SMatthew Michilot 	kfree(buf);
20237a786b84SMatthew Michilot 
20247a786b84SMatthew Michilot 	return ret;
20257a786b84SMatthew Michilot }
20267a786b84SMatthew Michilot 
ftdi_gpio_init_ft232r(struct usb_serial_port * port)2027ff32d97eSJohan Hovold static int ftdi_gpio_init_ft232r(struct usb_serial_port *port)
2028ff32d97eSJohan Hovold {
2029ff32d97eSJohan Hovold 	struct ftdi_private *priv = usb_get_serial_port_data(port);
2030ff32d97eSJohan Hovold 	u16 cbus_config;
2031ff32d97eSJohan Hovold 	u8 *buf;
2032ff32d97eSJohan Hovold 	int ret;
2033ff32d97eSJohan Hovold 	int i;
2034ff32d97eSJohan Hovold 
2035ff32d97eSJohan Hovold 	buf = kmalloc(2, GFP_KERNEL);
2036ff32d97eSJohan Hovold 	if (!buf)
2037ff32d97eSJohan Hovold 		return -ENOMEM;
2038ff32d97eSJohan Hovold 
2039ff32d97eSJohan Hovold 	ret = ftdi_read_eeprom(port->serial, buf, 0x14, 2);
2040ff32d97eSJohan Hovold 	if (ret < 0)
2041ff32d97eSJohan Hovold 		goto out_free;
2042ff32d97eSJohan Hovold 
2043ff32d97eSJohan Hovold 	cbus_config = le16_to_cpup((__le16 *)buf);
2044ff32d97eSJohan Hovold 	dev_dbg(&port->dev, "cbus_config = 0x%04x\n", cbus_config);
2045ff32d97eSJohan Hovold 
2046ff32d97eSJohan Hovold 	priv->gc.ngpio = 4;
2047ff32d97eSJohan Hovold 
2048ff32d97eSJohan Hovold 	priv->gpio_altfunc = 0xff;
2049ff32d97eSJohan Hovold 	for (i = 0; i < priv->gc.ngpio; ++i) {
2050ff32d97eSJohan Hovold 		if ((cbus_config & 0xf) == FTDI_FT232R_CBUS_MUX_GPIO)
2051ff32d97eSJohan Hovold 			priv->gpio_altfunc &= ~BIT(i);
2052ff32d97eSJohan Hovold 		cbus_config >>= 4;
2053ff32d97eSJohan Hovold 	}
2054ff32d97eSJohan Hovold out_free:
2055ff32d97eSJohan Hovold 	kfree(buf);
2056ff32d97eSJohan Hovold 
2057ff32d97eSJohan Hovold 	return ret;
2058ff32d97eSJohan Hovold }
2059ff32d97eSJohan Hovold 
ftdi_gpio_init_ftx(struct usb_serial_port * port)2060ff32d97eSJohan Hovold static int ftdi_gpio_init_ftx(struct usb_serial_port *port)
2061ba93cc7dSKaroly Pados {
2062ba93cc7dSKaroly Pados 	struct ftdi_private *priv = usb_get_serial_port_data(port);
2063ba93cc7dSKaroly Pados 	struct usb_serial *serial = port->serial;
2064ba93cc7dSKaroly Pados 	const u16 cbus_cfg_addr = 0x1a;
2065ba93cc7dSKaroly Pados 	const u16 cbus_cfg_size = 4;
2066ba93cc7dSKaroly Pados 	u8 *cbus_cfg_buf;
2067ba93cc7dSKaroly Pados 	int result;
2068ba93cc7dSKaroly Pados 	u8 i;
2069ba93cc7dSKaroly Pados 
2070ba93cc7dSKaroly Pados 	cbus_cfg_buf = kmalloc(cbus_cfg_size, GFP_KERNEL);
2071ba93cc7dSKaroly Pados 	if (!cbus_cfg_buf)
2072ba93cc7dSKaroly Pados 		return -ENOMEM;
2073ba93cc7dSKaroly Pados 
2074ba93cc7dSKaroly Pados 	result = ftdi_read_eeprom(serial, cbus_cfg_buf,
2075ba93cc7dSKaroly Pados 				  cbus_cfg_addr, cbus_cfg_size);
2076ba93cc7dSKaroly Pados 	if (result < 0)
2077ba93cc7dSKaroly Pados 		goto out_free;
2078ba93cc7dSKaroly Pados 
2079ba93cc7dSKaroly Pados 	/* FIXME: FT234XD alone has 1 GPIO, but how to recognize this IC? */
2080ba93cc7dSKaroly Pados 	priv->gc.ngpio = 4;
2081ba93cc7dSKaroly Pados 
2082ba93cc7dSKaroly Pados 	/* Determine which pins are configured for CBUS bitbanging */
2083ba93cc7dSKaroly Pados 	priv->gpio_altfunc = 0xff;
2084ba93cc7dSKaroly Pados 	for (i = 0; i < priv->gc.ngpio; ++i) {
2085ba93cc7dSKaroly Pados 		if (cbus_cfg_buf[i] == FTDI_FTX_CBUS_MUX_GPIO)
2086ba93cc7dSKaroly Pados 			priv->gpio_altfunc &= ~BIT(i);
2087ba93cc7dSKaroly Pados 	}
2088ba93cc7dSKaroly Pados 
2089ba93cc7dSKaroly Pados out_free:
2090ba93cc7dSKaroly Pados 	kfree(cbus_cfg_buf);
2091ba93cc7dSKaroly Pados 
2092ba93cc7dSKaroly Pados 	return result;
2093ba93cc7dSKaroly Pados }
2094ba93cc7dSKaroly Pados 
ftdi_gpio_init(struct usb_serial_port * port)2095ba93cc7dSKaroly Pados static int ftdi_gpio_init(struct usb_serial_port *port)
2096ba93cc7dSKaroly Pados {
2097ba93cc7dSKaroly Pados 	struct ftdi_private *priv = usb_get_serial_port_data(port);
2098ba93cc7dSKaroly Pados 	struct usb_serial *serial = port->serial;
2099ba93cc7dSKaroly Pados 	int result;
2100ba93cc7dSKaroly Pados 
2101ba93cc7dSKaroly Pados 	switch (priv->chip_type) {
21027a786b84SMatthew Michilot 	case FT232H:
21037a786b84SMatthew Michilot 		result = ftdi_gpio_init_ft232h(port);
21047a786b84SMatthew Michilot 		break;
210501aeb31fSJohan Hovold 	case FT232R:
2106ff32d97eSJohan Hovold 		result = ftdi_gpio_init_ft232r(port);
2107ff32d97eSJohan Hovold 		break;
2108ba93cc7dSKaroly Pados 	case FTX:
2109ff32d97eSJohan Hovold 		result = ftdi_gpio_init_ftx(port);
2110ba93cc7dSKaroly Pados 		break;
2111ba93cc7dSKaroly Pados 	default:
2112ba93cc7dSKaroly Pados 		return 0;
2113ba93cc7dSKaroly Pados 	}
2114ba93cc7dSKaroly Pados 
2115ba93cc7dSKaroly Pados 	if (result < 0)
2116ba93cc7dSKaroly Pados 		return result;
2117ba93cc7dSKaroly Pados 
2118ba93cc7dSKaroly Pados 	mutex_init(&priv->gpio_lock);
2119ba93cc7dSKaroly Pados 
2120ba93cc7dSKaroly Pados 	priv->gc.label = "ftdi-cbus";
2121ba93cc7dSKaroly Pados 	priv->gc.request = ftdi_gpio_request;
2122ba93cc7dSKaroly Pados 	priv->gc.get_direction = ftdi_gpio_direction_get;
2123ba93cc7dSKaroly Pados 	priv->gc.direction_input = ftdi_gpio_direction_input;
2124ba93cc7dSKaroly Pados 	priv->gc.direction_output = ftdi_gpio_direction_output;
212511fb08cfSMarc Zyngier 	priv->gc.init_valid_mask = ftdi_gpio_init_valid_mask;
2126ba93cc7dSKaroly Pados 	priv->gc.get = ftdi_gpio_get;
2127ba93cc7dSKaroly Pados 	priv->gc.set = ftdi_gpio_set;
2128ba93cc7dSKaroly Pados 	priv->gc.get_multiple = ftdi_gpio_get_multiple;
2129ba93cc7dSKaroly Pados 	priv->gc.set_multiple = ftdi_gpio_set_multiple;
2130ba93cc7dSKaroly Pados 	priv->gc.owner = THIS_MODULE;
2131ba93cc7dSKaroly Pados 	priv->gc.parent = &serial->interface->dev;
2132ba93cc7dSKaroly Pados 	priv->gc.base = -1;
2133ba93cc7dSKaroly Pados 	priv->gc.can_sleep = true;
2134ba93cc7dSKaroly Pados 
2135ba93cc7dSKaroly Pados 	result = gpiochip_add_data(&priv->gc, port);
2136ba93cc7dSKaroly Pados 	if (!result)
2137ba93cc7dSKaroly Pados 		priv->gpio_registered = true;
2138ba93cc7dSKaroly Pados 
2139ba93cc7dSKaroly Pados 	return result;
2140ba93cc7dSKaroly Pados }
2141ba93cc7dSKaroly Pados 
ftdi_gpio_remove(struct usb_serial_port * port)2142ba93cc7dSKaroly Pados static void ftdi_gpio_remove(struct usb_serial_port *port)
2143ba93cc7dSKaroly Pados {
2144ba93cc7dSKaroly Pados 	struct ftdi_private *priv = usb_get_serial_port_data(port);
2145ba93cc7dSKaroly Pados 
2146ba93cc7dSKaroly Pados 	if (priv->gpio_registered) {
2147ba93cc7dSKaroly Pados 		gpiochip_remove(&priv->gc);
2148ba93cc7dSKaroly Pados 		priv->gpio_registered = false;
2149ba93cc7dSKaroly Pados 	}
2150ba93cc7dSKaroly Pados 
2151ba93cc7dSKaroly Pados 	if (priv->gpio_used) {
2152ba93cc7dSKaroly Pados 		/* Exiting CBUS-mode does not reset pin states. */
2153ba93cc7dSKaroly Pados 		ftdi_exit_cbus_mode(port);
2154ba93cc7dSKaroly Pados 		priv->gpio_used = false;
2155ba93cc7dSKaroly Pados 	}
2156ba93cc7dSKaroly Pados }
2157ba93cc7dSKaroly Pados 
2158ba93cc7dSKaroly Pados #else
2159ba93cc7dSKaroly Pados 
ftdi_gpio_init(struct usb_serial_port * port)2160ba93cc7dSKaroly Pados static int ftdi_gpio_init(struct usb_serial_port *port)
2161ba93cc7dSKaroly Pados {
2162ba93cc7dSKaroly Pados 	return 0;
2163ba93cc7dSKaroly Pados }
2164ba93cc7dSKaroly Pados 
ftdi_gpio_remove(struct usb_serial_port * port)2165ba93cc7dSKaroly Pados static void ftdi_gpio_remove(struct usb_serial_port *port) { }
2166ba93cc7dSKaroly Pados 
2167ba93cc7dSKaroly Pados #endif	/* CONFIG_GPIOLIB */
2168ba93cc7dSKaroly Pados 
21691da177e4SLinus Torvalds /*
21701da177e4SLinus Torvalds  * ***************************************************************************
21711da177e4SLinus Torvalds  * FTDI driver specific functions
21721da177e4SLinus Torvalds  * ***************************************************************************
21731da177e4SLinus Torvalds  */
21741da177e4SLinus Torvalds 
ftdi_probe(struct usb_serial * serial,const struct usb_device_id * id)21756b2fe3dfSJohan Hovold static int ftdi_probe(struct usb_serial *serial, const struct usb_device_id *id)
21768f977e42SIan Abbott {
21776b2fe3dfSJohan Hovold 	const struct ftdi_quirk *quirk = (struct ftdi_quirk *)id->driver_info;
2178fa91d43bSTony Lindgren 
2179fa91d43bSTony Lindgren 	if (quirk && quirk->probe) {
2180fa91d43bSTony Lindgren 		int ret = quirk->probe(serial);
2181fa91d43bSTony Lindgren 		if (ret != 0)
2182fa91d43bSTony Lindgren 			return ret;
2183fa91d43bSTony Lindgren 	}
2184fa91d43bSTony Lindgren 
21858f977e42SIan Abbott 	usb_set_serial_data(serial, (void *)id->driver_info);
21868f977e42SIan Abbott 
2187fa91d43bSTony Lindgren 	return 0;
21888f977e42SIan Abbott }
21898f977e42SIan Abbott 
ftdi_port_probe(struct usb_serial_port * port)21906b2fe3dfSJohan Hovold static int ftdi_port_probe(struct usb_serial_port *port)
21911da177e4SLinus Torvalds {
21926b2fe3dfSJohan Hovold 	const struct ftdi_quirk *quirk = usb_get_serial_data(port->serial);
21931da177e4SLinus Torvalds 	struct ftdi_private *priv;
2194ba93cc7dSKaroly Pados 	int result;
21951da177e4SLinus Torvalds 
219680b6ca48SEric Sesterhenn 	priv = kzalloc(sizeof(struct ftdi_private), GFP_KERNEL);
219710c642d0SJohan Hovold 	if (!priv)
21981da177e4SLinus Torvalds 		return -ENOMEM;
21991da177e4SLinus Torvalds 
2200bd09a9f5SAlessio Igor Bogani 	mutex_init(&priv->cfg_lock);
22010076b4beSJohan Hovold 
22020ffbbe25SOliver Neukum 	if (quirk && quirk->port_probe)
22030ffbbe25SOliver Neukum 		quirk->port_probe(priv);
22040ffbbe25SOliver Neukum 
220512bdbe03SJim Radford 	usb_set_serial_port_data(port, priv);
22061da177e4SLinus Torvalds 
2207f353c0d4SJohan Hovold 	result = ftdi_determine_type(port);
2208f353c0d4SJohan Hovold 	if (result)
2209f353c0d4SJohan Hovold 		goto err_free;
2210f353c0d4SJohan Hovold 
2211895f28baSMark Adamson 	ftdi_set_max_packet_size(port);
22128c4f99cdSJohan Hovold 	if (read_latency_timer(port) < 0)
22138c4f99cdSJohan Hovold 		priv->latency = 16;
2214c19db4c9SJohan Hovold 	write_latency_timer(port);
2215ba93cc7dSKaroly Pados 
2216ba93cc7dSKaroly Pados 	result = ftdi_gpio_init(port);
2217ba93cc7dSKaroly Pados 	if (result < 0) {
2218ba93cc7dSKaroly Pados 		dev_err(&port->serial->interface->dev,
2219ba93cc7dSKaroly Pados 			"GPIO initialisation failed: %d\n",
2220ba93cc7dSKaroly Pados 			result);
2221ba93cc7dSKaroly Pados 	}
2222ba93cc7dSKaroly Pados 
222312bdbe03SJim Radford 	return 0;
2224f353c0d4SJohan Hovold 
2225f353c0d4SJohan Hovold err_free:
2226f353c0d4SJohan Hovold 	kfree(priv);
2227f353c0d4SJohan Hovold 
2228f353c0d4SJohan Hovold 	return result;
22291da177e4SLinus Torvalds }
22301da177e4SLinus Torvalds 
22318f977e42SIan Abbott /* Setup for the USB-UIRT device, which requires hardwired
22328f977e42SIan Abbott  * baudrate (38400 gets mapped to 312500) */
22331da177e4SLinus Torvalds /* Called from usbserial:serial_probe */
ftdi_USB_UIRT_setup(struct ftdi_private * priv)22340ffbbe25SOliver Neukum static void ftdi_USB_UIRT_setup(struct ftdi_private *priv)
22351da177e4SLinus Torvalds {
22361da177e4SLinus Torvalds 	priv->flags |= ASYNC_SPD_CUST;
22371da177e4SLinus Torvalds 	priv->custom_divisor = 77;
2238669a6db1SAlan Cox 	priv->force_baud = 38400;
2239e49bbce1SJohan Hovold }
22401da177e4SLinus Torvalds 
22418f977e42SIan Abbott /* Setup for the HE-TIRA1 device, which requires hardwired
22428f977e42SIan Abbott  * baudrate (38400 gets mapped to 100000) and RTS-CTS enabled.  */
2243464cbb24SAlan Cox 
ftdi_HE_TIRA1_setup(struct ftdi_private * priv)22440ffbbe25SOliver Neukum static void ftdi_HE_TIRA1_setup(struct ftdi_private *priv)
22458f977e42SIan Abbott {
22461da177e4SLinus Torvalds 	priv->flags |= ASYNC_SPD_CUST;
22471da177e4SLinus Torvalds 	priv->custom_divisor = 240;
2248669a6db1SAlan Cox 	priv->force_baud = 38400;
22491da177e4SLinus Torvalds 	priv->force_rtscts = 1;
2250e49bbce1SJohan Hovold }
22511da177e4SLinus Torvalds 
2252fa91d43bSTony Lindgren /*
2253b760dac2SMartin Geleynse  * Module parameter to control latency timer for NDI FTDI-based USB devices.
2254970e2486SLucas De Marchi  * If this value is not set in /etc/modprobe.d/ its value will be set
2255970e2486SLucas De Marchi  * to 1ms.
2256b760dac2SMartin Geleynse  */
2257b760dac2SMartin Geleynse static int ndi_latency_timer = 1;
2258b760dac2SMartin Geleynse 
2259b760dac2SMartin Geleynse /* Setup for the NDI FTDI-based USB devices, which requires hardwired
2260b760dac2SMartin Geleynse  * baudrate (19200 gets mapped to 1200000).
2261b760dac2SMartin Geleynse  *
2262b760dac2SMartin Geleynse  * Called from usbserial:serial_probe.
2263b760dac2SMartin Geleynse  */
ftdi_NDI_device_setup(struct usb_serial * serial)2264b760dac2SMartin Geleynse static int ftdi_NDI_device_setup(struct usb_serial *serial)
2265b760dac2SMartin Geleynse {
2266b760dac2SMartin Geleynse 	struct usb_device *udev = serial->dev;
2267b760dac2SMartin Geleynse 	int latency = ndi_latency_timer;
2268b760dac2SMartin Geleynse 
2269b760dac2SMartin Geleynse 	if (latency == 0)
2270b760dac2SMartin Geleynse 		latency = 1;
2271b760dac2SMartin Geleynse 	if (latency > 99)
2272b760dac2SMartin Geleynse 		latency = 99;
2273b760dac2SMartin Geleynse 
2274bfc51614SGreg Kroah-Hartman 	dev_dbg(&udev->dev, "%s setting NDI device latency to %d\n", __func__, latency);
2275bfc51614SGreg Kroah-Hartman 	dev_info(&udev->dev, "NDI device with a latency value of %d\n", latency);
2276b760dac2SMartin Geleynse 
2277c1284d77SJohan Hovold 	/* FIXME: errors are not returned */
2278c1284d77SJohan Hovold 	usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
2279b760dac2SMartin Geleynse 				FTDI_SIO_SET_LATENCY_TIMER_REQUEST,
2280b760dac2SMartin Geleynse 				FTDI_SIO_SET_LATENCY_TIMER_REQUEST_TYPE,
228166e47e60SJohan Hovold 				latency, 0, NULL, 0, WDR_TIMEOUT);
2282b760dac2SMartin Geleynse 	return 0;
2283b760dac2SMartin Geleynse }
2284b760dac2SMartin Geleynse 
2285b760dac2SMartin Geleynse /*
228620734345SHarald Welte  * First port on JTAG adaptors such as Olimex arm-usb-ocd or the FIC/OpenMoko
228720734345SHarald Welte  * Neo1973 Debug Board is reserved for JTAG interface and can be accessed from
228820734345SHarald Welte  * userspace using openocd.
2289fa91d43bSTony Lindgren  */
ftdi_jtag_probe(struct usb_serial * serial)229020734345SHarald Welte static int ftdi_jtag_probe(struct usb_serial *serial)
2291fa91d43bSTony Lindgren {
229275240ac4SJohan Hovold 	struct usb_interface *intf = serial->interface;
229375240ac4SJohan Hovold 	int ifnum = intf->cur_altsetting->desc.bInterfaceNumber;
2294fa91d43bSTony Lindgren 
229575240ac4SJohan Hovold 	if (ifnum == 0) {
229675240ac4SJohan Hovold 		dev_info(&intf->dev, "Ignoring interface reserved for JTAG\n");
2297fa91d43bSTony Lindgren 		return -ENODEV;
2298fa91d43bSTony Lindgren 	}
2299fa91d43bSTony Lindgren 
2300fa91d43bSTony Lindgren 	return 0;
2301fa91d43bSTony Lindgren }
23021da177e4SLinus Torvalds 
ftdi_8u2232c_probe(struct usb_serial * serial)2303c96fbdd0SJean-Christophe PLAGNIOL-VILLARD static int ftdi_8u2232c_probe(struct usb_serial *serial)
2304c96fbdd0SJean-Christophe PLAGNIOL-VILLARD {
2305c96fbdd0SJean-Christophe PLAGNIOL-VILLARD 	struct usb_device *udev = serial->dev;
2306c96fbdd0SJean-Christophe PLAGNIOL-VILLARD 
2307b229a0f8SDoug Goldstein 	if (udev->manufacturer && !strcmp(udev->manufacturer, "CALAO Systems"))
2308b229a0f8SDoug Goldstein 		return ftdi_jtag_probe(serial);
2309b229a0f8SDoug Goldstein 
2310b229a0f8SDoug Goldstein 	if (udev->product &&
2311470b5d6fSVasyl Vavrychuk 		(!strcmp(udev->product, "Arrow USB Blaster") ||
2312470b5d6fSVasyl Vavrychuk 		 !strcmp(udev->product, "BeagleBone/XDS100V2") ||
2313b229a0f8SDoug Goldstein 		 !strcmp(udev->product, "SNAP Connect E10")))
2314c96fbdd0SJean-Christophe PLAGNIOL-VILLARD 		return ftdi_jtag_probe(serial);
2315c96fbdd0SJean-Christophe PLAGNIOL-VILLARD 
2316c96fbdd0SJean-Christophe PLAGNIOL-VILLARD 	return 0;
2317c96fbdd0SJean-Christophe PLAGNIOL-VILLARD }
2318c96fbdd0SJean-Christophe PLAGNIOL-VILLARD 
2319546d7eecSKevin Vance /*
232071d9a2b9SAdrian Thomasset  * First two ports on JTAG adaptors using an FT4232 such as STMicroelectronics's
232171d9a2b9SAdrian Thomasset  * ST Micro Connect Lite are reserved for JTAG or other non-UART interfaces and
232271d9a2b9SAdrian Thomasset  * can be accessed from userspace.
232371d9a2b9SAdrian Thomasset  * The next two ports are enabled as UARTs by default, where port 2 is
232471d9a2b9SAdrian Thomasset  * a conventional RS-232 UART.
23256ec2f46cSJean-Christophe PLAGNIOL-VILLARD  */
ftdi_stmclite_probe(struct usb_serial * serial)23266ec2f46cSJean-Christophe PLAGNIOL-VILLARD static int ftdi_stmclite_probe(struct usb_serial *serial)
23276ec2f46cSJean-Christophe PLAGNIOL-VILLARD {
232875240ac4SJohan Hovold 	struct usb_interface *intf = serial->interface;
232975240ac4SJohan Hovold 	int ifnum = intf->cur_altsetting->desc.bInterfaceNumber;
23306ec2f46cSJean-Christophe PLAGNIOL-VILLARD 
233175240ac4SJohan Hovold 	if (ifnum < 2) {
233275240ac4SJohan Hovold 		dev_info(&intf->dev, "Ignoring interface reserved for JTAG\n");
23336ec2f46cSJean-Christophe PLAGNIOL-VILLARD 		return -ENODEV;
23346ec2f46cSJean-Christophe PLAGNIOL-VILLARD 	}
23356ec2f46cSJean-Christophe PLAGNIOL-VILLARD 
233671d9a2b9SAdrian Thomasset 	return 0;
233771d9a2b9SAdrian Thomasset }
233871d9a2b9SAdrian Thomasset 
ftdi_port_remove(struct usb_serial_port * port)23396b2fe3dfSJohan Hovold static void ftdi_port_remove(struct usb_serial_port *port)
234012bdbe03SJim Radford {
23411da177e4SLinus Torvalds 	struct ftdi_private *priv = usb_get_serial_port_data(port);
23421da177e4SLinus Torvalds 
2343ba93cc7dSKaroly Pados 	ftdi_gpio_remove(port);
2344ba93cc7dSKaroly Pados 
23454cba98ffSJohan Hovold 	kfree(priv);
234612bdbe03SJim Radford }
23471da177e4SLinus Torvalds 
ftdi_open(struct tty_struct * tty,struct usb_serial_port * port)2348a509a7e4SAlan Cox static int ftdi_open(struct tty_struct *tty, struct usb_serial_port *port)
2349e49bbce1SJohan Hovold {
23501da177e4SLinus Torvalds 	struct usb_device *dev = port->serial->dev;
23511da177e4SLinus Torvalds 	struct ftdi_private *priv = usb_get_serial_port_data(port);
23521da177e4SLinus Torvalds 
23531da177e4SLinus Torvalds 	/* No error checking for this (will get errors later anyway) */
23541da177e4SLinus Torvalds 	/* See ftdi_sio.h for description of what is reset */
23551da177e4SLinus Torvalds 	usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
23561da177e4SLinus Torvalds 			FTDI_SIO_RESET_REQUEST, FTDI_SIO_RESET_REQUEST_TYPE,
23571da177e4SLinus Torvalds 			FTDI_SIO_RESET_SIO,
2358027bf37dSJohan Hovold 			priv->channel, NULL, 0, WDR_TIMEOUT);
23591da177e4SLinus Torvalds 
23601da177e4SLinus Torvalds 	/* Termios defaults are set by usb_serial_init. We don't change
2361c4f01240SNick Andrew 	   port->tty->termios - this would lose speed settings, etc.
23621da177e4SLinus Torvalds 	   This is same behaviour as serial.c/rs_open() - Kuba */
23631da177e4SLinus Torvalds 
23641da177e4SLinus Torvalds 	/* ftdi_set_termios  will send usb control messages */
2365be0278ccSJohan Hovold 	if (tty)
2366be0278ccSJohan Hovold 		ftdi_set_termios(tty, port, NULL);
23671da177e4SLinus Torvalds 
23684cba98ffSJohan Hovold 	return usb_serial_generic_open(tty, port);
2369e49bbce1SJohan Hovold }
23701da177e4SLinus Torvalds 
ftdi_dtr_rts(struct usb_serial_port * port,int on)2371335f8514SAlan Cox static void ftdi_dtr_rts(struct usb_serial_port *port, int on)
2372335f8514SAlan Cox {
2373335f8514SAlan Cox 	struct ftdi_private *priv = usb_get_serial_port_data(port);
2374335f8514SAlan Cox 
2375335f8514SAlan Cox 	/* Disable flow control */
2376b2ca6990SJohan Hovold 	if (!on) {
2377b2ca6990SJohan Hovold 		if (usb_control_msg(port->serial->dev,
2378335f8514SAlan Cox 			    usb_sndctrlpipe(port->serial->dev, 0),
2379335f8514SAlan Cox 			    FTDI_SIO_SET_FLOW_CTRL_REQUEST,
2380335f8514SAlan Cox 			    FTDI_SIO_SET_FLOW_CTRL_REQUEST_TYPE,
2381027bf37dSJohan Hovold 			    0, priv->channel, NULL, 0,
2382335f8514SAlan Cox 			    WDR_TIMEOUT) < 0) {
2383335f8514SAlan Cox 			dev_err(&port->dev, "error from flowcontrol urb\n");
2384335f8514SAlan Cox 		}
2385b2ca6990SJohan Hovold 	}
2386335f8514SAlan Cox 	/* drop RTS and DTR */
2387335f8514SAlan Cox 	if (on)
2388335f8514SAlan Cox 		set_mctrl(port, TIOCM_DTR | TIOCM_RTS);
2389335f8514SAlan Cox 	else
2390335f8514SAlan Cox 		clear_mctrl(port, TIOCM_DTR | TIOCM_RTS);
2391335f8514SAlan Cox }
23921da177e4SLinus Torvalds 
23931da177e4SLinus Torvalds /* The SIO requires the first byte to have:
23941da177e4SLinus Torvalds  *  B0 1
23951da177e4SLinus Torvalds  *  B1 0
23961da177e4SLinus Torvalds  *  B2..7 length of message excluding byte 0
23971da177e4SLinus Torvalds  *
23981da177e4SLinus Torvalds  * The new devices do not require this byte
23991da177e4SLinus Torvalds  */
ftdi_prepare_write_buffer(struct usb_serial_port * port,void * dest,size_t size)2400d3901a06SJohan Hovold static int ftdi_prepare_write_buffer(struct usb_serial_port *port,
2401c23e5fc1SJohan Hovold 						void *dest, size_t size)
2402e49bbce1SJohan Hovold {
2403d3901a06SJohan Hovold 	struct ftdi_private *priv;
2404c23e5fc1SJohan Hovold 	int count;
2405c23e5fc1SJohan Hovold 	unsigned long flags;
24061da177e4SLinus Torvalds 
2407d3901a06SJohan Hovold 	priv = usb_get_serial_port_data(port);
24081da177e4SLinus Torvalds 
2409e8770484SJohan Hovold 	if (priv->chip_type == SIO) {
2410c23e5fc1SJohan Hovold 		unsigned char *buffer = dest;
2411c23e5fc1SJohan Hovold 		int i, len, c;
24121da177e4SLinus Torvalds 
2413c23e5fc1SJohan Hovold 		count = 0;
2414c23e5fc1SJohan Hovold 		spin_lock_irqsave(&port->lock, flags);
2415c23e5fc1SJohan Hovold 		for (i = 0; i < size - 1; i += priv->max_packet_size) {
2416c23e5fc1SJohan Hovold 			len = min_t(int, size - i, priv->max_packet_size) - 1;
2417c23e5fc1SJohan Hovold 			c = kfifo_out(&port->write_fifo, &buffer[i + 1], len);
2418c23e5fc1SJohan Hovold 			if (!c)
2419c23e5fc1SJohan Hovold 				break;
2420cb1676a6SJohan Hovold 			port->icount.tx += c;
2421c1aa075aSJohan Hovold 			buffer[i] = (c << 2) + 1;
2422c23e5fc1SJohan Hovold 			count += c + 1;
24231da177e4SLinus Torvalds 		}
2424c23e5fc1SJohan Hovold 		spin_unlock_irqrestore(&port->lock, flags);
24251da177e4SLinus Torvalds 	} else {
2426c23e5fc1SJohan Hovold 		count = kfifo_out_locked(&port->write_fifo, dest, size,
2427c23e5fc1SJohan Hovold 								&port->lock);
2428cb1676a6SJohan Hovold 		port->icount.tx += count;
24291da177e4SLinus Torvalds 	}
24301da177e4SLinus Torvalds 
24311da177e4SLinus Torvalds 	return count;
243295da310eSAlan Cox }
24331da177e4SLinus Torvalds 
2434166ceb69SJohan Hovold #define FTDI_RS_ERR_MASK (FTDI_RS_BI | FTDI_RS_PE | FTDI_RS_FE | FTDI_RS_OE)
2435166ceb69SJohan Hovold 
ftdi_process_packet(struct usb_serial_port * port,struct ftdi_private * priv,unsigned char * buf,int len)243692a19f9cSJiri Slaby static int ftdi_process_packet(struct usb_serial_port *port,
2437ab4cc4efSJohan Hovold 		struct ftdi_private *priv, unsigned char *buf, int len)
243895da310eSAlan Cox {
2439ab4cc4efSJohan Hovold 	unsigned char status;
2440733fff67SJohan Hovold 	bool brkint = false;
24411da177e4SLinus Torvalds 	int i;
2442cc01f17dSJohan Hovold 	char flag;
24431da177e4SLinus Torvalds 
2444cc01f17dSJohan Hovold 	if (len < 2) {
2445bfc51614SGreg Kroah-Hartman 		dev_dbg(&port->dev, "malformed packet\n");
2446cc01f17dSJohan Hovold 		return 0;
24471da177e4SLinus Torvalds 	}
24481da177e4SLinus Torvalds 
2449464cbb24SAlan Cox 	/* Compare new line status to the old one, signal if different/
2450464cbb24SAlan Cox 	   N.B. packet may be processed more than once, but differences
2451464cbb24SAlan Cox 	   are only processed once.  */
2452ab4cc4efSJohan Hovold 	status = buf[0] & FTDI_STATUS_B0_MASK;
2453cc01f17dSJohan Hovold 	if (status != priv->prev_status) {
2454fca5430dSSimon Arlott 		char diff_status = status ^ priv->prev_status;
2455fca5430dSSimon Arlott 
2456fca5430dSSimon Arlott 		if (diff_status & FTDI_RS0_CTS)
2457cb1676a6SJohan Hovold 			port->icount.cts++;
2458fca5430dSSimon Arlott 		if (diff_status & FTDI_RS0_DSR)
2459cb1676a6SJohan Hovold 			port->icount.dsr++;
2460fca5430dSSimon Arlott 		if (diff_status & FTDI_RS0_RI)
2461cb1676a6SJohan Hovold 			port->icount.rng++;
2462d14654dfSPaul Chavent 		if (diff_status & FTDI_RS0_RLSD) {
2463d14654dfSPaul Chavent 			struct tty_struct *tty;
2464d14654dfSPaul Chavent 
2465cb1676a6SJohan Hovold 			port->icount.dcd++;
2466d14654dfSPaul Chavent 			tty = tty_port_tty_get(&port->port);
2467d14654dfSPaul Chavent 			if (tty)
2468d14654dfSPaul Chavent 				usb_serial_handle_dcd_change(port, tty,
2469d14654dfSPaul Chavent 						status & FTDI_RS0_RLSD);
2470d14654dfSPaul Chavent 			tty_kref_put(tty);
2471d14654dfSPaul Chavent 		}
2472fca5430dSSimon Arlott 
2473f307e5cdSJohan Hovold 		wake_up_interruptible(&port->port.delta_msr_wait);
2474cc01f17dSJohan Hovold 		priv->prev_status = status;
24751da177e4SLinus Torvalds 	}
24761da177e4SLinus Torvalds 
2477a6bb1e17SJohan Hovold 	/* save if the transmitter is empty or not */
2478ab4cc4efSJohan Hovold 	if (buf[1] & FTDI_RS_TEMT)
2479a6bb1e17SJohan Hovold 		priv->transmit_empty = 1;
2480a6bb1e17SJohan Hovold 	else
2481a6bb1e17SJohan Hovold 		priv->transmit_empty = 0;
2482a6bb1e17SJohan Hovold 
2483ce054039SJohan Hovold 	if (len == 2)
2484a6bb1e17SJohan Hovold 		return 0;	/* status only */
2485a6bb1e17SJohan Hovold 
2486a6bb1e17SJohan Hovold 	/*
2487a6bb1e17SJohan Hovold 	 * Break and error status must only be processed for packets with
2488a6bb1e17SJohan Hovold 	 * data payload to avoid over-reporting.
2489a6bb1e17SJohan Hovold 	 */
2490cc01f17dSJohan Hovold 	flag = TTY_NORMAL;
2491ab4cc4efSJohan Hovold 	if (buf[1] & FTDI_RS_ERR_MASK) {
2492733fff67SJohan Hovold 		/*
2493733fff67SJohan Hovold 		 * Break takes precedence over parity, which takes precedence
2494733fff67SJohan Hovold 		 * over framing errors. Note that break is only associated
2495733fff67SJohan Hovold 		 * with the last character in the buffer and only when it's a
2496733fff67SJohan Hovold 		 * NUL.
2497733fff67SJohan Hovold 		 */
2498733fff67SJohan Hovold 		if (buf[1] & FTDI_RS_BI && buf[len - 1] == '\0') {
2499cb1676a6SJohan Hovold 			port->icount.brk++;
2500733fff67SJohan Hovold 			brkint = true;
2501733fff67SJohan Hovold 		}
2502733fff67SJohan Hovold 		if (buf[1] & FTDI_RS_PE) {
2503cc01f17dSJohan Hovold 			flag = TTY_PARITY;
2504cb1676a6SJohan Hovold 			port->icount.parity++;
2505ab4cc4efSJohan Hovold 		} else if (buf[1] & FTDI_RS_FE) {
2506cc01f17dSJohan Hovold 			flag = TTY_FRAME;
2507cb1676a6SJohan Hovold 			port->icount.frame++;
2508166ceb69SJohan Hovold 		}
2509166ceb69SJohan Hovold 		/* Overrun is special, not associated with a char */
2510ab4cc4efSJohan Hovold 		if (buf[1] & FTDI_RS_OE) {
2511cb1676a6SJohan Hovold 			port->icount.overrun++;
251292a19f9cSJiri Slaby 			tty_insert_flip_char(&port->port, 0, TTY_OVERRUN);
25131da177e4SLinus Torvalds 		}
2514005b3cdeSUwe Bonnes 	}
25151da177e4SLinus Torvalds 
2516ce054039SJohan Hovold 	port->icount.rx += len - 2;
2517cc01f17dSJohan Hovold 
251837ae2315SJohan Hovold 	if (brkint || port->sysrq) {
2519ce054039SJohan Hovold 		for (i = 2; i < len; i++) {
2520733fff67SJohan Hovold 			if (brkint && i == len - 1) {
2521733fff67SJohan Hovold 				if (usb_serial_handle_break(port))
2522733fff67SJohan Hovold 					return len - 3;
2523733fff67SJohan Hovold 				flag = TTY_BREAK;
2524733fff67SJohan Hovold 			}
2525ce054039SJohan Hovold 			if (usb_serial_handle_sysrq_char(port, buf[i]))
2526ce054039SJohan Hovold 				continue;
2527ce054039SJohan Hovold 			tty_insert_flip_char(&port->port, buf[i], flag);
2528cc01f17dSJohan Hovold 		}
252949b2597aSJohan Hovold 	} else {
2530ce054039SJohan Hovold 		tty_insert_flip_string_fixed_flag(&port->port, buf + 2, flag,
2531ce054039SJohan Hovold 				len - 2);
2532cc01f17dSJohan Hovold 	}
253349b2597aSJohan Hovold 
2534ce054039SJohan Hovold 	return len - 2;
2535cc01f17dSJohan Hovold }
2536cc01f17dSJohan Hovold 
ftdi_process_read_urb(struct urb * urb)25371b551015SJohan Hovold static void ftdi_process_read_urb(struct urb *urb)
2538cc01f17dSJohan Hovold {
25391b551015SJohan Hovold 	struct usb_serial_port *port = urb->context;
2540cc01f17dSJohan Hovold 	struct ftdi_private *priv = usb_get_serial_port_data(port);
2541eb0c68eaSJohan Hovold 	char *data = urb->transfer_buffer;
2542cc01f17dSJohan Hovold 	int i;
2543cc01f17dSJohan Hovold 	int len;
2544cc01f17dSJohan Hovold 	int count = 0;
2545cc01f17dSJohan Hovold 
2546cc01f17dSJohan Hovold 	for (i = 0; i < urb->actual_length; i += priv->max_packet_size) {
2547cc01f17dSJohan Hovold 		len = min_t(int, urb->actual_length - i, priv->max_packet_size);
254892a19f9cSJiri Slaby 		count += ftdi_process_packet(port, priv, &data[i], len);
2549cc01f17dSJohan Hovold 	}
2550cc01f17dSJohan Hovold 
2551cc01f17dSJohan Hovold 	if (count)
25522e124b4aSJiri Slaby 		tty_flip_buffer_push(&port->port);
2553cc01f17dSJohan Hovold }
25541da177e4SLinus Torvalds 
ftdi_break_ctl(struct tty_struct * tty,int break_state)25556ff58ae1SJohan Hovold static int ftdi_break_ctl(struct tty_struct *tty, int break_state)
25561da177e4SLinus Torvalds {
255795da310eSAlan Cox 	struct usb_serial_port *port = tty->driver_data;
25581da177e4SLinus Torvalds 	struct ftdi_private *priv = usb_get_serial_port_data(port);
255916410115SJohan Hovold 	u16 value;
25606ff58ae1SJohan Hovold 	int ret;
25611da177e4SLinus Torvalds 
25621da177e4SLinus Torvalds 	/* break_state = -1 to turn on break, and 0 to turn off break */
25631da177e4SLinus Torvalds 	/* see drivers/char/tty_io.c to see it used */
256416410115SJohan Hovold 	/* last_set_data_value NEVER has the break bit set in it */
25651da177e4SLinus Torvalds 
2566464cbb24SAlan Cox 	if (break_state)
256716410115SJohan Hovold 		value = priv->last_set_data_value | FTDI_SIO_SET_BREAK;
2568464cbb24SAlan Cox 	else
256916410115SJohan Hovold 		value = priv->last_set_data_value;
25701da177e4SLinus Torvalds 
25716ff58ae1SJohan Hovold 	ret = usb_control_msg(port->serial->dev,
2572464cbb24SAlan Cox 			usb_sndctrlpipe(port->serial->dev, 0),
25731da177e4SLinus Torvalds 			FTDI_SIO_SET_DATA_REQUEST,
25741da177e4SLinus Torvalds 			FTDI_SIO_SET_DATA_REQUEST_TYPE,
2575027bf37dSJohan Hovold 			value, priv->channel,
25766ff58ae1SJohan Hovold 			NULL, 0, WDR_TIMEOUT);
25776ff58ae1SJohan Hovold 	if (ret < 0) {
2578bfc51614SGreg Kroah-Hartman 		dev_err(&port->dev, "%s FAILED to enable/disable break state (state was %d)\n",
2579bfc51614SGreg Kroah-Hartman 			__func__, break_state);
25806ff58ae1SJohan Hovold 		return ret;
25811da177e4SLinus Torvalds 	}
25821da177e4SLinus Torvalds 
2583bfc51614SGreg Kroah-Hartman 	dev_dbg(&port->dev, "%s break state is %d - urb is %d\n", __func__,
258416410115SJohan Hovold 		break_state, value);
25851da177e4SLinus Torvalds 
25866ff58ae1SJohan Hovold 	return 0;
25871da177e4SLinus Torvalds }
25881da177e4SLinus Torvalds 
ftdi_tx_empty(struct usb_serial_port * port)2589a37025b5SJohan Hovold static bool ftdi_tx_empty(struct usb_serial_port *port)
25906f602912SJarkko Huijts {
25915fb0432eSJohan Hovold 	unsigned char buf[2];
25926f602912SJarkko Huijts 	int ret;
25936f602912SJarkko Huijts 
2594c4133648SJohan Hovold 	ret = ftdi_get_modem_status(port, buf);
25955fb0432eSJohan Hovold 	if (ret == 2) {
25966f602912SJarkko Huijts 		if (!(buf[1] & FTDI_RS_TEMT))
2597a37025b5SJohan Hovold 			return false;
25985fb0432eSJohan Hovold 	}
25996f602912SJarkko Huijts 
2600a37025b5SJohan Hovold 	return true;
26016f602912SJarkko Huijts }
26026f602912SJarkko Huijts 
26031da177e4SLinus Torvalds /* old_termios contains the original termios settings and tty->termios contains
26041da177e4SLinus Torvalds  * the new setting to be used
26051da177e4SLinus Torvalds  * WARNING: set_termios calls this with old_termios in kernel space
26061da177e4SLinus Torvalds  */
ftdi_set_termios(struct tty_struct * tty,struct usb_serial_port * port,const struct ktermios * old_termios)260795da310eSAlan Cox static void ftdi_set_termios(struct tty_struct *tty,
2608f6d47fe5SIlpo Järvinen 		             struct usb_serial_port *port,
2609f6d47fe5SIlpo Järvinen 		             const struct ktermios *old_termios)
2610e49bbce1SJohan Hovold {
26111da177e4SLinus Torvalds 	struct usb_device *dev = port->serial->dev;
2612bfc51614SGreg Kroah-Hartman 	struct device *ddev = &port->dev;
26131da177e4SLinus Torvalds 	struct ftdi_private *priv = usb_get_serial_port_data(port);
2614adc8d746SAlan Cox 	struct ktermios *termios = &tty->termios;
2615669a6db1SAlan Cox 	unsigned int cflag = termios->c_cflag;
2616df1cd63dSJohan Hovold 	u16 value, index;
2617df1cd63dSJohan Hovold 	int ret;
26181da177e4SLinus Torvalds 
2619464cbb24SAlan Cox 	/* Force baud rate if this device requires it, unless it is set to
2620464cbb24SAlan Cox 	   B0. */
2621669a6db1SAlan Cox 	if (priv->force_baud && ((termios->c_cflag & CBAUD) != B0)) {
2622bfc51614SGreg Kroah-Hartman 		dev_dbg(ddev, "%s: forcing baud rate for this device\n", __func__);
262395da310eSAlan Cox 		tty_encode_baud_rate(tty, priv->force_baud,
2624bd5e47ccSAndrew Morton 					priv->force_baud);
26251da177e4SLinus Torvalds 	}
26261da177e4SLinus Torvalds 
26271da177e4SLinus Torvalds 	/* Force RTS-CTS if this device requires it. */
26281da177e4SLinus Torvalds 	if (priv->force_rtscts) {
2629bfc51614SGreg Kroah-Hartman 		dev_dbg(ddev, "%s: forcing rtscts for this device\n", __func__);
2630669a6db1SAlan Cox 		termios->c_cflag |= CRTSCTS;
26311da177e4SLinus Torvalds 	}
26321da177e4SLinus Torvalds 
26338704211fSColin Leitner 	/*
2634c1f15196SColin Leitner 	 * All FTDI UART chips are limited to CS7/8. We shouldn't pretend to
26358704211fSColin Leitner 	 * support CS5/6 and revert the CSIZE setting instead.
2636c1f15196SColin Leitner 	 *
2637c1f15196SColin Leitner 	 * CS5 however is used to control some smartcard readers which abuse
2638c1f15196SColin Leitner 	 * this limitation to switch modes. Original FTDI chips fall back to
2639c1f15196SColin Leitner 	 * eight data bits.
2640c1f15196SColin Leitner 	 *
2641c1f15196SColin Leitner 	 * TODO: Implement a quirk to only allow this with mentioned
2642c1f15196SColin Leitner 	 *       readers. One I know of (Argolis Smartreader V1)
2643c1f15196SColin Leitner 	 *       returns "USB smartcard server" as iInterface string.
2644c1f15196SColin Leitner 	 *       The vendor didn't bother with a custom VID/PID of
2645c1f15196SColin Leitner 	 *       course.
26468704211fSColin Leitner 	 */
2647c1f15196SColin Leitner 	if (C_CSIZE(tty) == CS6) {
26488704211fSColin Leitner 		dev_warn(ddev, "requested CSIZE setting not supported\n");
26498704211fSColin Leitner 
26508704211fSColin Leitner 		termios->c_cflag &= ~CSIZE;
26518704211fSColin Leitner 		if (old_termios)
26528704211fSColin Leitner 			termios->c_cflag |= old_termios->c_cflag & CSIZE;
26538704211fSColin Leitner 		else
26548704211fSColin Leitner 			termios->c_cflag |= CS8;
26558704211fSColin Leitner 	}
26568704211fSColin Leitner 
2657669a6db1SAlan Cox 	cflag = termios->c_cflag;
26581da177e4SLinus Torvalds 
2659a816e311SYing Xue 	if (!old_termios)
2660c515598eSAndrew Worsley 		goto no_skip;
2661c515598eSAndrew Worsley 
2662b1ffb4c8SAndrew Worsley 	if (old_termios->c_cflag == termios->c_cflag
2663b1ffb4c8SAndrew Worsley 	    && old_termios->c_ispeed == termios->c_ispeed
2664b1ffb4c8SAndrew Worsley 	    && old_termios->c_ospeed == termios->c_ospeed)
2665b1ffb4c8SAndrew Worsley 		goto no_c_cflag_changes;
2666b1ffb4c8SAndrew Worsley 
26671da177e4SLinus Torvalds 	/* NOTE These routines can get interrupted by
2668464cbb24SAlan Cox 	   ftdi_sio_read_bulk_callback  - need to examine what this means -
2669464cbb24SAlan Cox 	   don't see any problems yet */
26701da177e4SLinus Torvalds 
2671b1ffb4c8SAndrew Worsley 	if ((old_termios->c_cflag & (CSIZE|PARODD|PARENB|CMSPAR|CSTOPB)) ==
2672b1ffb4c8SAndrew Worsley 	    (termios->c_cflag & (CSIZE|PARODD|PARENB|CMSPAR|CSTOPB)))
2673b1ffb4c8SAndrew Worsley 		goto no_data_parity_stop_changes;
2674b1ffb4c8SAndrew Worsley 
2675c515598eSAndrew Worsley no_skip:
26761da177e4SLinus Torvalds 	/* Set number of data bits, parity, stop bits */
26771da177e4SLinus Torvalds 
267816410115SJohan Hovold 	value = 0;
267916410115SJohan Hovold 	value |= (cflag & CSTOPB ? FTDI_SIO_SET_DATA_STOP_BITS_2 :
26801da177e4SLinus Torvalds 			FTDI_SIO_SET_DATA_STOP_BITS_1);
268138fcb830SRoland Koebler 	if (cflag & PARENB) {
268238fcb830SRoland Koebler 		if (cflag & CMSPAR)
268316410115SJohan Hovold 			value |= cflag & PARODD ?
268438fcb830SRoland Koebler 					FTDI_SIO_SET_DATA_PARITY_MARK :
268538fcb830SRoland Koebler 					FTDI_SIO_SET_DATA_PARITY_SPACE;
268638fcb830SRoland Koebler 		else
268716410115SJohan Hovold 			value |= cflag & PARODD ?
268838fcb830SRoland Koebler 					FTDI_SIO_SET_DATA_PARITY_ODD :
268938fcb830SRoland Koebler 					FTDI_SIO_SET_DATA_PARITY_EVEN;
269038fcb830SRoland Koebler 	} else {
269116410115SJohan Hovold 		value |= FTDI_SIO_SET_DATA_PARITY_NONE;
269238fcb830SRoland Koebler 	}
26931da177e4SLinus Torvalds 	switch (cflag & CSIZE) {
2694c1f15196SColin Leitner 	case CS5:
2695c1f15196SColin Leitner 		dev_dbg(ddev, "Setting CS5 quirk\n");
2696c1f15196SColin Leitner 		break;
2697bfc51614SGreg Kroah-Hartman 	case CS7:
269816410115SJohan Hovold 		value |= 7;
2699bfc51614SGreg Kroah-Hartman 		dev_dbg(ddev, "Setting CS7\n");
2700bfc51614SGreg Kroah-Hartman 		break;
27018704211fSColin Leitner 	default:
2702bfc51614SGreg Kroah-Hartman 	case CS8:
270316410115SJohan Hovold 		value |= 8;
2704bfc51614SGreg Kroah-Hartman 		dev_dbg(ddev, "Setting CS8\n");
2705bfc51614SGreg Kroah-Hartman 		break;
27061da177e4SLinus Torvalds 	}
27071da177e4SLinus Torvalds 
2708464cbb24SAlan Cox 	/* This is needed by the break command since it uses the same command
2709464cbb24SAlan Cox 	   - but is or'ed with this value  */
271016410115SJohan Hovold 	priv->last_set_data_value = value;
27111da177e4SLinus Torvalds 
27121da177e4SLinus Torvalds 	if (usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
27131da177e4SLinus Torvalds 			    FTDI_SIO_SET_DATA_REQUEST,
27141da177e4SLinus Torvalds 			    FTDI_SIO_SET_DATA_REQUEST_TYPE,
2715027bf37dSJohan Hovold 			    value, priv->channel,
271666e47e60SJohan Hovold 			    NULL, 0, WDR_SHORT_TIMEOUT) < 0) {
2717bfc51614SGreg Kroah-Hartman 		dev_err(ddev, "%s FAILED to set databits/stopbits/parity\n",
2718bfc51614SGreg Kroah-Hartman 			__func__);
27191da177e4SLinus Torvalds 	}
27201da177e4SLinus Torvalds 
27211da177e4SLinus Torvalds 	/* Now do the baudrate */
2722b1ffb4c8SAndrew Worsley no_data_parity_stop_changes:
27231da177e4SLinus Torvalds 	if ((cflag & CBAUD) == B0) {
27241da177e4SLinus Torvalds 		/* Disable flow control */
27251da177e4SLinus Torvalds 		if (usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
27261da177e4SLinus Torvalds 				    FTDI_SIO_SET_FLOW_CTRL_REQUEST,
27271da177e4SLinus Torvalds 				    FTDI_SIO_SET_FLOW_CTRL_REQUEST_TYPE,
2728027bf37dSJohan Hovold 				    0, priv->channel,
272966e47e60SJohan Hovold 				    NULL, 0, WDR_TIMEOUT) < 0) {
2730bfc51614SGreg Kroah-Hartman 			dev_err(ddev, "%s error from disable flowcontrol urb\n",
2731194343d9SGreg Kroah-Hartman 				__func__);
27321da177e4SLinus Torvalds 		}
27331da177e4SLinus Torvalds 		/* Drop RTS and DTR */
273474ede0ffSIan Abbott 		clear_mctrl(port, TIOCM_DTR | TIOCM_RTS);
27351da177e4SLinus Torvalds 	} else {
27361da177e4SLinus Torvalds 		/* set the baudrate determined before */
27379c67d28eSAlessio Igor Bogani 		mutex_lock(&priv->cfg_lock);
2738464cbb24SAlan Cox 		if (change_speed(tty, port))
2739bfc51614SGreg Kroah-Hartman 			dev_err(ddev, "%s urb failed to set baudrate\n", __func__);
27409c67d28eSAlessio Igor Bogani 		mutex_unlock(&priv->cfg_lock);
274172a755fcSPeter Favrholdt 		/* Ensure RTS and DTR are raised when baudrate changed from 0 */
27423177130fSJohan Hovold 		if (old_termios && (old_termios->c_cflag & CBAUD) == B0)
274374ede0ffSIan Abbott 			set_mctrl(port, TIOCM_DTR | TIOCM_RTS);
27441da177e4SLinus Torvalds 	}
27451da177e4SLinus Torvalds 
2746b1ffb4c8SAndrew Worsley no_c_cflag_changes:
2747df1cd63dSJohan Hovold 	/* Set hardware-assisted flow control */
2748df1cd63dSJohan Hovold 	value = 0;
27491da177e4SLinus Torvalds 
2750df1cd63dSJohan Hovold 	if (C_CRTSCTS(tty)) {
2751df1cd63dSJohan Hovold 		dev_dbg(&port->dev, "enabling rts/cts flow control\n");
2752df1cd63dSJohan Hovold 		index = FTDI_SIO_RTS_CTS_HS;
2753df1cd63dSJohan Hovold 	} else if (I_IXON(tty)) {
2754df1cd63dSJohan Hovold 		dev_dbg(&port->dev, "enabling xon/xoff flow control\n");
2755df1cd63dSJohan Hovold 		index = FTDI_SIO_XON_XOFF_HS;
2756df1cd63dSJohan Hovold 		value = STOP_CHAR(tty) << 8 | START_CHAR(tty);
27571da177e4SLinus Torvalds 	} else {
2758df1cd63dSJohan Hovold 		dev_dbg(&port->dev, "disabling flow control\n");
2759df1cd63dSJohan Hovold 		index = FTDI_SIO_DISABLE_FLOW_CTRL;
2760df1cd63dSJohan Hovold 	}
2761df1cd63dSJohan Hovold 
2762027bf37dSJohan Hovold 	index |= priv->channel;
2763df1cd63dSJohan Hovold 
2764df1cd63dSJohan Hovold 	ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
27651da177e4SLinus Torvalds 			FTDI_SIO_SET_FLOW_CTRL_REQUEST,
27661da177e4SLinus Torvalds 			FTDI_SIO_SET_FLOW_CTRL_REQUEST_TYPE,
2767df1cd63dSJohan Hovold 			value, index, NULL, 0, WDR_TIMEOUT);
2768df1cd63dSJohan Hovold 	if (ret < 0)
2769df1cd63dSJohan Hovold 		dev_err(&port->dev, "failed to set flow control: %d\n", ret);
277095da310eSAlan Cox }
27711da177e4SLinus Torvalds 
2772a4afff6bSJohan Hovold /*
2773a4afff6bSJohan Hovold  * Get modem-control status.
2774a4afff6bSJohan Hovold  *
2775a4afff6bSJohan Hovold  * Returns the number of status bytes retrieved (device dependant), or
2776a4afff6bSJohan Hovold  * negative error code.
2777a4afff6bSJohan Hovold  */
ftdi_get_modem_status(struct usb_serial_port * port,unsigned char status[2])2778c4133648SJohan Hovold static int ftdi_get_modem_status(struct usb_serial_port *port,
2779a4afff6bSJohan Hovold 						unsigned char status[2])
27801da177e4SLinus Torvalds {
27811da177e4SLinus Torvalds 	struct ftdi_private *priv = usb_get_serial_port_data(port);
278266e47e60SJohan Hovold 	unsigned char *buf;
2783a3f8168bSJohan Hovold 	int len;
27841da177e4SLinus Torvalds 	int ret;
27851da177e4SLinus Torvalds 
278666e47e60SJohan Hovold 	buf = kmalloc(2, GFP_KERNEL);
278766e47e60SJohan Hovold 	if (!buf)
278866e47e60SJohan Hovold 		return -ENOMEM;
2789a3f8168bSJohan Hovold 	/*
27906fbd9142SJohan Hovold 	 * The device returns a two byte value (the SIO a 1 byte value) in the
27916fbd9142SJohan Hovold 	 * same format as the data returned from the IN endpoint.
2792a3f8168bSJohan Hovold 	 */
27936fbd9142SJohan Hovold 	if (priv->chip_type == SIO)
2794a3f8168bSJohan Hovold 		len = 1;
27956fbd9142SJohan Hovold 	else
2796a3f8168bSJohan Hovold 		len = 2;
27971da177e4SLinus Torvalds 
2798a3f8168bSJohan Hovold 	ret = usb_control_msg(port->serial->dev,
2799a3f8168bSJohan Hovold 			usb_rcvctrlpipe(port->serial->dev, 0),
2800a3f8168bSJohan Hovold 			FTDI_SIO_GET_MODEM_STATUS_REQUEST,
2801a3f8168bSJohan Hovold 			FTDI_SIO_GET_MODEM_STATUS_REQUEST_TYPE,
2802027bf37dSJohan Hovold 			0, priv->channel,
2803a3f8168bSJohan Hovold 			buf, len, WDR_TIMEOUT);
2804427c3a95SJohan Hovold 
2805427c3a95SJohan Hovold 	/* NOTE: We allow short responses and handle that below. */
2806427c3a95SJohan Hovold 	if (ret < 1) {
2807a4afff6bSJohan Hovold 		dev_err(&port->dev, "failed to get modem status: %d\n", ret);
2808427c3a95SJohan Hovold 		if (ret >= 0)
2809427c3a95SJohan Hovold 			ret = -EIO;
28102c2ee545SJohan Hovold 		ret = usb_translate_errors(ret);
2811a3f8168bSJohan Hovold 		goto out;
28122c2ee545SJohan Hovold 	}
2813a3f8168bSJohan Hovold 
2814a4afff6bSJohan Hovold 	status[0] = buf[0];
2815a4afff6bSJohan Hovold 	if (ret > 1)
2816a4afff6bSJohan Hovold 		status[1] = buf[1];
2817a4afff6bSJohan Hovold 	else
2818a4afff6bSJohan Hovold 		status[1] = 0;
2819a4afff6bSJohan Hovold 
2820a4afff6bSJohan Hovold 	dev_dbg(&port->dev, "%s - 0x%02x%02x\n", __func__, status[0],
2821a4afff6bSJohan Hovold 								status[1]);
2822a4afff6bSJohan Hovold out:
2823a4afff6bSJohan Hovold 	kfree(buf);
2824a4afff6bSJohan Hovold 
2825a4afff6bSJohan Hovold 	return ret;
2826a4afff6bSJohan Hovold }
2827a4afff6bSJohan Hovold 
ftdi_tiocmget(struct tty_struct * tty)2828a4afff6bSJohan Hovold static int ftdi_tiocmget(struct tty_struct *tty)
2829a4afff6bSJohan Hovold {
2830a4afff6bSJohan Hovold 	struct usb_serial_port *port = tty->driver_data;
2831a4afff6bSJohan Hovold 	struct ftdi_private *priv = usb_get_serial_port_data(port);
2832a4afff6bSJohan Hovold 	unsigned char buf[2];
2833a4afff6bSJohan Hovold 	int ret;
2834a4afff6bSJohan Hovold 
2835c4133648SJohan Hovold 	ret = ftdi_get_modem_status(port, buf);
2836a4afff6bSJohan Hovold 	if (ret < 0)
2837a4afff6bSJohan Hovold 		return ret;
2838a4afff6bSJohan Hovold 
283966e47e60SJohan Hovold 	ret =	(buf[0] & FTDI_SIO_DSR_MASK  ? TIOCM_DSR : 0) |
28401da177e4SLinus Torvalds 		(buf[0] & FTDI_SIO_CTS_MASK  ? TIOCM_CTS : 0) |
28411da177e4SLinus Torvalds 		(buf[0] & FTDI_SIO_RI_MASK   ? TIOCM_RI  : 0) |
28421da177e4SLinus Torvalds 		(buf[0] & FTDI_SIO_RLSD_MASK ? TIOCM_CD  : 0) |
28431da177e4SLinus Torvalds 		priv->last_dtr_rts;
2844a4afff6bSJohan Hovold 
284566e47e60SJohan Hovold 	return ret;
28461da177e4SLinus Torvalds }
28471da177e4SLinus Torvalds 
ftdi_tiocmset(struct tty_struct * tty,unsigned int set,unsigned int clear)284820b9d177SAlan Cox static int ftdi_tiocmset(struct tty_struct *tty,
284995da310eSAlan Cox 			unsigned int set, unsigned int clear)
28501da177e4SLinus Torvalds {
285195da310eSAlan Cox 	struct usb_serial_port *port = tty->driver_data;
2852a09aa7ddSGreg Kroah-Hartman 
285374ede0ffSIan Abbott 	return update_mctrl(port, set, clear);
28541da177e4SLinus Torvalds }
28551da177e4SLinus Torvalds 
ftdi_ioctl(struct tty_struct * tty,unsigned int cmd,unsigned long arg)285600a0d0d6SAlan Cox static int ftdi_ioctl(struct tty_struct *tty,
2857464cbb24SAlan Cox 					unsigned int cmd, unsigned long arg)
28581da177e4SLinus Torvalds {
285995da310eSAlan Cox 	struct usb_serial_port *port = tty->driver_data;
286059556608SJohan Hovold 	void __user *argp = (void __user *)arg;
28611da177e4SLinus Torvalds 
28621da177e4SLinus Torvalds 	switch (cmd) {
2863c466cd2bSGreg Kroah-Hartman 	case TIOCSERGETLSR:
286459556608SJohan Hovold 		return get_lsr_info(port, argp);
28651da177e4SLinus Torvalds 	default:
28661da177e4SLinus Torvalds 		break;
28671da177e4SLinus Torvalds 	}
28684d5147ecSJohan Hovold 
286995da310eSAlan Cox 	return -ENOIOCTLCMD;
287095da310eSAlan Cox }
28711da177e4SLinus Torvalds 
28726b2fe3dfSJohan Hovold static struct usb_serial_driver ftdi_device = {
2873a8619505SJohan Hovold 	.driver = {
2874a8619505SJohan Hovold 		.owner =	THIS_MODULE,
2875a8619505SJohan Hovold 		.name =		"ftdi_sio",
2876a8619505SJohan Hovold 		.dev_groups =	ftdi_groups,
2877a8619505SJohan Hovold 	},
2878a8619505SJohan Hovold 	.description =		"FTDI USB Serial Device",
2879a8619505SJohan Hovold 	.id_table =		id_table_combined,
2880a8619505SJohan Hovold 	.num_ports =		1,
2881a8619505SJohan Hovold 	.bulk_in_size =		512,
2882a8619505SJohan Hovold 	.bulk_out_size =	256,
28836b2fe3dfSJohan Hovold 	.probe =		ftdi_probe,
28846b2fe3dfSJohan Hovold 	.port_probe =		ftdi_port_probe,
28856b2fe3dfSJohan Hovold 	.port_remove =		ftdi_port_remove,
2886a8619505SJohan Hovold 	.open =			ftdi_open,
2887a8619505SJohan Hovold 	.dtr_rts =		ftdi_dtr_rts,
2888a8619505SJohan Hovold 	.throttle =		usb_serial_generic_throttle,
2889a8619505SJohan Hovold 	.unthrottle =		usb_serial_generic_unthrottle,
2890a8619505SJohan Hovold 	.process_read_urb =	ftdi_process_read_urb,
2891a8619505SJohan Hovold 	.prepare_write_buffer =	ftdi_prepare_write_buffer,
2892a8619505SJohan Hovold 	.tiocmget =		ftdi_tiocmget,
2893a8619505SJohan Hovold 	.tiocmset =		ftdi_tiocmset,
2894a8619505SJohan Hovold 	.tiocmiwait =		usb_serial_generic_tiocmiwait,
2895a8619505SJohan Hovold 	.get_icount =		usb_serial_generic_get_icount,
2896a8619505SJohan Hovold 	.ioctl =		ftdi_ioctl,
2897a8619505SJohan Hovold 	.get_serial =		get_serial_info,
2898a8619505SJohan Hovold 	.set_serial =		set_serial_info,
2899a8619505SJohan Hovold 	.set_termios =		ftdi_set_termios,
2900a8619505SJohan Hovold 	.break_ctl =		ftdi_break_ctl,
2901a8619505SJohan Hovold 	.tx_empty =		ftdi_tx_empty,
2902a8619505SJohan Hovold };
2903a8619505SJohan Hovold 
2904a8619505SJohan Hovold static struct usb_serial_driver * const serial_drivers[] = {
29056b2fe3dfSJohan Hovold 	&ftdi_device, NULL
2906a8619505SJohan Hovold };
2907e17c1aa2SJohan Hovold module_usb_serial_driver(serial_drivers, id_table_combined);
29081da177e4SLinus Torvalds 
29091da177e4SLinus Torvalds MODULE_AUTHOR(DRIVER_AUTHOR);
29101da177e4SLinus Torvalds MODULE_DESCRIPTION(DRIVER_DESC);
29111da177e4SLinus Torvalds MODULE_LICENSE("GPL");
29121da177e4SLinus Torvalds 
2913a65ab973SUtkarsh Verma module_param(ndi_latency_timer, int, 0644);
2914b760dac2SMartin Geleynse MODULE_PARM_DESC(ndi_latency_timer, "NDI device latency timer override");
2915