2 * This file is part of the libserialport project.
4 * Copyright (C) 2013 Martin Ling <martin-libserialport@earth.li>
5 * Copyright (C) 2014 Aurelien Jacobs <aurel@gnuage.org>
7 * This program is free software: you can redistribute it and/or modify
8 * it under the terms of the GNU Lesser General Public License as
9 * published by the Free Software Foundation, either version 3 of the
10 * License, or (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public License
18 * along with this program. If not, see <http://www.gnu.org/licenses/>.
22 #include "libserialport.h"
23 #include "libserialport_internal.h"
25 SP_PRIV
enum sp_return
get_port_details(struct sp_port
*port
)
28 * Description limited to 127 char, anything longer
29 * would not be user friendly anyway.
31 char description
[128];
33 unsigned int vid
, pid
;
34 char manufacturer
[128], product
[128], serial
[128];
36 const char dir_name
[] = "/sys/class/tty/%s/device/%s%s";
37 char sub_dir
[32] = "", file_name
[PATH_MAX
];
38 char *ptr
, *dev
= port
->name
+ 5;
43 if (strncmp(port
->name
, "/dev/", 5))
44 RETURN_ERROR(SP_ERR_ARG
, "Device name not recognized");
46 snprintf(file_name
, sizeof(file_name
), "/sys/class/tty/%s", dev
);
47 if (lstat(file_name
, &statbuf
) == -1)
48 RETURN_ERROR(SP_ERR_ARG
, "Device not found");
49 if (!S_ISLNK(statbuf
.st_mode
))
50 snprintf(file_name
, sizeof(file_name
), "/sys/class/tty/%s/device", dev
);
51 count
= readlink(file_name
, file_name
, sizeof(file_name
));
52 if (count
<= 0 || count
>= (int)(sizeof(file_name
) - 1))
53 RETURN_ERROR(SP_ERR_ARG
, "Device not found");
55 if (strstr(file_name
, "bluetooth"))
56 port
->transport
= SP_TRANSPORT_BLUETOOTH
;
57 else if (strstr(file_name
, "usb"))
58 port
->transport
= SP_TRANSPORT_USB
;
60 if (port
->transport
== SP_TRANSPORT_USB
) {
61 for (i
= 0; i
< 5; i
++) {
62 strcat(sub_dir
, "../");
64 snprintf(file_name
, sizeof(file_name
), dir_name
, dev
, sub_dir
, "busnum");
65 if (!(file
= fopen(file_name
, "r")))
67 count
= fscanf(file
, "%d", &bus
);
72 snprintf(file_name
, sizeof(file_name
), dir_name
, dev
, sub_dir
, "devnum");
73 if (!(file
= fopen(file_name
, "r")))
75 count
= fscanf(file
, "%d", &address
);
80 snprintf(file_name
, sizeof(file_name
), dir_name
, dev
, sub_dir
, "idVendor");
81 if (!(file
= fopen(file_name
, "r")))
83 count
= fscanf(file
, "%4x", &vid
);
88 snprintf(file_name
, sizeof(file_name
), dir_name
, dev
, sub_dir
, "idProduct");
89 if (!(file
= fopen(file_name
, "r")))
91 count
= fscanf(file
, "%4x", &pid
);
97 port
->usb_address
= address
;
101 snprintf(file_name
, sizeof(file_name
), dir_name
, dev
, sub_dir
, "product");
102 if ((file
= fopen(file_name
, "r"))) {
103 if ((ptr
= fgets(description
, sizeof(description
), file
))) {
104 ptr
= description
+ strlen(description
) - 1;
105 if (ptr
>= description
&& *ptr
== '\n')
107 port
->description
= strdup(description
);
112 port
->description
= strdup(dev
);
114 snprintf(file_name
, sizeof(file_name
), dir_name
, dev
, sub_dir
, "manufacturer");
115 if ((file
= fopen(file_name
, "r"))) {
116 if ((ptr
= fgets(manufacturer
, sizeof(manufacturer
), file
))) {
117 ptr
= manufacturer
+ strlen(manufacturer
) - 1;
118 if (ptr
>= manufacturer
&& *ptr
== '\n')
120 port
->usb_manufacturer
= strdup(manufacturer
);
125 snprintf(file_name
, sizeof(file_name
), dir_name
, dev
, sub_dir
, "product");
126 if ((file
= fopen(file_name
, "r"))) {
127 if ((ptr
= fgets(product
, sizeof(product
), file
))) {
128 ptr
= product
+ strlen(product
) - 1;
129 if (ptr
>= product
&& *ptr
== '\n')
131 port
->usb_product
= strdup(product
);
136 snprintf(file_name
, sizeof(file_name
), dir_name
, dev
, sub_dir
, "serial");
137 if ((file
= fopen(file_name
, "r"))) {
138 if ((ptr
= fgets(serial
, sizeof(serial
), file
))) {
139 ptr
= serial
+ strlen(serial
) - 1;
140 if (ptr
>= serial
&& *ptr
== '\n')
142 port
->usb_serial
= strdup(serial
);
147 /* If present, add serial to description for better identification. */
148 if (port
->usb_serial
&& strlen(port
->usb_serial
)) {
149 snprintf(description
, sizeof(description
),
150 "%s - %s", port
->description
, port
->usb_serial
);
151 if (port
->description
)
152 free(port
->description
);
153 port
->description
= strdup(description
);
159 port
->description
= strdup(dev
);
161 if (port
->transport
== SP_TRANSPORT_BLUETOOTH
) {
162 snprintf(file_name
, sizeof(file_name
), dir_name
, dev
, "", "address");
163 if ((file
= fopen(file_name
, "r"))) {
164 if ((ptr
= fgets(baddr
, sizeof(baddr
), file
))) {
165 ptr
= baddr
+ strlen(baddr
) - 1;
166 if (ptr
>= baddr
&& *ptr
== '\n')
168 port
->bluetooth_address
= strdup(baddr
);
178 SP_PRIV
enum sp_return
list_ports(struct sp_port
***list
)
180 char name
[PATH_MAX
], target
[PATH_MAX
];
181 struct dirent
*entry
;
182 #ifdef HAVE_STRUCT_SERIAL_STRUCT
183 struct serial_struct serial_info
;
186 char buf
[sizeof(entry
->d_name
) + 23];
192 DEBUG("Enumerating tty devices");
193 if (!(dir
= opendir("/sys/class/tty")))
194 RETURN_FAIL("Could not open /sys/class/tty");
196 DEBUG("Iterating over results");
197 while ((entry
= readdir(dir
))) {
198 snprintf(buf
, sizeof(buf
), "/sys/class/tty/%s", entry
->d_name
);
199 if (lstat(buf
, &statbuf
) == -1)
201 if (!S_ISLNK(statbuf
.st_mode
))
202 snprintf(buf
, sizeof(buf
), "/sys/class/tty/%s/device", entry
->d_name
);
203 len
= readlink(buf
, target
, sizeof(target
));
204 if (len
<= 0 || len
>= (int)(sizeof(target
) - 1))
207 if (strstr(target
, "virtual"))
209 snprintf(name
, sizeof(name
), "/dev/%s", entry
->d_name
);
210 DEBUG_FMT("Found device %s", name
);
211 if (strstr(target
, "serial8250")) {
213 * The serial8250 driver has a hardcoded number of ports.
214 * The only way to tell which actually exist on a given system
215 * is to try to open them and make an ioctl call.
217 DEBUG("serial8250 device, attempting to open");
218 if ((fd
= open(name
, O_RDWR
| O_NONBLOCK
| O_NOCTTY
)) < 0) {
219 DEBUG("Open failed, skipping");
222 #ifdef HAVE_STRUCT_SERIAL_STRUCT
223 ioctl_result
= ioctl(fd
, TIOCGSERIAL
, &serial_info
);
226 #ifdef HAVE_STRUCT_SERIAL_STRUCT
227 if (ioctl_result
!= 0) {
228 DEBUG("ioctl failed, skipping");
231 if (serial_info
.type
== PORT_UNKNOWN
) {
232 DEBUG("Port type is unknown, skipping");
237 DEBUG_FMT("Found port %s", name
);
238 *list
= list_append(*list
, name
);
240 SET_ERROR(ret
, SP_ERR_MEM
, "List append failed");