Re: Kernel patch for driver/usb/serial/cp210x.c

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Hello,

Here is the new patch for the cp210x driver. 

I have made the strcmp in the startup code. I now set the private data
and use that to check if it is a cp2104 device. Is this the right way of
doing it?

Best regards,
Andreas Madsen

On Thu, 2012-01-12 at 07:59 -0800, Greg KH wrote:
> On Thu, Jan 12, 2012 at 01:28:21PM +0100, Andreas wrote:
> > Hello Greg Kroah-Hartman.
> > 
> > I have made a patch for the cp210x driver.
> > 
> > I use ubuntu, with kernel version 2.6.38.
> > 
> > It is the first time I have made a patch for a linux driver, so I hope I
> > have done it right :)
> > 
> > The reason that I made the patch is because Silicon Labs have a new
> > device, cp2104, and there is a problem with setting the baudrate. I have
> > seen that there is also other people that have the same problem
> > (https://bugs.launchpad.net/ubuntu/+source/linux/+bug/793261).
> > 
> > The change is that I check the iProduct string of the device to see if
> > it is a cp2104 device, and then I set the baudrate instead of the
> > baudrate divisor.
> 
> Thanks, but do you really want to do this string query on ever baud rate
> change?  How about determining this when the device is plugged in and
> then do this change only if this type of device is present?
> 
> And they don't change the device id, just the string in the device?
> That's crazy, and not very nice of them.
> 
> You should run your patch through the scripts/checkpatch.pl script, and
> fix the errors that it give you (hint, the coding style is not correct.)
> 
> And finally, you should make this patch against a more modern kernel,
> 2.6.38 is quite old, please use 3.2, which can be downloaded from
> kernel.org.  I can't go and apply patches against older kernels.
> 
> Oh, and also please cc: the linux-usb@xxxxxxxxxxxxxxx mailing list with
> any usb patches, so that all developers can see them and review them.
> 
> Care to redo the patch based on this and resend it?
> 
> > 
> > I have tested it with a cp2104 and a cp2103 device, and both works fine.
> > 
> > Best regards,
> > Andreas Madsen
> > Seluxit ApS
> 
> > --- linux-source-2.6.38/drivers/usb/serial/cp210x.c	2012-01-03 14:44:25.000000000 +0100
> > +++ linux-source-2.6.38/drivers/usb/serial/cp210x_new.c	2012-01-10 08:24:20.610580474 +0100
> > @@ -201,6 +201,7 @@
> >  #define CP210X_EMBED_EVENTS	0x15
> >  #define CP210X_GET_EVENTSTATE	0x16
> >  #define CP210X_SET_CHARS	0x19
> > +#define CP210X_SET_BAUDRATE	0x1E
> >  
> >  /* CP210X_IFC_ENABLE */
> >  #define UART_ENABLE		0x0001
> > @@ -583,6 +584,7 @@
> >  	unsigned int cflag, old_cflag;
> >  	unsigned int baud = 0, bits;
> >  	unsigned int modem_ctl[4];
> > +	char prod[128];
> >  
> >  	dbg("%s - port %d", __func__, port->number);
> >  
> > @@ -594,8 +596,23 @@
> >  	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) {
> > +	
> > +	/* Read the "iProduct" from the device and check if it is a CP2104,
> > +	 * then use SET_BAUDRATE to change the baudrate. */
> > +	usb_string(port->serial->dev,2,prod,sizeof(prod));
> > +	if(strcmp(prod,"CP2104 USB to UART Bridge Controller") == 0 && baud != 0)
> > +	{
> > +	  dbg("%s - Setting baud rate to %d baud", __func__, baud);
> > +
> > +	  if(cp210x_set_config(port, CP210X_SET_BAUDRATE, &baud, 4)) {		  
> > +	    dbg("Baud rate requested not supported by device");
> > +	    baud = tty_termios_baud_rate(old_termios);
> > +	  }
> > +	}
> > +	else
> > +	{
> > +	  /* 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,
> > @@ -603,6 +620,7 @@
> >  			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);
> 
> 
> 
> 
--- linux-3.2/drivers/usb/serial/cp210x.c	2012-01-05 00:55:44.000000000 +0100
+++ linux-3.2.patch/drivers/usb/serial/cp210x.c	2012-01-13 10:16:50.630613034 +0100
@@ -30,6 +30,10 @@
 #define DRIVER_VERSION "v0.09"
 #define DRIVER_DESC "Silicon Labs CP210x RS232 serial adaptor driver"
 
+struct cp210x_private {
+	bool cp2104_device;
+};
+
 /*
  * Function Prototypes
  */
@@ -47,6 +51,7 @@
 		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 debug;
@@ -168,6 +173,7 @@
 	.tiocmget 		= cp210x_tiocmget,
 	.tiocmset		= cp210x_tiocmset,
 	.attach			= cp210x_startup,
+	.release                = cp210x_release,
 	.dtr_rts		= cp210x_dtr_rts
 };
 
@@ -200,6 +206,7 @@
 #define CP210X_EMBED_EVENTS	0x15
 #define CP210X_GET_EVENTSTATE	0x16
 #define CP210X_SET_CHARS	0x19
+#define CP210X_SET_BAUDRATE	0x1E
 
 /* CP210X_IFC_ENABLE */
 #define UART_ENABLE		0x0001
@@ -582,6 +589,7 @@
 	unsigned int cflag, old_cflag;
 	unsigned int baud = 0, bits;
 	unsigned int modem_ctl[4];
+	struct cp210x_private *priv;
 
 	dbg("%s - port %d", __func__, port->number);
 
@@ -593,8 +601,18 @@
 	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) {
+	priv = usb_get_serial_data(port->serial);
+	if (priv && priv->cp2104_device && baud != 0) {
+		dbg("%s - Setting baud rate to %d baud", __func__, baud);
+
+		if (cp210x_set_config(port, CP210X_SET_BAUDRATE,
+				      &baud, 4)) {
+			dbg("Baud rate requested not supported by device");
+			baud = tty_termios_baud_rate(old_termios);
+		}
+	} else {
+	  /* 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,
@@ -602,6 +620,7 @@
 			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);
@@ -784,11 +803,34 @@
 
 static int cp210x_startup(struct usb_serial *serial)
 {
+	char prod[255];
+	struct cp210x_private *priv;
+
 	/* cp210x buffers behave strangely unless device is reset */
 	usb_reset_device(serial->dev);
+
+	/* Read the iProduct string to check if the device is a cp2104 */
+	usb_string(serial->dev, 2, prod, sizeof(prod));
+	if (strcmp(prod, "CP2104 USB to UART Bridge Controller") == 0) {
+		priv = kzalloc(sizeof(struct cp210x_private), GFP_KERNEL);
+		if (!priv) {
+			dev_err(&serial->dev->dev, "%s- kmalloc(%Zd) failed.\n",
+				__func__, sizeof(struct cp210x_private));
+			return -ENOMEM;
+		}
+		priv->cp2104_device = 1;
+		usb_set_serial_data(serial, (void *)priv);
+	}
 	return 0;
 }
 
+static void cp210x_release(struct usb_serial *serial)
+{
+	/* Free private data if pressent */
+	struct cp210x_private *priv = usb_get_serial_data(serial);
+	kfree(priv);
+}
+
 static int __init cp210x_init(void)
 {
 	int retval;

Attachment: smime.p7s
Description: S/MIME cryptographic signature


[Index of Archives]     [Linux Media]     [Linux Input]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]     [Old Linux USB Devel Archive]

  Powered by Linux