views:

590

answers:

2

What is the proper way to get a list of all available serial ports/devices on a Linux system?

In other words, when I iterate over all devices in /dev/, how do I tell which ones are serial ports in the classic way, i.e. those usually supporting baud rates and RTS/CTS flow control?

The solution would be coded in C.

I ask because I am using a 3rd party library that does this clearly wrong: It appears to only iterate over /dev/ttyS*. The problem is that there are, for instance, serial ports over USB (provided by USB-RS232 adapters), and those are listed under /dev/ttyUSB*. And reading the Serial-HOWTO at Linux.org, I get the idea that there'll be other name spaces as well, as time comes.

So I need to find the official way to detect serial devices. Problem is that there appears none documented, or I can't find it.

I imagine one way would be to open all files from /dev/tty* and call a specific ioctl() on them that is only available on serial devices. Would that be a good solution, though?

Update

hrickards suggested to look at the source for "setserial". Its code does exactly what I had in mind:

First, it opens a device with:

fd = open (path, O_RDWR | O_NONBLOCK)

Then it invokes:

ioctl (fd, TIOCGSERIAL, &serinfo)

If that call returns no error, then it's a serial dev, apparently.

I found similar code here, which suggested to also add the O_NOCTTY option.

There is one problem with this approach, though:

When I tested this code on BSD Unix (i.e. OSX), it worked as well, however serial devices that are provided thru Bluetooth cause the system (driver) to try to connect to the bluetooth device, which takes a while before it'll return with a timeout error. This is caused by just opening the device. And I can imagine that similar things can happen on Linux as well - ideally, I should not need to open the device to figure out its type. I wonder if there's also a way to invoke ioctl functions without an open, or open a device in a way that it does not cause connections to be made?

Any ideas?

+1  A: 

setserial with the -g option appears to do what you want and the C source is available at http://www.koders.com/c/fid39344DABD14604E70DF1B8FEA7D920A94AF78BF8.aspx.

hrickards
I looked at the code and it has the flaw I explain in my question at the end as it has to open the device, which may already lead to a connection attempt - which in turn is not good. But then, maybe Linux drivers are smarter than current OSX driver when it comes to bluetooth support, as they won't open a connection right away? Who knows?Maybe I should start a new question to clarify that specifically. If it turns out that that's fine, then I can accept your answer here as well. Hmmm...
Thomas Tempelmann
A: 

I have no serial device here to test it, but if you have python and dbus you can try it yourself.

import dbus
bus = dbus.SystemBus()
hwmanager = bus.get_object('org.freedesktop.Hal', '/org/freedesktop/Hal/Manager')
hwmanager_i = dbus.Interface(hwmanager, 'org.freedesktop.Hal.Manager')
print hwmanager_i.FindDeviceByCapability("serial")

If it fails you can search inside hwmanager_i.GetAllDevicesWithProperties() to see if the capability name "serial" that I just guessed has a different name.

HTH

baol