Forum > Linux
kernel 6.8 and checking serial ports - failure to match driver name
robert rozee:
hi,
i'm having troubles with some code i've been using for quite some time to validate serial ports, so that a user can be presented with a list if 'live' ports. jumping right into it, here is the main chunk of code i'm using, with a few writeln statements added in for debugging:
--- Code: Pascal [+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i < x.length; i++) { x[i].style.maxHeight='none'; x[i].style.height = Math.min(x[i].clientHeight+15,306)+'px'; x[i].style.resize = "vertical";}};} ---// method based on information obtained from the following two sites:// https://www.lazarusforum.de/viewtopic.php?p=72837// https://stackoverflow.com/questions/2530096function CheckDevice(DeviceName:string):boolean; // checks to see if the device named is a livevar DriverName:string; // ... serial port. this is done by checking FD:longint; // ... entries in /sys/class/tty including the SS:TSerialStruct; // ... presence of a link to a device driver. ST:stat; S:string;begin Result:=false; ST.st_mode:=0; if (DeviceName<>'.') and (DeviceName<>'..') then if FileExists('/sys/class/tty/'+DeviceName+'/device/driver') or // this suffices with FPC prior to 3.20 DirectoryExists('/sys/class/tty/'+DeviceName+'/device/driver') then // from FPC 3.20 onwards we need this instead if fpLstat('/sys/class/tty/'+DeviceName+'/device', ST)=0 then if fpS_ISLNK(ST.st_mode) then begin S:=fpReadLink('/sys/class/tty/'+DeviceName+'/device/driver'); DriverName:=ExtractFileName(S); writeln('/sys/class/tty/'+DeviceName+'/device/driver'); writeln('fpReadLink returns ',S); writeln('driver name is "',DriverName, '"'); if (DriverName<>'serial8250')// and (DriverName<>'port') then Result:=true else begin writeln('checking serial8250 device'); FD:=fpOpen('/dev/'+DeviceName, O_RDWR or O_NONBLOCK or O_NOCTTY); if FD>0 then try if fpIOCtl(FD, TIOCGSERIAL, @SS)<>-1 then if SS.typ<>0 then Result:=true; fpclose(FD) except end end end; if Result then writeln('>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> PASS >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>'); writelnend;
using a pre-6.8 kernel, passing in, for instance, 'ttyS2', will return a false result as ttyS2 does not exist as a functional serial port on my computer. whereas, ttyS0, tyS4 and ttyS5 are all valid serial ports and returned true with a pre-6.8 kernel. S4 and S5 are even genuine 16x50 silicon sitting on an PCI card.
but when using a 6.8 kernel, all ttySn ports return a true result %) as far as i have been able to determine, this is the result of either: a far more convoluted symlink arrangement within the /sys/ directory tree, or, possibly, fpReadLink not correctly handling paths that have a symlink in the middle. to be honest, i've just spent an evening trying to follow through the various symlinks and just ended up more confused than when i started!
here is some sample output from the above function, run over the serial ports ttyS0..5, and ttyUSB*:
--- Code: ---/sys/class/tty/ttyUSB1/device/driver
fpReadLink returns ../../../../../../../../bus/usb-serial/drivers/cp210x
driver name is "cp210x"
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> PASS >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
/sys/class/tty/ttyS4/device/driver
fpReadLink returns ../../../../../../../bus/serial-base/drivers/port
driver name is "port"
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> PASS >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
/sys/class/tty/ttyS2/device/driver
fpReadLink returns ../../../../../bus/serial-base/drivers/port
driver name is "port"
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> PASS >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
/sys/class/tty/ttyS0/device/driver
fpReadLink returns ../../../../../bus/serial-base/drivers/port
driver name is "port"
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> PASS >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
/sys/class/tty/ttyS5/device/driver
fpReadLink returns ../../../../../../../bus/serial-base/drivers/port
driver name is "port"
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> PASS >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
/sys/class/tty/ttyUSB0/device/driver
fpReadLink returns ../../../../../../../../bus/usb-serial/drivers/cp210x
driver name is "cp210x"
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> PASS >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
/sys/class/tty/ttyS3/device/driver
fpReadLink returns ../../../../../bus/serial-base/drivers/port
driver name is "port"
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> PASS >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
/sys/class/tty/ttyS1/device/driver
fpReadLink returns ../../../../../bus/serial-base/drivers/port
driver name is "port"
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> PASS >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
--- End code ---
and here it is with the line " and (DriverName<>'port') " no longer commented out:
--- Code: ---/sys/class/tty/ttyUSB1/device/driver
fpReadLink returns ../../../../../../../../bus/usb-serial/drivers/cp210x
driver name is "cp210x"
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> PASS >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
/sys/class/tty/ttyS4/device/driver
fpReadLink returns ../../../../../../../bus/serial-base/drivers/port
driver name is "port"
checking serial8250 device
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> PASS >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
/sys/class/tty/ttyS2/device/driver
fpReadLink returns ../../../../../bus/serial-base/drivers/port
driver name is "port"
checking serial8250 device
/sys/class/tty/ttyS0/device/driver
fpReadLink returns ../../../../../bus/serial-base/drivers/port
driver name is "port"
checking serial8250 device
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> PASS >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
/sys/class/tty/ttyS5/device/driver
fpReadLink returns ../../../../../../../bus/serial-base/drivers/port
driver name is "port"
checking serial8250 device
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> PASS >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
/sys/class/tty/ttyUSB0/device/driver
fpReadLink returns ../../../../../../../../bus/usb-serial/drivers/cp210x
driver name is "cp210x"
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> PASS >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
/sys/class/tty/ttyS3/device/driver
fpReadLink returns ../../../../../bus/serial-base/drivers/port
driver name is "port"
checking serial8250 device
/sys/class/tty/ttyS1/device/driver
fpReadLink returns ../../../../../bus/serial-base/drivers/port
driver name is "port"
checking serial8250 device
--- End code ---
the added condition " and (DriverName<>'port') " is a bit of a hack based upon observed output from the debug statements, forcing the code through the path that tries to open the port. while this works in my case, i'm quite sure it is wrong!
has anyone else encountered problems in checking serial ports when using a 6.8 kernel? any suggestions on a good way forward? i am pretty sure the above code, that i've been using for years, has been used by a number of other folks in the past.
cheers,
rob :-)
MarkMLl:
I'm only on 6.1 (from Debian "stable") I'm afraid, and I've never had to search for ttyS ports: only the variants of USB devices.
There /might/ /possibly/ be something in https://github.com/MarkMLl/serialcomms that helps. However the major "take-home" from doing that stuff was that the positioning of stuff in the /sys tree was very much at the whim of the kernel module writer, so it's entirely plausible that somebody has broken something by trying to "clean it up and adopt a standard layout".
MarkMLl
robert rozee:
--- Quote from: MarkMLl on November 24, 2024, 04:39:06 pm ---it's entirely plausible that somebody has broken something by trying to "clean it up and adopt a standard layout"
--- End quote ---
that is the feeling i get. i think it can be summed up as:
pre-6.8 kernel:
/sys/class/tty/ttyS2/device/driver resolves to /sys/bus/platform/drivers/serial8250
6.8 kernel:
/sys/class/tty/ttyS2/device/driver resolves to /sys/bus/serial-base/drivers/port
this change breaks the check for the path ending in "serial8250".
any idea where i can ask about this? i've just had a look for an online linux kernel mailing list, and there seem to be a number of them - which one is the 'official' one?
quite separately to this, i am concerned about fpReadLink returning a string containing way too many back-steps ("/../"):
--- Code: ---/sys/class/tty/ttyS5/device/driver
fpReadLink returns ../../../../../../../bus/serial-base/drivers/port
--- End code ---
in the above example this is seven steps back up a directory tree that is nowhere near that deep. my guess is that this equates to a path that is:
/sys/class/tty/ttyS5/device/driver/../../../../../../../bus/serial-base/drivers/port
whereas, as far as i can figure, there should be only five back-steps.
cheers,
rob :-)
MarkMLl:
--- Quote from: robert rozee on November 25, 2024, 10:45:33 am ---
--- Quote from: MarkMLl on November 24, 2024, 04:39:06 pm ---it's entirely plausible that somebody has broken something by trying to "clean it up and adopt a standard layout"
--- End quote ---
that is the feeling i get. i think it can be summed up as:
pre-6.8 kernel:
/sys/class/tty/ttyS2/device/driver resolves to /sys/bus/platform/driver2/serial8250
6.8 kernel:
/sys/class/tty/ttyS2/device/driver resolves to /sys/bus/serial-base/drivers/port
this change breaks the check for the path ending in "serial8250".
--- End quote ---
I've just been sniffing around (because of the number of USB-connected devices I've got) and I think I see what's happening at least on older versions: ports which don't quite exist get allocated the serial8250 driver, while ones which really exist are allocated a more recent one.
Not sure that helps you...
--- Quote ---any idea where i can ask about this? i've just had a look for a linux kernel mailing list, and there seem to be a number of them - which one is the 'official' one?
--- End quote ---
I think the thing to do is find the Git commit that changed it, note who's responsible, and find where he's discussed it in the past... probably somewhere in https://lkml.org/ But if that's been committed it's unlikely that they'll backtrack, since that would leave one or a small number of kernel versions behaving anomalously rather than there being a recognisable change at one specific point.
...And the /sys tree is an internal interface.
--- Quote ---quite separately to this, i am concerned about fpReadLink returning a string containing way too many back-steps ("/../"):
--- Quote ---[/sys/class/tty/ttyS5/device/driver
fpReadLink returns ../../../../../../../bus/serial-base/drivers/port/quote]
in the above example this is seven steps back up a directory tree that is nowhere near that deep. my guess is that this equates to a path that is:
/sys/class/tty/ttyS5/device/driver/../../../../../../../bus/serial-base/drivers/port
whereas, as far as i can figure, there should be only five back-steps.
--- End quote ---
--- End quote ---
But what you're seeing there is literally what the driver is telling you to look at, when you ask it for information about itself (remember that these are kernel abstractions, not "real" files and directories). There is almost certainly something in the RTL which would canonicalise that path, but while it would certainly be useful to be able to see it it might not be strictly correct to rely on it: and a defensive kernel hacker might be dismissive if you take that sort of liberty :-/
MarkMLl
robert rozee:
--- Quote from: MarkMLl on November 25, 2024, 11:08:46 am ---I've just been sniffing around (because of the number of USB-connected devices I've got) and I think I see what's happening at least on older versions: ports which don't quite exist get allocated the serial8250 driver, while ones which really exist are allocated a more recent one
--- End quote ---
with a pre-6.8 kernel, all the /dev/ttySxx ports seem to be associated with the "serial8250" driver, and my code has to iterate over all of them trying to open each /dev/ttySxx to verify if a given port's hardware exists or not. this check is handled with the fragment of code:
--- Code: Pascal [+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i < x.length; i++) { x[i].style.maxHeight='none'; x[i].style.height = Math.min(x[i].clientHeight+15,306)+'px'; x[i].style.resize = "vertical";}};} ---Result:=false;[...]FD:=fpOpen('/dev/'+DeviceName, O_RDWR or O_NONBLOCK or O_NOCTTY);if FD>0 thentry if fpIOCtl(FD, TIOCGSERIAL, @SS)<>-1 then // note: TIOCGSERIAL is not supported by all USB serial ports, so should only be used on fixed (8250 et al) ports if SS.typ<>0 then Result:=true; fpclose(FD)except end
if a port is not associated with the "serial8250" driver, then it is assumed that the hardware is present. ie, removable (USB) serial ports do not use the "serial8250" driver; fixed serial ports always use the serial8250" driver. note, i didn't write this code, but merely translated it from what others have variously written, including some C versions. my assumption is that not trying to open removable/USB serial ports is to save time (i recall reading somewhere that some bluetooth devices may take a long time to respond). in the past i've found that this code works pretty reliably, but of course that is no guarantee the same approach will continue to work in future!
with the 6.8 kernel, as far as i can tell all /dev/ttySxx port entries (existent or not) seem to be associated with a driver called "port", /sys/bus/serial-base/drivers/port.
playing around a bit more with following along the symlinks, i'm now feeling a little more comfortable and can see (roughly) how all the extra back-steps are consumed:
user@user-DH61BE:~$
user@user-DH61BE:/$ cd /
user@user-DH61BE:/$ cd -P sys
user@user-DH61BE:/sys$ cd -P class
user@user-DH61BE:/sys/class$ cd -P tty
user@user-DH61BE:/sys/class/tty$ cd -P ttyS5
user@user-DH61BE:/sys/devices/pci0000:00/0000:00:1c.0/0000:01:00.0/0000:02:00.0/0000:02:00.0:0/0000:02:00.0:0.1/tty/ttyS5$ cd -P device
user@user-DH61BE:/sys/devices/pci0000:00/0000:00:1c.0/0000:01:00.0/0000:02:00.0/0000:02:00.0:0/0000:02:00.0:0.1$ cd -P ../../../../../../../bus/serial-base/drivers
user@user-DH61BE:/sys/bus/serial-base/drivers$
user@user-DH61BE:/sys/bus/serial-base/drivers$
so it looks like fpReadLink must follow down the directory tree one level at a time, stopping before the last step into driver (which is a final symlink to a file). this gives it a count of how many back-steps are then needed:
/sys/devices/pci0000:00/0000:00:1c.0/0000:01:00.0/0000:02:00.0/0000:02:00.0:0/0000:02:00.0:0.1
so 7 back-steps, highlighted in red (4) and green (3).
it would be a whole lot easier of fpReadLink were to return an absolute path, although in the present case we are just interested in the name at the end of the path.
--- Quote from: MarkMLl on November 25, 2024, 11:08:46 am ---a defensive kernel hacker might be dismissive if you take that sort of liberty :-/
--- End quote ---
a good point! i just need to figure out if the path ... serial-base/drivers/port can be relied upon in the same way that the name serial8250 could previously be; just relying upon port as the identifier feels a tad dangerous!
cheers,
rob :-)
Navigation
[0] Message Index
[#] Next page