[PATCH] USB: CP2101 Add support for flow control

Added support to get/set flow control line levels using TIOCMGET and
TIOCMSET.
Added support for RTSCTS hardware flow control.
cp2101_get_config and cp2101_set_config modified to support long request
strings, required for configuring flow control.

Signed-off-by: Craig Shelley craig@microtron.org.uk
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
diff --git a/drivers/usb/serial/cp2101.c b/drivers/usb/serial/cp2101.c
index 7e9bb63..4ace996 100644
--- a/drivers/usb/serial/cp2101.c
+++ b/drivers/usb/serial/cp2101.c
@@ -7,6 +7,14 @@
  *	modify it under the terms of the GNU General Public License version
  *	2 as published by the Free Software Foundation.
  *
+ * Support to set flow control line levels using TIOCMGET and TIOCMSET
+ * thanks to Karl Hiramoto karl@hiramoto.org. RTSCTS hardware flow
+ * control thanks to Munir Nassar nassarmu@real-time.com
+ *
+ * Outstanding Issues:
+ *  Buffers are not flushed when the port is opened.
+ *  Multiple calls to write() may fail with "Resource temporarily unavailable"
+ *
  */
 
 #include <linux/config.h>
@@ -24,7 +32,7 @@
 /*
  * Version Information
  */
-#define DRIVER_VERSION "v0.03"
+#define DRIVER_VERSION "v0.04"
 #define DRIVER_DESC "Silicon Labs CP2101/CP2102 RS232 serial adaptor driver"
 
 /*
@@ -35,6 +43,9 @@
 static void cp2101_close(struct usb_serial_port*, struct file*);
 static void cp2101_get_termios(struct usb_serial_port*);
 static void cp2101_set_termios(struct usb_serial_port*, struct termios*);
+static int cp2101_tiocmget (struct usb_serial_port *, struct file *);
+static int cp2101_tiocmset (struct usb_serial_port *, struct file *,
+		unsigned int, unsigned int);
 static void cp2101_break_ctl(struct usb_serial_port*, int);
 static int cp2101_startup (struct usb_serial *);
 static void cp2101_shutdown(struct usb_serial*);
@@ -43,9 +54,10 @@
 static int debug;
 
 static struct usb_device_id id_table [] = {
-	{USB_DEVICE(0x10c4, 0xea60) },	/*Silicon labs factory default*/
-	{USB_DEVICE(0x10ab, 0x10c5) },	/*Siemens MC60 Cable*/
-	{ } /* Terminating Entry*/
+	{ USB_DEVICE(0x10C4, 0xEA60) },	/* Silicon Labs factory default */
+	{ USB_DEVICE(0x10C4, 0x80CA) },	/* Degree Controls Inc */
+	{ USB_DEVICE(0x10AB, 0x10C5) },	/* Siemens MC60 Cable */
+	{ } /* Terminating Entry */
 };
 
 MODULE_DEVICE_TABLE (usb, id_table);
@@ -70,32 +82,35 @@
 	.close			= cp2101_close,
 	.break_ctl		= cp2101_break_ctl,
 	.set_termios		= cp2101_set_termios,
+	.tiocmget 		= cp2101_tiocmget,
+	.tiocmset		= cp2101_tiocmset,
 	.attach			= cp2101_startup,
 	.shutdown		= cp2101_shutdown,
 };
 
-/*Config request types*/
+/* Config request types */
 #define REQTYPE_HOST_TO_DEVICE	0x41
 #define REQTYPE_DEVICE_TO_HOST	0xc1
 
-/*Config SET requests. To GET, add 1 to the request number*/
-#define CP2101_UART 		0x00	/*Enable / Disable*/
-#define CP2101_BAUDRATE		0x01	/*(BAUD_RATE_GEN_FREQ / baudrate)*/
-#define CP2101_BITS		0x03	/*0x(0)(data bits)(parity)(stop bits)*/
-#define CP2101_BREAK		0x05	/*On / Off*/
-#define CP2101_DTRRTS		0x07	/*101 / 202  ???*/
-#define CP2101_CONFIG_16	0x13	/*16 bytes of config data ???*/
-#define CP2101_CONFIG_6		0x19	/*6 bytes of config data ???*/
+/* Config SET requests. To GET, add 1 to the request number */
+#define CP2101_UART 		0x00	/* Enable / Disable */
+#define CP2101_BAUDRATE		0x01	/* (BAUD_RATE_GEN_FREQ / baudrate) */
+#define CP2101_BITS		0x03	/* 0x(0)(databits)(parity)(stopbits) */
+#define CP2101_BREAK		0x05	/* On / Off */
+#define CP2101_CONTROL		0x07	/* Flow control line states */
+#define CP2101_MODEMCTL		0x13	/* Modem controls */
+#define CP2101_CONFIG_6		0x19	/* 6 bytes of config data ??? */
 
