diff options
Diffstat (limited to 'drivers/usb/serial/cp210x.c')
| -rw-r--r-- | drivers/usb/serial/cp210x.c | 495 | 
1 files changed, 273 insertions, 222 deletions
diff --git a/drivers/usb/serial/cp210x.c b/drivers/usb/serial/cp210x.c index 8d7731dbf47..330df5ce435 100644 --- a/drivers/usb/serial/cp210x.c +++ b/drivers/usb/serial/cp210x.c @@ -24,10 +24,6 @@  #include <linux/uaccess.h>  #include <linux/usb/serial.h> -/* - * Version Information - */ -#define DRIVER_VERSION "v0.09"  #define DRIVER_DESC "Silicon Labs CP210x RS232 serial adaptor driver"  /* @@ -35,23 +31,21 @@   */  static int cp210x_open(struct tty_struct *tty, struct usb_serial_port *);  static void cp210x_close(struct usb_serial_port *); -static void cp210x_get_termios(struct tty_struct *, -	struct usb_serial_port *port); +static void cp210x_get_termios(struct tty_struct *, struct usb_serial_port *);  static void cp210x_get_termios_port(struct usb_serial_port *port,  	unsigned int *cflagp, unsigned int *baudp); +static void cp210x_change_speed(struct tty_struct *, struct usb_serial_port *, +							struct ktermios *);  static void cp210x_set_termios(struct tty_struct *, struct usb_serial_port *,  							struct ktermios*); -static int cp210x_tiocmget(struct tty_struct *, struct file *); -static int cp210x_tiocmset(struct tty_struct *, struct file *, -		unsigned int, unsigned int); -static int cp210x_tiocmset_port(struct usb_serial_port *port, struct file *, +static int cp210x_tiocmget(struct tty_struct *); +static int cp210x_tiocmset(struct tty_struct *, unsigned int, unsigned int); +static int cp210x_tiocmset_port(struct usb_serial_port *port,  		unsigned int, unsigned int);  static void cp210x_break_ctl(struct tty_struct *, int);  static int cp210x_startup(struct usb_serial *); +static void cp210x_release(struct usb_serial *);  static void cp210x_dtr_rts(struct usb_serial_port *p, int on); -static int cp210x_carrier_raised(struct usb_serial_port *p); - -static int debug;  static const struct usb_device_id id_table[] = {  	{ USB_DEVICE(0x045B, 0x0053) }, /* Renesas RX610 RX-Stick */ @@ -59,6 +53,7 @@ static const struct usb_device_id id_table[] = {  	{ USB_DEVICE(0x0489, 0xE000) }, /* Pirelli Broadband S.p.A, DP-L10 SIP/GSM Mobile */  	{ USB_DEVICE(0x0489, 0xE003) }, /* Pirelli Broadband S.p.A, DP-L10 SIP/GSM Mobile */  	{ USB_DEVICE(0x0745, 0x1000) }, /* CipherLab USB CCD Barcode Scanner 1000 */ +	{ USB_DEVICE(0x0846, 0x1100) }, /* NetGear Managed Switch M4100 series, M5300 series, M7100 series */  	{ USB_DEVICE(0x08e6, 0x5501) }, /* Gemalto Prox-PU/CU contactless smartcard reader */  	{ USB_DEVICE(0x08FD, 0x000A) }, /* Digianswer A/S , ZigBee/802.15.4 MAC Device */  	{ USB_DEVICE(0x0BED, 0x1100) }, /* MEI (TM) Cashflow-SC Bill/Voucher Acceptor */ @@ -66,6 +61,7 @@ static const struct usb_device_id id_table[] = {  	{ USB_DEVICE(0x0FCF, 0x1003) }, /* Dynastream ANT development board */  	{ USB_DEVICE(0x0FCF, 0x1004) }, /* Dynastream ANT2USB */  	{ USB_DEVICE(0x0FCF, 0x1006) }, /* Dynastream ANT development board */ +	{ USB_DEVICE(0x0FDE, 0xCA05) }, /* OWL Wireless Electricity Monitor CM-160 */  	{ USB_DEVICE(0x10A6, 0xAA26) }, /* Knock-off DCU-11 cable */  	{ USB_DEVICE(0x10AB, 0x10C5) }, /* Siemens MC60 Cable */  	{ USB_DEVICE(0x10B5, 0xAC70) }, /* Nokia CA-42 USB */ @@ -81,20 +77,23 @@ static const struct usb_device_id id_table[] = {  	{ USB_DEVICE(0x10C4, 0x8066) }, /* Argussoft In-System Programmer */  	{ USB_DEVICE(0x10C4, 0x806F) }, /* IMS USB to RS422 Converter Cable */  	{ USB_DEVICE(0x10C4, 0x807A) }, /* Crumb128 board */ +	{ USB_DEVICE(0x10C4, 0x80C4) }, /* Cygnal Integrated Products, Inc., Optris infrared thermometer */  	{ USB_DEVICE(0x10C4, 0x80CA) }, /* Degree Controls Inc */  	{ USB_DEVICE(0x10C4, 0x80DD) }, /* Tracient RFID */  	{ USB_DEVICE(0x10C4, 0x80F6) }, /* Suunto sports instrument */  	{ USB_DEVICE(0x10C4, 0x8115) }, /* Arygon NFC/Mifare Reader */  	{ USB_DEVICE(0x10C4, 0x813D) }, /* Burnside Telecom Deskmobile */  	{ USB_DEVICE(0x10C4, 0x813F) }, /* Tams Master Easy Control */ -	{ USB_DEVICE(0x10C4, 0x8149) }, /* West Mountain Radio Computerized Battery Analyzer */  	{ USB_DEVICE(0x10C4, 0x814A) }, /* West Mountain Radio RIGblaster P&P */  	{ USB_DEVICE(0x10C4, 0x814B) }, /* West Mountain Radio RIGtalk */ +	{ USB_DEVICE(0x2405, 0x0003) }, /* West Mountain Radio RIGblaster Advantage */  	{ USB_DEVICE(0x10C4, 0x8156) }, /* B&G H3000 link cable */  	{ USB_DEVICE(0x10C4, 0x815E) }, /* Helicomm IP-Link 1220-DVM */ +	{ USB_DEVICE(0x10C4, 0x815F) }, /* Timewave HamLinkUSB */  	{ USB_DEVICE(0x10C4, 0x818B) }, /* AVIT Research USB to TTL */  	{ USB_DEVICE(0x10C4, 0x819F) }, /* MJS USB Toslink Switcher */  	{ USB_DEVICE(0x10C4, 0x81A6) }, /* ThinkOptics WavIt */ +	{ USB_DEVICE(0x10C4, 0x81A9) }, /* Multiplex RC Interface */  	{ USB_DEVICE(0x10C4, 0x81AC) }, /* MSD Dash Hawk */  	{ USB_DEVICE(0x10C4, 0x81AD) }, /* INSYS USB Modem */  	{ USB_DEVICE(0x10C4, 0x81C8) }, /* Lipowsky Industrie Elektronik GmbH, Baby-JTAG */ @@ -104,17 +103,29 @@ static const struct usb_device_id id_table[] = {  	{ USB_DEVICE(0x10C4, 0x81F2) }, /* C1007 HF band RFID controller */  	{ USB_DEVICE(0x10C4, 0x8218) }, /* Lipowsky Industrie Elektronik GmbH, HARP-1 */  	{ USB_DEVICE(0x10C4, 0x822B) }, /* Modem EDGE(GSM) Comander 2 */ -	{ USB_DEVICE(0x10C4, 0x826B) }, /* Cygnal Integrated Products, Inc., Fasttrax GPS demostration module */ -	{ USB_DEVICE(0x10C4, 0x8293) }, /* Telegesys ETRX2USB */ +	{ USB_DEVICE(0x10C4, 0x826B) }, /* Cygnal Integrated Products, Inc., Fasttrax GPS demonstration module */ +	{ USB_DEVICE(0x10C4, 0x8281) }, /* Nanotec Plug & Drive */ +	{ USB_DEVICE(0x10C4, 0x8293) }, /* Telegesis ETRX2USB */  	{ USB_DEVICE(0x10C4, 0x82F9) }, /* Procyon AVS */  	{ USB_DEVICE(0x10C4, 0x8341) }, /* Siemens MC35PU GPRS Modem */  	{ USB_DEVICE(0x10C4, 0x8382) }, /* Cygnal Integrated Products, Inc. */  	{ USB_DEVICE(0x10C4, 0x83A8) }, /* Amber Wireless AMB2560 */ +	{ USB_DEVICE(0x10C4, 0x83D8) }, /* DekTec DTA Plus VHF/UHF Booster/Attenuator */  	{ USB_DEVICE(0x10C4, 0x8411) }, /* Kyocera GPS Module */ +	{ USB_DEVICE(0x10C4, 0x8418) }, /* IRZ Automation Teleport SG-10 GSM/GPRS Modem */  	{ USB_DEVICE(0x10C4, 0x846E) }, /* BEI USB Sensor Interface (VCP) */  	{ USB_DEVICE(0x10C4, 0x8477) }, /* Balluff RFID */ +	{ USB_DEVICE(0x10C4, 0x85EA) }, /* AC-Services IBUS-IF */ +	{ USB_DEVICE(0x10C4, 0x85EB) }, /* AC-Services CIS-IBUS */ +	{ USB_DEVICE(0x10C4, 0x85F8) }, /* Virtenio Preon32 */ +	{ USB_DEVICE(0x10C4, 0x8664) }, /* AC-Services CAN-IF */ +	{ USB_DEVICE(0x10C4, 0x8665) }, /* AC-Services OBD-IF */ +	{ USB_DEVICE(0x10C4, 0x88A4) }, /* MMB Networks ZigBee USB Device */ +	{ USB_DEVICE(0x10C4, 0x88A5) }, /* Planet Innovation Ingeni ZigBee USB Device */  	{ USB_DEVICE(0x10C4, 0xEA60) }, /* Silicon Labs factory default */  	{ USB_DEVICE(0x10C4, 0xEA61) }, /* Silicon Labs factory default */ +	{ USB_DEVICE(0x10C4, 0xEA70) }, /* Silicon Labs factory default */ +	{ USB_DEVICE(0x10C4, 0xEA80) }, /* Silicon Labs factory default */  	{ USB_DEVICE(0x10C4, 0xEA71) }, /* Infinity GPS-MIC-1 Radio Monophone */  	{ USB_DEVICE(0x10C4, 0xF001) }, /* Elan Digital Systems USBscope50 */  	{ USB_DEVICE(0x10C4, 0xF002) }, /* Elan Digital Systems USBwave12 */ @@ -124,36 +135,65 @@ static const struct usb_device_id id_table[] = {  	{ USB_DEVICE(0x10CE, 0xEA6A) }, /* Silicon Labs MobiData GPRS USB Modem 100EU */  	{ USB_DEVICE(0x13AD, 0x9999) }, /* Baltech card reader */  	{ USB_DEVICE(0x1555, 0x0004) }, /* Owen AC4 USB-RS485 Converter */ +	{ USB_DEVICE(0x166A, 0x0201) }, /* Clipsal 5500PACA C-Bus Pascal Automation Controller */ +	{ USB_DEVICE(0x166A, 0x0301) }, /* Clipsal 5800PC C-Bus Wireless PC Interface */  	{ USB_DEVICE(0x166A, 0x0303) }, /* Clipsal 5500PCU C-Bus USB interface */ +	{ USB_DEVICE(0x166A, 0x0304) }, /* Clipsal 5000CT2 C-Bus Black and White Touchscreen */ +	{ USB_DEVICE(0x166A, 0x0305) }, /* Clipsal C-5000CT2 C-Bus Spectrum Colour Touchscreen */ +	{ USB_DEVICE(0x166A, 0x0401) }, /* Clipsal L51xx C-Bus Architectural Dimmer */ +	{ USB_DEVICE(0x166A, 0x0101) }, /* Clipsal 5560884 C-Bus Multi-room Audio Matrix Switcher */  	{ USB_DEVICE(0x16D6, 0x0001) }, /* Jablotron serial interface */  	{ USB_DEVICE(0x16DC, 0x0010) }, /* W-IE-NE-R Plein & Baus GmbH PL512 Power Supply */  	{ USB_DEVICE(0x16DC, 0x0011) }, /* W-IE-NE-R Plein & Baus GmbH RCM Remote Control for MARATON Power Supply */  	{ USB_DEVICE(0x16DC, 0x0012) }, /* W-IE-NE-R Plein & Baus GmbH MPOD Multi Channel Power Supply */  	{ USB_DEVICE(0x16DC, 0x0015) }, /* W-IE-NE-R Plein & Baus GmbH CML Control, Monitoring and Data Logger */ +	{ USB_DEVICE(0x17A8, 0x0001) }, /* Kamstrup Optical Eye/3-wire */ +	{ USB_DEVICE(0x17A8, 0x0005) }, /* Kamstrup M-Bus Master MultiPort 250D */  	{ USB_DEVICE(0x17F4, 0xAAAA) }, /* Wavesense Jazz blood glucose meter */  	{ USB_DEVICE(0x1843, 0x0200) }, /* Vaisala USB Instrument Cable */  	{ USB_DEVICE(0x18EF, 0xE00F) }, /* ELV USB-I2C-Interface */ +	{ USB_DEVICE(0x1ADB, 0x0001) }, /* Schweitzer Engineering C662 Cable */ +	{ USB_DEVICE(0x1B1C, 0x1C00) }, /* Corsair USB Dongle */  	{ USB_DEVICE(0x1BE3, 0x07A6) }, /* WAGO 750-923 USB Service Cable */ +	{ USB_DEVICE(0x1E29, 0x0102) }, /* Festo CPX-USB */ +	{ USB_DEVICE(0x1E29, 0x0501) }, /* Festo CMSP */ +	{ USB_DEVICE(0x1FB9, 0x0100) }, /* Lake Shore Model 121 Current Source */ +	{ USB_DEVICE(0x1FB9, 0x0200) }, /* Lake Shore Model 218A Temperature Monitor */ +	{ USB_DEVICE(0x1FB9, 0x0201) }, /* Lake Shore Model 219 Temperature Monitor */ +	{ USB_DEVICE(0x1FB9, 0x0202) }, /* Lake Shore Model 233 Temperature Transmitter */ +	{ USB_DEVICE(0x1FB9, 0x0203) }, /* Lake Shore Model 235 Temperature Transmitter */ +	{ USB_DEVICE(0x1FB9, 0x0300) }, /* Lake Shore Model 335 Temperature Controller */ +	{ USB_DEVICE(0x1FB9, 0x0301) }, /* Lake Shore Model 336 Temperature Controller */ +	{ USB_DEVICE(0x1FB9, 0x0302) }, /* Lake Shore Model 350 Temperature Controller */ +	{ USB_DEVICE(0x1FB9, 0x0303) }, /* Lake Shore Model 371 AC Bridge */ +	{ USB_DEVICE(0x1FB9, 0x0400) }, /* Lake Shore Model 411 Handheld Gaussmeter */ +	{ USB_DEVICE(0x1FB9, 0x0401) }, /* Lake Shore Model 425 Gaussmeter */ +	{ USB_DEVICE(0x1FB9, 0x0402) }, /* Lake Shore Model 455A Gaussmeter */ +	{ USB_DEVICE(0x1FB9, 0x0403) }, /* Lake Shore Model 475A Gaussmeter */ +	{ USB_DEVICE(0x1FB9, 0x0404) }, /* Lake Shore Model 465 Three Axis Gaussmeter */ +	{ USB_DEVICE(0x1FB9, 0x0600) }, /* Lake Shore Model 625A Superconducting MPS */ +	{ USB_DEVICE(0x1FB9, 0x0601) }, /* Lake Shore Model 642A Magnet Power Supply */ +	{ USB_DEVICE(0x1FB9, 0x0602) }, /* Lake Shore Model 648 Magnet Power Supply */ +	{ USB_DEVICE(0x1FB9, 0x0700) }, /* Lake Shore Model 737 VSM Controller */ +	{ USB_DEVICE(0x1FB9, 0x0701) }, /* Lake Shore Model 776 Hall Matrix */ +	{ USB_DEVICE(0x3195, 0xF190) }, /* Link Instruments MSO-19 */ +	{ USB_DEVICE(0x3195, 0xF280) }, /* Link Instruments MSO-28 */ +	{ USB_DEVICE(0x3195, 0xF281) }, /* Link Instruments MSO-28 */  	{ USB_DEVICE(0x413C, 0x9500) }, /* DW700 GPS USB interface */  	{ } /* Terminating Entry */  };  MODULE_DEVICE_TABLE(usb, id_table); -static struct usb_driver cp210x_driver = { -	.name		= "cp210x", -	.probe		= usb_serial_probe, -	.disconnect	= usb_serial_disconnect, -	.id_table	= id_table, -	.no_dynamic_id	= 	1, +struct cp210x_serial_private { +	__u8			bInterfaceNumber;  };  static struct usb_serial_driver cp210x_device = {  	.driver = {  		.owner =	THIS_MODULE, -		.name = 	"cp210x", +		.name =		"cp210x",  	}, -	.usb_driver		= &cp210x_driver,  	.id_table		= id_table,  	.num_ports		= 1,  	.bulk_in_size		= 256, @@ -162,16 +202,22 @@ static struct usb_serial_driver cp210x_device = {  	.close			= cp210x_close,  	.break_ctl		= cp210x_break_ctl,  	.set_termios		= cp210x_set_termios, -	.tiocmget 		= cp210x_tiocmget, +	.tiocmget		= cp210x_tiocmget,  	.tiocmset		= cp210x_tiocmset,  	.attach			= cp210x_startup, -	.dtr_rts		= cp210x_dtr_rts, -	.carrier_raised		= cp210x_carrier_raised +	.release		= cp210x_release, +	.dtr_rts		= cp210x_dtr_rts +}; + +static struct usb_serial_driver * const serial_drivers[] = { +	&cp210x_device, NULL  };  /* Config request types */ -#define REQTYPE_HOST_TO_DEVICE	0x41 -#define REQTYPE_DEVICE_TO_HOST	0xc1 +#define REQTYPE_HOST_TO_INTERFACE	0x41 +#define REQTYPE_INTERFACE_TO_HOST	0xc1 +#define REQTYPE_HOST_TO_DEVICE	0x40 +#define REQTYPE_DEVICE_TO_HOST	0xc0  /* Config request codes */  #define CP210X_IFC_ENABLE	0x00 @@ -198,6 +244,8 @@ static struct usb_serial_driver cp210x_device = {  #define CP210X_EMBED_EVENTS	0x15  #define CP210X_GET_EVENTSTATE	0x16  #define CP210X_SET_CHARS	0x19 +#define CP210X_GET_BAUDRATE	0x1D +#define CP210X_SET_BAUDRATE	0x1E  /* CP210X_IFC_ENABLE */  #define UART_ENABLE		0x0001 @@ -251,22 +299,22 @@ static int cp210x_get_config(struct usb_serial_port *port, u8 request,  		unsigned int *data, int size)  {  	struct usb_serial *serial = port->serial; +	struct cp210x_serial_private *spriv = usb_get_serial_data(serial);  	__le32 *buf;  	int result, i, length;  	/* Number of integers required to contain the array */ -	length = (((size - 1) | 3) + 1)/4; +	length = (((size - 1) | 3) + 1) / 4;  	buf = kcalloc(length, sizeof(__le32), GFP_KERNEL); -	if (!buf) { -		dev_err(&port->dev, "%s - out of memory.\n", __func__); +	if (!buf)  		return -ENOMEM; -	}  	/* Issue the request, attempting to read 'size' bytes */  	result = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0), -				request, REQTYPE_DEVICE_TO_HOST, 0x0000, -				0, buf, size, 300); +				request, REQTYPE_INTERFACE_TO_HOST, 0x0000, +				spriv->bInterfaceNumber, buf, size, +				USB_CTRL_GET_TIMEOUT);  	/* Convert data into an array of integers */  	for (i = 0; i < length; i++) @@ -275,10 +323,12 @@ static int cp210x_get_config(struct usb_serial_port *port, u8 request,  	kfree(buf);  	if (result != size) { -		dbg("%s - Unable to send config request, " -				"request=0x%x size=%d result=%d\n", -				__func__, request, size, result); -		return -EPROTO; +		dev_dbg(&port->dev, "%s - Unable to send config request, request=0x%x size=%d result=%d\n", +			__func__, request, size, result); +		if (result > 0) +			result = -EPROTO; + +		return result;  	}  	return 0; @@ -294,18 +344,16 @@ static int cp210x_set_config(struct usb_serial_port *port, u8 request,  		unsigned int *data, int size)  {  	struct usb_serial *serial = port->serial; +	struct cp210x_serial_private *spriv = usb_get_serial_data(serial);  	__le32 *buf;  	int result, i, length;  	/* Number of integers required to contain the array */ -	length = (((size - 1) | 3) + 1)/4; +	length = (((size - 1) | 3) + 1) / 4;  	buf = kmalloc(length * sizeof(__le32), GFP_KERNEL); -	if (!buf) { -		dev_err(&port->dev, "%s - out of memory.\n", -				__func__); +	if (!buf)  		return -ENOMEM; -	}  	/* Array of integers into bytes */  	for (i = 0; i < length; i++) @@ -314,22 +362,26 @@ static int cp210x_set_config(struct usb_serial_port *port, u8 request,  	if (size > 2) {  		result = usb_control_msg(serial->dev,  				usb_sndctrlpipe(serial->dev, 0), -				request, REQTYPE_HOST_TO_DEVICE, 0x0000, -				0, buf, size, 300); +				request, REQTYPE_HOST_TO_INTERFACE, 0x0000, +				spriv->bInterfaceNumber, buf, size, +				USB_CTRL_SET_TIMEOUT);  	} else {  		result = usb_control_msg(serial->dev,  				usb_sndctrlpipe(serial->dev, 0), -				request, REQTYPE_HOST_TO_DEVICE, data[0], -				0, NULL, 0, 300); +				request, REQTYPE_HOST_TO_INTERFACE, data[0], +				spriv->bInterfaceNumber, NULL, 0, +				USB_CTRL_SET_TIMEOUT);  	}  	kfree(buf);  	if ((size > 2 && result != size) || result < 0) { -		dbg("%s - Unable to send request, " -				"request=0x%x size=%d result=%d\n", -				__func__, request, size, result); -		return -EPROTO; +		dev_dbg(&port->dev, "%s - Unable to send request, request=0x%x size=%d result=%d\n", +			__func__, request, size, result); +		if (result > 0) +			result = -EPROTO; + +		return result;  	}  	return 0; @@ -350,9 +402,10 @@ static inline int cp210x_set_config_single(struct usb_serial_port *port,   * cp210x_quantise_baudrate   * Quantises the baud rate as per AN205 Table 1   */ -static unsigned int cp210x_quantise_baudrate(unsigned int baud) { -	if      (baud <= 56)       baud = 0; -	else if (baud <= 300)      baud = 300; +static unsigned int cp210x_quantise_baudrate(unsigned int baud) +{ +	if (baud <= 300) +		baud = 300;  	else if (baud <= 600)      baud = 600;  	else if (baud <= 1200)     baud = 1200;  	else if (baud <= 1800)     baud = 1800; @@ -380,10 +433,10 @@ static unsigned int cp210x_quantise_baudrate(unsigned int baud) {  	else if (baud <= 491520)   baud = 460800;  	else if (baud <= 567138)   baud = 500000;  	else if (baud <= 670254)   baud = 576000; -	else if (baud <= 1053257)  baud = 921600; -	else if (baud <= 1474560)  baud = 1228800; -	else if (baud <= 2457600)  baud = 1843200; -	else                       baud = 3686400; +	else if (baud < 1000000) +		baud = 921600; +	else if (baud > 2000000) +		baud = 2000000;  	return baud;  } @@ -391,33 +444,27 @@ static int cp210x_open(struct tty_struct *tty, struct usb_serial_port *port)  {  	int result; -	dbg("%s - port %d", __func__, port->number); - -	if (cp210x_set_config_single(port, CP210X_IFC_ENABLE, UART_ENABLE)) { -		dev_err(&port->dev, "%s - Unable to enable UART\n", -				__func__); -		return -EPROTO; -	} - -	result = usb_serial_generic_open(tty, port); -	if (result) +	result = cp210x_set_config_single(port, CP210X_IFC_ENABLE, +								UART_ENABLE); +	if (result) { +		dev_err(&port->dev, "%s - Unable to enable UART\n", __func__);  		return result; +	}  	/* Configure the termios structure */  	cp210x_get_termios(tty, port); -	return 0; + +	/* The baud rate must be initialised on cp2104 */ +	if (tty) +		cp210x_change_speed(tty, port, NULL); + +	return usb_serial_generic_open(tty, port);  }  static void cp210x_close(struct usb_serial_port *port)  { -	dbg("%s - port %d", __func__, port->number); -  	usb_serial_generic_close(port); - -	mutex_lock(&port->serial->disc_mutex); -	if (!port->serial->disconnected) -		cp210x_set_config_single(port, CP210X_IFC_ENABLE, UART_DISABLE); -	mutex_unlock(&port->serial->disc_mutex); +	cp210x_set_config_single(port, CP210X_IFC_ENABLE, UART_DISABLE);  }  /* @@ -433,11 +480,9 @@ static void cp210x_get_termios(struct tty_struct *tty,  	if (tty) {  		cp210x_get_termios_port(tty->driver_data, -			&tty->termios->c_cflag, &baud); +			&tty->termios.c_cflag, &baud);  		tty_encode_baud_rate(tty, baud, baud); -	} - -	else { +	} else {  		unsigned int cflag;  		cflag = 0;  		cp210x_get_termios_port(port, &cflag, &baud); @@ -451,18 +496,14 @@ static void cp210x_get_termios(struct tty_struct *tty,  static void cp210x_get_termios_port(struct usb_serial_port *port,  	unsigned int *cflagp, unsigned int *baudp)  { +	struct device *dev = &port->dev;  	unsigned int cflag, modem_ctl[4];  	unsigned int baud;  	unsigned int bits; -	dbg("%s - port %d", __func__, port->number); - -	cp210x_get_config(port, CP210X_GET_BAUDDIV, &baud, 2); -	/* Convert to baudrate */ -	if (baud) -		baud = cp210x_quantise_baudrate((BAUD_RATE_GEN_FREQ + baud/2)/ baud); +	cp210x_get_config(port, CP210X_GET_BAUDRATE, &baud, 4); -	dbg("%s - baud rate = %d", __func__, baud); +	dev_dbg(dev, "%s - baud rate = %d\n", __func__, baud);  	*baudp = baud;  	cflag = *cflagp; @@ -471,31 +512,30 @@ static void cp210x_get_termios_port(struct usb_serial_port *port,  	cflag &= ~CSIZE;  	switch (bits & BITS_DATA_MASK) {  	case BITS_DATA_5: -		dbg("%s - data bits = 5", __func__); +		dev_dbg(dev, "%s - data bits = 5\n", __func__);  		cflag |= CS5;  		break;  	case BITS_DATA_6: -		dbg("%s - data bits = 6", __func__); +		dev_dbg(dev, "%s - data bits = 6\n", __func__);  		cflag |= CS6;  		break;  	case BITS_DATA_7: -		dbg("%s - data bits = 7", __func__); +		dev_dbg(dev, "%s - data bits = 7\n", __func__);  		cflag |= CS7;  		break;  	case BITS_DATA_8: -		dbg("%s - data bits = 8", __func__); +		dev_dbg(dev, "%s - data bits = 8\n", __func__);  		cflag |= CS8;  		break;  	case BITS_DATA_9: -		dbg("%s - data bits = 9 (not supported, using 8 data bits)", -								__func__); +		dev_dbg(dev, "%s - data bits = 9 (not supported, using 8 data bits)\n", __func__);  		cflag |= CS8;  		bits &= ~BITS_DATA_MASK;  		bits |= BITS_DATA_8;  		cp210x_set_config(port, CP210X_SET_LINE_CTL, &bits, 2);  		break;  	default: -		dbg("%s - Unknown number of data bits, using 8", __func__); +		dev_dbg(dev, "%s - Unknown number of data bits, using 8\n", __func__);  		cflag |= CS8;  		bits &= ~BITS_DATA_MASK;  		bits |= BITS_DATA_8; @@ -505,34 +545,29 @@ static void cp210x_get_termios_port(struct usb_serial_port *port,  	switch (bits & BITS_PARITY_MASK) {  	case BITS_PARITY_NONE: -		dbg("%s - parity = NONE", __func__); +		dev_dbg(dev, "%s - parity = NONE\n", __func__);  		cflag &= ~PARENB;  		break;  	case BITS_PARITY_ODD: -		dbg("%s - parity = ODD", __func__); +		dev_dbg(dev, "%s - parity = ODD\n", __func__);  		cflag |= (PARENB|PARODD);  		break;  	case BITS_PARITY_EVEN: -		dbg("%s - parity = EVEN", __func__); +		dev_dbg(dev, "%s - parity = EVEN\n", __func__);  		cflag &= ~PARODD;  		cflag |= PARENB;  		break;  	case BITS_PARITY_MARK: -		dbg("%s - parity = MARK (not supported, disabling parity)", -				__func__); -		cflag &= ~PARENB; -		bits &= ~BITS_PARITY_MASK; -		cp210x_set_config(port, CP210X_SET_LINE_CTL, &bits, 2); +		dev_dbg(dev, "%s - parity = MARK\n", __func__); +		cflag |= (PARENB|PARODD|CMSPAR);  		break;  	case BITS_PARITY_SPACE: -		dbg("%s - parity = SPACE (not supported, disabling parity)", -				__func__); -		cflag &= ~PARENB; -		bits &= ~BITS_PARITY_MASK; -		cp210x_set_config(port, CP210X_SET_LINE_CTL, &bits, 2); +		dev_dbg(dev, "%s - parity = SPACE\n", __func__); +		cflag &= ~PARODD; +		cflag |= (PARENB|CMSPAR);  		break;  	default: -		dbg("%s - Unknown parity mode, disabling parity", __func__); +		dev_dbg(dev, "%s - Unknown parity mode, disabling parity\n", __func__);  		cflag &= ~PARENB;  		bits &= ~BITS_PARITY_MASK;  		cp210x_set_config(port, CP210X_SET_LINE_CTL, &bits, 2); @@ -542,21 +577,19 @@ static void cp210x_get_termios_port(struct usb_serial_port *port,  	cflag &= ~CSTOPB;  	switch (bits & BITS_STOP_MASK) {  	case BITS_STOP_1: -		dbg("%s - stop bits = 1", __func__); +		dev_dbg(dev, "%s - stop bits = 1\n", __func__);  		break;  	case BITS_STOP_1_5: -		dbg("%s - stop bits = 1.5 (not supported, using 1 stop bit)", -								__func__); +		dev_dbg(dev, "%s - stop bits = 1.5 (not supported, using 1 stop bit)\n", __func__);  		bits &= ~BITS_STOP_MASK;  		cp210x_set_config(port, CP210X_SET_LINE_CTL, &bits, 2);  		break;  	case BITS_STOP_2: -		dbg("%s - stop bits = 2", __func__); +		dev_dbg(dev, "%s - stop bits = 2\n", __func__);  		cflag |= CSTOPB;  		break;  	default: -		dbg("%s - Unknown number of stop bits, using 1 stop bit", -								__func__); +		dev_dbg(dev, "%s - Unknown number of stop bits, using 1 stop bit\n", __func__);  		bits &= ~BITS_STOP_MASK;  		cp210x_set_config(port, CP210X_SET_LINE_CTL, &bits, 2);  		break; @@ -564,45 +597,82 @@ static void cp210x_get_termios_port(struct usb_serial_port *port,  	cp210x_get_config(port, CP210X_GET_FLOW, modem_ctl, 16);  	if (modem_ctl[0] & 0x0008) { -		dbg("%s - flow control = CRTSCTS", __func__); +		dev_dbg(dev, "%s - flow control = CRTSCTS\n", __func__);  		cflag |= CRTSCTS;  	} else { -		dbg("%s - flow control = NONE", __func__); +		dev_dbg(dev, "%s - flow control = NONE\n", __func__);  		cflag &= ~CRTSCTS;  	}  	*cflagp = cflag;  } +/* + * CP2101 supports the following baud rates: + * + *	300, 600, 1200, 1800, 2400, 4800, 7200, 9600, 14400, 19200, 28800, + *	38400, 56000, 57600, 115200, 128000, 230400, 460800, 921600 + * + * CP2102 and CP2103 support the following additional rates: + * + *	4000, 16000, 51200, 64000, 76800, 153600, 250000, 256000, 500000, + *	576000 + * + * The device will map a requested rate to a supported one, but the result + * of requests for rates greater than 1053257 is undefined (see AN205). + * + * CP2104, CP2105 and CP2110 support most rates up to 2M, 921k and 1M baud, + * respectively, with an error less than 1%. The actual rates are determined + * by + * + *	div = round(freq / (2 x prescale x request)) + *	actual = freq / (2 x prescale x div) + * + * For CP2104 and CP2105 freq is 48Mhz and prescale is 4 for request <= 365bps + * or 1 otherwise. + * For CP2110 freq is 24Mhz and prescale is 4 for request <= 300bps or 1 + * otherwise. + */ +static void cp210x_change_speed(struct tty_struct *tty, +		struct usb_serial_port *port, struct ktermios *old_termios) +{ +	u32 baud; + +	baud = tty->termios.c_ospeed; + +	/* This maps the requested rate to a rate valid on cp2102 or cp2103, +	 * or to an arbitrary rate in [1M,2M]. +	 * +	 * NOTE: B0 is not implemented. +	 */ +	baud = cp210x_quantise_baudrate(baud); + +	dev_dbg(&port->dev, "%s - setting baud rate to %u\n", __func__, baud); +	if (cp210x_set_config(port, CP210X_SET_BAUDRATE, &baud, +							sizeof(baud))) { +		dev_warn(&port->dev, "failed to set baud rate to %u\n", baud); +		if (old_termios) +			baud = old_termios->c_ospeed; +		else +			baud = 9600; +	} + +	tty_encode_baud_rate(tty, baud, baud); +} +  static void cp210x_set_termios(struct tty_struct *tty,  		struct usb_serial_port *port, struct ktermios *old_termios)  { +	struct device *dev = &port->dev;  	unsigned int cflag, old_cflag; -	unsigned int baud = 0, bits; +	unsigned int bits;  	unsigned int modem_ctl[4]; -	dbg("%s - port %d", __func__, port->number); - -	if (!tty) -		return; - -	tty->termios->c_cflag &= ~CMSPAR; -	cflag = tty->termios->c_cflag; +	cflag = tty->termios.c_cflag;  	old_cflag = old_termios->c_cflag; -	baud = cp210x_quantise_baudrate(tty_get_baud_rate(tty)); - -	/* If the baud rate is to be updated*/ -	if (baud != tty_termios_baud_rate(old_termios) && baud != 0) { -		dbg("%s - Setting baud rate to %d baud", __func__, -				baud); -		if (cp210x_set_config_single(port, CP210X_SET_BAUDDIV, -					((BAUD_RATE_GEN_FREQ + baud/2) / baud))) { -			dbg("Baud rate requested not supported by device"); -			baud = tty_termios_baud_rate(old_termios); -		} -	} -	/* Report back the resulting baud rate */ -	tty_encode_baud_rate(tty, baud, baud); + +	if (tty->termios.c_ospeed != old_termios->c_ospeed) +		cp210x_change_speed(tty, port, old_termios);  	/* If the number of data bits is to be updated */  	if ((cflag & CSIZE) != (old_cflag & CSIZE)) { @@ -611,51 +681,58 @@ static void cp210x_set_termios(struct tty_struct *tty,  		switch (cflag & CSIZE) {  		case CS5:  			bits |= BITS_DATA_5; -			dbg("%s - data bits = 5", __func__); +			dev_dbg(dev, "%s - data bits = 5\n", __func__);  			break;  		case CS6:  			bits |= BITS_DATA_6; -			dbg("%s - data bits = 6", __func__); +			dev_dbg(dev, "%s - data bits = 6\n", __func__);  			break;  		case CS7:  			bits |= BITS_DATA_7; -			dbg("%s - data bits = 7", __func__); +			dev_dbg(dev, "%s - data bits = 7\n", __func__);  			break;  		case CS8:  			bits |= BITS_DATA_8; -			dbg("%s - data bits = 8", __func__); +			dev_dbg(dev, "%s - data bits = 8\n", __func__);  			break;  		/*case CS9:  			bits |= BITS_DATA_9; -			dbg("%s - data bits = 9", __func__); +			dev_dbg(dev, "%s - data bits = 9\n", __func__);  			break;*/  		default: -			dbg("cp210x driver does not " -					"support the number of bits requested," -					" using 8 bit mode\n"); -				bits |= BITS_DATA_8; -				break; +			dev_dbg(dev, "cp210x driver does not support the number of bits requested, using 8 bit mode\n"); +			bits |= BITS_DATA_8; +			break;  		}  		if (cp210x_set_config(port, CP210X_SET_LINE_CTL, &bits, 2)) -			dbg("Number of data bits requested " -					"not supported by device\n"); +			dev_dbg(dev, "Number of data bits requested not supported by device\n");  	} -	if ((cflag & (PARENB|PARODD)) != (old_cflag & (PARENB|PARODD))) { +	if ((cflag     & (PARENB|PARODD|CMSPAR)) != +	    (old_cflag & (PARENB|PARODD|CMSPAR))) {  		cp210x_get_config(port, CP210X_GET_LINE_CTL, &bits, 2);  		bits &= ~BITS_PARITY_MASK;  		if (cflag & PARENB) { -			if (cflag & PARODD) { -				bits |= BITS_PARITY_ODD; -				dbg("%s - parity = ODD", __func__); +			if (cflag & CMSPAR) { +				if (cflag & PARODD) { +					bits |= BITS_PARITY_MARK; +					dev_dbg(dev, "%s - parity = MARK\n", __func__); +				} else { +					bits |= BITS_PARITY_SPACE; +					dev_dbg(dev, "%s - parity = SPACE\n", __func__); +				}  			} else { -				bits |= BITS_PARITY_EVEN; -				dbg("%s - parity = EVEN", __func__); +				if (cflag & PARODD) { +					bits |= BITS_PARITY_ODD; +					dev_dbg(dev, "%s - parity = ODD\n", __func__); +				} else { +					bits |= BITS_PARITY_EVEN; +					dev_dbg(dev, "%s - parity = EVEN\n", __func__); +				}  			}  		}  		if (cp210x_set_config(port, CP210X_SET_LINE_CTL, &bits, 2)) -			dbg("Parity mode not supported " -					"by device\n"); +			dev_dbg(dev, "Parity mode not supported by device\n");  	}  	if ((cflag & CSTOPB) != (old_cflag & CSTOPB)) { @@ -663,56 +740,53 @@ static void cp210x_set_termios(struct tty_struct *tty,  		bits &= ~BITS_STOP_MASK;  		if (cflag & CSTOPB) {  			bits |= BITS_STOP_2; -			dbg("%s - stop bits = 2", __func__); +			dev_dbg(dev, "%s - stop bits = 2\n", __func__);  		} else {  			bits |= BITS_STOP_1; -			dbg("%s - stop bits = 1", __func__); +			dev_dbg(dev, "%s - stop bits = 1\n", __func__);  		}  		if (cp210x_set_config(port, CP210X_SET_LINE_CTL, &bits, 2)) -			dbg("Number of stop bits requested " -					"not supported by device\n"); +			dev_dbg(dev, "Number of stop bits requested not supported by device\n");  	}  	if ((cflag & CRTSCTS) != (old_cflag & CRTSCTS)) {  		cp210x_get_config(port, CP210X_GET_FLOW, modem_ctl, 16); -		dbg("%s - read modem controls = 0x%.4x 0x%.4x 0x%.4x 0x%.4x", -				__func__, modem_ctl[0], modem_ctl[1], -				modem_ctl[2], modem_ctl[3]); +		dev_dbg(dev, "%s - read modem controls = 0x%.4x 0x%.4x 0x%.4x 0x%.4x\n", +			__func__, modem_ctl[0], modem_ctl[1], +			modem_ctl[2], modem_ctl[3]);  		if (cflag & CRTSCTS) {  			modem_ctl[0] &= ~0x7B;  			modem_ctl[0] |= 0x09;  			modem_ctl[1] = 0x80; -			dbg("%s - flow control = CRTSCTS", __func__); +			dev_dbg(dev, "%s - flow control = CRTSCTS\n", __func__);  		} else {  			modem_ctl[0] &= ~0x7B;  			modem_ctl[0] |= 0x01;  			modem_ctl[1] |= 0x40; -			dbg("%s - flow control = NONE", __func__); +			dev_dbg(dev, "%s - flow control = NONE\n", __func__);  		} -		dbg("%s - write modem controls = 0x%.4x 0x%.4x 0x%.4x 0x%.4x", -				__func__, modem_ctl[0], modem_ctl[1], -				modem_ctl[2], modem_ctl[3]); +		dev_dbg(dev, "%s - write modem controls = 0x%.4x 0x%.4x 0x%.4x 0x%.4x\n", +			__func__, modem_ctl[0], modem_ctl[1], +			modem_ctl[2], modem_ctl[3]);  		cp210x_set_config(port, CP210X_SET_FLOW, modem_ctl, 16);  	}  } -static int cp210x_tiocmset (struct tty_struct *tty, struct file *file, +static int cp210x_tiocmset(struct tty_struct *tty,  		unsigned int set, unsigned int clear)  {  	struct usb_serial_port *port = tty->driver_data; -	return cp210x_tiocmset_port(port, file, set, clear); +	return cp210x_tiocmset_port(port, set, clear);  } -static int cp210x_tiocmset_port(struct usb_serial_port *port, struct file *file, +static int cp210x_tiocmset_port(struct usb_serial_port *port,  		unsigned int set, unsigned int clear)  {  	unsigned int control = 0; -	dbg("%s - port %d", __func__, port->number); -  	if (set & TIOCM_RTS) {  		control |= CONTROL_RTS;  		control |= CONTROL_WRITE_RTS; @@ -730,7 +804,7 @@ static int cp210x_tiocmset_port(struct usb_serial_port *port, struct file *file,  		control |= CONTROL_WRITE_DTR;  	} -	dbg("%s - control = 0x%.4x", __func__, control); +	dev_dbg(&port->dev, "%s - control = 0x%.4x\n", __func__, control);  	return cp210x_set_config(port, CP210X_SET_MHS, &control, 2);  } @@ -738,19 +812,17 @@ static int cp210x_tiocmset_port(struct usb_serial_port *port, struct file *file,  static void cp210x_dtr_rts(struct usb_serial_port *p, int on)  {  	if (on) -		cp210x_tiocmset_port(p, NULL,  TIOCM_DTR|TIOCM_RTS, 0); +		cp210x_tiocmset_port(p, TIOCM_DTR|TIOCM_RTS, 0);  	else -		cp210x_tiocmset_port(p, NULL,  0, TIOCM_DTR|TIOCM_RTS); +		cp210x_tiocmset_port(p, 0, TIOCM_DTR|TIOCM_RTS);  } -static int cp210x_tiocmget (struct tty_struct *tty, struct file *file) +static int cp210x_tiocmget(struct tty_struct *tty)  {  	struct usb_serial_port *port = tty->driver_data;  	unsigned int control;  	int result; -	dbg("%s - port %d", __func__, port->number); -  	cp210x_get_config(port, CP210X_GET_MDMSTS, &control, 1);  	result = ((control & CONTROL_DTR) ? TIOCM_DTR : 0) @@ -760,75 +832,54 @@ static int cp210x_tiocmget (struct tty_struct *tty, struct file *file)  		|((control & CONTROL_RING)? TIOCM_RI  : 0)  		|((control & CONTROL_DCD) ? TIOCM_CD  : 0); -	dbg("%s - control = 0x%.2x", __func__, control); +	dev_dbg(&port->dev, "%s - control = 0x%.2x\n", __func__, control);  	return result;  } -static int cp210x_carrier_raised(struct usb_serial_port *p) -{ -	unsigned int control; -	cp210x_get_config(p, CP210X_GET_MDMSTS, &control, 1); -	if (control & CONTROL_DCD) -		return 1; -	return 0; -} - -static void cp210x_break_ctl (struct tty_struct *tty, int break_state) +static void cp210x_break_ctl(struct tty_struct *tty, int break_state)  {  	struct usb_serial_port *port = tty->driver_data;  	unsigned int state; -	dbg("%s - port %d", __func__, port->number);  	if (break_state == 0)  		state = BREAK_OFF;  	else  		state = BREAK_ON; -	dbg("%s - turning break %s", __func__, -			state == BREAK_OFF ? "off" : "on"); +	dev_dbg(&port->dev, "%s - turning break %s\n", __func__, +		state == BREAK_OFF ? "off" : "on");  	cp210x_set_config(port, CP210X_SET_BREAK, &state, 2);  }  static int cp210x_startup(struct usb_serial *serial)  { +	struct usb_host_interface *cur_altsetting; +	struct cp210x_serial_private *spriv; +  	/* cp210x buffers behave strangely unless device is reset */  	usb_reset_device(serial->dev); -	return 0; -} -static int __init cp210x_init(void) -{ -	int retval; +	spriv = kzalloc(sizeof(*spriv), GFP_KERNEL); +	if (!spriv) +		return -ENOMEM; -	retval = usb_serial_register(&cp210x_device); -	if (retval) -		return retval; /* Failed to register */ +	cur_altsetting = serial->interface->cur_altsetting; +	spriv->bInterfaceNumber = cur_altsetting->desc.bInterfaceNumber; -	retval = usb_register(&cp210x_driver); -	if (retval) { -		/* Failed to register */ -		usb_serial_deregister(&cp210x_device); -		return retval; -	} +	usb_set_serial_data(serial, spriv); -	/* Success */ -	printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_VERSION ":" -	       DRIVER_DESC "\n");  	return 0;  } -static void __exit cp210x_exit(void) +static void cp210x_release(struct usb_serial *serial)  { -	usb_deregister(&cp210x_driver); -	usb_serial_deregister(&cp210x_device); +	struct cp210x_serial_private *spriv; + +	spriv = usb_get_serial_data(serial); +	kfree(spriv);  } -module_init(cp210x_init); -module_exit(cp210x_exit); +module_usb_serial_driver(serial_drivers, id_table);  MODULE_DESCRIPTION(DRIVER_DESC); -MODULE_VERSION(DRIVER_VERSION);  MODULE_LICENSE("GPL"); - -module_param(debug, bool, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(debug, "Enable verbose debugging messages");  | 
