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

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

 



On Fri, May 14, 2010 at 10:20:17AM -0600, Steve McKown wrote:
> 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.

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.

A few comments on the changes.

> @@ -11,6 +11,9 @@
>   * thanks to Karl Hiramoto karl@xxxxxxxxxxxxx RTSCTS hardware flow
>   * control thanks to Munir Nassar nassarmu@xxxxxxxxxxxxx
>   *
> + * R. Steve McKown, Titanium Mirror, Inc., rsmckown@xxxxxxxxxx
> + * Added port configuration, usb descriptor and gpio management.
> + *

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

> @@ -221,6 +227,339 @@
>  #define CONTROL_WRITE_DTR	0x0100
>  #define CONTROL_WRITE_RTS	0x0200
>  
> +/* CP2103 ioctls */
> +#define IOCTL_GPIOGET		0x8000	/* Get gpio bits */
> +#define IOCTL_GPIOSET		0x8001	/* Set gpio bits */
> +#define IOCTL_GPIOBIC		0x8002	/* Clear specific gpio bit(s) */
> +#define IOCTL_GPIOBIS		0x8003	/* Set specific gpio bit(s) */

Have you thought about using the standard gpio interface instead of
custom ioctls?  That would play much nicer with the rest of the kernel
and any userspace tools that are used to accessing gpio ports.

> +/* CP210x ioctls principally used during initial device configuration */
> +#define IOCTL_DEVICERESET	0x8004	/* Reset the cp210x */
> +#define IOCTL_PORTCONFGET	0x8005	/* Get port configuration */
> +#define IOCTL_PORTCONFSET	0x8006	/* Set port configuration */
> +#define IOCTL_SETVID		0x8007	/* Set vendor id */
> +#define IOCTL_SETPID		0x8008	/* Set product id */
> +#define IOCTL_SETMFG		0x8009	/* Set manufacturer string */
> +#define IOCTL_SETPRODUCT	0x800a	/* Set product string */
> +#define IOCTL_SETSERIAL		0x800b	/* Set serial number string */
> +#define IOCTL_SETDEVVER		0x800c	/* set device version id */

Shouldn't these all be in a .h file somewhere?

> +/* FIXME: where is IOCTL_SETMFG? */

What is this message?

> +/* CP2103 GPIO */
> +#define GPIO_0			0x01
> +#define GPIO_1			0x02
> +#define GPIO_2			0x04
> +#define GPIO_3			0x08
> +#define GPIO_MASK		(GPIO_0|GPIO_1|GPIO_2|GPIO_3)
> +
> +/* GetDeviceVersion() return codes */
> +#define CP210x_CP2101_VERSION	0x01
> +#define	CP210x_CP2102_VERSION	0x02
> +#define	CP210x_CP2103_VERSION	0x03

Why is this needed?  Can't we just expose the version in a sysfs file
instead of using an ioctl?

> +
> +/* Return codes */
> +#define	CP210x_SUCCESS			0x00
> +#define	CP210x_DEVICE_NOT_FOUND		0xFF

This isn't ever used, and doesn't make sense :)

> +#define	CP210x_INVALID_HANDLE		0x01
> +#define	CP210x_INVALID_PARAMETER	0x02

These aren't used.

> +#define	CP210x_DEVICE_IO_FAILED		0x03
> +#define	CP210x_FUNCTION_NOT_SUPPORTED	0x04

This one isn't ever used.

> +#define	CP210x_GLOBAL_DATA_ERROR	0x05
> +#define	CP210x_FILE_ERROR		0x06
> +#define	CP210x_COMMAND_FAILED		0x08
> +#define	CP210x_INVALID_ACCESS_TYPE	0x09

Nor are these four.

> +/* USB descriptor sizes */
> +#define	CP210x_MAX_DEVICE_STRLEN	256

This is never used.

> +#define	CP210x_MAX_PRODUCT_STRLEN	126
> +#define	CP210x_MAX_SERIAL_STRLEN	63
> +#define	CP210x_MAX_MAXPOWER		250

