Re: Proposed patch for cp210x: GPIO and USB descriptor control

Previous thread: [PATCH v2] USB: FHCI: cq_get() should check kfifo_out()'s return value by Anton Vorontsov on Friday, May 14, 2010 - 7:33 am. (1 message)

Next thread: patch usb-ehci-fix-controller-wakeup-flag-settings-during-suspend.patch added to gregkh-2.6 tree by gregkh on Friday, May 14, 2010 - 12:20 pm. (1 message)
From: Steve McKown
Date: Friday, May 14, 2010 - 9:20 am

Hello,

A couple of years ago, Silicon Labs granted my company access to API 
documentation for their cp210x "runtime" and "manufacturing" DLLs (provided 
we release our work via the GPL, which we did).  The former allows USB host 
manipulation of cp210c GPIO pins; the latter allows setting cp210x port 
configuration and USB descriptors.  With this information I was able to add 
support for these features in the cp210x driver, exposed via ioctl.  We use 
this driver regularly with good results.

SiLabs wanted to push the changes to the Linux community itself, but doesn't 
seem to have ever done so.  I'd like to make them available now.  However, 
I'm no kernel developer and have only passing familiarity with the relevant 
kernel interfaces.  I'm hoping that someone might be willing to 'mentor' me 
through the process of getting this code suitably crafted and organized for 
possible inclusion.

The patch for our driver is included below, relative to cp210x from Linus' 
tree @ v2.6.34-rc7.

All the best,
Steve

--- cp210x.c-2.6.34-rc7	2010-05-13 16:48:48.000000000 -0600
+++ cp210x.c.tmi	2010-05-13 17:36:10.000000000 -0600
@@ -11,6 +11,9 @@
  * thanks to Karl Hiramoto karl@hiramoto.org. RTSCTS hardware flow
  * control thanks to Munir Nassar nassarmu@real-time.com
  *
+ * R. Steve McKown, Titanium Mirror, Inc., rsmckown@gmail.com.
+ * Added port configuration, usb descriptor and gpio management.
+ *
  */
 
 #include <linux/kernel.h>
@@ -50,6 +53,8 @@
 static void cp210x_break_ctl(struct tty_struct *, int);
 static int cp210x_startup(struct usb_serial *);
 static void cp210x_disconnect(struct usb_serial *);
+static int cp210x_ioctl(struct tty_struct *, struct file *,
+		unsigned int, unsigned long);
 static void cp210x_dtr_rts(struct usb_serial_port *p, int on);
 static int cp210x_carrier_raised(struct usb_serial_port *p);
 
@@ -140,6 +145,7 @@
 	.num_ports		= 1,
 	.open			= cp210x_open,
 	.close			= cp210x_close,
+	.ioctl			= cp210x_ioctl,
 	.break_ctl		= ...
From: Greg KH
Date: Friday, May 14, 2010 - 9:35 am

Thanks for the patch, but could you take a look at the file,
Documentation/SubmittingPatches and resend the patch in a format that I
could apply it in?  We also need a Signed-off-by: line to do so.


This isn't needed, it will show up in the git changelog instead.  Please

Have you thought about using the standard gpio interface instead of
custom ioctls?  That would play much nicer with the rest of the kernel



Why is this needed?  Can't we just expose the version in a sysfs file







If this really is crossing the user/kernel boundry, please use the
variable types that are safe to do so.  They all start with '__'.  For
this one, I would suggest:
	__u8 *buf;
	__s32 len;

Also, please do not define new typedefs.  Running your code through the
checkpatch.pl tool will point this out.  That's always good to do before


What do you mean here?  sizeof will take the "real" size.  If you handle
your structures correctly, you can use sizeof().  You might need to

Please run the 'sparse' tool on this code and fix all of the warnings it



Care to fix this up before submitting it?

That's enough to get started with :)

thanks,

greg k-h
--

From: R. Steve McKown
Date: Monday, May 17, 2010 - 5:50 pm

Hi Greg,

I believe I've addressed your earlier points except for kernel gpio, and 
part number visibility via sysfs.  I'll try to add the former in the 
coming weeks.  The patch passes checkpatch.pl and the code shows no 
errors from 'sparse'.  I hope you are willing to continue the mentorship 
for a few more rounds.  What additional changes are needed?  Thanks again 
for taking the extra time with me on this.


As of a year or so ago, CP210X internal firmware didn't offer the ability 
to change the USB Manufacturer descriptor.  SiLabs said they might change 
this.  See cp210x_has_setmfg().  Perhaps I should yank all the mfg set 

cp210x_get_partnum() is used internally only to interact with the cp210x 
according to what part it actually is.  For example, only cp2103 supports 
GPIO.  Not sure how useful it is to export this information to userspace.

And now for the patch proper
============================

Add GPIO, port configuration and USB descriptor management
via IOCTL to cp210x.

Signed-off-by: R. Steve McKown <rsmckown@gmail.com>
---

This patch is based on linus' v2.6.34-rc7.

diff --git a/drivers/usb/serial/cp210x.c b/drivers/usb/serial/cp210x.c
index ec9b044..3086ab6 100644
--- a/drivers/usb/serial/cp210x.c
+++ b/drivers/usb/serial/cp210x.c
@@ -23,6 +23,7 @@
 #include <linux/usb.h>
 #include <linux/uaccess.h>
 #include <linux/usb/serial.h>
+#include "cp210x.h"
 
 /*
  * Version Information
@@ -50,6 +51,8 @@ static int cp210x_tiocmset_port(struct usb_serial_port *port, struct file *,
 static void cp210x_break_ctl(struct tty_struct *, int);
 static int cp210x_startup(struct usb_serial *);
 static void cp210x_disconnect(struct usb_serial *);
+static int cp210x_ioctl(struct tty_struct *, struct file *,
+		unsigned int, unsigned long);
 static void cp210x_dtr_rts(struct usb_serial_port *p, int on);
 static int cp210x_carrier_raised(struct usb_serial_port *p);
 
@@ -140,6 +143,7 @@ static struct usb_serial_driver cp210x_device = {
 	.num_ports		= 1,
 ...
From: Greg KH
Date: Monday, May 17, 2010 - 9:19 pm

Internally is fine, but I don't think we need an ioctl for something

Don't redefine an existing, well-known, define.  That forces people to
try to have to dig back and figure out what is going on here.  What's



Helper based on what?  16bit character string length?  Again, just spell

Is this something that we need/want in the usb core?  Are you sure we




No, you need to fail this properly with -EFAULT somehow back to

Could you just have overflowed that t.len check?  Be _very_ careful

t.buf should already be a __u8 __user *, right?  Don't use the same
structure types in userspace and in the kernel.

And how does this handle a 64bit kernel in a 32bit userspace?  Have you
hooked up the ioctl compatibility layer properly?



Wait, this isn't the standard Linux GPIO layer.  What happened to using
that instead of a custom ioctl?  That is the correct way to do this,
don't create custom messages here please, it makes support much more
difficult.

Just hook up these GPIO pins to the already-in-kernel gpio layer and
that will export them to userspace properly and you will not have to add
any new ioctls.

thanks,

greg k-h
--

From: Steve McKown
Date: Tuesday, May 18, 2010 - 7:44 am

Would following the guidance of ftdi_sio be a better approach?

/* FTDI_SIO_RESET */
#define FTDI_SIO_RESET_REQUEST FTDI_SIO_RESET
#define FTDI_SIO_RESET_REQUEST_TYPE 0x40

then

        rv = usb_control_msg(port->serial->dev,
                               usb_sndctrlpipe(port->serial->dev, 0),
                               FTDI_SIO_SET_MODEM_CTRL_REQUEST,
                               FTDI_SIO_SET_MODEM_CTRL_REQUEST_TYPE,
                               urb_value, priv->interface,

I can fix the unhelpful comment.

Determining bytes needed to store a string properly encoded to send to the 
cp210x happens in several places through the code.  I thought it would be 
more correct to encapsulate the logic behind this mapping in a single 


OK, I'll try to get up to speed on unicode and figure out something better 

You're right.  This is a static function only called from the local compile 

Yes.  The snippet above is in cp210x_usbstr_from_user.  All callers are in 
cp210x_ioctl and must see a non-zero return from cp210x_usbstr_from_user else 

Do you mean that t.len*2+2, which is what the USBSTRLEN(t.len) resolves to, 
might wrap in its size_t?  I can solve this by moving the assigment of slen 


I'm not at all familiar with "ioctl compatibility layer" and will do some 


It's already on my todo list; I just haven't got to it yet.

I'll get to work on your latest suggestions. 
Thank you for your continued help.
Steve
--

From: Greg KH
Date: Tuesday, May 18, 2010 - 7:55 am

No, please just spell out the "real" usb flags here, don't bury them

I agree it is good to put it in a consistant place, but you are using
"strlen" which kind of implies that this is a real function that will

No, sorry, it was more a joke.  USB strings were always supposed to be a
"real" 16bit value per character, but yet, it is very rare that anyone
ever used that other 8 bits.  You are doing the same thing here, never

Ok, but how are you detecting the two different error modes (invalid
parameters and bad copy)?

As I think you will be getting rid of your ioctl call, this isn't going

Yes.  What happens if I pass a "negative" or very big value as len here?


Ok, that's the big change that I would like to see happen.  I don't want
to add new ioctls to the kernel if at all possible, especially one-off
ones like this that only work for one specific driver/device.

thanks,

greg k-h
--

From: Steve McKown
Date: Tuesday, May 18, 2010 - 3:57 pm

A few ioctls remain in the patch even after porting to kernel gpio:

- Get and set port configuration.  Defines the configuration of the
	internal port pins on the cp210x.  This includes things like
	pull-ups, pin function, reset state, etc.
- Set VID, PID and descriptors: product, serial, and device version.

We use these ioctls to properly configure the cp210x embedded in several of 
our USB device designs.  Currently, the patch includes cp210x.h which can be 
included from userspace too, so that the ioctl commands, starting at 
SIOCDEVPRIVATE, can be known without defining new ioctls globally.  Is this 
enough isolation to consider their inclusion?  If no, what other methods 
could be considered?

Thanks,
Steve
--

From: Greg KH
Date: Tuesday, May 18, 2010 - 7:01 pm

You can dynamically change the vid and pid and stuff?  Heh, that's going
to be fun to track :)


configfs was created for configuring things, perhaps you might want to
look into using that?

Or, if they are single value things, like the vid/pid and such, then a
writable sysfs file also would work well, and be much simpler than an
ioctl for userspace to control.

thanks,

greg k-h
--

Previous thread: [PATCH v2] USB: FHCI: cq_get() should check kfifo_out()'s return value by Anton Vorontsov on Friday, May 14, 2010 - 7:33 am. (1 message)

Next thread: patch usb-ehci-fix-controller-wakeup-flag-settings-during-suspend.patch added to gregkh-2.6 tree by gregkh on Friday, May 14, 2010 - 12:20 pm. (1 message)