[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