Move list_ports() implementations to OS-specific files.
This commit is contained in:
parent
235269990b
commit
48a4076f69
|
@ -187,5 +187,8 @@ extern void (*sp_debug_handler)(const char *format, ...);
|
||||||
|
|
||||||
#define TRY(x) do { int ret = x; if (ret != SP_OK) RETURN_CODEVAL(ret); } while (0)
|
#define TRY(x) do { int ret = x; if (ret != SP_OK) RETURN_CODEVAL(ret); } while (0)
|
||||||
|
|
||||||
|
struct sp_port **list_append(struct sp_port **list, const char *portname);
|
||||||
|
|
||||||
/* OS-specific Helper functions. */
|
/* OS-specific Helper functions. */
|
||||||
enum sp_return get_port_details(struct sp_port *port);
|
enum sp_return get_port_details(struct sp_port *port);
|
||||||
|
enum sp_return list_ports(struct sp_port ***list);
|
||||||
|
|
55
linux.c
55
linux.c
|
@ -155,3 +155,58 @@ enum sp_return get_port_details(struct sp_port *port)
|
||||||
|
|
||||||
RETURN_OK();
|
RETURN_OK();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
enum sp_return list_ports(struct sp_port ***list)
|
||||||
|
{
|
||||||
|
char name[PATH_MAX], target[PATH_MAX];
|
||||||
|
struct dirent entry, *result;
|
||||||
|
struct serial_struct serial_info;
|
||||||
|
int len, fd, ioctl_result;
|
||||||
|
DIR *dir;
|
||||||
|
int ret = SP_OK;
|
||||||
|
|
||||||
|
DEBUG("Enumerating tty devices");
|
||||||
|
if (!(dir = opendir("/sys/class/tty")))
|
||||||
|
RETURN_FAIL("could not open /sys/class/tty");
|
||||||
|
|
||||||
|
DEBUG("Iterating over results");
|
||||||
|
while (!readdir_r(dir, &entry, &result) && result) {
|
||||||
|
len = readlinkat(dirfd(dir), entry.d_name, target, sizeof(target));
|
||||||
|
if (len <= 0 || len >= (int) sizeof(target)-1)
|
||||||
|
continue;
|
||||||
|
target[len] = 0;
|
||||||
|
if (strstr(target, "virtual"))
|
||||||
|
continue;
|
||||||
|
snprintf(name, sizeof(name), "/dev/%s", entry.d_name);
|
||||||
|
DEBUG("Found device %s", name);
|
||||||
|
if (strstr(target, "serial8250")) {
|
||||||
|
/* The serial8250 driver has a hardcoded number of ports.
|
||||||
|
* The only way to tell which actually exist on a given system
|
||||||
|
* is to try to open them and make an ioctl call. */
|
||||||
|
DEBUG("serial8250 device, attempting to open");
|
||||||
|
if ((fd = open(name, O_RDWR | O_NONBLOCK | O_NOCTTY)) < 0) {
|
||||||
|
DEBUG("open failed, skipping");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
ioctl_result = ioctl(fd, TIOCGSERIAL, &serial_info);
|
||||||
|
close(fd);
|
||||||
|
if (ioctl_result != 0) {
|
||||||
|
DEBUG("ioctl failed, skipping");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (serial_info.type == PORT_UNKNOWN) {
|
||||||
|
DEBUG("port type is unknown, skipping");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
DEBUG("Found port %s", name);
|
||||||
|
*list = list_append(*list, name);
|
||||||
|
if (!list) {
|
||||||
|
SET_ERROR(ret, SP_ERR_MEM, "list append failed");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
closedir(dir);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
49
macosx.c
49
macosx.c
|
@ -174,3 +174,52 @@ enum sp_return get_port_details(struct sp_port *port)
|
||||||
|
|
||||||
RETURN_OK();
|
RETURN_OK();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
enum sp_return list_ports(struct sp_port ***list)
|
||||||
|
{
|
||||||
|
CFMutableDictionaryRef classes;
|
||||||
|
io_iterator_t iter;
|
||||||
|
char path[PATH_MAX];
|
||||||
|
io_object_t port;
|
||||||
|
CFTypeRef cf_path;
|
||||||
|
Boolean result;
|
||||||
|
int ret = SP_OK;
|
||||||
|
|
||||||
|
DEBUG("Creating matching dictionary");
|
||||||
|
if (!(classes = IOServiceMatching(kIOSerialBSDServiceValue))) {
|
||||||
|
SET_FAIL(ret, "IOServiceMatching() failed");
|
||||||
|
goto out_done;
|
||||||
|
}
|
||||||
|
|
||||||
|
DEBUG("Getting matching services");
|
||||||
|
if (IOServiceGetMatchingServices(kIOMasterPortDefault, classes,
|
||||||
|
&iter) != KERN_SUCCESS) {
|
||||||
|
SET_FAIL(ret, "IOServiceGetMatchingServices() failed");
|
||||||
|
goto out_done;
|
||||||
|
}
|
||||||
|
|
||||||
|
DEBUG("Iterating over results");
|
||||||
|
while ((port = IOIteratorNext(iter))) {
|
||||||
|
cf_path = IORegistryEntryCreateCFProperty(port,
|
||||||
|
CFSTR(kIOCalloutDeviceKey), kCFAllocatorDefault, 0);
|
||||||
|
if (cf_path) {
|
||||||
|
result = CFStringGetCString(cf_path, path, sizeof(path),
|
||||||
|
kCFStringEncodingASCII);
|
||||||
|
CFRelease(cf_path);
|
||||||
|
if (result) {
|
||||||
|
DEBUG("Found port %s", path);
|
||||||
|
if (!(*list = list_append(*list, path))) {
|
||||||
|
SET_ERROR(ret, SP_ERR_MEM, "list append failed");
|
||||||
|
IOObjectRelease(port);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
IOObjectRelease(port);
|
||||||
|
}
|
||||||
|
out:
|
||||||
|
IOObjectRelease(iter);
|
||||||
|
out_done:
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
175
serialport.c
175
serialport.c
|
@ -287,7 +287,7 @@ void sp_free_port(struct sp_port *port)
|
||||||
RETURN();
|
RETURN();
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct sp_port **list_append(struct sp_port **list, const char *portname)
|
struct sp_port **list_append(struct sp_port **list, const char *portname)
|
||||||
{
|
{
|
||||||
void *tmp;
|
void *tmp;
|
||||||
unsigned int count;
|
unsigned int count;
|
||||||
|
@ -309,7 +309,7 @@ fail:
|
||||||
enum sp_return sp_list_ports(struct sp_port ***list_ptr)
|
enum sp_return sp_list_ports(struct sp_port ***list_ptr)
|
||||||
{
|
{
|
||||||
struct sp_port **list;
|
struct sp_port **list;
|
||||||
int ret = SP_ERR_SUPP;
|
int ret;
|
||||||
|
|
||||||
TRACE("%p", list_ptr);
|
TRACE("%p", list_ptr);
|
||||||
|
|
||||||
|
@ -323,176 +323,7 @@ enum sp_return sp_list_ports(struct sp_port ***list_ptr)
|
||||||
|
|
||||||
list[0] = NULL;
|
list[0] = NULL;
|
||||||
|
|
||||||
#ifdef _WIN32
|
ret = list_ports(&list);
|
||||||
HKEY key;
|
|
||||||
TCHAR *value, *data;
|
|
||||||
DWORD max_value_len, max_data_size, max_data_len;
|
|
||||||
DWORD value_len, data_size, data_len;
|
|
||||||
DWORD type, index = 0;
|
|
||||||
char *name;
|
|
||||||
int name_len;
|
|
||||||
|
|
||||||
ret = SP_OK;
|
|
||||||
|
|
||||||
DEBUG("Opening registry key");
|
|
||||||
if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, _T("HARDWARE\\DEVICEMAP\\SERIALCOMM"),
|
|
||||||
0, KEY_QUERY_VALUE, &key) != ERROR_SUCCESS) {
|
|
||||||
SET_FAIL(ret, "RegOpenKeyEx() failed");
|
|
||||||
goto out_done;
|
|
||||||
}
|
|
||||||
DEBUG("Querying registry key value and data sizes");
|
|
||||||
if (RegQueryInfoKey(key, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
|
|
||||||
&max_value_len, &max_data_size, NULL, NULL) != ERROR_SUCCESS) {
|
|
||||||
SET_FAIL(ret, "RegQueryInfoKey() failed");
|
|
||||||
goto out_close;
|
|
||||||
}
|
|
||||||
max_data_len = max_data_size / sizeof(TCHAR);
|
|
||||||
if (!(value = malloc((max_value_len + 1) * sizeof(TCHAR)))) {
|
|
||||||
SET_ERROR(ret, SP_ERR_MEM, "registry value malloc failed");
|
|
||||||
goto out_close;
|
|
||||||
}
|
|
||||||
if (!(data = malloc((max_data_len + 1) * sizeof(TCHAR)))) {
|
|
||||||
SET_ERROR(ret, SP_ERR_MEM, "registry data malloc failed");
|
|
||||||
goto out_free_value;
|
|
||||||
}
|
|
||||||
DEBUG("Iterating over values");
|
|
||||||
while (
|
|
||||||
value_len = max_value_len + 1,
|
|
||||||
data_size = max_data_size,
|
|
||||||
RegEnumValue(key, index, value, &value_len,
|
|
||||||
NULL, &type, (LPBYTE)data, &data_size) == ERROR_SUCCESS)
|
|
||||||
{
|
|
||||||
data_len = data_size / sizeof(TCHAR);
|
|
||||||
data[data_len] = '\0';
|
|
||||||
#ifdef UNICODE
|
|
||||||
name_len = WideCharToMultiByte(CP_ACP, 0, data, -1, NULL, 0, NULL, NULL);
|
|
||||||
#else
|
|
||||||
name_len = data_len + 1;
|
|
||||||
#endif
|
|
||||||
if (!(name = malloc(name_len))) {
|
|
||||||
SET_ERROR(ret, SP_ERR_MEM, "registry port name malloc failed");
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
#ifdef UNICODE
|
|
||||||
WideCharToMultiByte(CP_ACP, 0, data, -1, name, name_len, NULL, NULL);
|
|
||||||
#else
|
|
||||||
strcpy(name, data);
|
|
||||||
#endif
|
|
||||||
if (type == REG_SZ) {
|
|
||||||
DEBUG("Found port %s", name);
|
|
||||||
if (!(list = list_append(list, name))) {
|
|
||||||
SET_ERROR(ret, SP_ERR_MEM, "list append failed");
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
index++;
|
|
||||||
}
|
|
||||||
out:
|
|
||||||
free(data);
|
|
||||||
out_free_value:
|
|
||||||
free(value);
|
|
||||||
out_close:
|
|
||||||
RegCloseKey(key);
|
|
||||||
out_done:
|
|
||||||
#endif
|
|
||||||
#ifdef __APPLE__
|
|
||||||
CFMutableDictionaryRef classes;
|
|
||||||
io_iterator_t iter;
|
|
||||||
char path[PATH_MAX];
|
|
||||||
io_object_t port;
|
|
||||||
CFTypeRef cf_path;
|
|
||||||
Boolean result;
|
|
||||||
|
|
||||||
ret = SP_OK;
|
|
||||||
|
|
||||||
DEBUG("Creating matching dictionary");
|
|
||||||
if (!(classes = IOServiceMatching(kIOSerialBSDServiceValue))) {
|
|
||||||
SET_FAIL(ret, "IOServiceMatching() failed");
|
|
||||||
goto out_done;
|
|
||||||
}
|
|
||||||
|
|
||||||
DEBUG("Getting matching services");
|
|
||||||
if (IOServiceGetMatchingServices(kIOMasterPortDefault, classes,
|
|
||||||
&iter) != KERN_SUCCESS) {
|
|
||||||
SET_FAIL(ret, "IOServiceGetMatchingServices() failed");
|
|
||||||
goto out_done;
|
|
||||||
}
|
|
||||||
|
|
||||||
DEBUG("Iterating over results");
|
|
||||||
while ((port = IOIteratorNext(iter))) {
|
|
||||||
cf_path = IORegistryEntryCreateCFProperty(port,
|
|
||||||
CFSTR(kIOCalloutDeviceKey), kCFAllocatorDefault, 0);
|
|
||||||
if (cf_path) {
|
|
||||||
result = CFStringGetCString(cf_path, path, sizeof(path),
|
|
||||||
kCFStringEncodingASCII);
|
|
||||||
CFRelease(cf_path);
|
|
||||||
if (result) {
|
|
||||||
DEBUG("Found port %s", path);
|
|
||||||
if (!(list = list_append(list, path))) {
|
|
||||||
SET_ERROR(ret, SP_ERR_MEM, "list append failed");
|
|
||||||
IOObjectRelease(port);
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
IOObjectRelease(port);
|
|
||||||
}
|
|
||||||
out:
|
|
||||||
IOObjectRelease(iter);
|
|
||||||
out_done:
|
|
||||||
#endif
|
|
||||||
#ifdef __linux__
|
|
||||||
char name[PATH_MAX], target[PATH_MAX];
|
|
||||||
struct dirent entry, *result;
|
|
||||||
struct serial_struct serial_info;
|
|
||||||
int len, fd, ioctl_result;
|
|
||||||
DIR *dir;
|
|
||||||
|
|
||||||
ret = SP_OK;
|
|
||||||
|
|
||||||
DEBUG("Enumerating tty devices");
|
|
||||||
if (!(dir = opendir("/sys/class/tty")))
|
|
||||||
RETURN_FAIL("could not open /sys/class/tty");
|
|
||||||
|
|
||||||
DEBUG("Iterating over results");
|
|
||||||
while (!readdir_r(dir, &entry, &result) && result) {
|
|
||||||
len = readlinkat(dirfd(dir), entry.d_name, target, sizeof(target));
|
|
||||||
if (len <= 0 || len >= (int) sizeof(target)-1)
|
|
||||||
continue;
|
|
||||||
target[len] = 0;
|
|
||||||
if (strstr(target, "virtual"))
|
|
||||||
continue;
|
|
||||||
snprintf(name, sizeof(name), "/dev/%s", entry.d_name);
|
|
||||||
DEBUG("Found device %s", name);
|
|
||||||
if (strstr(target, "serial8250")) {
|
|
||||||
/* The serial8250 driver has a hardcoded number of ports.
|
|
||||||
* The only way to tell which actually exist on a given system
|
|
||||||
* is to try to open them and make an ioctl call. */
|
|
||||||
DEBUG("serial8250 device, attempting to open");
|
|
||||||
if ((fd = open(name, O_RDWR | O_NONBLOCK | O_NOCTTY)) < 0) {
|
|
||||||
DEBUG("open failed, skipping");
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
ioctl_result = ioctl(fd, TIOCGSERIAL, &serial_info);
|
|
||||||
close(fd);
|
|
||||||
if (ioctl_result != 0) {
|
|
||||||
DEBUG("ioctl failed, skipping");
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (serial_info.type == PORT_UNKNOWN) {
|
|
||||||
DEBUG("port type is unknown, skipping");
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
DEBUG("Found port %s", name);
|
|
||||||
list = list_append(list, name);
|
|
||||||
if (!list) {
|
|
||||||
SET_ERROR(ret, SP_ERR_MEM, "list append failed");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
closedir(dir);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
switch (ret) {
|
switch (ret) {
|
||||||
case SP_OK:
|
case SP_OK:
|
||||||
|
|
75
windows.c
75
windows.c
|
@ -1,6 +1,7 @@
|
||||||
/*
|
/*
|
||||||
* This file is part of the libserialport project.
|
* This file is part of the libserialport project.
|
||||||
*
|
*
|
||||||
|
* Copyright (C) 2013-2014 Martin Ling <martin-libserialport@earth.li>
|
||||||
* Copyright (C) 2014 Aurelien Jacobs <aurel@gnuage.org>
|
* Copyright (C) 2014 Aurelien Jacobs <aurel@gnuage.org>
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
@ -454,3 +455,77 @@ enum sp_return get_port_details(struct sp_port *port)
|
||||||
RETURN_OK();
|
RETURN_OK();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
enum sp_return list_ports(struct sp_port ***list)
|
||||||
|
{
|
||||||
|
HKEY key;
|
||||||
|
TCHAR *value, *data;
|
||||||
|
DWORD max_value_len, max_data_size, max_data_len;
|
||||||
|
DWORD value_len, data_size, data_len;
|
||||||
|
DWORD type, index = 0;
|
||||||
|
char *name;
|
||||||
|
int name_len;
|
||||||
|
int ret = SP_OK;
|
||||||
|
|
||||||
|
DEBUG("Opening registry key");
|
||||||
|
if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, _T("HARDWARE\\DEVICEMAP\\SERIALCOMM"),
|
||||||
|
0, KEY_QUERY_VALUE, &key) != ERROR_SUCCESS) {
|
||||||
|
SET_FAIL(ret, "RegOpenKeyEx() failed");
|
||||||
|
goto out_done;
|
||||||
|
}
|
||||||
|
DEBUG("Querying registry key value and data sizes");
|
||||||
|
if (RegQueryInfoKey(key, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
|
||||||
|
&max_value_len, &max_data_size, NULL, NULL) != ERROR_SUCCESS) {
|
||||||
|
SET_FAIL(ret, "RegQueryInfoKey() failed");
|
||||||
|
goto out_close;
|
||||||
|
}
|
||||||
|
max_data_len = max_data_size / sizeof(TCHAR);
|
||||||
|
if (!(value = malloc((max_value_len + 1) * sizeof(TCHAR)))) {
|
||||||
|
SET_ERROR(ret, SP_ERR_MEM, "registry value malloc failed");
|
||||||
|
goto out_close;
|
||||||
|
}
|
||||||
|
if (!(data = malloc((max_data_len + 1) * sizeof(TCHAR)))) {
|
||||||
|
SET_ERROR(ret, SP_ERR_MEM, "registry data malloc failed");
|
||||||
|
goto out_free_value;
|
||||||
|
}
|
||||||
|
DEBUG("Iterating over values");
|
||||||
|
while (
|
||||||
|
value_len = max_value_len + 1,
|
||||||
|
data_size = max_data_size,
|
||||||
|
RegEnumValue(key, index, value, &value_len,
|
||||||
|
NULL, &type, (LPBYTE)data, &data_size) == ERROR_SUCCESS)
|
||||||
|
{
|
||||||
|
data_len = data_size / sizeof(TCHAR);
|
||||||
|
data[data_len] = '\0';
|
||||||
|
#ifdef UNICODE
|
||||||
|
name_len = WideCharToMultiByte(CP_ACP, 0, data, -1, NULL, 0, NULL, NULL);
|
||||||
|
#else
|
||||||
|
name_len = data_len + 1;
|
||||||
|
#endif
|
||||||
|
if (!(name = malloc(name_len))) {
|
||||||
|
SET_ERROR(ret, SP_ERR_MEM, "registry port name malloc failed");
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
#ifdef UNICODE
|
||||||
|
WideCharToMultiByte(CP_ACP, 0, data, -1, name, name_len, NULL, NULL);
|
||||||
|
#else
|
||||||
|
strcpy(name, data);
|
||||||
|
#endif
|
||||||
|
if (type == REG_SZ) {
|
||||||
|
DEBUG("Found port %s", name);
|
||||||
|
if (!(*list = list_append(*list, name))) {
|
||||||
|
SET_ERROR(ret, SP_ERR_MEM, "list append failed");
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
index++;
|
||||||
|
}
|
||||||
|
out:
|
||||||
|
free(data);
|
||||||
|
out_free_value:
|
||||||
|
free(value);
|
||||||
|
out_close:
|
||||||
|
RegCloseKey(key);
|
||||||
|
out_done:
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue