X-Git-Url: https://sigrok.org/gitweb/?a=blobdiff_plain;f=serialport.c;h=93303767c05dfb512926c538cbb6748dcade4db6;hb=d4babed247a917219709f5bb50241d54e1a037be;hp=a8f410eea624b1879bfe01173738aba46430fe6e;hpb=08fe0bdbdb1a3e10bc7e2b07b317e271ce99049a;p=libserialport.git diff --git a/serialport.c b/serialport.c index a8f410e..9330376 100644 --- a/serialport.c +++ b/serialport.c @@ -34,34 +34,51 @@ #include #endif #ifdef __APPLE__ -#include -#include +#include +#include +#include #endif #ifdef __linux__ #include "libudev.h" +#include "linux/serial.h" #endif #include "serialport.h" -static char **sp_list_new(void) +struct sp_port *sp_get_port_by_name(const char *portname) { - char **list; - if ((list = malloc(sizeof(char *)))) - list[0] = NULL; - return list; + struct sp_port *port; + int len; + + if (!portname) + return NULL; + + if (!(port = malloc(sizeof(struct sp_port)))) + return NULL; + + len = strlen(portname) + 1; + + if (!(port->name = malloc(len))) + { + free(port); + return NULL; + } + + memcpy(port->name, portname, len); + + return port; } -static char **sp_list_append(char **list, void *data, size_t len) +static struct sp_port **sp_list_append(struct sp_port **list, const char *portname) { void *tmp; unsigned int count; for (count = 0; list[count]; count++); - if (!(tmp = realloc(list, sizeof(char *) * (count + 2)))) + if (!(tmp = realloc(list, sizeof(struct sp_port *) * (count + 2)))) goto fail; list = tmp; - if (!(list[count] = malloc(len))) + if (!(list[count] = sp_get_port_by_name(portname))) goto fail; - memcpy(list[count], data, len); list[count + 1] = NULL; return list; fail: @@ -74,48 +91,64 @@ fail: * * @return A null-terminated array of port name strings. */ -char **sp_list_ports(void) +struct sp_port **sp_list_ports(void) { - char **list = NULL; + struct sp_port **list; + + if (!(list = malloc(sizeof(struct sp_port **)))) + return NULL; + + list[0] = NULL; #ifdef _WIN32 HKEY key; - TCHAR *name, *data; - DWORD max_name_len, max_data_size, max_data_len; - DWORD name_len, data_size, data_len; + 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; if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, _T("HARDWARE\\DEVICEMAP\\SERIALCOMM"), 0, KEY_QUERY_VALUE, &key) != ERROR_SUCCESS) return NULL; if (RegQueryInfoKey(key, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - &max_name_len, &max_data_size, NULL, NULL) != ERROR_SUCCESS) + &max_value_len, &max_data_size, NULL, NULL) != ERROR_SUCCESS) goto out_close; max_data_len = max_data_size / sizeof(TCHAR); - if (!(name = malloc((max_name_len + 1) * sizeof(TCHAR)))) + if (!(value = malloc((max_value_len + 1) * sizeof(TCHAR)))) goto out_close; if (!(data = malloc((max_data_len + 1) * sizeof(TCHAR)))) - goto out_free_name; - if (!(list = sp_list_new())) - goto out; + goto out_free_value; while ( - name_len = max_name_len, + value_len = max_value_len, data_size = max_data_size, - RegEnumValue(key, index, name, &name_len, + 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))) + goto out; +#ifdef UNICODE + WideCharToMultiByte(CP_ACP, 0, data, -1, name, name_len, NULL, NULL); +#else + strcpy(name, data); +#endif if (type == REG_SZ) - if (!(list = sp_list_append(list, - data, (data_len + 1) * sizeof(TCHAR)))) + if (!(list = sp_list_append(list, name))) goto out; index++; } out: free(data); -out_free_name: - free(name); +out_free_value: + free(value); out_close: RegCloseKey(key); return list; @@ -144,10 +177,7 @@ out_close: if (!(path = malloc(PATH_MAX))) goto out_release; - if (!(list = sp_list_new())) - goto out; - - while (port = IOIteratorNext(iter)) { + while ((port = IOIteratorNext(iter))) { cf_path = IORegistryEntryCreateCFProperty(port, CFSTR(kIOCalloutDeviceKey), kCFAllocatorDefault, 0); if (cf_path) { @@ -155,7 +185,7 @@ out_close: path, PATH_MAX, kCFStringEncodingASCII); CFRelease(cf_path); if (result) - if (!(list = sp_list_append(list, path, strlen(path) + 1))) + if (!(list = sp_list_append(list, path))) { IOObjectRelease(port); goto out; @@ -178,14 +208,15 @@ out_release: const char *path; struct udev_device *ud_dev, *ud_parent; const char *name; + const char *driver; + int fd, ioctl_result; + struct serial_struct serial_info; ud = udev_new(); ud_enumerate = udev_enumerate_new(ud); udev_enumerate_add_match_subsystem(ud_enumerate, "tty"); udev_enumerate_scan_devices(ud_enumerate); ud_list = udev_enumerate_get_list_entry(ud_enumerate); - if (!(list = sp_list_new())) - goto out; udev_list_entry_foreach(ud_entry, ud_list) { path = udev_list_entry_get_name(ud_entry); @@ -198,7 +229,23 @@ out_release: continue; } name = udev_device_get_devnode(ud_dev); - list = sp_list_append(list, (void *)name, strlen(name) + 1); + /* 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. */ + driver = udev_device_get_driver(ud_parent); + if (driver && !strcmp(driver, "serial8250")) + { + if ((fd = open(name, O_RDWR | O_NONBLOCK | O_NOCTTY)) < 0) + goto skip; + ioctl_result = ioctl(fd, TIOCGSERIAL, &serial_info); + close(fd); + if (ioctl_result != 0) + goto skip; + if (serial_info.type == PORT_UNKNOWN) + goto skip; + } + list = sp_list_append(list, name); +skip: udev_device_unref(ud_dev); if (!list) goto out; @@ -213,7 +260,7 @@ out: /** * Free a port list returned by sp_list_ports. */ -void sp_free_port_list(char **list) +void sp_free_port_list(struct sp_port **list) { unsigned int i; for (i = 0; list[i]; i++) @@ -248,16 +295,11 @@ static int sp_validate_port(struct sp_port *port) * @return SP_OK on success, SP_ERR_FAIL on failure, * or SP_ERR_ARG if an invalid port or name is passed. */ -int sp_open(struct sp_port *port, char *portname, int flags) +int sp_open(struct sp_port *port, int flags) { if (!port) return SP_ERR_ARG; - if (!portname) - return SP_ERR_ARG; - - port->name = portname; - #ifdef _WIN32 DWORD desired_access = 0, flags_and_attributes = 0; /* Map 'flags' to the OS-specific settings. */