-/*CP2101_UART*/
+/* CP2101_UART */
 #define UART_ENABLE		0x0001
 #define UART_DISABLE		0x0000
 
-/*CP2101_BAUDRATE*/
+/* CP2101_BAUDRATE */
 #define BAUD_RATE_GEN_FREQ	0x384000
 
-/*CP2101_BITS*/
+/* CP2101_BITS */
 #define BITS_DATA_MASK		0X0f00
+#define BITS_DATA_5		0X0500
 #define BITS_DATA_6		0X0600
 #define BITS_DATA_7		0X0700
 #define BITS_DATA_8		0X0800
@@ -112,64 +127,137 @@
 #define BITS_STOP_1		0x0000
 #define BITS_STOP_1_5		0x0001
 #define BITS_STOP_2		0x0002
+
+/* CP2101_BREAK */
 #define BREAK_ON		0x0000
 #define BREAK_OFF		0x0001
 
+/* CP2101_CONTROL */
+#define CONTROL_DTR		0x0001
+#define CONTROL_RTS		0x0002
+#define CONTROL_CTS		0x0010
+#define CONTROL_DSR		0x0020
+#define CONTROL_RING		0x0040
+#define CONTROL_DCD		0x0080
+#define CONTROL_WRITE_DTR	0x0100
+#define CONTROL_WRITE_RTS	0x0200
 
-static int cp2101_get_config(struct usb_serial_port* port, u8 request)
+/*
+ * cp2101_get_config
+ * Reads from the CP2101 configuration registers
+ * 'size' is specified in bytes.
+ * 'data' is a pointer to a pre-allocated array of integers large
+ * enough to hold 'size' bytes (with 4 bytes to each integer)
+ */
+static int cp2101_get_config(struct usb_serial_port* port, u8 request,
+		unsigned int *data, int size)
 {
 	struct usb_serial *serial = port->serial;
-	unsigned char buf[4];
-	unsigned int value;
-	int result, i;
+	u32 *buf;
+	int result, i, length;
 
-	/*For get requests, the request number must be incremented*/
+	/* Number of integers required to contain the array */
+	length = (((size - 1) | 3) + 1)/4;
+
+	buf = kmalloc (length * sizeof(u32), GFP_KERNEL);
+	memset(buf, 0, length * sizeof(u32));
+
+	if (!buf) {
+		dev_err(&port->dev, "%s - out of memory.\n", __FUNCTION__);
+		return -ENOMEM;
+	}
+
+	/* For get requests, the request number must be incremented */
 	request++;
 
-	/*Issue the request, attempting to read 4 bytes*/
+	/* 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, 4, 300);
+				0, buf, size, 300);
 
-	if (result < 0) {
+	/* Convert data into an array of integers */
+	for (i=0; i<length; i++)
+		data[i] = le32_to_cpu(buf[i]);
+
+	kfree(buf);
+
+	if (result != size) {
 		dev_err(&port->dev, "%s - Unable to send config request, "
-				"request=0x%x result=%d\n",
-				__FUNCTION__, request, result);
-		return result;
+				"request=0x%x size=%d result=%d\n",
+				__FUNCTION__, request, size, result);
+		return -EPROTO;
 	}
 
-	/*Assemble each byte read into an integer value*/
-	value = 0;
-	for (i=0; i<4 && i<result; i++)
-		value |= (buf[i] << (i * 8));
-
-	dbg( " %s - request=0x%x result=%d value=0x%x",
-			__FUNCTION__, request, result, value);
-
-	return value;
-}
-
-static int cp2101_set_config(struct usb_serial_port* port, u8 request, u16 value)
-{
-	struct usb_serial *serial = port->serial;
-	int result;
-	result = usb_control_msg (serial->dev, usb_sndctrlpipe(serial->dev, 0),
-			request, REQTYPE_HOST_TO_DEVICE, value,
-			0, NULL, 0, 300);
-
-	if (result <0) {
-		dev_err(&port->dev, "%s - Unable to send config request, "
-				"request=0x%x value=0x%x result=%d\n",
-				__FUNCTION__, request, value, result);
-		return result;
-	}
-
-	dbg(" %s - request=0x%x value=0x%x result=%d",
-			__FUNCTION__, request, value, result);
-
 	return 0;
 }
 
