From patchwork Mon Aug 3 17:55:06 2015 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ted Hess X-Patchwork-Id: 503257 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from arrakis.dune.hu (arrakis.dune.hu [78.24.191.176]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 04D5A1402D1 for ; Tue, 4 Aug 2015 03:55:36 +1000 (AEST) Received: from arrakis.dune.hu (localhost [127.0.0.1]) by arrakis.dune.hu (Postfix) with ESMTP id 05F22283F28; Mon, 3 Aug 2015 19:54:48 +0200 (CEST) X-Spam-Checker-Version: SpamAssassin 3.3.2 (2011-06-06) on arrakis.dune.hu X-Spam-Level: X-Spam-Status: No, score=-1.5 required=5.0 tests=BAYES_00 autolearn=unavailable version=3.3.2 Received: from arrakis.dune.hu (localhost [127.0.0.1]) by arrakis.dune.hu (Postfix) with ESMTP id 74D3B28155D for ; Mon, 3 Aug 2015 19:54:41 +0200 (CEST) X-policyd-weight: NOT_IN_SBL_XBL_SPAMHAUS=-1.5 NOT_IN_SPAMCOP=-1.5 NOT_IN_BL_NJABL=-1.5 CL_IP_EQ_HELO_IP=-2 (check from: .kitschensync. - helo: .mailout.easymail. - helo-domain: .easymail.) FROM/MX_MATCHES_HELO(DOMAIN)=-2; rate: -8.5 Received: from mailout.easymail.ca (mailout.easymail.ca [64.68.201.169]) by arrakis.dune.hu (Postfix) with ESMTPS for ; Mon, 3 Aug 2015 19:54:33 +0200 (CEST) Received: from localhost (localhost [127.0.0.1]) by mailout.easymail.ca (Postfix) with ESMTP id 740D1E228 for ; Mon, 3 Aug 2015 13:55:07 -0400 (EDT) X-Virus-Scanned: Debian amavisd-new at mailout.easymail.ca Received: from mailout.easymail.ca ([127.0.0.1]) by localhost (easymail-mailout.easydns.vpn [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id MSSoWpcRVAwB for ; Mon, 3 Aug 2015 13:55:03 -0400 (EDT) Received: from twonky7 (pool-98-118-10-131.bstnma.fios.verizon.net [98.118.10.131]) (using TLSv1 with cipher AES256-SHA (256/256 bits)) (No client certificate requested) by mailout.easymail.ca (Postfix) with ESMTPSA id 83484E23D for ; Mon, 3 Aug 2015 13:55:03 -0400 (EDT) Message-ID: From: "Ted Hess" To: "OpenWrt developers" Date: Mon, 3 Aug 2015 13:55:06 -0400 MIME-Version: 1.0 X-Priority: 3 X-MSMail-Priority: Normal Importance: Normal X-Mailer: Microsoft Windows Live Mail 16.4.3528.331 X-MimeOLE: Produced By Microsoft MimeOLE V16.4.3528.331 X-Antivirus: avast! (VPS 150803-1, 08/03/2015), Outbound message X-Antivirus-Status: Clean Subject: [OpenWrt-Devel] [PATCH] [kernel] cp201x: Add GPIO ioctl commands (from Silicon Labs) X-BeenThere: openwrt-devel@lists.openwrt.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: OpenWrt Development List List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: openwrt-devel-bounces@lists.openwrt.org Sender: "openwrt-devel" 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 --- .../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 + #include + +-#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 + #include + +-#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; + }