From: Aurelien Jacobs Date: Fri, 13 Jun 2014 21:52:16 +0000 (+0200) Subject: Move list_ports() implementations to OS-specific files. X-Git-Tag: libserialport-0.1.1~123 X-Git-Url: https://sigrok.org/gitaction?a=commitdiff_plain;h=48a4076f692ffe34026c37815580a32b2f70592b;p=libserialport.git Move list_ports() implementations to OS-specific files. --- diff --git a/libserialport_internal.h b/libserialport_internal.h index ca1add1..3553b12 100644 --- a/libserialport_internal.h +++ b/libserialport_internal.h @@ -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) +struct sp_port **list_append(struct sp_port **list, const char *portname); + /* OS-specific Helper functions. */ enum sp_return get_port_details(struct sp_port *port); +enum sp_return list_ports(struct sp_port ***list); diff --git a/linux.c b/linux.c index 2325851..730ba9d 100644 --- a/linux.c +++ b/linux.c @@ -155,3 +155,58 @@ enum sp_return get_port_details(struct sp_port *port) 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; +} diff --git a/macosx.c b/macosx.c index 71bf0a0..38495fd 100644 --- a/macosx.c +++ b/macosx.c @@ -174,3 +174,52 @@ enum sp_return get_port_details(struct sp_port *port) 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; +} diff --git a/serialport.c b/serialport.c index 558322e..c759821 100644 --- a/serialport.c +++ b/serialport.c @@ -287,7 +287,7 @@ void sp_free_port(struct sp_port *port) 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; unsigned int count; @@ -309,7 +309,7 @@ fail: enum sp_return sp_list_ports(struct sp_port ***list_ptr) { struct sp_port **list; - int ret = SP_ERR_SUPP; + int ret; TRACE("%p", list_ptr); @@ -323,176 +323,7 @@ enum sp_return sp_list_ports(struct sp_port ***list_ptr) list[0] = NULL; -#ifdef _WIN32 - 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 + ret = list_ports(&list); switch (ret) { case SP_OK: diff --git a/windows.c b/windows.c index 13be8f5..4c81e2e 100644 --- a/windows.c +++ b/windows.c @@ -1,6 +1,7 @@ /* * This file is part of the libserialport project. * + * Copyright (C) 2013-2014 Martin Ling * Copyright (C) 2014 Aurelien Jacobs * * 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(); } +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; +}