+/*
+ * cp2101_set_config
+ * Writes to the CP2101 configuration registers
+ * Values less than 16 bits wide are sent directly
+ * 'size' is specified in bytes.
+ */
+static int cp2101_set_config(struct usb_serial_port* port, u8 request,
+		unsigned int *data, int size)
+{
+	struct usb_serial *serial = port->serial;
+	u32 *buf;
+	int result, i, length;
+
+	/* Number of integers required to contain the array */
+	length = (((size - 1) | 3) + 1)/4;
+
+	buf = kmalloc(length * sizeof(u32), GFP_KERNEL);
+	if (!buf) {
+		dev_err(&port->dev, "%s - out of memory.\n",
+				__FUNCTION__);
+		return -ENOMEM;
+	}
+
+	/* Array of integers into bytes */
+	for (i = 0; i < length; i++)
+		buf[i] = cpu_to_le32(data[i]);
+
+	if (size > 2) {
+		result = usb_control_msg (serial->dev,
+				usb_sndctrlpipe(serial->dev, 0),
+				request, REQTYPE_HOST_TO_DEVICE, 0x0000,
+				0, buf, size, 300);
+	} else {
+		result = usb_control_msg (serial->dev,
+				usb_sndctrlpipe(serial->dev, 0),
+				request, REQTYPE_HOST_TO_DEVICE, data[0],
+				0, NULL, 0, 300);
+	}
+
+	kfree(buf);
+
+	if ((size > 2 && result != size) || result < 0) {
+		dev_err(&port->dev, "%s - Unable to send request, "
+				"request=0x%x size=%d result=%d\n",
+				__FUNCTION__, request, size, result);
+		return -EPROTO;
+	}
+
+	/* Single data value */
+	result = usb_control_msg (serial->dev,
+			usb_sndctrlpipe(serial->dev, 0),
+			request, REQTYPE_HOST_TO_DEVICE, data[0],
+			0, NULL, 0, 300);
+	return 0;
+}
+
+/*
+ * cp2101_set_config_single
+ * Convenience function for calling cp2101_set_config on single data values
+ * without requiring an integer pointer
+ */
+static inline int cp2101_set_config_single(struct usb_serial_port* port,
+		u8 request, unsigned int data)
+{
+	return cp2101_set_config(port, request, &data, 2);
+}
+
 static int cp2101_open (struct usb_serial_port *port, struct file *filp)
 {
 	struct usb_serial *serial = port->serial;
@@ -177,7 +265,7 @@
 
 	dbg("%s - port %d", __FUNCTION__, port->number);
 
-	if (cp2101_set_config(port, CP2101_UART, UART_ENABLE)) {
+	if (cp2101_set_config_single(port, CP2101_UART, UART_ENABLE)) {
 		dev_err(&port->dev, "%s - Unable to enable UART\n",
 				__FUNCTION__);
 		return -EPROTO;
@@ -198,9 +286,12 @@
 		return result;
 	}
 
-	/*Configure the termios structure*/
+	/* Configure the termios structure */
 	cp2101_get_termios(port);
 
+	/* Set the DTR and RTS pins low */
+	cp2101_tiocmset(port, NULL, TIOCM_DTR | TIOCM_RTS, 0);
+
 	return 0;
 }
 
@@ -228,16 +319,18 @@
 	usb_kill_urb(port->write_urb);
 	usb_kill_urb(port->read_urb);
 
-	cp2101_set_config(port, CP2101_UART, UART_DISABLE);
+	cp2101_set_config_single(port, CP2101_UART, UART_DISABLE);
 }
 
-/* cp2101_get_termios*/
-/* Reads the baud rate, data bits, parity and stop bits from the device*/
-/* Corrects any unsupported values*/
-/* Configures the termios structure to reflect the state of the device*/
+/*
+ * cp2101_get_termios
+ * Reads the baud rate, data bits, parity, stop bits and flow control mode
+ * from the device, corrects any unsupported values, and configures the
+ * termios structure to reflect the state of the device
+ */
 static void cp2101_get_termios (struct usb_serial_port *port)
 {
-	unsigned int cflag;
+	unsigned int cflag, modem_ctl[4];
 	int baud;
 	int bits;
 
@@ -249,15 +342,16 @@
 	}
 	cflag = port->tty->termios->c_cflag;
 