And this one isn't used either.

> +
> +/* Used to pass variable sized buffers between user and kernel space (ioctls) 
> */
> +typedef struct {
> +	char *buf;
> +	size_t len;
> +} cp210x_buffer_t;

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
submitting a kernel patch.

> +
> +/* Port config definitions */
> +typedef struct {
> +	uint16_t mode;		/* Push-pull = 1, Open-drain = 0 */
> +	uint16_t lowPower;
> +	uint16_t latch;		/* Logic high = 1, Logic low = 0 */
> +} cp210x_port_state_t;
> +
> +typedef struct {
> +	cp210x_port_state_t reset;
> +	cp210x_port_state_t suspend;
> +	uint8_t enhancedFxn;
> +} cp210x_port_config_t;

Same thing here for typedefs and variable types.

> +
> +#define PORT_CONFIG_LEN	13	/* Because sizeof() will pad to full words */

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
"pack" your structure then, right?

> +/*
> + * cp210x_buf_from_user
> + * Copy a buffer from user space, returning the number of bytes copied
> + * from ubuf.buf into kbuf.  klen is the size of the buffer at kbuf.
> + */
> +static size_t copy_buf_from_user(char *kbuf, unsigned long ubuf, size_t klen)
> +{
> +	cp210x_buffer_t t;
> +
> +	if (!kbuf || !ubuf || !klen ||
> +			copy_from_user(&t, (cp210x_buffer_t *)ubuf, sizeof(t)))
> +		return 0;
> +	if (t.len < klen)
> +		klen = t.len;
> +	if (!t.buf || !t.len || copy_from_user(kbuf, t.buf, klen))
> +		return 0;
> +	return klen;
> +}

Please run the 'sparse' tool on this code and fix all of the warnings it
will spit out here.

> +/*
> + * cp210x_ctlmsg
> + * A generic usb control message interface.
> + * Returns the actual size of the data read or written within the message, 0
> + * if no data were read or written, or a negative value to indicate an error.
> + */
> +static int cp210x_ctlmsg(struct usb_serial_port *port, u8 request,
> +		u8 requestype, u16 value, u16 index, void *data, u16 size)
> +{
> +	struct usb_device *dev = port->serial->dev;
> +	u8 *tbuf;
> +	int ret;
> +
> +	if (!(tbuf = kmalloc(size, GFP_KERNEL)))
> +		return -ENOMEM;
> +	if (requestype & 0x80) {

Can you use the proper usb.h define here to make it a bit more readable?

> +		ret = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), request,
> +				requestype, value, index, tbuf, size, 300);
> +		if (ret > 0 && size)
> +			memcpy(data, tbuf, size);
> +	} else {
> +		if (size)
> +			memcpy(tbuf, data, size);
> +		ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), request,
> +				requestype, value, index, tbuf, size, 300);
> +	}
> +	kfree(tbuf);
> +	if (ret < 0 && ret != -EPIPE) {
> +		dev_printk(KERN_DEBUG, &dev->dev, "cp210x: control failed cmd rqt %u "
> +				"rq %u len %u ret %d\n", requestype, request, size, ret);
> +	}
> +	return ret;
> +}
> +
> +static int cp210x_reset(struct usb_serial_port *port)
> +{
> +	dbg("%s", __FUNCTION__);
> +
> +#if 1
> +    /* Is this better than usb_device_reset?  It may be.  Once a client 
> issues

Your email client wrapped the patch :(

> +	 * the reset ioctl, it must disconnect and reconnect, since the USB
> +	 * connections are torn down.  We also ignore the error return, since
> +	 * the part resets and doesn't send one...
> +	 */
> +	cp210x_ctlmsg(port, 0xff, 0x40, 0x0008, 0x00, 0, 0);
> +#else
> +	usb_reset_device(port->serial->dev);
> +#endif
> +	return 0;

Care to fix this up before submitting it?

That's enough to get started with :)

thanks,

greg k-h
--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html

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

  Powered by Linux