lkml.org 
[lkml]   [2012]   [May]   [1]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[PATCH 3/3] usb: cp210x: Add ioctl for GPIO support
    Date
    This patch adds support for GPIO for CP210x devices that support it through two
    IOCTLs to get or set the GPIO latch on a CP210x device. The specification for
    this can be found in Silicon Labs AN571 document on section 5.27.1-4.

    Signed-off-by: Preston Fick <preston.fick@silabs.com>
    ---
    drivers/usb/serial/cp210x.c | 98 +++++++++++++++++++++++++++++++++++++++++++
    1 files changed, 98 insertions(+), 0 deletions(-)

    diff --git a/drivers/usb/serial/cp210x.c b/drivers/usb/serial/cp210x.c
    index b3646b8..9d1e542 100644
    --- a/drivers/usb/serial/cp210x.c
    +++ b/drivers/usb/serial/cp210x.c
    @@ -35,6 +35,8 @@
    */
    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 *port);
    static void cp210x_get_termios_port(struct usb_serial_port *port,
    @@ -175,6 +177,7 @@ static struct usb_serial_driver cp210x_device = {
    .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,
    @@ -195,6 +198,10 @@ static struct usb_serial_driver * const serial_drivers[] = {
    #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
    @@ -235,6 +242,8 @@ static struct usb_serial_driver * const serial_drivers[] = {
    #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 */
    @@ -467,6 +476,95 @@ static void cp210x_close(struct usb_serial_port *port)
    mutex_unlock(&port->serial->disc_mutex);
    }

    +static int cp210x_ioctl(struct tty_struct *tty,
    + unsigned int cmd, unsigned long arg)
    +{
    + struct usb_serial_port *port = tty->driver_data;
    + struct cp210x_port_private *port_priv = usb_get_serial_port_data(port);
    + 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
    --
    1.7.5.4


    \
     
     \ /
      Last update: 2012-05-01 06:42    [W:0.036 / U:91.860 seconds]
    ©2003-2016 Jasper Spaans. hosted at Digital OceanAdvertise on this site