-	baud = cp2101_get_config(port, CP2101_BAUDRATE);
-	/*Convert to baudrate*/
+	cp2101_get_config(port, CP2101_BAUDRATE, &baud, 2);
+	/* Convert to baudrate */
 	if (baud)
 		baud = BAUD_RATE_GEN_FREQ / baud;
 
 	dbg("%s - baud rate = %d", __FUNCTION__, baud);
 	cflag &= ~CBAUD;
 	switch (baud) {
-		/* The baud rates which are commented out below
+		/*
+		 * The baud rates which are commented out below
 		 * appear to be supported by the device
 		 * but are non-standard
 		 */
@@ -284,14 +378,18 @@
 			dbg("%s - Baud rate is not supported, "
 					"using 9600 baud", __FUNCTION__);
 			cflag |= B9600;
-			cp2101_set_config(port, CP2101_BAUDRATE,
+			cp2101_set_config_single(port, CP2101_BAUDRATE,
 					(BAUD_RATE_GEN_FREQ/9600));
 			break;
 	}
 
-	bits = cp2101_get_config(port, CP2101_BITS);
+	cp2101_get_config(port, CP2101_BITS, &bits, 2);
 	cflag &= ~CSIZE;
 	switch(bits & BITS_DATA_MASK) {
+		case BITS_DATA_5:
+			dbg("%s - data bits = 5", __FUNCTION__);
+			cflag |= CS5;
+			break;
 		case BITS_DATA_6:
 			dbg("%s - data bits = 6", __FUNCTION__);
 			cflag |= CS6;
@@ -310,7 +408,7 @@
 			cflag |= CS8;
 			bits &= ~BITS_DATA_MASK;
 			bits |= BITS_DATA_8;
-			cp2101_set_config(port, CP2101_BITS, bits);
+			cp2101_set_config(port, CP2101_BITS, &bits, 2);
 			break;
 		default:
 			dbg("%s - Unknown number of data bits, "
@@ -318,7 +416,7 @@
 			cflag |= CS8;
 			bits &= ~BITS_DATA_MASK;
 			bits |= BITS_DATA_8;
-			cp2101_set_config(port, CP2101_BITS, bits);
+			cp2101_set_config(port, CP2101_BITS, &bits, 2);
 			break;
 	}
 
@@ -341,21 +439,21 @@
 					"disabling parity)", __FUNCTION__);
 			cflag &= ~PARENB;
 			bits &= ~BITS_PARITY_MASK;
-			cp2101_set_config(port, CP2101_BITS, bits);
+			cp2101_set_config(port, CP2101_BITS, &bits, 2);
 			break;
 		case BITS_PARITY_SPACE:
 			dbg("%s - parity = SPACE (not supported, "
 					"disabling parity)", __FUNCTION__);
 			cflag &= ~PARENB;
 			bits &= ~BITS_PARITY_MASK;
-			cp2101_set_config(port, CP2101_BITS, bits);
+			cp2101_set_config(port, CP2101_BITS, &bits, 2);
 			break;
 		default:
 			dbg("%s - Unknown parity mode, "
 					"disabling parity", __FUNCTION__);
 			cflag &= ~PARENB;
 			bits &= ~BITS_PARITY_MASK;
-			cp2101_set_config(port, CP2101_BITS, bits);
+			cp2101_set_config(port, CP2101_BITS, &bits, 2);
 			break;
 	}
 
@@ -366,9 +464,9 @@
 			break;
 		case BITS_STOP_1_5:
 			dbg("%s - stop bits = 1.5 (not supported, "
-					"using 1 stop bit", __FUNCTION__);
+					"using 1 stop bit)", __FUNCTION__);
 			bits &= ~BITS_STOP_MASK;
-			cp2101_set_config(port, CP2101_BITS, bits);
+			cp2101_set_config(port, CP2101_BITS, &bits, 2);
 			break;
 		case BITS_STOP_2:
 			dbg("%s - stop bits = 2", __FUNCTION__);
@@ -378,10 +476,19 @@
 			dbg("%s - Unknown number of stop bits, "
 					"using 1 stop bit", __FUNCTION__);
 			bits &= ~BITS_STOP_MASK;
-			cp2101_set_config(port, CP2101_BITS, bits);
+			cp2101_set_config(port, CP2101_BITS, &bits, 2);
 			break;
 	}
 
