Move list_ports() implementations to OS-specific files.

This commit is contained in:
Aurelien Jacobs 2014-06-13 23:52:16 +02:00
parent 235269990b
commit 48a4076f69
5 changed files with 185 additions and 172 deletions

View File

@ -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
View File

@ -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;
}

View File

@ -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;
}

View File

@ -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:

View File

@ -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;
}