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
)
26 * Description limited to 127 char, anything longer
27 * would not be user friendly anyway.
29 char description
[128];
31 unsigned int vid
, pid
;
32 char manufacturer
[128], product
[128], serial
[128];
34 const char dir_name
[] = "/sys/class/tty/%s/device/%s%s";
35 char sub_dir
[32] = "", file_name
[PATH_MAX
];
36 char *ptr
, *dev
= port
->name
+ 5;
40 if (strncmp(port
->name
, "/dev/", 5))
41 RETURN_ERROR(SP_ERR_ARG
, "Device name not recognized");
43 snprintf(file_name
, sizeof(file_name
), "/sys/class/tty/%s", dev
);
44 count
= readlink(file_name
, file_name
, sizeof(file_name
));
45 if (count
<= 0 || count
>= (int)(sizeof(file_name
) - 1))
46 RETURN_ERROR(SP_ERR_ARG
, "Device not found");
48 if (strstr(file_name
, "bluetooth"))
49 port
->transport
= SP_TRANSPORT_BLUETOOTH
;
50 else if (strstr(file_name
, "usb"))
51 port
->transport
= SP_TRANSPORT_USB
;
53 if (port
->transport
== SP_TRANSPORT_USB
) {
54 for (i
= 0; i
< 5; i
++) {
55 strcat(sub_dir
, "../");
57 snprintf(file_name
, sizeof(file_name
), dir_name
, dev
, sub_dir
, "busnum");
58 if (!(file
= fopen(file_name
, "r")))
60 count
= fscanf(file
, "%d", &bus
);
65 snprintf(file_name
, sizeof(file_name
), dir_name
, dev
, sub_dir
, "devnum");
66 if (!(file
= fopen(file_name
, "r")))
68 count
= fscanf(file
, "%d", &address
);
73 snprintf(file_name
, sizeof(file_name
), dir_name
, dev
, sub_dir
, "idVendor");
74 if (!(file
= fopen(file_name
, "r")))
76 count
= fscanf(file
, "%4x", &vid
);
81 snprintf(file_name
, sizeof(file_name
), dir_name
, dev
, sub_dir
, "idProduct");
82 if (!(file
= fopen(file_name
, "r")))
84 count
= fscanf(file
, "%4x", &pid
);
90 port
->usb_address
= address
;
94 snprintf(file_name
, sizeof(file_name
), dir_name
, dev
, sub_dir
, "product");
95 if ((file
= fopen(file_name
, "r"))) {
96 if ((ptr
= fgets(description
, sizeof(description
), file
))) {
97 ptr
= description
+ strlen(description
) - 1;
98 if (ptr
>= description
&& *ptr
== '\n')
100 port
->description
= strdup(description
);
105 port
->description
= strdup(dev
);
107 snprintf(file_name
, sizeof(file_name
), dir_name
, dev
, sub_dir
, "manufacturer");
108 if ((file
= fopen(file_name
, "r"))) {
109 if ((ptr
= fgets(manufacturer
, sizeof(manufacturer
), file
))) {
110 ptr
= manufacturer
+ strlen(manufacturer
) - 1;
111 if (ptr
>= manufacturer
&& *ptr
== '\n')
113 port
->usb_manufacturer
= strdup(manufacturer
);
118 snprintf(file_name
, sizeof(file_name
), dir_name
, dev
, sub_dir
, "product");
119 if ((file
= fopen(file_name
, "r"))) {
120 if ((ptr
= fgets(product
, sizeof(product
), file
))) {
121 ptr
= product
+ strlen(product
) - 1;
122 if (ptr
>= product
&& *ptr
== '\n')
124 port
->usb_product
= strdup(product
);
129 snprintf(file_name
, sizeof(file_name
), dir_name
, dev
, sub_dir
, "serial");
130 if ((file
= fopen(file_name
, "r"))) {
131 if ((ptr
= fgets(serial
, sizeof(serial
), file
))) {
132 ptr
= serial
+ strlen(serial
) - 1;
133 if (ptr
>= serial
&& *ptr
== '\n')
135 port
->usb_serial
= strdup(serial
);
140 /* If present, add serial to description for better identification. */
141 if (port
->usb_serial
&& strlen(port
->usb_serial
)) {
142 snprintf(description
, sizeof(description
),
143 "%s - %s", port
->description
, port
->usb_serial
);
144 if (port
->description
)
145 free(port
->description
);
146 port
->description
= strdup(description
);
152 port
->description
= strdup(dev
);
154 if (port
->transport
== SP_TRANSPORT_BLUETOOTH
) {
155 snprintf(file_name
, sizeof(file_name
), dir_name
, dev
, "", "address");
156 if ((file
= fopen(file_name
, "r"))) {
157 if ((ptr
= fgets(baddr
, sizeof(baddr
), file
))) {
158 ptr
= baddr
+ strlen(baddr
) - 1;
159 if (ptr
>= baddr
&& *ptr
== '\n')
161 port
->bluetooth_address
= strdup(baddr
);
171 SP_PRIV
enum sp_return
list_ports(struct sp_port
***list
)
173 char name
[PATH_MAX
], target
[PATH_MAX
];
174 struct dirent entry
, *result
;
175 #ifdef HAVE_SERIAL_STRUCT
176 struct serial_struct serial_info
;
179 char buf
[sizeof(entry
.d_name
) + 16];
184 DEBUG("Enumerating tty devices");
185 if (!(dir
= opendir("/sys/class/tty")))
186 RETURN_FAIL("Could not open /sys/class/tty");
188 DEBUG("Iterating over results");
189 while (!readdir_r(dir
, &entry
, &result
) && result
) {
190 snprintf(buf
, sizeof(buf
), "/sys/class/tty/%s", entry
.d_name
);
191 len
= readlink(buf
, target
, sizeof(target
));
192 if (len
<= 0 || len
>= (int)(sizeof(target
) - 1))
195 if (strstr(target
, "virtual"))
197 snprintf(name
, sizeof(name
), "/dev/%s", entry
.d_name
);
198 DEBUG_FMT("Found device %s", name
);
199 if (strstr(target
, "serial8250")) {
201 * The serial8250 driver has a hardcoded number of ports.
202 * The only way to tell which actually exist on a given system
203 * is to try to open them and make an ioctl call.
205 DEBUG("serial8250 device, attempting to open");
206 if ((fd
= open(name
, O_RDWR
| O_NONBLOCK
| O_NOCTTY
)) < 0) {
207 DEBUG("Open failed, skipping");
210 #ifdef HAVE_SERIAL_STRUCT
211 ioctl_result
= ioctl(fd
, TIOCGSERIAL
, &serial_info
);
214 #ifdef HAVE_SERIAL_STRUCT
215 if (ioctl_result
!= 0) {
216 DEBUG("ioctl failed, skipping");
219 if (serial_info
.type
== PORT_UNKNOWN
) {
220 DEBUG("Port type is unknown, skipping");
225 DEBUG_FMT("Found port %s", name
);
226 *list
= list_append(*list
, name
);
228 SET_ERROR(ret
, SP_ERR_MEM
, "List append failed");