[PATCH] USB: cypress_m8: add support for the Nokia ca42-version 2 cable

This patch adds support for the Nokia ca42 version 2 cable to the
cypress_m8 driver.  The device was tested by others with this patch and
found to be compatible with the cypress_m8 driver.  A special note
should be taken that this cable seems to vary in the type of chipset
used.  This patch supports the cable with product id 0x4101.

Signed-off-by: Lonnie Mendez <lmendez19@austin.rr.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
diff --git a/drivers/usb/serial/cypress_m8.c b/drivers/usb/serial/cypress_m8.c
index 71af3bf..7212fbe 100644
--- a/drivers/usb/serial/cypress_m8.c
+++ b/drivers/usb/serial/cypress_m8.c
@@ -98,10 +98,16 @@
 	{ }						/* Terminating entry */
 };
 
+static struct usb_device_id id_table_nokiaca42v2 [] = {
+	{ USB_DEVICE(VENDOR_ID_DAZZLE, PRODUCT_ID_CA42) },
+	{ }						/* Terminating entry */
+};
+
 static struct usb_device_id id_table_combined [] = {
 	{ USB_DEVICE(VENDOR_ID_DELORME, PRODUCT_ID_EARTHMATEUSB) },
 	{ USB_DEVICE(VENDOR_ID_DELORME, PRODUCT_ID_EARTHMATEUSB_LT20) },
 	{ USB_DEVICE(VENDOR_ID_CYPRESS, PRODUCT_ID_CYPHIDCOM) },
+	{ USB_DEVICE(VENDOR_ID_DAZZLE, PRODUCT_ID_CA42) },
 	{ }						/* Terminating entry */
 };
 
@@ -149,6 +155,7 @@
 /* function prototypes for the Cypress USB to serial device */
 static int  cypress_earthmate_startup	(struct usb_serial *serial);
 static int  cypress_hidcom_startup	(struct usb_serial *serial);
+static int  cypress_ca42v2_startup	(struct usb_serial *serial);
 static void cypress_shutdown		(struct usb_serial *serial);
 static int  cypress_open		(struct usb_serial_port *port, struct file *filp);
 static void cypress_close		(struct usb_serial_port *port, struct file *filp);
@@ -235,6 +242,34 @@
 	.write_int_callback =		cypress_write_int_callback,
 };
 
+static struct usb_serial_driver cypress_ca42v2_device = {
+	.driver = {
+		.owner =		THIS_MODULE,
+                .name =			"nokiaca42v2",
+	},
+	.description =			"Nokia CA-42 V2 Adapter",
+	.id_table =			id_table_nokiaca42v2,
+	.num_interrupt_in =		1,
+	.num_interrupt_out =		1,
+	.num_bulk_in =			NUM_DONT_CARE,
+	.num_bulk_out =			NUM_DONT_CARE,
+	.num_ports =			1,
+	.attach =			cypress_ca42v2_startup,
+	.shutdown =			cypress_shutdown,
+	.open =				cypress_open,
+	.close =			cypress_close,
+	.write =			cypress_write,
+	.write_room =			cypress_write_room,
+	.ioctl =			cypress_ioctl,
+	.set_termios =			cypress_set_termios,
+	.tiocmget =			cypress_tiocmget,
+	.tiocmset =			cypress_tiocmset,
+	.chars_in_buffer =		cypress_chars_in_buffer,
+	.throttle =			cypress_throttle,
+	.unthrottle =			cypress_unthrottle,
+	.read_int_callback =		cypress_read_int_callback,
+	.write_int_callback =		cypress_write_int_callback,
+};
 
 /*****************************************************************************
  * Cypress serial helper functions
@@ -286,6 +321,12 @@
 						    __FUNCTION__);
 						new_baudrate = priv->baud_rate;
 					}
+				} else if (priv->chiptype == CT_CA42V2) {
+					if ( (new_baudrate = mask_to_rate(baud_mask)) == -1) {
+						err("%s - failed setting baud rate, unsupported speed",
+						    __FUNCTION__);
+						new_baudrate = priv->baud_rate;
+					}
 				} else if (priv->chiptype == CT_GENERIC) {
 					if ( (new_baudrate = mask_to_rate(baud_mask)) == -1) {
 						err("%s - failed setting baud rate, unsupported speed",
@@ -499,6 +540,25 @@
 } /* cypress_hidcom_startup */
 
 
+static int cypress_ca42v2_startup (struct usb_serial *serial)
+{
+	struct cypress_private *priv;
+
+	dbg("%s", __FUNCTION__);
+
+	if (generic_startup(serial)) {
+		dbg("%s - Failed setting up port %d", __FUNCTION__,
+				serial->port[0]->number);
+		return 1;
+	}
+
+	priv = usb_get_serial_port_data(serial->port[0]);
+	priv->chiptype = CT_CA42V2;
+
+	return 0;
+} /* cypress_ca42v2_startup */
+
+
 static void cypress_shutdown (struct usb_serial *serial)
 {
 	struct cypress_private *priv;
@@ -943,6 +1003,10 @@
 			*(tty->termios) = tty_std_termios;
 			tty->termios->c_cflag = B9600 | CS8 | CREAD | HUPCL |
 				CLOCAL;
+		} else if (priv->chiptype == CT_CA42V2) {
+			*(tty->termios) = tty_std_termios;
+			tty->termios->c_cflag = B9600 | CS8 | CREAD | HUPCL |
+				CLOCAL;
 		}
 		priv->termios_initialized = 1;
 	}
@@ -1541,6 +1605,9 @@
 	retval = usb_serial_register(&cypress_hidcom_device);
 	if (retval)
 		goto failed_hidcom_register;
+	retval = usb_serial_register(&cypress_ca42v2_device);
+	if (retval)
+		goto failed_ca42v2_register;
 	retval = usb_register(&cypress_driver);
 	if (retval)
 		goto failed_usb_register;
@@ -1549,6 +1616,8 @@
 	return 0;
 failed_usb_register:
 	usb_deregister(&cypress_driver);
+failed_ca42v2_register:
+	usb_serial_deregister(&cypress_ca42v2_device);
 failed_hidcom_register:
 	usb_serial_deregister(&cypress_hidcom_device);
 failed_em_register:
@@ -1565,6 +1634,7 @@
 	usb_deregister (&cypress_driver);
 	usb_serial_deregister (&cypress_earthmate_device);
 	usb_serial_deregister (&cypress_hidcom_device);
+	usb_serial_deregister (&cypress_ca42v2_device);
 }