Message ID | 20220527222713.A369E3740211@freecalypso.org |
---|---|
State | New |
Headers | show |
Series | [1/6] tty: add port flag to suppress raising DTR & RTS on open | expand |
On Sat, May 28, 2022 at 2:22 AM Mychaela N. Falconia <falcon@freecalypso.org> wrote: > > Add a manual_rtsdtr sysfs attribute to suppress automatic raising of > DTR and RTS modem control signals on serial port open. > > This special mode can be used to prevent undesirable side effects on > open for applications where these lines are used for non-standard > purposes such as generating power-on and reset pulses. As I read this I think of the pins used as GPIOs. So, sounds like what we need instead is to list the pins that are used for (dedicated) GPIOs and pass this information to serial mctrl layer and perhaps prepare that layer to handle exclusions like these. The given (in this series) approach sounds to me like a (hackish?) workaround of this simple idea.
Andy Shevchenko wrote: > As I read this I think of the pins used as GPIOs. Viewing my repurposed DTR & RTS outputs as GPIOs is a valid way to look at them. The target application has one 8-wire UART, a secondary 2-wire UART, and two GPIO (really GPO, output-only) controls. Because no major USB-to-X chip vendor makes a chip that goes from one USB to this combination of two UARTs plus GPIO (there are some that may seem to qualify at first glance, such as CP2105, but that one and others I know of have other issues that preclude their use), I took the next most practical route: I used FT2232D, and repurposed its otherwise unused Channel B DTR & RTS outputs to be GPOs. > So, sounds like what > we need instead is to list the pins that are used for (dedicated) > GPIOs and pass this information to serial mctrl layer and perhaps > prepare that layer to handle exclusions like these. What you are describing would be quite easy to implement for *my* device, and the implementation would be entirely contained in the ftdi_sio driver. My particular FTDI chip (FT2232D) doesn't have any pins that are officially regarded as GPIOs, but other FTDI chips do (single-channel FT232H, FT232R and FT-X), and Linux ftdi_sio driver already has support for presenting FT232H/R/FT-X CBUS pins to gpiolib as a gpio_chip. It would be fairly easy to implement a second kind of gpio_chip within ftdi_sio, made out of an otherwise-serial channel's DTR and RTS outputs - but here is the big BUT: I don't know how to conditionalize enabling of this special mode (stealing DTR & RTS from the ttyUSBx device and handing them over to gpiolib control instead) other than by keying on specific USB VID:PID codes. The latter approach would work great for my application, but I keep being told that the solution must work for "everyone", whatever that global specifier could mean in this context. However, this idea of moving an FTDI device's DTR & RTS outputs to gpiolib control at the ftdi_sio driver level will not help anyone who has an old-fashioned RS-232 (not USB-serial) device in which DTR and/or RTS have been repurposed in a way that does not tolerate automatic unconditional assertion of these signals on open. I don't know whether or not any such devices exist: there aren't any in _my_ world, but I keep being told to think generically, outside of my own repertoire of use cases. At this point I need to ask the maintainers with decision-making powers: which approach would be more acceptable? The two approaches which I see as feasible are: Option 1: implement a special mode for all serial ports, both "hard" and USB-serial, that suppresses automatic assertion of DTR & RTS on open - but allows them to be controlled with TIOCMBIS and TIOCMBIC. Yes, the signals are really GPIOs in this case, but just how would one go about turning UART signals into true Linux GPIOs on any arbitrary serial port, whenever an end user decides to connect a particular RS-232 device that needs special handling? Option 2: implement a VID:PID-keyed solution in the ftdi_sio driver, stealing DTR & RTS completely from the tty device and handing them over to gpiolib control. This solution would work for my specific USB device, and if anyone else builds anything similar, they could reuse the same ftdi_sio driver quirk - but this solution provides no help at all to RS-232 tinkerers, if any exist. M~
diff --git a/Documentation/ABI/testing/sysfs-tty b/Documentation/ABI/testing/sysfs-tty index 820e412d38a8..3e666538451b 100644 --- a/Documentation/ABI/testing/sysfs-tty +++ b/Documentation/ABI/testing/sysfs-tty @@ -161,3 +161,13 @@ Contact: Andy Shevchenko <andriy.shevchenko@linux.intel.com> Description: Allows user to detach or attach back the given device as kernel console. It shows and accepts a boolean variable. + +What: /sys/class/tty/tty<x>/manual_rtsdtr +Date: May 2022 +Contact: Mychaela N. Falconia <falcon@freecalypso.org> +Description: + Writing 1 into this flag attribute suppresses automatic + assertion of DTR & RTS on serial port open, putting these + signals under manual control (TIOCMBIS & TIOCMBIC). + Writing 0 restores standard POSIX/SUS behaviour of + automatically asserting both DTR and RTS on open. diff --git a/drivers/tty/serial/serial_core.c b/drivers/tty/serial/serial_core.c index 9a85b41caa0a..b47004a3fb77 100644 --- a/drivers/tty/serial/serial_core.c +++ b/drivers/tty/serial/serial_core.c @@ -2870,6 +2870,31 @@ static ssize_t console_store(struct device *dev, return ret < 0 ? ret : count; } +static ssize_t manual_rtsdtr_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct tty_port *port = dev_get_drvdata(dev); + + return sprintf(buf, "%d\n", tty_port_manual_rtsdtr(port)); +} + +static ssize_t manual_rtsdtr_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct tty_port *port = dev_get_drvdata(dev); + bool val; + int ret; + + ret = kstrtobool(buf, &val); + if (ret) + return ret; + + tty_port_set_manual_rtsdtr(port, val); + + return count; +} + static DEVICE_ATTR_RO(uartclk); static DEVICE_ATTR_RO(type); static DEVICE_ATTR_RO(line); @@ -2884,6 +2909,7 @@ static DEVICE_ATTR_RO(io_type); static DEVICE_ATTR_RO(iomem_base); static DEVICE_ATTR_RO(iomem_reg_shift); static DEVICE_ATTR_RW(console); +static DEVICE_ATTR_RW(manual_rtsdtr); static struct attribute *tty_dev_attrs[] = { &dev_attr_uartclk.attr, @@ -2900,6 +2926,7 @@ static struct attribute *tty_dev_attrs[] = { &dev_attr_iomem_base.attr, &dev_attr_iomem_reg_shift.attr, &dev_attr_console.attr, + &dev_attr_manual_rtsdtr.attr, NULL };