[OpenWrt-Devel] [PATCH] [kernel] cp201x: Add GPIO ioctl commands (from Silicon Labs)
Ted Hess
thess at kitschensync.net
Mon Aug 3 13:55:06 EDT 2015
Silicon Labs driver has ioctl support on devices which have GPIO pins. The
driver
in the kernel repo does not have this feature.
Ref:
http://www.silabs.com/Support%20Documents/Software/Linux_CP210x_VCP_3.x.x_Release_Notes.txt
Signed-off-by: Ted Hess <thess at kitschensync.net>
---
.../patches-3.18/824-cp210x_add_gpio_ioctl.patch | 194 +++++++++++++++++++++
.../patches-4.1/824-cp210x_add_gpio_ioctl.patch | 194 +++++++++++++++++++++
2 files changed, 388 insertions(+)
create mode 100644
target/linux/generic/patches-3.18/824-cp210x_add_gpio_ioctl.patch
create mode 100644
target/linux/generic/patches-4.1/824-cp210x_add_gpio_ioctl.patch
diff --git a/target/linux/generic/patches-3.18/824-cp210x_add_gpio_ioctl.patch
b/target/linux/generic/patches-3.18/824-cp210x_add_gpio_ioctl.patch
new file mode 100644
index 0000000..695647a
--- /dev/null
+++ b/target/linux/generic/patches-3.18/824-cp210x_add_gpio_ioctl.patch
@@ -0,0 +1,194 @@
+--- a/drivers/usb/serial/cp210x.c
++++ b/drivers/usb/serial/cp210x.c
+@@ -24,13 +24,15 @@
+ #include <linux/uaccess.h>
+ #include <linux/usb/serial.h>
+
+-#define DRIVER_DESC "Silicon Labs CP210x RS232 serial adaptor driver"
++#define DRIVER_DESC "Silicon Labs CP210x RS232 serial adaptor driver (with
GPIO support)"
+
+ /*
+ * Function Prototypes
+ */
+ static int cp210x_open(struct tty_struct *tty, struct usb_serial_port *);
+ static void cp210x_close(struct usb_serial_port *);
++static int cp210x_ioctl(struct tty_struct *tty,
++ unsigned int cmd, unsigned long arg);
+ static void cp210x_get_termios(struct tty_struct *, struct usb_serial_port *);
+ static void cp210x_get_termios_port(struct usb_serial_port *port,
+ unsigned int *cflagp, unsigned int *baudp);
+@@ -185,6 +187,7 @@
+
+ struct cp210x_serial_private {
+ __u8 bInterfaceNumber;
++ __u8 bPartNumber;
+ };
+
+ static struct usb_serial_driver cp210x_device = {
+@@ -198,6 +201,7 @@
+ .bulk_out_size = 256,
+ .open = cp210x_open,
+ .close = cp210x_close,
++ .ioctl = cp210x_ioctl,
+ .break_ctl = cp210x_break_ctl,
+ .set_termios = cp210x_set_termios,
+ .tiocmget = cp210x_tiocmget,
+@@ -211,6 +215,17 @@
+ &cp210x_device, NULL
+ };
+
++/* Part number definitions */
++#define CP2101_PARTNUM 0x01
++#define CP2102_PARTNUM 0x02
++#define CP2103_PARTNUM 0x03
++#define CP2104_PARTNUM 0x04
++#define CP2105_PARTNUM 0x05
++
++/* IOCTLs */
++#define IOCTL_GPIOGET 0x8000
++#define IOCTL_GPIOSET 0x8001
++
+ /* Config request types */
+ #define REQTYPE_HOST_TO_INTERFACE 0x41
+ #define REQTYPE_INTERFACE_TO_HOST 0xc1
+@@ -244,11 +259,17 @@
+ #define CP210X_SET_CHARS 0x19
+ #define CP210X_GET_BAUDRATE 0x1D
+ #define CP210X_SET_BAUDRATE 0x1E
++#define CP210X_VENDOR_SPECIFIC 0xFF
+
+ /* CP210X_IFC_ENABLE */
+ #define UART_ENABLE 0x0001
+ #define UART_DISABLE 0x0000
+
++/* CP210X_VENDOR_SPECIFIC */
++#define CP210X_WRITE_LATCH 0x37E1
++#define CP210X_READ_LATCH 0x00C2
++#define CP210X_GET_PARTNUM 0x370B
++
+ /* CP210X_(SET|GET)_BAUDDIV */
+ #define BAUD_RATE_GEN_FREQ 0x384000
+
+@@ -469,6 +490,96 @@
+ cp210x_set_config_single(port, CP210X_IFC_ENABLE, UART_DISABLE);
+ }
+
++static int cp210x_ioctl(struct tty_struct *tty,
++ unsigned int cmd, unsigned long arg)
++{
++ struct usb_serial_port *port = tty->driver_data;
++ struct usb_serial *serial = port->serial;
++ struct cp210x_serial_private *port_priv = usb_get_serial_data(serial);
++ int result = 0;
++ unsigned int latch_setting = 0;
++
++ switch (cmd) {
++
++ case IOCTL_GPIOGET:
++ if ((port_priv->bPartNumber == CP2103_PARTNUM) ||
++ (port_priv->bPartNumber == CP2104_PARTNUM)) {
++ result = usb_control_msg(port->serial->dev,
++ usb_rcvctrlpipe(port->serial->dev, 0),
++ CP210X_VENDOR_SPECIFIC,
++ REQTYPE_DEVICE_TO_HOST,
++ CP210X_READ_LATCH,
++ port_priv->bInterfaceNumber,
++ &latch_setting, 1,
++ USB_CTRL_GET_TIMEOUT);
++ if (result != 1)
++ return -EPROTO;
++ *(unsigned long *)arg = (unsigned long)latch_setting;
++ return 0;
++ } else if (port_priv->bPartNumber == CP2105_PARTNUM) {
++ result = usb_control_msg(port->serial->dev,
++ usb_rcvctrlpipe(port->serial->dev, 0),
++ CP210X_VENDOR_SPECIFIC,
++ REQTYPE_INTERFACE_TO_HOST,
++ CP210X_READ_LATCH,
++ port_priv->bInterfaceNumber,
++ &latch_setting, 1,
++ USB_CTRL_GET_TIMEOUT);
++ if (result != 1)
++ return -EPROTO;
++ *(unsigned long *)arg = (unsigned long)latch_setting;
++ return 0;
++ } else {
++ return -ENOTSUPP;
++ }
++ break;
++
++ case IOCTL_GPIOSET:
++ if ((port_priv->bPartNumber == CP2103_PARTNUM) ||
++ (port_priv->bPartNumber == CP2104_PARTNUM)) {
++ latch_setting =
++ *(unsigned int *)arg & 0x000000FF;
++ latch_setting |=
++ (*(unsigned int *)arg & 0x00FF0000) >> 8;
++ result = usb_control_msg(port->serial->dev,
++ usb_sndctrlpipe(port->serial->dev, 0),
++ CP210X_VENDOR_SPECIFIC,
++ REQTYPE_HOST_TO_DEVICE,
++ CP210X_WRITE_LATCH,
++ latch_setting,
++ NULL, 0,
++ USB_CTRL_SET_TIMEOUT);
++ if (result != 0)
++ return -EPROTO;
++ return 0;
++ } else if (port_priv->bPartNumber == CP2105_PARTNUM) {
++ latch_setting =
++ *(unsigned int *)arg & 0x000000FF;
++ latch_setting |=
++ (*(unsigned int *)arg & 0x00FF0000) >> 8;
++ result = usb_control_msg(port->serial->dev,
++ usb_sndctrlpipe(port->serial->dev, 0),
++ CP210X_VENDOR_SPECIFIC,
++ REQTYPE_HOST_TO_INTERFACE,
++ CP210X_WRITE_LATCH,
++ port_priv->bInterfaceNumber,
++ &latch_setting, 2,
++ USB_CTRL_SET_TIMEOUT);
++ if (result != 2)
++ return -EPROTO;
++ return 0;
++ } else {
++ return -ENOTSUPP;
++ }
++ break;
++
++ default:
++ break;
++ }
++
++ return -ENOIOCTLCMD;
++}
++
+ /*
+ * cp210x_get_termios
+ * Reads the baud rate, data bits, parity, stop bits and flow control mode
+@@ -862,6 +973,7 @@
+ {
+ struct usb_host_interface *cur_altsetting;
+ struct cp210x_serial_private *spriv;
++ unsigned int partNum;
+
+ /* cp210x buffers behave strangely unless device is reset */
+ usb_reset_device(serial->dev);
+@@ -875,6 +987,17 @@
+
+ usb_set_serial_data(serial, spriv);
+
++ /* Get the 1-byte part number of the cp210x device */
++ usb_control_msg(serial->dev,
++ usb_rcvctrlpipe(serial->dev, 0),
++ CP210X_VENDOR_SPECIFIC,
++ REQTYPE_DEVICE_TO_HOST,
++ CP210X_GET_PARTNUM,
++ spriv->bInterfaceNumber,
++ &partNum, 1,
++ USB_CTRL_GET_TIMEOUT);
++ spriv->bPartNumber = partNum & 0xFF;
++
+ return 0;
+ }
+
diff --git a/target/linux/generic/patches-4.1/824-cp210x_add_gpio_ioctl.patch
b/target/linux/generic/patches-4.1/824-cp210x_add_gpio_ioctl.patch
new file mode 100644
index 0000000..f737140
--- /dev/null
+++ b/target/linux/generic/patches-4.1/824-cp210x_add_gpio_ioctl.patch
@@ -0,0 +1,194 @@
+--- a/drivers/usb/serial/cp210x.c
++++ b/drivers/usb/serial/cp210x.c
+@@ -24,13 +24,15 @@
+ #include <linux/uaccess.h>
+ #include <linux/usb/serial.h>
+
+-#define DRIVER_DESC "Silicon Labs CP210x RS232 serial adaptor driver"
++#define DRIVER_DESC "Silicon Labs CP210x RS232 serial adaptor driver (with
GPIO support)"
+
+ /*
+ * Function Prototypes
+ */
+ static int cp210x_open(struct tty_struct *tty, struct usb_serial_port *);
+ static void cp210x_close(struct usb_serial_port *);
++static int cp210x_ioctl(struct tty_struct *tty,
++ unsigned int cmd, unsigned long arg);
+ static void cp210x_get_termios(struct tty_struct *, struct usb_serial_port *);
+ static void cp210x_get_termios_port(struct usb_serial_port *port,
+ unsigned int *cflagp, unsigned int *baudp);
+@@ -198,6 +200,7 @@ MODULE_DEVICE_TABLE(usb, id_table);
+
+ struct cp210x_serial_private {
+ __u8 bInterfaceNumber;
++ __u8 bPartNumber;
+ };
+
+ static struct usb_serial_driver cp210x_device = {
+@@ -211,6 +214,7 @@ static struct usb_serial_driver cp210x_d
+ .bulk_out_size = 256,
+ .open = cp210x_open,
+ .close = cp210x_close,
++ .ioctl = cp210x_ioctl,
+ .break_ctl = cp210x_break_ctl,
+ .set_termios = cp210x_set_termios,
+ .tiocmget = cp210x_tiocmget,
+@@ -224,6 +228,17 @@ static struct usb_serial_driver * const
+ &cp210x_device, NULL
+ };
+
++/* Part number definitions */
++#define CP2101_PARTNUM 0x01
++#define CP2102_PARTNUM 0x02
++#define CP2103_PARTNUM 0x03
++#define CP2104_PARTNUM 0x04
++#define CP2105_PARTNUM 0x05
++
++/* IOCTLs */
++#define IOCTL_GPIOGET 0x8000
++#define IOCTL_GPIOSET 0x8001
++
+ /* Config request types */
+ #define REQTYPE_HOST_TO_INTERFACE 0x41
+ #define REQTYPE_INTERFACE_TO_HOST 0xc1
+@@ -257,11 +272,17 @@ static struct usb_serial_driver * const
+ #define CP210X_SET_CHARS 0x19
+ #define CP210X_GET_BAUDRATE 0x1D
+ #define CP210X_SET_BAUDRATE 0x1E
++#define CP210X_VENDOR_SPECIFIC 0xFF
+
+ /* CP210X_IFC_ENABLE */
+ #define UART_ENABLE 0x0001
+ #define UART_DISABLE 0x0000
+
++/* CP210X_VENDOR_SPECIFIC */
++#define CP210X_WRITE_LATCH 0x37E1
++#define CP210X_READ_LATCH 0x00C2
++#define CP210X_GET_PARTNUM 0x370B
++
+ /* CP210X_(SET|GET)_BAUDDIV */
+ #define BAUD_RATE_GEN_FREQ 0x384000
+
+@@ -478,6 +499,96 @@ static void cp210x_close(struct usb_seri
+ cp210x_set_config_single(port, CP210X_IFC_ENABLE, UART_DISABLE);
+ }
+
++static int cp210x_ioctl(struct tty_struct *tty,
++ unsigned int cmd, unsigned long arg)
++{
++ struct usb_serial_port *port = tty->driver_data;
++ struct usb_serial *serial = port->serial;
++ struct cp210x_serial_private *port_priv = usb_get_serial_data(serial);
++ int result = 0;
++ unsigned int latch_setting = 0;
++
++ switch (cmd) {
++
++ case IOCTL_GPIOGET:
++ if ((port_priv->bPartNumber == CP2103_PARTNUM) ||
++ (port_priv->bPartNumber == CP2104_PARTNUM)) {
++ result = usb_control_msg(port->serial->dev,
++ usb_rcvctrlpipe(port->serial->dev, 0),
++ CP210X_VENDOR_SPECIFIC,
++ REQTYPE_DEVICE_TO_HOST,
++ CP210X_READ_LATCH,
++ port_priv->bInterfaceNumber,
++ &latch_setting, 1,
++ USB_CTRL_GET_TIMEOUT);
++ if (result != 1)
++ return -EPROTO;
++ *(unsigned long *)arg = (unsigned long)latch_setting;
++ return 0;
++ } else if (port_priv->bPartNumber == CP2105_PARTNUM) {
++ result = usb_control_msg(port->serial->dev,
++ usb_rcvctrlpipe(port->serial->dev, 0),
++ CP210X_VENDOR_SPECIFIC,
++ REQTYPE_INTERFACE_TO_HOST,
++ CP210X_READ_LATCH,
++ port_priv->bInterfaceNumber,
++ &latch_setting, 1,
++ USB_CTRL_GET_TIMEOUT);
++ if (result != 1)
++ return -EPROTO;
++ *(unsigned long *)arg = (unsigned long)latch_setting;
++ return 0;
++ } else {
++ return -ENOTSUPP;
++ }
++ break;
++
++ case IOCTL_GPIOSET:
++ if ((port_priv->bPartNumber == CP2103_PARTNUM) ||
++ (port_priv->bPartNumber == CP2104_PARTNUM)) {
++ latch_setting =
++ *(unsigned int *)arg & 0x000000FF;
++ latch_setting |=
++ (*(unsigned int *)arg & 0x00FF0000) >> 8;
++ result = usb_control_msg(port->serial->dev,
++ usb_sndctrlpipe(port->serial->dev, 0),
++ CP210X_VENDOR_SPECIFIC,
++ REQTYPE_HOST_TO_DEVICE,
++ CP210X_WRITE_LATCH,
++ latch_setting,
++ NULL, 0,
++ USB_CTRL_SET_TIMEOUT);
++ if (result != 0)
++ return -EPROTO;
++ return 0;
++ } else if (port_priv->bPartNumber == CP2105_PARTNUM) {
++ latch_setting =
++ *(unsigned int *)arg & 0x000000FF;
++ latch_setting |=
++ (*(unsigned int *)arg & 0x00FF0000) >> 8;
++ result = usb_control_msg(port->serial->dev,
++ usb_sndctrlpipe(port->serial->dev, 0),
++ CP210X_VENDOR_SPECIFIC,
++ REQTYPE_HOST_TO_INTERFACE,
++ CP210X_WRITE_LATCH,
++ port_priv->bInterfaceNumber,
++ &latch_setting, 2,
++ USB_CTRL_SET_TIMEOUT);
++ if (result != 2)
++ return -EPROTO;
++ return 0;
++ } else {
++ return -ENOTSUPP;
++ }
++ break;
++
++ default:
++ break;
++ }
++
++ return -ENOIOCTLCMD;
++}
++
+ /*
+ * cp210x_get_termios
+ * Reads the baud rate, data bits, parity, stop bits and flow control mode
+@@ -866,6 +977,7 @@ static int cp210x_startup(struct usb_ser
+ {
+ struct usb_host_interface *cur_altsetting;
+ struct cp210x_serial_private *spriv;
++ unsigned int partNum;
+
+ spriv = kzalloc(sizeof(*spriv), GFP_KERNEL);
+ if (!spriv)
+@@ -876,6 +988,17 @@ static int cp210x_startup(struct usb_ser
+
+ usb_set_serial_data(serial, spriv);
+
++ /* Get the 1-byte part number of the cp210x device */
++ usb_control_msg(serial->dev,
++ usb_rcvctrlpipe(serial->dev, 0),
++ CP210X_VENDOR_SPECIFIC,
++ REQTYPE_DEVICE_TO_HOST,
++ CP210X_GET_PARTNUM,
++ spriv->bInterfaceNumber,
++ &partNum, 1,
++ USB_CTRL_GET_TIMEOUT);
++ spriv->bPartNumber = partNum & 0xFF;
++
+ return 0;
+ }
+
--
1.9.0
_______________________________________________
openwrt-devel mailing list
openwrt-devel at lists.openwrt.org
https://lists.openwrt.org/cgi-bin/mailman/listinfo/openwrt-devel
More information about the openwrt-devel
mailing list