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

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

 



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.

You had some questions:

> > +/* FIXME: where is IOCTL_SETMFG? */
> 
> What is this message?

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 
code for now (aka as simple as possible)?

> > +#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?

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@xxxxxxxxx>
---

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,
 	.open			= cp210x_open,
 	.close			= cp210x_close,
+	.ioctl			= cp210x_ioctl,
 	.break_ctl		= cp210x_break_ctl,
 	.set_termios		= cp210x_set_termios,
 	.tiocmget 		= cp210x_tiocmget,
@@ -150,9 +154,13 @@ static struct usb_serial_driver cp210x_device = {
 	.carrier_raised		= cp210x_carrier_raised
 };
 
+/* Control request types */
+#define REQTYPE_CTL_TO_DEVICE	USB_TYPE_VENDOR
+#define REQTYPE_CTL_TO_HOST	(USB_DIR_IN|REQTYPE_CTL_TO_DEVICE)
+
 /* Config request types */
-#define REQTYPE_HOST_TO_DEVICE	0x41
-#define REQTYPE_DEVICE_TO_HOST	0xc1
+#define REQTYPE_HOST_TO_DEVICE	(USB_TYPE_VENDOR|USB_RECIP_INTERFACE)
+#define REQTYPE_DEVICE_TO_HOST	(USB_DIR_IN|REQTYPE_HOST_TO_DEVICE)
 
 /* Config request codes */
 #define CP210X_IFC_ENABLE	0x00
@@ -221,6 +229,290 @@ static struct usb_serial_driver cp210x_device = {
 #define CONTROL_WRITE_DTR	0x0100
 #define CONTROL_WRITE_RTS	0x0200
 
+/* cp210x_get_partnum() return codes */
+#define CP210x_PART_UNKNOWN	0x00
+#define CP210x_PART_CP2101	0x01
+#define CP210x_PART_CP2102	0x02
+#define CP210x_PART_CP2103	0x03
+
+/* Helper to make usb string size */
+#define USBSTRLEN(x)		(x * 2 + 2)
+
+/* Populates usbstr with: (len) + (0x03) + unicode(str).  Each char in str
+ * takes two bytes in unicode format.
+ * Returns the resulting length of the string in usbstr.
+ * This function can accept overlapping usbstr and str as long as the overlap
+ * does not cause data written to usbstr to overwrite data not yet read from
+ * str.
+ */
+static int make_usb_string(char *usbstr, size_t usblen, char *src,
+		size_t srclen)
+{
+	int len = 0;
+
+	if (usbstr && usblen >= 2 && src && *src && srclen) {
+		char *p;
+
+		if (usblen > 255)
+			usblen = 255;
+
+		p = usbstr + 1;
+		*p++ = 0x03;
+		len = 2;
+		while (srclen && len < usblen) {
+			*p++ = *src++;
+			*p++ = 0;
+			len += 2;
+			srclen--;
+		}
+		*usbstr = (char)len;
+	}
+	return len;
+}
+
+/*
+ * cp210x_usbstr_from_user
+ * Populate kbuf with a usb string derived from a user space variable.  klen
+ * is the size of the buffer at kbuf.
+ * Returns the number of bytes used in kbuf.
+ */
+static size_t cp210x_usbstr_from_user(char *kbuf, unsigned long ubuf,
+		size_t klen)
+{
+	struct cp210x_buffer t;
+	char *str;
+	size_t slen;
+
+	if (!kbuf || !ubuf || !klen)
+		return 0;
+	if (copy_from_user(&t, (struct cp210x_buffer __user *)ubuf, sizeof(t)))
+		return 0;
+	if (!t.buf || !t.len || USBSTRLEN(t.len) > klen)
+		return 0;
+	slen = (klen - 2) / 2;
+	if (t.len < slen)
+		slen = t.len;
+	str = kbuf + klen - slen;
+	if (copy_from_user(str, (u8 __user *)t.buf, slen))
+		return 0;
+	return make_usb_string(kbuf, klen, str, slen);
+}
+
+/* cp210x_has_setmfg
+ * Returns 1 if the CP210X part includes firmware that allows setting the
+ * USB MFG descriptor, else 0.  As of this writing, no CP210X firmware allows
+ * this.  SiLabs has suggested this may change in future firmware versions or
+ * parts.
+ */
+static inline int cp210x_has_setmfg(void)
+{
+	return 0;
+}
+
+/*
+ * 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;
+
+	tbuf = kmalloc(size, GFP_KERNEL);
+	if (!tbuf)
+		return -ENOMEM;
+	if (requestype & USB_DIR_IN) {
+		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: ctl 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", __func__);
+
+	/* Instructing the CP210X to reset seems to work more reliably than
+	 * calling usb_reset_device().
+	 */
+	cp210x_ctlmsg(port, 0xff, REQTYPE_CTL_TO_DEVICE,
+			0x0008, 0x00, NULL, 0);
+	return 0;
+}
+
+static int cp210x_get_partnum(struct usb_serial_port *port)
+{
+	static u8 _partnum = CP210x_PART_UNKNOWN;
+
+	if (_partnum == CP210x_PART_UNKNOWN) {
+		u8 addr = port->serial->dev->actconfig->interface[0]->
+			cur_altsetting->endpoint[0].desc.bEndpointAddress &
+			USB_ENDPOINT_NUMBER_MASK;
+
+		if (addr == 0x03 || addr == 0x02)
+			_partnum = CP210x_PART_CP2101;
+		else if (addr == 0x01) {
+			/* Must query part to determine part number */
+			if (cp210x_ctlmsg(port, 0xff, REQTYPE_CTL_TO_HOST,
+					0x370b, 0x00, &_partnum, 1) != 1)
+				_partnum = CP210x_PART_UNKNOWN;
+		}
+	}
+	dbg("%s - partnum %u", __func__, _partnum);
+	return _partnum;
+}
+
+static inline int cp210x_setu16(struct usb_serial_port *port, int cmd,
+		unsigned int value)
+{
+	return cp210x_ctlmsg(port, 0xff, REQTYPE_CTL_TO_DEVICE,
+			0x3700 | (cmd & 0xff), value, NULL, 0);
+}
+
+/*
+ * cp210x_setstr
+ *
+ * Set a USB string descriptor using proprietary cp210x control messages.
+ * Return the number of characters actually written.
+ */
+static int cp210x_setstr(struct usb_serial_port *port, int cmd, char *usbstr)
+{
+	unsigned len = usbstr[0];
+	int ret = cp210x_ctlmsg(port, 0xff, REQTYPE_CTL_TO_DEVICE,
+			0x3700 | (cmd & 0xff), 0, usbstr, len);
+	dbg("%s - cmd 0x%02x len %d ret %d", __func__, cmd, len, ret);
+	return ret;
+}
+
+/* Set all gpio simultaneously */
+static int cp210x_gpioset(struct usb_serial_port *port, u8 gpio)
+{
+	dbg("%s - port %d, gpio = 0x%.2x", __func__, port->number, gpio);
+
+	return cp210x_ctlmsg(port, 0xff, REQTYPE_CTL_TO_DEVICE,
+			0x37e1, ((uint16_t)gpio << 8) | GPIO_MASK, NULL, 0);
+}
+
+/* Set select gpio bits */
+static int cp210x_gpiosetb(struct usb_serial_port *port, u8 set, u8 clear)
+{
+	u16 gpio = 0;
+
+	/* The bitmask is in the LSB, the values in the MSB */
+	if (set & GPIO_0)
+		gpio |= (GPIO_0 << 8)|GPIO_0;
+	if (set & GPIO_1)
+		gpio |= (GPIO_1 << 8)|GPIO_1;
+	if (set & GPIO_2)
+		gpio |= (GPIO_2 << 8)|GPIO_2;
+	if (set & GPIO_3)
+		gpio |= (GPIO_3 << 8)|GPIO_3;
+	if (clear & GPIO_0)
+		gpio = (gpio & ~(GPIO_0 << 8))|GPIO_0;
+	if (clear & GPIO_1)
+		gpio = (gpio & ~(GPIO_1 << 8))|GPIO_1;
+	if (clear & GPIO_2)
+		gpio = (gpio & ~(GPIO_2 << 8))|GPIO_2;
+	if (clear & GPIO_3)
+		gpio = (gpio & ~(GPIO_3 << 8))|GPIO_3;
+
+	dbg("%s - port %d, gpiob = 0x%.4x", __func__, port->number, gpio);
+
+	return cp210x_ctlmsg(port, 0xff, REQTYPE_CTL_TO_DEVICE,
+			0x37e1, gpio, NULL, 0);
+}
+
+static int cp210x_gpioget(struct usb_serial_port *port, u8 *gpio)
+{
+	int ret;
+
+	dbg("%s - port %d", __func__, port->number);
+
+	ret = cp210x_ctlmsg(port, 0xff, REQTYPE_CTL_TO_HOST,
+			0x00c2, 0, gpio, 1);
+
+	dbg("%s - gpio = 0x%.2x (%d)", __func__, *gpio, ret);
+
+	return (ret == 1) ? 0 : -1;
+}
+
+static int cp210x_portconfset(struct usb_serial_port *port,
+		struct cp210x_port_config *config)
+{
+	struct cp210x_port_config lconfig;
+	int ret;
+
+	dbg("%s", __func__);
+
+	memcpy(&lconfig, config, sizeof(lconfig));
+
+	/* Words from cp210x are MSB */
+	lconfig.reset.mode = cpu_to_be16(config->reset.mode);
+	lconfig.reset.latch = cpu_to_be16(config->reset.latch);
+	lconfig.suspend.mode = cpu_to_be16(config->suspend.mode);
+	lconfig.suspend.latch = cpu_to_be16(config->suspend.latch);
+	/* apparently not implemented by CP210X firmware */
+	lconfig.suspend.lowPower = 0;
+	lconfig.reset.lowPower = 0;
+
+	ret = cp210x_ctlmsg(port, 0xff, REQTYPE_CTL_TO_DEVICE, 0x370c,
+			0, &lconfig, sizeof(struct cp210x_port_config));
+	if (ret == sizeof(struct cp210x_port_config))
+		return 0;
+	else if (ret >= 0)
+		return -1;
+	else
+		return ret;
+}
+
+static int cp210x_portconfget(struct usb_serial_port *port,
+		struct cp210x_port_config *config)
+{
+	int ret;
+
+	dbg("%s", __func__);
+
+	ret = cp210x_ctlmsg(port, 0xff, REQTYPE_CTL_TO_HOST,
+			0x370c, 0, config, sizeof(struct cp210x_port_config));
+	if (ret == sizeof(struct cp210x_port_config)) {
+		/* Words from cp210x are MSB */
+		config->reset.mode = be16_to_cpu(config->reset.mode);
+		config->reset.lowPower = be16_to_cpu(config->reset.lowPower);
+		config->reset.latch = be16_to_cpu(config->reset.latch);
+		config->suspend.mode = be16_to_cpu(config->suspend.mode);
+		config->suspend.lowPower =
+				be16_to_cpu(config->suspend.lowPower);
+		config->suspend.latch = be16_to_cpu(config->suspend.latch);
+
+		/* apparently not implemented yet */
+		config->reset.lowPower = 0;
+		config->suspend.lowPower = 0;
+
+		return 0;
+	} else if (ret >= 0)
+		return -1;
+	else
+		return ret;
+
+}
+
 /*
  * cp210x_get_config
  * Reads from the CP210x configuration registers
@@ -431,6 +723,168 @@ static void cp210x_close(struct usb_serial_port *port)
 	mutex_unlock(&port->serial->disc_mutex);
 }
 
+static int cp210x_ioctl(struct tty_struct *tty, struct file *file,
+		unsigned int cmd, unsigned long arg)
+{
+	struct usb_serial_port *port = tty->driver_data;
+
+	dbg("%s (%d) cmd = 0x%04x", __func__, port->number, cmd);
+
+	switch (cmd) {
+
+	case TIOCMGET:
+	{
+		int result = cp210x_tiocmget(tty, file);
+		if (copy_to_user((int __user *)&arg, &result, sizeof(int)))
+			return -EFAULT;
+		return 0;
+	}
+	break;
+
+	case TIOCMSET:
+	case TIOCMBIS:
+	case TIOCMBIC:
+	{
+		int val = 0;
+
+		if (copy_from_user(&val, (int __user *)&arg, sizeof(int)))
+			return -EFAULT;
+
+		/* this looks wrong: TIOCMSET isn't going to work right */
+		if (cp210x_tiocmset(tty, file, (cmd == TIOCMBIC) ? 0 : val,
+					(cmd == TIOCMBIC) ? val : 0))
+			return -EFAULT;
+		return 0;
+	}
+	break;
+
+	case CP210x_IOCTL_GPIOGET:
+	if (cp210x_get_partnum(port) == CP210x_PART_CP2103) {
+		u8 gpio = 0;
+		if (!cp210x_gpioget(port, &gpio) && !copy_to_user(
+					(u8 __user *)arg, &gpio, sizeof(gpio)))
+			return 0;
+	}
+	return -EFAULT;
+	break;
+
+	case CP210x_IOCTL_GPIOSET:
+	if (cp210x_get_partnum(port) == CP210x_PART_CP2103 &&
+			!cp210x_gpioset(port, arg))
+		return 0;
+	return -EFAULT;
+	break;
+
+	case CP210x_IOCTL_GPIOBIC:
+	case CP210x_IOCTL_GPIOBIS:
+	if (cp210x_get_partnum(port) == CP210x_PART_CP2103 &&
+			!cp210x_gpiosetb(port,
+				(cmd == CP210x_IOCTL_GPIOBIC) ?  0 : arg,
+				(cmd == CP210x_IOCTL_GPIOBIC) ? arg : 0))
+		return 0;
+	return -EFAULT;
+	break;
+
+	case CP210x_IOCTL_DEVICERESET:
+	return cp210x_reset(port);
+	break;
+
+	case CP210x_IOCTL_PORTCONFGET:
+	{
+		struct cp210x_port_config config;
+		if (!cp210x_portconfget(port, &config) && !copy_to_user(
+					(struct cp210x_port_config __user *)arg,
+					&config, sizeof(config)))
+			return 0;
+	}
+	return -EFAULT;
+	break;
+
+	case CP210x_IOCTL_PORTCONFSET:
+	{
+	struct cp210x_port_config config;
+	if (!copy_from_user(&config, (struct cp210x_port_config __user *)arg,
+			sizeof(config)) &&
+			!cp210x_portconfset(port, &config))
+		return 0;
+	return -EFAULT;
+	}
+	break;
+
+	case CP210x_IOCTL_SETVID:
+	{
+		unsigned int vid;
+		if (!copy_from_user(&vid, (unsigned int __user *)arg,
+				sizeof(unsigned int)) &&
+				!cp210x_setu16(port, 0x01, vid))
+			return 0;
+		return -EFAULT;
+	}
+	break;
+
+	case CP210x_IOCTL_SETPID:
+	{
+		unsigned int pid;
+		if (!copy_from_user(&pid, (unsigned int __user *)arg,
+				sizeof(unsigned int)) &&
+				!cp210x_setu16(port, 0x02, pid))
+			return 0;
+		return -EFAULT;
+	}
+	break;
+
+	case CP210x_IOCTL_SETMFG:
+	if (cp210x_has_setmfg()) {
+		char usbstr[USBSTRLEN(CP210x_MAX_MFG_STRLEN)];
+		size_t len = cp210x_usbstr_from_user(usbstr, arg,
+				sizeof(usbstr));
+		if (len && cp210x_setstr(port, 0x00, usbstr) == len)
+			return 0;
+	}
+	return -EFAULT;
+	break;
+
+	case CP210x_IOCTL_SETPRODUCT:
+	{
+		char usbstr[USBSTRLEN(CP210x_MAX_PRODUCT_STRLEN)];
+		size_t len = cp210x_usbstr_from_user(usbstr, arg,
+				sizeof(usbstr));
+		if (len && cp210x_setstr(port, 0x03, usbstr) == len)
+			return 0;
+		return -EFAULT;
+	}
+	break;
+
+	case CP210x_IOCTL_SETSERIAL:
+	{
+		char usbstr[USBSTRLEN(CP210x_MAX_SERIAL_STRLEN)];
+		size_t len = cp210x_usbstr_from_user(usbstr, arg,
+				sizeof(usbstr));
+		if (len && cp210x_setstr(port, 0x04, usbstr) == len)
+			return 0;
+		return -EFAULT;
+	}
+	break;
+
+	case CP210x_IOCTL_SETDEVVER:
+	{
+		unsigned int ver;
+		if (!copy_from_user(&ver, (unsigned int __user *)arg,
+				sizeof(unsigned int)) &&
+				!cp210x_setu16(port, 0x07, ver))
+			return 0;
+		return -EFAULT;
+	}
+	break;
+
+	default:
+	dbg("%s not supported = 0x%04x", __func__, cmd);
+	break;
+	}
+
+	return -ENOIOCTLCMD;
+}
+
 /*
  * cp210x_get_termios
  * Reads the baud rate, data bits, parity, stop bits and flow control mode
diff --git a/drivers/usb/serial/cp210x.h b/drivers/usb/serial/cp210x.h
new file mode 100644
index 0000000..14a13f4
--- /dev/null
+++ b/drivers/usb/serial/cp210x.h
@@ -0,0 +1,145 @@
+/*
+ * Silicon Laboratories CP210x USB to RS232 serial adaptor driver
+ *
+ * Copyright (C) 2005 Craig Shelley (craig@xxxxxxxxxxxxxxxx)
+ *
+ *	This program is free software; you can redistribute it and/or
+ *	modify it under the terms of the GNU General Public License version
+ *	2 as published by the Free Software Foundation.
+ *
+ * Header file shared by both the cp210x kernel module and userspace.
+ *
+ */
+
+#if !defined(CP210X_H)
+#define CP210X_H
+
+#if defined(__KERNEL__)
+#include <linux/sockios.h>
+#else
+#include <linux/types.h>
+#include <sys/ioctl.h>
+#endif
+
+/* CP2103 GPIO ioctls */
+#define CP210x_IOCTL_GPIOGET		(SIOCDEVPRIVATE + 0)
+#define CP210x_IOCTL_GPIOSET		(SIOCDEVPRIVATE + 1)
+#define CP210x_IOCTL_GPIOBIC		(SIOCDEVPRIVATE + 2)
+#define CP210x_IOCTL_GPIOBIS		(SIOCDEVPRIVATE + 3)
+
+/* CP210x ioctls principally used during initial device configuration */
+#define CP210x_IOCTL_DEVICERESET	(SIOCDEVPRIVATE + 4)
+#define CP210x_IOCTL_PORTCONFGET	(SIOCDEVPRIVATE + 5)
+#define CP210x_IOCTL_PORTCONFSET	(SIOCDEVPRIVATE + 6)
+#define CP210x_IOCTL_SETVID		(SIOCDEVPRIVATE + 7)
+#define CP210x_IOCTL_SETPID		(SIOCDEVPRIVATE + 8)
+#define CP210x_IOCTL_SETMFG		(SIOCDEVPRIVATE + 9)
+#define CP210x_IOCTL_SETPRODUCT		(SIOCDEVPRIVATE + 10)
+#define CP210x_IOCTL_SETSERIAL		(SIOCDEVPRIVATE + 11)
+#define CP210x_IOCTL_SETDEVVER		(SIOCDEVPRIVATE + 12)
+
+/* CP2103 GPIO bit positions */
+#define GPIO_0			0x01
+#define GPIO_1			0x02
+#define GPIO_2			0x04
+#define GPIO_3			0x08
+#define GPIO_MASK		(GPIO_3|GPIO_2|GPIO_1|GPIO_0)
+
+/* USB descriptor sizes */
+#define	CP210x_MAX_MFG_STRLEN		255
+#define	CP210x_MAX_PRODUCT_STRLEN	126
+#define	CP210x_MAX_SERIAL_STRLEN	63
+
+#if !defined(__KERNEL__)
+/* Mode and latch bit to pin assignments. See AN223 from SiLabs:
+ * https://www.silabs.com/Support Documents/TechnicalDocs/an223.pdf
+ *
+ *  15 - /SUSPEND	Can't configure latch
+ *  14 - SUSPEND	Can't configure latch
+ *  13 - unused
+ *  12 - unused
+ *  11 - GPIO_3
+ *  10 - GPIO_2
+ *   9 - GPIO_1
+ *   8 - GPIO_0
+ *   7 - /CTS
+ *   6 - /RTS
+ *   5 - RXD	Note: set latch value to '1' for proper operation.
+ *   4 - TXD
+ *   3 - /DSR
+ *   2 - /DTR
+ *   1 - /DCD
+ *   0 - /RI
+ *
+ * Mode bit values:
+ *   1 - A value of one in a bit places the corresponding IO pin in push-
+ *       pull output mode.
+ *   0 - A value of zero in a bit places the corresponding IO pin in open-
+ *       drain output mode.
+ *
+ * Latch bit values:
+ *   1 - A value of one in a bit sets the corresponding IO pin's value to
+ *       output high.  If the mode is push-pull, the pin sources current
+ *       from VIO.  If the mode is open-drain, the pin driver is in high
+ *       impedance.
+ *   0 - A value of zero in a bit sets the corresponding IO pin's value to
+ *       output low.  In either mode, push-pull or open-drain, the pin
+ *       driver sinks current to ground.
+ */
+#define CP210x_CFG_nSUSPEND		0x8000
+#define CP210x_CFG_SUSPEND		0x4000
+#define CP210x_CFG_UNUSED13		0x2000
+#define CP210x_CFG_UNUSED12		0x1000
+#define CP210x_CFG_GPIO_3		0x0800
+#define CP210x_CFG_GPIO_2		0x0400
+#define CP210x_CFG_GPIO_1		0x0200
+#define CP210x_CFG_GPIO_0		0x0100
+#define CP210x_CFG_nCTS			0x0080
+#define CP210x_CFG_nRTS			0x0040
+#define CP210x_CFG_RXD			0x0020
+#define CP210x_CFG_TXD			0x0010
+#define CP210x_CFG_nDSR			0x0008
+#define CP210x_CFG_nDTR			0x0004
+#define CP210x_CFG_nDCD			0x0002
+#define CP210x_CFG_nRI			0x0001
+
+/* Enhanced function bits:
+ *   7 - GPIO dynamic suspend, for 4 GPIO signals
+ *   6 - Serial dynamic suspend, for 8 UART/Modem signals
+ *   5 - unused, leave zero
+ *   4 - Enable weak pull-ups
+ *   3 - unused, leave zero
+ *   2 - /RS485_TX on GPIO_2
+ *   1 - /RXLED on GPIO_1
+ *   0 - /TXLED on GPIO_0
+*/
+#define CP210x_ENH_GPIO_DYNSUSP		0x80
+#define CP210x_ENH_SERIAL_DYNSUSP	0x40
+#define CP210x_ENH_UNUSED5		0x20
+#define CP210x_ENH_PULLUPS		0x10
+#define CP210x_ENH_UNUSED3		0x08
+#define CP210x_ENH_nRS485_TX		0x04
+#define CP210x_ENH_nRXLED		0x02
+#define CP210x_ENH_nTXLED		0x01
+#endif /* __KERNEL__ */
+
+/* Used to pass variable size buffers between user and kernel space (ioctls) */
+struct cp210x_buffer {
+	__u8 *buf;
+	__s32 len;
+};
+
+/* Port config definitions */
+struct cp210x_port_state {
+	__u16 mode;		/* Push-pull = 1, Open-drain = 0 */
+	__u16 lowPower;
+	__u16 latch;		/* Logic high = 1, Logic low = 0 */
+} __attribute__((packed));
+
+struct cp210x_port_config {
+	struct cp210x_port_state reset;
+	struct cp210x_port_state suspend;
+	__u8 enhancedFxn;
+} __attribute__((packed));
+
+#endif /* CP210X_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