Recent

Author Topic: kernel 6.8 and checking serial ports - failure to match driver name  (Read 5384 times)

robert rozee

  • Full Member
  • ***
  • Posts: 200
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  [Select][+][-]
  1. // method based on information obtained from the following two sites:
  2. // https://www.lazarusforum.de/viewtopic.php?p=72837
  3. // https://stackoverflow.com/questions/2530096
  4. function CheckDevice(DeviceName:string):boolean;               // checks to see if the device named is a live
  5. var DriverName:string;                                         // ... serial port. this is done by checking
  6.             FD:longint;                                        // ... entries in /sys/class/tty including the
  7.             SS:TSerialStruct;                                  // ... presence of a link to a device driver.
  8.             ST:stat;
  9.              S:string;
  10. begin
  11.   Result:=false;
  12.  
  13.   ST.st_mode:=0;
  14.   if (DeviceName<>'.') and (DeviceName<>'..') then
  15.   if FileExists('/sys/class/tty/'+DeviceName+'/device/driver')  or              // this suffices with FPC prior to 3.20
  16.      DirectoryExists('/sys/class/tty/'+DeviceName+'/device/driver')  then       // from FPC 3.20 onwards we need this instead
  17.   if fpLstat('/sys/class/tty/'+DeviceName+'/device', ST)=0 then
  18.   if fpS_ISLNK(ST.st_mode) then
  19.   begin
  20.     S:=fpReadLink('/sys/class/tty/'+DeviceName+'/device/driver');
  21.     DriverName:=ExtractFileName(S);
  22.  
  23.     writeln('/sys/class/tty/'+DeviceName+'/device/driver');
  24.     writeln('fpReadLink returns ',S);
  25.     writeln('driver name is "',DriverName, '"');
  26.  
  27.     if (DriverName<>'serial8250')
  28. //   and (DriverName<>'port')
  29.                                 then Result:=true
  30.                                 else begin
  31.                                        writeln('checking serial8250 device');
  32.                                        FD:=fpOpen('/dev/'+DeviceName, O_RDWR or O_NONBLOCK or O_NOCTTY);
  33.                                        if FD>0 then
  34.                                        try
  35.                                          if fpIOCtl(FD, TIOCGSERIAL, @SS)<>-1 then
  36.                                          if SS.typ<>0 then Result:=true;
  37.                                          fpclose(FD)
  38.                                        except end
  39.                                      end
  40.   end;
  41.   if Result then writeln('>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> PASS >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>');
  42.   writeln
  43. end;

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: [Select]
/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 >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

and here it is with the line   " and (DriverName<>'port') "   no longer commented out:

Code: [Select]
/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

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

  • Hero Member
  • *****
  • Posts: 8090
Re: kernel 6.8 and checking serial ports - failure to match driver name
« Reply #1 on: November 24, 2024, 04:39:06 pm »
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
MT+86 & Turbo Pascal v1 on CCP/M-86, multitasking with LAN & graphics in 128Kb.
Logitech, TopSpeed & FTL Modula-2 on bare metal (Z80, '286 protected mode).
Pet hate: people who boast about the size and sophistication of their computer.
GitHub repositories: https://github.com/MarkMLl?tab=repositories

robert rozee

  • Full Member
  • ***
  • Posts: 200
Re: kernel 6.8 and checking serial ports - failure to match driver name
« Reply #2 on: November 25, 2024, 10:45:33 am »
it's entirely plausible that somebody has broken something by trying to "clean it up and adopt a standard layout"

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: [Select]
/sys/class/tty/ttyS5/device/driver
fpReadLink returns ../../../../../../../bus/serial-base/drivers/port
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   :-)



« Last Edit: December 14, 2024, 01:25:36 pm by robert rozee »

MarkMLl

  • Hero Member
  • *****
  • Posts: 8090
Re: kernel 6.8 and checking serial ports - failure to match driver name
« Reply #3 on: November 25, 2024, 11:08:46 am »
it's entirely plausible that somebody has broken something by trying to "clean it up and adopt a standard layout"

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".

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?

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.

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
MT+86 & Turbo Pascal v1 on CCP/M-86, multitasking with LAN & graphics in 128Kb.
Logitech, TopSpeed & FTL Modula-2 on bare metal (Z80, '286 protected mode).
Pet hate: people who boast about the size and sophistication of their computer.
GitHub repositories: https://github.com/MarkMLl?tab=repositories

robert rozee

  • Full Member
  • ***
  • Posts: 200
Re: kernel 6.8 and checking serial ports - failure to match driver name
« Reply #4 on: November 25, 2024, 01:24:27 pm »
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

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  [Select][+][-]
  1. Result:=false;
  2. [...]
  3. FD:=fpOpen('/dev/'+DeviceName, O_RDWR or O_NONBLOCK or O_NOCTTY);
  4. if FD>0 then
  5. try
  6.   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
  7.   if SS.typ<>0 then Result:=true;
  8.   fpclose(FD)
  9. 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.

a defensive kernel hacker might be dismissive if you take that sort of liberty :-/

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   :-)

