2 * This file is part of the libserialport project.
4 * Copyright (C) 2014 Aurelien Jacobs <aurel@gnuage.org>
6 * This program is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU Lesser General Public License as
8 * published by the Free Software Foundation, either version 3 of the
9 * License, or (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public License
17 * along with this program. If not, see <http://www.gnu.org/licenses/>.
20 #include "libserialport.h"
21 #include "libserialport_internal.h"
23 SP_PRIV
enum sp_return
get_port_details(struct sp_port
*port
)
25 /* Description limited to 127 char,
26 anything longer would not be user friendly anyway */
27 char description
[128];
29 unsigned int vid
, pid
;
30 char manufacturer
[128], product
[128], serial
[128];
32 const char dir_name
[] = "/sys/class/tty/%s/device/%s%s";
33 char sub_dir
[32] = "", file_name
[PATH_MAX
];
34 char *ptr
, *dev
= port
->name
+ 5;
38 if (strncmp(port
->name
, "/dev/", 5))
39 RETURN_ERROR(SP_ERR_ARG
, "Device name not recognized.");
41 snprintf(file_name
, sizeof(file_name
), "/sys/class/tty/%s", dev
);
42 count
= readlink(file_name
, file_name
, sizeof(file_name
));
43 if (count
<= 0 || count
>= (int) sizeof(file_name
)-1)
44 RETURN_ERROR(SP_ERR_ARG
, "Device not found.");
46 if (strstr(file_name
, "bluetooth"))
47 port
->transport
= SP_TRANSPORT_BLUETOOTH
;
48 else if (strstr(file_name
, "usb"))
49 port
->transport
= SP_TRANSPORT_USB
;
51 if (port
->transport
== SP_TRANSPORT_USB
) {
53 strcat(sub_dir
, "../");
55 snprintf(file_name
, sizeof(file_name
), dir_name
, dev
, sub_dir
, "busnum");
56 if (!(file
= fopen(file_name
, "r")))
58 count
= fscanf(file
, "%d", &bus
);
63 snprintf(file_name
, sizeof(file_name
), dir_name
, dev
, sub_dir
, "devnum");
64 if (!(file
= fopen(file_name
, "r")))
66 count
= fscanf(file
, "%d", &address
);
71 snprintf(file_name
, sizeof(file_name
), dir_name
, dev
, sub_dir
, "idVendor");
72 if (!(file
= fopen(file_name
, "r")))
74 count
= fscanf(file
, "%4x", &vid
);
79 snprintf(file_name
, sizeof(file_name
), dir_name
, dev
, sub_dir
, "idProduct");
80 if (!(file
= fopen(file_name
, "r")))
82 count
= fscanf(file
, "%4x", &pid
);
88 port
->usb_address
= address
;
92 snprintf(file_name
, sizeof(file_name
), dir_name
, dev
, sub_dir
, "product");
93 if ((file
= fopen(file_name
, "r"))) {
94 if ((ptr
= fgets(description
, sizeof(description
), file
))) {
95 ptr
= description
+ strlen(description
) - 1;
96 if (ptr
>= description
&& *ptr
== '\n')
98 port
->description
= strdup(description
);
103 port
->description
= strdup(dev
);
105 snprintf(file_name
, sizeof(file_name
), dir_name
, dev
, sub_dir
, "manufacturer");
106 if ((file
= fopen(file_name
, "r"))) {
107 if ((ptr
= fgets(manufacturer
, sizeof(manufacturer
), file
))) {
108 ptr
= manufacturer
+ strlen(manufacturer
) - 1;
109 if (ptr
>= manufacturer
&& *ptr
== '\n')
111 port
->usb_manufacturer
= strdup(manufacturer
);
116 snprintf(file_name
, sizeof(file_name
), dir_name
, dev
, sub_dir
, "product");
117 if ((file
= fopen(file_name
, "r"))) {
118 if ((ptr
= fgets(product
, sizeof(product
), file
))) {
119 ptr
= product
+ strlen(product
) - 1;
120 if (ptr
>= product
&& *ptr
== '\n')
122 port
->usb_product
= strdup(product
);
127 snprintf(file_name
, sizeof(file_name
), dir_name
, dev
, sub_dir
, "serial");
128 if ((file
= fopen(file_name
, "r"))) {
129 if ((ptr
= fgets(serial
, sizeof(serial
), file
))) {
130 ptr
= serial
+ strlen(serial
) - 1;
131 if (ptr
>= serial
&& *ptr
== '\n')
133 port
->usb_serial
= strdup(serial
);
141 port
->description
= strdup(dev
);
143 if (port
->transport
== SP_TRANSPORT_BLUETOOTH
) {
144 snprintf(file_name
, sizeof(file_name
), dir_name
, dev
, "", "address");
145 if ((file
= fopen(file_name
, "r"))) {
146 if ((ptr
= fgets(baddr
, sizeof(baddr
), file
))) {
147 ptr
= baddr
+ strlen(baddr
) - 1;
148 if (ptr
>= baddr
&& *ptr
== '\n')
150 port
->bluetooth_address
= strdup(baddr
);
160 SP_PRIV
enum sp_return
list_ports(struct sp_port
***list
)
162 char name
[PATH_MAX
], target
[PATH_MAX
];
163 struct dirent entry
, *result
;
164 #ifdef HAVE_SERIAL_STRUCT
165 struct serial_struct serial_info
;
168 #ifndef HAVE_READLINKAT
169 char buf
[sizeof(entry
.d_name
) + 16];
175 DEBUG("Enumerating tty devices");
176 if (!(dir
= opendir("/sys/class/tty")))
177 RETURN_FAIL("could not open /sys/class/tty");
179 DEBUG("Iterating over results");
180 while (!readdir_r(dir
, &entry
, &result
) && result
) {
181 #ifdef HAVE_READLINKAT
182 len
= readlinkat(dirfd(dir
), entry
.d_name
, target
, sizeof(target
));
184 snprintf(buf
, sizeof(buf
), "/sys/class/tty/%s", entry
.d_name
);
185 len
= readlink(buf
, target
, sizeof(target
));
187 if (len
<= 0 || len
>= (int) sizeof(target
)-1)
190 if (strstr(target
, "virtual"))
192 snprintf(name
, sizeof(name
), "/dev/%s", entry
.d_name
);
193 DEBUG_FMT("Found device %s", name
);
194 if (strstr(target
, "serial8250")) {
195 /* The serial8250 driver has a hardcoded number of ports.
196 * The only way to tell which actually exist on a given system
197 * is to try to open them and make an ioctl call. */
198 DEBUG("serial8250 device, attempting to open");
199 if ((fd
= open(name
, O_RDWR
| O_NONBLOCK
| O_NOCTTY
)) < 0) {
200 DEBUG("open failed, skipping");
203 #ifdef HAVE_SERIAL_STRUCT
204 ioctl_result
= ioctl(fd
, TIOCGSERIAL
, &serial_info
);
207 #ifdef HAVE_SERIAL_STRUCT
208 if (ioctl_result
!= 0) {
209 DEBUG("ioctl failed, skipping");
212 if (serial_info
.type
== PORT_UNKNOWN
) {
213 DEBUG("port type is unknown, skipping");
218 DEBUG_FMT("Found port %s", name
);
219 *list
= list_append(*list
, name
);
221 SET_ERROR(ret
, SP_ERR_MEM
, "list append failed");