Tho*_*ann 104 linux serial-port
获取Linux系统上所有可用串行端口/设备列表的正确方法是什么?
换句话说,当我迭代所有设备时/dev/
,如何以经典的方式判断哪些是串行端口,即那些通常支持波特率和RTS/CTS流控制?
解决方案将用C编码.
我问,因为我正在使用第三方库,这显然是错误的:它似乎只是迭代/dev/ttyS*
.问题是,例如,USB上的串行端口(由USB-RS232适配器提供),并且这些端口列在/ dev/ttyUSB*下.在Linux.org上阅读Serial-HOWTO,我认为随着时间的推移,还会有其他名称空间.
所以我需要找到检测串行设备的官方方法.问题是似乎没有记录,或者我找不到它.
我想有一种方法是打开所有文件/dev/tty*
并调用特定的文件,这些文件ioctl()
仅在串行设备上可用.那会是一个很好的解决方案吗?
hrickards建议查看"setserial"的来源.它的代码完全符合我的想法:
首先,它打开一个设备:
fd = open (path, O_RDWR | O_NONBLOCK)
Run Code Online (Sandbox Code Playgroud)
然后它调用:
ioctl (fd, TIOCGSERIAL, &serinfo)
Run Code Online (Sandbox Code Playgroud)
如果该调用没有返回错误,那么它显然是一个串行设备.
我在Serial Programming/termios中找到了类似的代码,建议也添加该O_NOCTTY
选项.
但是,这种方法存在一个问题:
当我在BSD Unix(即Mac OS X)上测试此代码时,它也能正常工作.但是,通过蓝牙提供的串行设备会导致系统(驱动程序)尝试连接到蓝牙设备,这需要一段时间才能返回超时错误.这是因为只需打开设备即可.我可以想象在Linux上也会发生类似的事情 - 理想情况下,我不需要打开设备来弄清楚它的类型.我想知道是否还有一种方法可以在ioctl
没有打开的情况下调用函数,或者以不会导致连接的方式打开设备?
我该怎么办?
A.H*_*.H. 71
该/sys
文件系统应该包含你的追求大量的信息.我的系统(2.6.32-40-generic#87-Ubuntu)建议:
/sys/class/tty
Run Code Online (Sandbox Code Playgroud)
其中介绍了系统已知的所有TTY设备.修剪过的例子:
# ll /sys/class/tty/ttyUSB*
lrwxrwxrwx 1 root root 0 2012-03-28 20:43 /sys/class/tty/ttyUSB0 -> ../../devices/pci0000:00/0000:00:1d.0/usb2/2-1/2-1.4/2-1.4:1.0/ttyUSB0/tty/ttyUSB0/
lrwxrwxrwx 1 root root 0 2012-03-28 20:44 /sys/class/tty/ttyUSB1 -> ../../devices/pci0000:00/0000:00:1d.0/usb2/2-1/2-1.3/2-1.3:1.0/ttyUSB1/tty/ttyUSB1/
Run Code Online (Sandbox Code Playgroud)
遵循以下链接之一:
# ll /sys/class/tty/ttyUSB0/
insgesamt 0
drwxr-xr-x 3 root root 0 2012-03-28 20:43 ./
drwxr-xr-x 3 root root 0 2012-03-28 20:43 ../
-r--r--r-- 1 root root 4096 2012-03-28 20:49 dev
lrwxrwxrwx 1 root root 0 2012-03-28 20:43 device -> ../../../ttyUSB0/
drwxr-xr-x 2 root root 0 2012-03-28 20:49 power/
lrwxrwxrwx 1 root root 0 2012-03-28 20:43 subsystem -> ../../../../../../../../../../class/tty/
-rw-r--r-- 1 root root 4096 2012-03-28 20:43 uevent
Run Code Online (Sandbox Code Playgroud)
这里的dev
文件包含以下信息:
# cat /sys/class/tty/ttyUSB0/dev
188:0
Run Code Online (Sandbox Code Playgroud)
这是主要/次要节点.可以在/dev
目录中搜索这些以获得用户友好的名称:
# ll -R /dev |grep "188, *0"
crw-rw---- 1 root dialout 188, 0 2012-03-28 20:44 ttyUSB0
Run Code Online (Sandbox Code Playgroud)
该/sys/class/tty
目录包含了所有TTY设备,但您可能希望排除那些讨厌的虚拟终端和伪终端.我建议你只检查那些有device/driver
条目的人:
# ll /sys/class/tty/*/device/driver
lrwxrwxrwx 1 root root 0 2012-03-28 19:07 /sys/class/tty/ttyS0/device/driver -> ../../../bus/pnp/drivers/serial/
lrwxrwxrwx 1 root root 0 2012-03-28 19:07 /sys/class/tty/ttyS1/device/driver -> ../../../bus/pnp/drivers/serial/
lrwxrwxrwx 1 root root 0 2012-03-28 19:07 /sys/class/tty/ttyS2/device/driver -> ../../../bus/platform/drivers/serial8250/
lrwxrwxrwx 1 root root 0 2012-03-28 19:07 /sys/class/tty/ttyS3/device/driver -> ../../../bus/platform/drivers/serial8250/
lrwxrwxrwx 1 root root 0 2012-03-28 20:43 /sys/class/tty/ttyUSB0/device/driver -> ../../../../../../../../bus/usb-serial/drivers/ftdi_sio/
lrwxrwxrwx 1 root root 0 2012-03-28 21:15 /sys/class/tty/ttyUSB1/device/driver -> ../../../../../../../../bus/usb-serial/drivers/ftdi_sio/
Run Code Online (Sandbox Code Playgroud)
小智 26
在最近的内核中(不确定从何时开始),您可以列出/ dev/serial的内容以获取系统上的串行端口列表.它们实际上是指向正确的/ dev/node的符号链接:
flu0@laptop:~$ ls /dev/serial/
total 0
drwxr-xr-x 2 root root 60 2011-07-20 17:12 by-id/
drwxr-xr-x 2 root root 60 2011-07-20 17:12 by-path/
flu0@laptop:~$ ls /dev/serial/by-id/
total 0
lrwxrwxrwx 1 root root 13 2011-07-20 17:12 usb-Prolific_Technology_Inc._USB-Serial_Controller-if00-port0 -> ../../ttyUSB0
flu0@laptop:~$ ls /dev/serial/by-path/
total 0
lrwxrwxrwx 1 root root 13 2011-07-20 17:12 pci-0000:00:0b.0-usb-0:3:1.0-port0 -> ../../ttyUSB0
Run Code Online (Sandbox Code Playgroud)
您可以看到,这是一个USB串行适配器.请注意,当系统上没有串行端口时,/ dev/serial /目录不存在.希望这可以帮助 :).
Sør*_*olm 13
我正在做类似下面的代码.它适用于USB设备以及我们都有30个的愚蠢的serial8250-devuices - 但只有其中几个真正有效.
基本上我使用以前答案的概念.首先枚举/ sys/class/tty /中的所有tty-devices.不包含/ device子目录的设备将被过滤掉./ sys/class/tty/console就是这样一个设备.然后,实际包含设备的设备随后被接受为有效的串行端口,具体取决于driver-symlink fx的目标.
$ ls -al /sys/class/tty/ttyUSB0//device/driver
lrwxrwxrwx 1 root root 0 sep 6 21:28 /sys/class/tty/ttyUSB0//device/driver -> ../../../bus/platform/drivers/usbserial
Run Code Online (Sandbox Code Playgroud)
并为ttyS0
$ ls -al /sys/class/tty/ttyS0//device/driver
lrwxrwxrwx 1 root root 0 sep 6 21:28 /sys/class/tty/ttyS0//device/driver -> ../../../bus/platform/drivers/serial8250
Run Code Online (Sandbox Code Playgroud)
由serial8250驱动的所有驱动程序必须使用前面提到的ioctl进行探测.
if (ioctl(fd, TIOCGSERIAL, &serinfo)==0) {
// If device type is no PORT_UNKNOWN we accept the port
if (serinfo.type != PORT_UNKNOWN)
the_port_is_valid
Run Code Online (Sandbox Code Playgroud)
仅报告有效设备类型的端口有效.
枚举串口的完整源代码如下所示.欢迎加入.
#include <stdlib.h>
#include <dirent.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <string.h>
#include <fcntl.h>
#include <termios.h>
#include <sys/ioctl.h>
#include <linux/serial.h>
#include <iostream>
#include <list>
using namespace std;
static string get_driver(const string& tty) {
struct stat st;
string devicedir = tty;
// Append '/device' to the tty-path
devicedir += "/device";
// Stat the devicedir and handle it if it is a symlink
if (lstat(devicedir.c_str(), &st)==0 && S_ISLNK(st.st_mode)) {
char buffer[1024];
memset(buffer, 0, sizeof(buffer));
// Append '/driver' and return basename of the target
devicedir += "/driver";
if (readlink(devicedir.c_str(), buffer, sizeof(buffer)) > 0)
return basename(buffer);
}
return "";
}
static void register_comport( list<string>& comList, list<string>& comList8250, const string& dir) {
// Get the driver the device is using
string driver = get_driver(dir);
// Skip devices without a driver
if (driver.size() > 0) {
string devfile = string("/dev/") + basename(dir.c_str());
// Put serial8250-devices in a seperate list
if (driver == "serial8250") {
comList8250.push_back(devfile);
} else
comList.push_back(devfile);
}
}
static void probe_serial8250_comports(list<string>& comList, list<string> comList8250) {
struct serial_struct serinfo;
list<string>::iterator it = comList8250.begin();
// Iterate over all serial8250-devices
while (it != comList8250.end()) {
// Try to open the device
int fd = open((*it).c_str(), O_RDWR | O_NONBLOCK | O_NOCTTY);
if (fd >= 0) {
// Get serial_info
if (ioctl(fd, TIOCGSERIAL, &serinfo)==0) {
// If device type is no PORT_UNKNOWN we accept the port
if (serinfo.type != PORT_UNKNOWN)
comList.push_back(*it);
}
close(fd);
}
it ++;
}
}
list<string> getComList() {
int n;
struct dirent **namelist;
list<string> comList;
list<string> comList8250;
const char* sysdir = "/sys/class/tty/";
// Scan through /sys/class/tty - it contains all tty-devices in the system
n = scandir(sysdir, &namelist, NULL, NULL);
if (n < 0)
perror("scandir");
else {
while (n--) {
if (strcmp(namelist[n]->d_name,"..") && strcmp(namelist[n]->d_name,".")) {
// Construct full absolute file path
string devicedir = sysdir;
devicedir += namelist[n]->d_name;
// Register the device
register_comport(comList, comList8250, devicedir);
}
free(namelist[n]);
}
free(namelist);
}
// Only non-serial8250 has been added to comList without any further testing
// serial8250-devices must be probe to check for validity
probe_serial8250_comports(comList, comList8250);
// Return the lsit of detected comports
return comList;
}
int main() {
list<string> l = getComList();
list<string>::iterator it = l.begin();
while (it != l.end()) {
cout << *it << endl;
it++;
}
return 0;
}
Run Code Online (Sandbox Code Playgroud)
小智 12
我想我在我的内核源代码文档中找到了答案:/usr/src/linux-2.6.37-rc3/Documentation/filesystems/proc.txt
1.7 TTY info in /proc/tty
-------------------------
Information about the available and actually used tty's can be found in the
directory /proc/tty.You'll find entries for drivers and line disciplines in
this directory, as shown in Table 1-11.
Table 1-11: Files in /proc/tty
..............................................................................
File Content
drivers list of drivers and their usage
ldiscs registered line disciplines
driver/serial usage statistic and status of single tty lines
..............................................................................
To see which tty's are currently in use, you can simply look into the file
/proc/tty/drivers:
> cat /proc/tty/drivers
pty_slave /dev/pts 136 0-255 pty:slave
pty_master /dev/ptm 128 0-255 pty:master
pty_slave /dev/ttyp 3 0-255 pty:slave
pty_master /dev/pty 2 0-255 pty:master
serial /dev/cua 5 64-67 serial:callout
serial /dev/ttyS 4 64-67 serial
/dev/tty0 /dev/tty0 4 0 system:vtmaster
/dev/ptmx /dev/ptmx 5 2 system
/dev/console /dev/console 5 1 system:console
/dev/tty /dev/tty 5 0 system:/dev/tty
unknown /dev/tty 4 1-63 console
Run Code Online (Sandbox Code Playgroud)
以下是此文件的链接:http://git.kernel.org/?p = linux/kernel/git/next/linux-next.git; a = blob_plain; f = Document /filesystems/proc.txt; hb = e8883f8057c0f7c9950fa9f20568f37bfa62f34a
带有 -g 选项的 setserial 似乎可以执行您想要的操作,并且 C 源代码可在http://www.koders.com/c/fid39344DABD14604E70DF1B8FEA7D920A94AF78BF8.aspx上找到。
使用 /proc/tty/drivers 仅指示加载了哪些 tty 驱动程序。如果您要查找串行端口列表,请查看 /dev/serial,它将有两个子目录:by-id 和 by-path。
前任:
# find . -type l
./by-path/usb-0:1.1:1.0-port0
./by-id/usb-Prolific_Technology_Inc._USB-Serial_Controller-if00-port0
Run Code Online (Sandbox Code Playgroud)
感谢这篇文章:https://superuser.com/questions/131044/how-do-i-know-which-dev-ttys-is-my-serial-port
我通过组拨出的方法让每个具有用户“拨出”的 tty
ls -l /dev/tty* | grep 'dialout'
仅获取其文件夹
ls -l /dev/tty* | grep 'dialout' | rev | cut -d " " -f1 | rev
轻松监听 tty 输出,例如当 arduino 串行输出时:
head --lines 1 < /dev/ttyUSB0
仅侦听每个 tty 的一行:
for i in $(ls -l /dev/tty* | grep 'dialout' | rev | cut -d " " -f1 | rev); do head --lines 1 < $i; done
我真的很喜欢通过寻找驱动程序的方法:
ll /sys/class/tty/*/device/driver
您现在可以选择 tty-Name:
ls /sys/class/tty/*/device/driver | grep 'driver' | cut -d "/" -f 5