robert rozee

  • Full Member
  • ***
  • Posts: 200
Re: kernel 6.8 and checking serial ports - failure to match driver name
« Reply #5 on: November 25, 2024, 01:53:50 pm »
a few more data points, sorted, with 6.8 kernel:

ttyS0    : port     : /sys/class/tty/ttyS0/device/driver/../../../../../bus/serial-base/drivers/port
ttyS1    : port     : /sys/class/tty/ttyS1/device/driver/../../../../../bus/serial-base/drivers/port
ttyS2    : port     : /sys/class/tty/ttyS2/device/driver/../../../../../bus/serial-base/drivers/port
ttyS3    : port     : /sys/class/tty/ttyS3/device/driver/../../../../../bus/serial-base/drivers/port
ttyS4    : port     : /sys/class/tty/ttyS4/device/driver/../../../../../../../bus/serial-base/drivers/port
ttyS5    : port     : /sys/class/tty/ttyS5/device/driver/../../../../../../../bus/serial-base/drivers/port

ttyS6    : port     : /sys/class/tty/ttyS6/device/driver/../../../../../bus/serial-base/drivers/port
ttyS7    : port     : /sys/class/tty/ttyS7/device/driver/../../../../../bus/serial-base/drivers/port
ttyS8    : port     : /sys/class/tty/ttyS8/device/driver/../../../../../bus/serial-base/drivers/port
ttyS9    : port     : /sys/class/tty/ttyS9/device/driver/../../../../../bus/serial-base/drivers/port
ttyACM0  : cdc_acm  : /sys/class/tty/ttyACM0/device/driver/../../../../../../../bus/usb/drivers/cdc_acm
ttyUSB0  : cp210x   : /sys/class/tty/ttyUSB0/device/driver/../../../../../../../../bus/usb-serial/drivers/cp210x
ttyUSB1  : cp210x   : /sys/class/tty/ttyUSB1/device/driver/../../../../../../../../bus/usb-serial/drivers/cp210x


those ports in red are real ports that exist, the others are not real. i've clipped out the higher numbered ttySxx ports. note that there is a pattern amongst the real ports that is broken by ttyS0   :-(


cheers,
rob   :-)

Thaddy

  • Hero Member
  • *****
  • Posts: 16343
  • Censorship about opinions does not belong here.
Re: kernel 6.8 and checking serial ports - failure to match driver name
« Reply #6 on: November 25, 2024, 02:07:00 pm »
Looks more like something incompatible in the kernel, because what fpc does is perform straight system calls. I bet you can also reproduce it in other languages.
There is nothing wrong with being blunt. At a minimum it is also honest.

robert rozee

  • Full Member
  • ***
  • Posts: 200
Re: kernel 6.8 and checking serial ports - failure to match driver name
« Reply #7 on: November 25, 2024, 02:34:35 pm »
Looks more like something incompatible in the kernel, because what fpc does is perform straight system calls. I bet you can also reproduce it in other languages.

yes, i am sure i most certainly can. i'm just hoping that someone else on here has (or is) looking into ways around the problem! do you know of where/how to get hold of and communicate with the linux kernel developers? the code i've been using for many years has, up until now, provided a good solution to allow users to select serial ports from a short list of 'real' ports (ones that are connected to real hardware). but not now   :-(


cheers,
rob   :-)

MarkMLl

  • Hero Member
  • *****
  • Posts: 8090
Re: kernel 6.8 and checking serial ports - failure to match driver name
« Reply #8 on: November 25, 2024, 03:06:05 pm »
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.

No, that's definitely not a safe assumption. It will only use the serial8250 driver if PCI etc. enumeration can't explicitly identify the device as something more recent.

I'm not going clambering over things, but I /think/ the machine I'm working on has two serial ports: it certainly has one because there's a classic serial SpaceMouse plugged into it (lsof confirms this is ttyS0).

dmesg tells me

Code: [Select]
[    0.562187] Serial: 8250/16550 driver, 4 ports, IRQ sharing enabled
[    0.562347] 00:07: ttyS0 at I/O 0x3f8 (irq = 4, base_baud = 115200) is a 16550A
[    0.562974] 0000:00:16.3: ttyS1 at I/O 0xf0e0 (irq = 19, base_baud = 115200) is a 16550A

Hence the 8250 driver has been loaded (which will almost always be the case for a PC), it has initially claimed all four potential ports (at the PC legacy addresses), it has recognised the legacy ttyS0 as a 16550A and released it, and it has enumerated ttyS1 on the PCI bus as a 16550A and released it. Subsequent to that PCI enumeration has caused the serial module to be loaded, which has claimed ttyS0 and ttyS1 while leaving ttyS2 and ttyS3 to serial8250.

But if for some reason serial8250 couldn't decide what ttyS0 or ttyS1 was, it wouldn't release it.

Code: Text  [Select][+][-]
  1. /sys# find devices -name 'ttyS*'
  2.  
  3. devices/pnp0/00:07/tty/ttyS0
  4. devices/pci0000:00/0000:00:16.3/tty/ttyS1 # Reordered here for clarity
  5. devices/platform/serial8250/tty/ttyS2
  6. devices/platform/serial8250/tty/ttyS3
  7.  
  8. /sys# ls -l devices/pci0000:00/0000:00:16.3/tty/ttyS1/device
  9.  
  10. lrwxrwxrwx 1 root root 0 Nov 23 15:19 devices/pci0000:00/0000:00:16.3/tty/ttyS1/device -> ../../../0000:00:16.3
  11.  
  12. /sys# ls -l devices/pci0000:00/0000:00:16.3/tty/ttyS1/device/driver
  13.  
  14. lrwxrwxrwx 1 root root 0 Nov 23 15:19 devices/pci0000:00/0000:00:16.3/tty/ttyS1/device/driver -> ../../../bus/pci/drivers/serial
  15.  
  16. /sys# ls -l devices/platform/serial8250/tty/ttyS2/device
  17.  
  18. lrwxrwxrwx 1 root root 0 Nov 25 09:30 devices/platform/serial8250/tty/ttyS2/device -> ../../../serial8250
  19.  
  20. /sys# ls -l devices/platform/serial8250/tty/ttyS2/device/driver
  21.  
  22. lrwxrwxrwx 1 root root 0 Nov 23 15:19 devices/platform/serial8250/tty/ttyS2/device/driver -> ../../../bus/platform/drivers/serial8250
  23.  
  24. /sys# ls -l devices/platform/serial8250/tty/ttyS3/device
  25.  
  26. lrwxrwxrwx 1 root root 0 Nov 25 09:30 devices/platform/serial8250/tty/ttyS3/device -> ../../../serial8250
  27.  
  28. /sys# ls -l devices/platform/serial8250/tty/ttyS3/device/driver
  29.  
  30. lrwxrwxrwx 1 root root 0 Nov 23 15:19 devices/platform/serial8250/tty/ttyS3/device/driver -> ../../../bus/platform/drivers/serial8250
  31.  

So on this specific system, it's unambiguous that ttyS0 and ttyS1 are using the serial driver, while the non-present ttyS2 and ttyS3 are defaulting to serial8250.

That's a moderately-recent Dell. I'd expect the lower-spec Dell underneath my desk to enumerate differently.

But again I'd emphasise: the paths that you get from consulting the content of /sys are entirely at the whim of the kernel module authors.

MarkMLl
MT+86 & Turbo Pascal v1 on CCP/M-86, multitasking with LAN & graphics in 128Kb.
Logitech, TopSpeed & FTL Modula-2 on bare metal (Z80, '286 protected mode).
Pet hate: people who boast about the size and sophistication of their computer.
GitHub repositories: https://github.com/MarkMLl?tab=repositories

robert rozee

  • Full Member
  • ***
  • Posts: 200
Re: kernel 6.8 and checking serial ports - failure to match driver name
« Reply #9 on: November 25, 2024, 03:55:10 pm »
well, dmesg indeed produces the following interesting results here:

user@user-DH61BE:~$
user@user-DH61BE:~$ dmesg | grep "tty"
[    0.000000] printk: legacy console [tty0] enabled
[    0.252542] 00:05: ttyS0 at I/O 0x3f8 (irq = 4, base_baud = 115200) is a 16550A
[    0.276564] 0000:02:00.0: ttyS4 at I/O 0xe000 (irq = 16, base_baud = 921600) is a 16550A
[    0.298087] 0000:02:00.0: ttyS5 at I/O 0xe008 (irq = 16, base_baud = 921600) is a 16550A
[    2.885920] usb 1-1.1: cp210x converter now attached to ttyUSB0
[99704.693883] usb 3-3: cp210x converter now attached to ttyUSB1
[178459.275692] cdc_acm 1-1.5:1.0: ttyACM0: USB ACM device
user@user-DH61BE:~$


ignoring tty0, the others cover all the real serial ports on the machine i'm sitting in front of, with no extras. would you advise simply using the output of dmesg to build a list of serial ports? this would, of course, also require either: (a) tracking unplug events reported in the output from dmesg as well, or (b) [perhaps easier] validating the list of ports collected against /dev/* and removing from our list any that are not present in /dev (this would also take care of tty0 as there is, on my desktop machine at least, no entry in /dev for tty0. on another machine running a much older kernel there is an entry for tty0).

i would be very happy if a solution using the output of dmesg was workable!


cheers,
rob   :-)
« Last Edit: November 25, 2024, 04:03:32 pm by robert rozee »

