Discovering Serial Ports on Linux
Serial ports, traditionally used for connecting peripherals like modems and terminals, are still prevalent in embedded systems, industrial equipment, and various hardware projects. On Linux systems, identifying available serial ports can be essential for software development, system administration, and hardware diagnostics. This tutorial explores methods to reliably detect serial ports without needing to open or interact with them directly.
Understanding Serial Port Names
Traditionally, serial ports were named sequentially: ttyS0, ttyS1, ttyS2, and so on, representing the standard serial ports built into the motherboard. However, modern systems often include serial ports provided through USB adapters (USB-to-Serial converters), Bluetooth connections, or virtualized environments. These ports can have different naming conventions, such as ttyUSBx or ttyACMx, making a simple scan for ttyS* insufficient.
Methods for Detecting Serial Ports
Here are several methods to reliably detect serial ports on a Linux system:
1. Exploring the /sys Filesystem
The /sys filesystem provides a dynamic view of the kernel’s data structures, making it a powerful tool for system introspection. The /sys/class/tty directory is the key to discovering serial ports.
-
Listing TTY Devices: A simple
ls /sys/class/ttywill list all TTY devices known to the system. -
Identifying Device Drivers: For each device within
/sys/class/tty, examine thedevice/driversymbolic link. This link points to the kernel driver responsible for the device. This is crucial for distinguishing actual serial ports from virtual terminals or pseudo-terminals. For example,cat /sys/class/tty/ttyUSB0/device/drivermight output../../../../../../../../bus/usb-serial/drivers/ftdi_sio/, indicating a USB-to-Serial adapter using theftdi_siodriver. -
Finding Major/Minor Numbers: The
/sys/class/tty/<port>/devfile contains the major and minor device numbers. You can use these numbers to find the corresponding device node in/dev. For example, if/sys/class/tty/ttyUSB0/devcontains188:0, you can then usels -l /dev | grep "188, 0"to confirm the device node is/dev/ttyUSB0.
Example:
ls /sys/class/tty
cd /sys/class/tty/ttyUSB0
cat device/driver
cat dev
2. Utilizing /dev/serial/
Some Linux distributions create a /dev/serial/ directory that contains symbolic links to available serial ports. This directory provides an organized way to list serial ports, but its presence isn’t guaranteed across all distributions.
- Listing Serial Ports: A simple
ls /dev/serial/will list the available serial ports if the directory exists. Theby-idandby-pathsubdirectories contain more descriptive links.
Example:
ls /dev/serial/
ls /dev/serial/by-id/
3. Inspecting Kernel Messages with dmesg
The dmesg command displays kernel ring buffer messages, which often include information about detected serial ports.
- Filtering for TTY: Use
dmesg | grep ttyto filter the output and display lines related to TTY devices.
Example:
dmesg | grep tty
4. Programmatic Approach (C)
While the goal is to avoid opening ports, you might need to programmatically determine their existence. You can combine the methods above within a C program to create a robust serial port discovery function. You can iterate through the /sys/class/tty directory, check for device drivers, and extract the corresponding /dev paths.
#include <stdio.h>
#include <dirent.h>
#include <string.h>
int main() {
DIR *dir;
struct dirent *ent;
dir = opendir("/sys/class/tty");
if (dir != NULL) {
while ((ent = readdir(dir)) != NULL) {
if (strncmp(ent->d_name, "tty", 3) == 0) {
char path[256];
snprintf(path, sizeof(path), "/sys/class/tty/%s/device/driver", ent->d_name);
FILE *driver_file = fopen(path, "r");
if (driver_file != NULL) {
char driver[256];
if (fgets(driver, sizeof(driver), driver_file) != NULL) {
printf("Port: %s, Driver: %s\n", ent->d_name, driver);
}
fclose(driver_file);
}
}
}
closedir(dir);
} else {
perror("Could not open /sys/class/tty");
}
return 0;
}
Best Practices
-
Prioritize
/sysFilesystem: The/sysfilesystem provides the most reliable and platform-independent method for discovering serial ports. -
Verify Device Drivers: Always check the device driver associated with each TTY device to ensure it is a genuine serial port.
-
Handle Errors: Implement robust error handling in your code to gracefully handle cases where directories or files are inaccessible.
-
Adapt to Distribution Differences: Be aware that some Linux distributions may have slight variations in directory structures or naming conventions.