comparison Linux-DTR-RTS-flaw @ 100:48ea323c1c47

Linux-DTR-RTS-flaw: import from freecalypso-hwlab
author Mychaela Falconia <falcon@freecalypso.org>
date Mon, 11 Sep 2023 06:22:47 +0000
parents
children 916488f7a8e0
comparison
equal deleted inserted replaced
99:c28a1518d268 100:48ea323c1c47
1 There is a fundamental flaw in the Linux kernel serial port handling subsystem
2 that affects anyone who builds special hardware in which DTR and/or RTS modem
3 control lines are repurposed for some non-traditional functions. The flaw is
4 that whenever a serial port is opened under Linux, the kernel immediately and
5 unstoppably asserts DTR and RTS (their initial power-up state prior to software
6 action is negated on every sane serial port hardware implementation), *without*
7 giving userspace applications any ability to say "no, please don't do it".
8
9 As long as DTR and RTS modem control outputs from the DTE are used for their
10 original RS-232 functions, automatically raising both signals on serial port
11 open is harmless - and because these signals often need to be asserted in order
12 for serial communication to take place, having them raised automatically on
13 open (without requiring an explicit TIOCMBIS ioctl) is a convenience which many
14 applications rely on - if this standard kernel behaviour were to be changed
15 for the general case (outside of special quirk configurations), a lot of
16 applications will break. Linux implements this standard behaviour as mandated
17 by POSIX and other similar standards, and those standards are in turn based on
18 the original 1970s UNIX where this architectural design originates.
19
20 However, this standard Linux behaviour (and going all the way back to 1970s in
21 the greater UNIX family) is a total killer for custom hardware designs in which
22 DTR and/or RTS outputs from the UART are repurposed for some totally different
23 functions. Suppose that the hardware is wired in such a way that asserting the
24 control output causes an explosive charge to be set off, or causes a radio
25 transmitter to turn on (perhaps operating on some tightly regulated frequency
26 supporting mission-critical services, where spurious out-of-protocol
27 transmissions are not permissible), or applies a hard reset to some other
28 component that may be part of a live production system that must not be casually
29 reset - in all listed examples having such hardware wiring would be perfectly
30 safe in an OS-less environment where the custom application controls the custom
31 hardware as desired, without any OS inserting its own mind: the hardware design
32 of most serial ports (both traditional and USB-serial) guarantees that the
33 initial power-up state of both DTR and RTS outputs prior to software action will
34 always be negated, and the custom application thus gets to decide if and when
35 each of the two signals (independent of each other) should be asserted.
36
37 Everything works great if the application runs on the bare metal and directly
38 controls the hardware (or runs under something like DOS, which is the same as
39 running on bare metal for the present purpose of operating serial ports), but
40 add Linux into the equation, and things quickly begin to break. The problem is
41 that the moment you open a serial port under Linux (and sadly, the same thing
42 happens under most other current OSes too), the kernel automatically asserts
43 both DTR and RTS immediately on the open operation itself, without giving
44 userspace applications any way to say "no, please don't do it". Some people
45 have been proposing new termios flags that would suppress this auto-assertion
46 on subsequent opens, but you have to open the port first in order to do termios
47 or other ioctls on it, and if the auto-assertion of DTR and RTS on that initial
48 open causes irreparable damage, then you are screwed no matter what you do.
49
50 The only currently possible solution to this madness is to patch the kernel to
51 suppress this automatic assertion of DTR & RTS upon serial port open. But one
52 cannot simply change the standard behaviour for all serial ports, as lots of
53 standard applications for classic serial communication (where DTR and RTS do
54 need to be asserted) will break in that case. Instead the suppression of
55 automatic assertion of DTR & RTS on open needs to be conditionalized in some
56 way, so that the modified against-standards serial port open behaviour is
57 applied ONLY when special modem-control-repurposed hardware is being operated
58 on, and not for ordinary applications operating on ordinary serial ports.
59
60 Given the current state of Linux and what is possible in the current reality,
61 if a patch is to be applied to the kernel, creating the ability to exempt
62 certain serial port open operations from the standard POSIX requirement of
63 automatically asserting DTR & RTS, there are only 3 practically feasible ways
64 to communicate to the kernel that a given serial port (or a given individual
65 open operation on a serial port) should be exempt from automatic assertion of
66 DTR & RTS:
67
68 1) Create a new open flag like O_NODTR, or reuse/abuse some existing open flag
69 like O_DIRECT which currently has no effect on serial ports.
70
71 2) Create a sysfs attribute that is attached to every serial port, controlling
72 whether or not DTR & RTS should be automatically asserted on open, with the
73 default being standards-mandated traditional UNIX behaviour of
74 auto-assertion.
75
76 3) In special cases where the custom DTR/RTS-repurposed hardware is inseparably
77 integrated (on the same custom PCB) with a USB-serial chip, such that the
78 EEPROM controlling the USB VID:PID of the USB-serial device identifies not
79 just the USB-serial converter part, but the entire product board as a whole,
80 including the circuits that repurpose DTR and RTS for non-serial purposes,
81 then the most sensible approach is to mark the USB-serial device as special
82 and disable auto-assertion of DTR & RTS on this special device when the
83 custom USB VID:PID is detected.
84
85 As it happens, our own FreeCalypso hardware gadget with repurposed DTR & RTS
86 that requires suppression of auto-assertion of these signals (the optional boot
87 control feature of our DUART28 adapter) falls into the last special category
88 above (custom USB-serial device unambiguously distinguished by a custom USB ID),
89 hence this special case is the one that I (Mother Mychaela) have been focusing
90 on the most - as humans, we all have a natural right to put our own self-
91 interest first.
92
93 I (Mother Mychaela) have no way of knowing whether or not there is even one
94 person alive on Earth today who has an active use case where a need exists to
95 suppress automatic assertion of DTR & RTS for some serial device, but that
96 device does not have the same quality of being inseparably integrated with a
97 custom USB ID as our DUART28C, i.e., an active use case where a need exists to
98 signal to the kernel "please don't auto-assert DTR & RTS on this serial port"
99 and moreover do this special signaling for "any" serial port, rather than one
100 identified by a custom USB VID:PID. For all I know, I may very well be the
101 only person alive on Earth today who has an active need for auto-DTR/RTS
102 suppression - but I need it ONLY for a device that has a unique distinctive USB
103 VID:PID, not for "any" serial port.
104
105 I currently run Slackware Linux 14.2 as my personal OS, running Linux kernel
106 version 4.4.14 around which this version of Slackware was built - when I tried
107 running newer 4.4.x kernels, I was getting crashes which I could not debug. I
108 currently run this elderly Linux kernel version with my own custom patch applied
109 to the ftdi_sio driver, a patch that adds support for FreeCalypso DUART28C
110 (custom USB ID) and applies the appropriate special quirk just for this USB ID,
111 not affecting any other devices - a quirk that suppresses automatic DTR & RTS
112 assertion on FT2232D Channel B, the UART channel on which these signals are
113 repurposed on DUART28 hardware. Several different versions of this patch (made
114 to apply cleanly to several different kernel versions) can be found in the
115 linux-patch directory in the present source repository.
116
117 In 2020-09 I made a good-faith, due-diligence attempt to get the hardware
118 support patch for DUART28C (a patch to ftdi_sio driver that recognizes the new
119 USB ID and applies the necessary quirk, entirely contained inside this driver)
120 mainlined - I submitted the patch to ftdi_sio maintainer Johan Hovold. I was
121 quickly met with hostility, with Johan telling me to redesign my hardware (he
122 was basically telling me to throw away 20 perfectly good boards) in some
123 different way that would be more in line with the 1970s UNIX worldview for DTR
124 and RTS, which is what Linux currently implements.
125
126 Some time later I was able to kinda-somewhat-partially convince Johan that the
127 current handling of DTR and RTS is a serious problem for some users, and he was
128 a little more agreeable to my patch - but instead of merging it as-is, he
129 proposed an expanded patch (getting into the tty subsystem, outside of just
130 USB-serial) that solves a more general problem. Johan's proposed patch
131 introduced an internal flag telling the tty layer to suppress DTR & RTS
132 assertion on open, and a sysfs attribute (added to all classic serial and USB-
133 serial ports) that exposes this flag. A patch to ftdi_sio that recognizes my
134 custom USB ID and sets this flag in the quirk function was still included in
135 that proposed patch series, so I was happy with the proposal.
136
137 However, Johan's sysfs proposal was quickly shot down by other kernel
138 maintainers who didn't like the sysfs approach, and Johan himself was not too
139 interested in defending his sysfs proposal either - instead he favors a termios
140 flag that would only affect second and subsequent repeated opens of a device,
141 after the initial open to set that flag. Of course this termios flag idea does
142 not help at all, given that the very first open of the serial port would still
143 unstoppably assert DTR & RTS, causing irreparable damage - if these control
144 signals are wired to set off explosives, for example, the user's house would be
145 up in flames the moment he issues that magic stty command to set the new termios
146 flag, and Johan's assurances that second and subsequent opens of the same
147 serial port would not auto-assert DTR & RTS would be of little help to the poor
148 guy who just lost his house.
149
150 By the end of 2021-01 I realized that my battle against Johan and Greg K-H is
151 hopeless, so I give up. The only workable solution at this point is for all
152 affected people to stop running unpatched mainline kernels and to apply our own
153 local patches instead, preferably with our own coordination amongst ourselves
154 so we have some degree of standardization among our kind. The whole discussion
155 is archived here:
156
157 https://lore.kernel.org/linux-serial/X8iuCXYhOBVMGvXv@localhost/T/
158
159 I shall indefinitely, for as long as I am alive, maintain my ftdi_sio driver
160 patch that adds support for FreeCalypso DUART28C hardware. And because I do
161 not know whether or not there exists even one person on Earth who would benefit
162 from an ability to suppress DTR & RTS assertion under Linux on "any" serial
163 port, outside of tightly integrated USB-based devices with custom USB IDs, I
164 also make the following conditional offer: *if* at least one person comes
165 forward to me and demonstrates that he or she has an active use case of the
166 kind I am talking about, *then* I will also dig up Johan's patch (the one
167 rejected by other maintainers) adding a sysfs attribute, providing a working
168 solution for "any" serial port, start actively supporting that sysfs patch, and
169 maybe even make another attempt at convincing kernel maintainers to mainline it.
170 But I will go down that path *only* if there is at least one person alive on
171 Earth (just one person would be enough) who would actively benefit from this
172 feature - otherwise there is no point.