+	cp2101_get_config(port, CP2101_MODEMCTL, modem_ctl, 16);
+	if (modem_ctl[0] & 0x0008) {
+		dbg("%s - flow control = CRTSCTS", __FUNCTION__);
+		cflag |= CRTSCTS;
+	} else {
+		dbg("%s - flow control = NONE", __FUNCTION__);
+		cflag &= ~CRTSCTS;
+	}
+
 	port->tty->termios->c_cflag = cflag;
 }
 
@@ -389,8 +496,8 @@
 		struct termios *old_termios)
 {
 	unsigned int cflag, old_cflag=0;
-	int baud=0;
-	int bits;
+	int baud=0, bits;
+	unsigned int modem_ctl[4];
 
 	dbg("%s - port %d", __FUNCTION__, port->number);
 
@@ -400,7 +507,7 @@
 	}
 	cflag = port->tty->termios->c_cflag;
 
-	/* check that they really want us to change something */
+	/* Check that they really want us to change something */
 	if (old_termios) {
 		if ((cflag == old_termios->c_cflag) &&
 				(RELEVANT_IFLAG(port->tty->termios->c_iflag)
@@ -415,7 +522,8 @@
 	/* If the baud rate is to be updated*/
 	if ((cflag & CBAUD) != (old_cflag & CBAUD)) {
 		switch (cflag & CBAUD) {
-			/* The baud rates which are commented out below
+			/*
+			 * The baud rates which are commented out below
 			 * appear to be supported by the device
 			 * but are non-standard
 			 */
@@ -448,18 +556,22 @@
 		if (baud) {
 			dbg("%s - Setting baud rate to %d baud", __FUNCTION__,
 					baud);
-			if (cp2101_set_config(port, CP2101_BAUDRATE,
+			if (cp2101_set_config_single(port, CP2101_BAUDRATE,
 						(BAUD_RATE_GEN_FREQ / baud)))
 				dev_err(&port->dev, "Baud rate requested not "
 						"supported by device\n");
 		}
 	}
 
-	/*If the number of data bits is to be updated*/
+	/* If the number of data bits is to be updated */
 	if ((cflag & CSIZE) != (old_cflag & CSIZE)) {
-		bits = cp2101_get_config(port, CP2101_BITS);
+		cp2101_get_config(port, CP2101_BITS, &bits, 2);
 		bits &= ~BITS_DATA_MASK;
 		switch (cflag & CSIZE) {
+			case CS5:
+				bits |= BITS_DATA_5;
+				dbg("%s - data bits = 5", __FUNCTION__);
+				break;
 			case CS6:
 				bits |= BITS_DATA_6;
 				dbg("%s - data bits = 6", __FUNCTION__);
@@ -483,13 +595,13 @@
 				bits |= BITS_DATA_8;
 				break;
 		}
-		if (cp2101_set_config(port, CP2101_BITS, bits))
+		if (cp2101_set_config(port, CP2101_BITS, &bits, 2))
 			dev_err(&port->dev, "Number of data bits requested "
 					"not supported by device\n");
 	}
 
 	if ((cflag & (PARENB|PARODD)) != (old_cflag & (PARENB|PARODD))) {
-		bits = cp2101_get_config(port, CP2101_BITS);
+		cp2101_get_config(port, CP2101_BITS, &bits, 2);
 		bits &= ~BITS_PARITY_MASK;
 		if (cflag & PARENB) {
 			if (cflag & PARODD) {
@@ -500,13 +612,13 @@
 				dbg("%s - parity = EVEN", __FUNCTION__);
 			}
 		}
-		if (cp2101_set_config(port, CP2101_BITS, bits))
+		if (cp2101_set_config(port, CP2101_BITS, &bits, 2))
 			dev_err(&port->dev, "Parity mode not supported "
 					"by device\n");
 	}
 
 	if ((cflag & CSTOPB) != (old_cflag & CSTOPB)) {
-		bits = cp2101_get_config(port, CP2101_BITS);
+		cp2101_get_config(port, CP2101_BITS, &bits, 2);
 		bits &= ~BITS_STOP_MASK;
 		if (cflag & CSTOPB) {
 			bits |= BITS_STOP_2;
@@ -515,15 +627,90 @@
 			bits |= BITS_STOP_1;
 			dbg("%s - stop bits = 1", __FUNCTION__);
 		}
-		if (cp2101_set_config(port, CP2101_BITS, bits))
+		if (cp2101_set_config(port, CP2101_BITS, &bits, 2))
 			dev_err(&port->dev, "Number of stop bits requested "
 					"not supported by device\n");
 	}
+
+	if ((cflag & CRTSCTS) != (old_cflag & CRTSCTS)) {
+		cp2101_get_config(port, CP2101_MODEMCTL, modem_ctl, 16);
+		dbg("%s - read modem controls = 0x%.4x 0x%.4x 0x%.4x 0x%.4x",
+				__FUNCTION__, 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", __FUNCTION__);
+		} else {
+			modem_ctl[0] &= ~0x7B;
+			modem_ctl[0] |= 0x01;
+			modem_ctl[1] |= 0x40;
+			dbg("%s - flow control = NONE", __FUNCTION__);
+		}
+
+		dbg("%s - write modem controls = 0x%.4x 0x%.4x 0x%.4x 0x%.4x",
+				__FUNCTION__, modem_ctl[0], modem_ctl[1],
+				modem_ctl[2], modem_ctl[3]);
+		cp2101_set_config(port, CP2101_MODEMCTL, modem_ctl, 16);
+	}
+
+}
+
+static int cp2101_tiocmset (struct usb_serial_port *port, struct file *file,
+		unsigned int set, unsigned int clear)
+{
+	int control = 0;
+
+	dbg("%s - port %d", __FUNCTION__, port->number);
+
+	if (set & TIOCM_RTS) {
+		control |= CONTROL_RTS;
+		control |= CONTROL_WRITE_RTS;
+	}
+	if (set & TIOCM_DTR) {
+		control |= CONTROL_DTR;
+		control |= CONTROL_WRITE_DTR;
+	}
+	if (clear & TIOCM_RTS) {
+		control &= ~CONTROL_RTS;
+		control |= CONTROL_WRITE_RTS;
+	}
+	if (clear & TIOCM_DTR) {
+		control &= ~CONTROL_DTR;
+		control |= CONTROL_WRITE_DTR;
+	}
+
+	dbg("%s - control = 0x%.4x", __FUNCTION__, control);
+
+	return cp2101_set_config(port, CP2101_CONTROL, &control, 2);
+
+}
+
+static int cp2101_tiocmget (struct usb_serial_port *port, struct file *file)
+{
+	int control, result;
+
+	dbg("%s - port %d", __FUNCTION__, port->number);
+
+	cp2101_get_config(port, CP2101_CONTROL, &control, 1);
+
+	result = ((control & CONTROL_DTR) ? TIOCM_DTR : 0)
+		|((control & CONTROL_RTS) ? TIOCM_RTS : 0)
+		|((control & CONTROL_CTS) ? TIOCM_CTS : 0)
+		|((control & CONTROL_DSR) ? TIOCM_DSR : 0)
+		|((control & CONTROL_RING)? TIOCM_RI  : 0)
+		|((control & CONTROL_DCD) ? TIOCM_CD  : 0);
+
+	dbg("%s - control = 0x%.2x", __FUNCTION__, control);
+
+	return result;
 }
 
 static void cp2101_break_ctl (struct usb_serial_port *port, int break_state)
 {
-	u16 state;
+	int state;
 
 	dbg("%s - port %d", __FUNCTION__, port->number);
 	if (break_state == 0)
@@ -532,12 +719,12 @@
 		state = BREAK_ON;
 	dbg("%s - turning break %s", __FUNCTION__,
 			state==BREAK_OFF ? "off" : "on");
-	cp2101_set_config(port, CP2101_BREAK, state);
+	cp2101_set_config(port, CP2101_BREAK, &state, 2);
 }
 
 static int cp2101_startup (struct usb_serial *serial)
 {
-	/*CP2101 buffers behave strangely unless device is reset*/
+	/* CP2101 buffers behave strangely unless device is reset */
 	usb_reset_device(serial->dev);
 	return 0;
 }
@@ -548,7 +735,7 @@
 
 	dbg("%s", __FUNCTION__);
 
-	/* stop reads and writes on all ports */
+	/* Stop reads and writes on all ports */
 	for (i=0; i < serial->num_ports; ++i) {
 		cp2101_cleanup(serial->port[i]);
 	}
@@ -560,16 +747,16 @@
 
 	retval = usb_serial_register(&cp2101_device);
 	if (retval)
-		return retval; /*Failed to register*/
+		return retval; /* Failed to register */
 
 	retval = usb_register(&cp2101_driver);
 	if (retval) {
-		/*Failed to register*/
+		/* Failed to register */
 		usb_serial_deregister(&cp2101_device);
 		return retval;
 	}
 
-	/*Success*/
+	/* Success */
 	info(DRIVER_DESC " " DRIVER_VERSION);
 	return 0;
 }