This introduces the `uart_mode` sysfs attribute as seen in the `io_ti`
USB serial driver, allowing this USB serial interface to be switched
between RS-232, 2-wire RS-485 and 4-wire RS-485.

/sys/class/tty/ttyUSB${num}/device/uart takes a single integer:

        0:      RS-232 mode (default for RS-232-compatible dongles)
        1:      RS-485 2w mode (default for RS-485-only dongles)
        2:      RS-485 4w mode / RS-422 mode

Write this *before* opening your serial device.

This has been successfully tested on a Moxa UPort 1150 in 4-wire RS-485
mode.

Signed-off-by: Stuart Longland <stua...@vrt.com.au>
---
 drivers/usb/serial/ti_usb_3410_5052.c | 48 +++++++++++++++++++++++++++++++++++
 1 file changed, 48 insertions(+)

diff --git a/drivers/usb/serial/ti_usb_3410_5052.c 
b/drivers/usb/serial/ti_usb_3410_5052.c
index 8fc3854e5e69..fb30d7ff32d7 100644
--- a/drivers/usb/serial/ti_usb_3410_5052.c
+++ b/drivers/usb/serial/ti_usb_3410_5052.c
@@ -514,6 +514,46 @@ MODULE_DEVICE_TABLE(usb, ti_id_table_combined);
 
 module_usb_serial_driver(serial_drivers, ti_id_table_combined);
 
+/* Sysfs Attributes */
+
+static ssize_t uart_mode_show(struct device *dev,
+       struct device_attribute *attr, char *buf)
+{
+       struct usb_serial_port *port = to_usb_serial_port(dev);
+       struct ti_port *tport = usb_get_serial_port_data(port);
+
+       return sprintf(buf, "%d\n", tport->tp_uart_mode);
+}
+
+static ssize_t uart_mode_store(struct device *dev,
+       struct device_attribute *attr, const char *valbuf, size_t count)
+{
+       struct usb_serial_port *port = to_usb_serial_port(dev);
+       struct ti_port *tport = usb_get_serial_port_data(port);
+       unsigned int v = simple_strtoul(valbuf, NULL, 0);
+
+       dev_dbg(dev, "%s: setting uart_mode = %d\n", __func__, v);
+
+       if (v < 256)
+               tport->tp_uart_mode = v;
+       else
+               dev_err(dev, "%s - uart_mode %d is invalid\n", __func__, v);
+
+       return count;
+}
+static DEVICE_ATTR_RW(uart_mode);
+
+static int ti_create_sysfs_attrs(struct usb_serial_port *port)
+{
+       return device_create_file(&port->dev, &dev_attr_uart_mode);
+}
+
+static int ti_remove_sysfs_attrs(struct usb_serial_port *port)
+{
+       device_remove_file(&port->dev, &dev_attr_uart_mode);
+       return 0;
+}
+
 static int ti_startup(struct usb_serial *serial)
 {
        struct ti_device *tdev;
@@ -607,6 +647,7 @@ static void ti_release(struct usb_serial *serial)
 static int ti_port_probe(struct usb_serial_port *port)
 {
        struct ti_port *tport;
+       int status;
 
        tport = kzalloc(sizeof(*tport), GFP_KERNEL);
        if (!tport)
@@ -628,6 +669,12 @@ static int ti_port_probe(struct usb_serial_port *port)
 
        usb_set_serial_port_data(port, tport);
 
+       status = ti_create_sysfs_attrs(port);
+       if (status) {
+               kfree(tport);
+               return status;
+       }
+
        port->port.drain_delay = 3;
 
        return 0;
@@ -638,6 +685,7 @@ static int ti_port_remove(struct usb_serial_port *port)
        struct ti_port *tport;
 
        tport = usb_get_serial_port_data(port);
+       ti_remove_sysfs_attrs(port);
        kfree(tport);
 
        return 0;
-- 
2.13.0

--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to