MarkMLl

  • Hero Member
  • *****
  • Posts: 8090
Re: kernel 6.8 and checking serial ports - failure to match driver name
« Reply #10 on: November 25, 2024, 04:12:34 pm »
i would be very happy if a solution using the output of dmesg was workable!

No, you can't trust it because it is once more at the mercy of the module developers: who can change the detail they're including with even more impunity than they can change /sys content.

The /only/ safe thing is to walk the /sys tree and look for patterns, which is what I'm doing in the Github project I pointed you at. Looking at /dev/ttyS[0123], you can't even rely on the device numbers to tell you anything useful.

I was going to append to my earlier posting but thought I'd give you another interesting case to think about. You can use an RPi Pico (RP2040) to interpret a PC's LPC bus protocol (plugged into the TPM connector). It would be "relatively easy" to program one of those to look like the missing ttyS2 and ttyS3 ports, and if they didn't enumerate as 16550 chips they'd be left on the serial8250 module's list. You could detect their actual presence by using the 8250's loopback, but I don't think you /could/ enumerate them since LPC's not PCI so unless good old 1990s PnP worked...

MarkMLl
MT+86 & Turbo Pascal v1 on CCP/M-86, multitasking with LAN & graphics in 128Kb.
Logitech, TopSpeed & FTL Modula-2 on bare metal (Z80, '286 protected mode).
Pet hate: people who boast about the size and sophistication of their computer.
GitHub repositories: https://github.com/MarkMLl?tab=repositories

MarkMLl

  • Hero Member
  • *****
  • Posts: 8090
Re: kernel 6.8 and checking serial ports - failure to match driver name
« Reply #11 on: November 27, 2024, 11:18:20 am »
I'm taking the opportunity to tidy up some stuff in my own port detection code, which leads me to a couple of observations.

The first is that I think it's necessary to find out what bus the device is enumerated on: in the case of these non-PCI devices that's going to be /sys/devices/pnp* vs /sys/devices/pci*. It appears that at least some BIOSes either have the ports for 8250s hardcoded or there's an (EE)PROM record for them associated with (the successor to) the SuperIO device, whether or not they exist.

If a device enumerates as a 16550 on the PCI bus, then it's reasonable to assume that it exists, although as you've discovered the path to check the driver name might vary.

If a device appears as an 8250 on the PnP bus, then it might or might not exist. In that case use TIOCM_LOOP to do an internal chip wraparound, send a character and see if it appears on the input.

I've not checked that latter yet, but as far as I can see the RTL and kernel support it so it /should/ work (i.e. in the same way that setting other MCR bits like DTR etc. work).

MarkMLl
MT+86 & Turbo Pascal v1 on CCP/M-86, multitasking with LAN & graphics in 128Kb.
Logitech, TopSpeed & FTL Modula-2 on bare metal (Z80, '286 protected mode).
Pet hate: people who boast about the size and sophistication of their computer.
GitHub repositories: https://github.com/MarkMLl?tab=repositories

robert rozee

  • Full Member
  • ***
  • Posts: 200
Re: kernel 6.8 and checking serial ports - failure to match driver name
« Reply #12 on: November 27, 2024, 12:22:06 pm »
In that case use TIOCM_LOOP to do an internal chip wraparound, send a character and see if it appears on the input

what happens if you use TIOCM_LOOP on a port that has already been opened and locked exclusively by another process? in my own code i commonly do:
Code: Pascal  [Select][+][-]
  1. try fpIOCtl(SerialHandle, TIOCEXCL, nil) except end;
right after i open any serial port i'll be using, so as to avoid the embarrassment and potential mayhem of having two programs accessing it at the same time.

would this work as an alternative to TIOCM_LOOP, as it is just reading status information?
Code: Pascal  [Select][+][-]
  1. Result:=false
  2. if fpIOCtl(FD, TIOCGSERIAL, @SS)<>-1 then if SS.typ<>0 then Result:=true;


i would be very happy if a solution using the output of dmesg was workable!
No, you can't trust it because it is once more at the mercy of the module developers: who can change the detail they're including with even more impunity than they can change /sys content.
The only safe thing is to walk the /sys tree and look for patterns

years ago i worked with a rather clever engineer who had a note pinned up in his cubicle that read:
For every complex problem
there is a simple solution
that does not work.

but for my own application case, i wonder if dmesg may provide a relatively simple solution that, while far from perfect, is still good enough. i shall carry on digging, including through your code at https://github.com/MarkMLl/serialcomms


cheers,
rob   :-)
« Last Edit: November 27, 2024, 12:24:13 pm by robert rozee »

MarkMLl

  • Hero Member
  • *****
  • Posts: 8090
Re: kernel 6.8 and checking serial ports - failure to match driver name
« Reply #13 on: November 27, 2024, 12:49:14 pm »
If it's already opened exclusively then you shouldn't (be able to) touch it. But if it's opened then it's reasonable to assume that it's a real device...

I'm pretty sure that everything that's needed is accessible in the /sys tree, except possibly distinguishing between a non-existing PnP 8250 and a real one. There's also the obvious issue of hotplugging to be considered.

I'm currently working through that project and disabling some tests- for example for idVendor/idProduct- if the bus is PnP or PCI. It /might/ /possibly/ be sufficient to note that a device is in the /sys/devices/platform subtree to decide that it's a dummy, so the combination of finding the bus type plus noting the kernel version might be sufficient to tell you where to look for the driver which in turn should allow you to distinguish between an 8250 and a 16550.

And in practice you can obviously do that using code which is much more straightforward than I'm using: I'm not saying it's NBG, but it's probably excessively complex once you know what you're looking for.

updated: The order that I'm checking the fields in the description is obviously wrong: since one appears to need to know the bus type in order to find the driver that must be done early, and must be saved as internal state. The reason for that order is that in most cases I was looking at USB or Bluetooth (etc.) devices where you were more likely to know the vendor/product than anything else, so putting them at the start of the record to allow things like the driver and serial number to be omitted makes sense.

MarkMLl
« Last Edit: November 27, 2024, 12:56:52 pm by MarkMLl »
MT+86 & Turbo Pascal v1 on CCP/M-86, multitasking with LAN & graphics in 128Kb.
Logitech, TopSpeed & FTL Modula-2 on bare metal (Z80, '286 protected mode).
Pet hate: people who boast about the size and sophistication of their computer.
GitHub repositories: https://github.com/MarkMLl?tab=repositories

Dzandaa

  • Sr. Member
  • ****
  • Posts: 404
  • From C# to Lazarus
Re: kernel 6.8 and checking serial ports - failure to match driver name
« Reply #14 on: November 27, 2024, 03:39:40 pm »
Maybe irrelevant, but here's the function I use to find the USB ports (in my case AVR Arduino) in Linux:

Code: Pascal  [Select][+][-]
  1. {$IFDEF UNIX}
  2.  
  3. // **********************************
  4. // ***** Get Serial Ports Linux *****
  5. // **********************************
  6. function GetSerialPortNames: string;
  7. var
  8.  SearchResult : TSearchRec;
  9.  v: TStringList;
  10. begin
  11.   v := TStringList.Create;
  12.   {$IFDEF LINUX}
  13.    If (FindFirst('/dev/ttyUSB*', (faAnyFile And Not faDirectory), SearchResult) = 0) or
  14.       (FindFirst('/dev/ttyACM*', (faAnyFile And Not faDirectory), SearchResult) = 0) Then
  15.   {$ELSE} // For MacOS
  16.    If (FindFirst('/dev/tty.usbmodem*', (faAnyFile And Not faDirectory), SearchResult) = 0) or
  17.      (FindFirst('/dev/tty.usbserial*', (faAnyFile And Not faDirectory), SearchResult) = 0) Then
  18.   {$ENDIF}
  19.   begin
  20.    v.Add('/dev/'+SearchResult.Name);
  21.    while FindNext (SearchResult) = 0 Do
  22.    begin
  23.     v.Add('/dev/'+SearchResult.Name);
  24.    end;
  25.   end;
  26.   Result := v.CommaText;
  27.   FindClose (SearchResult);
  28.   v.Free;
  29. end;
  30. {$ENDIF}  
  31.  

B->
Regards,
Dzandaa

 

TinyPortal © 2005-2018