X-Git-Url: http://sigrok.org/gitweb/?a=blobdiff_plain;f=serialport.c;h=074534edb8a898c280109a25b3da9ae537e1820e;hb=f14809393ace8e5f9a664975f34b701d1e35d2fa;hp=9ebc2da7f226324fa83ef0363620734a203b35eb;hpb=a93fb468885de8775f1d200625dac114d3050b1d;p=libserialport.git diff --git a/serialport.c b/serialport.c index 9ebc2da..074534e 100644 --- a/serialport.c +++ b/serialport.c @@ -21,138 +21,10 @@ * along with this program. If not, see . */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#ifdef _WIN32 -#include -#include -#include -#include -#include -#else -#include -#include -#include -#include -#include -#include -#endif -#ifdef __APPLE__ -#include -#include -#include -#include -#include -#endif -#ifdef __linux__ -#include -#ifndef __ANDROID__ -#include "linux/serial.h" -#endif -#include "linux_termios.h" - -/* TCGETX/TCSETX is not available everywhere. */ -#if defined(TCGETX) && defined(TCSETX) && defined(HAVE_TERMIOX) -#define USE_TERMIOX -#endif -#endif - -/* TIOCINQ/TIOCOUTQ is not available everywhere. */ -#if !defined(TIOCINQ) && defined(FIONREAD) -#define TIOCINQ FIONREAD -#endif -#if !defined(TIOCOUTQ) && defined(FIONWRITE) -#define TIOCOUTQ FIONWRITE -#endif - -/* Non-standard baudrates are not available everywhere. */ -#if defined(HAVE_TERMIOS_SPEED) || defined(HAVE_TERMIOS2_SPEED) -#define USE_TERMIOS_SPEED -#endif - #include "libserialport.h" +#include "libserialport_internal.h" -struct sp_port { - char *name; - char *description; - enum sp_transport transport; - int usb_bus; - int usb_address; - int usb_vid; - int usb_pid; - char *usb_manufacturer; - char *usb_product; - char *usb_serial; - char *bluetooth_address; -#ifdef _WIN32 - char *usb_path; - HANDLE hdl; - COMMTIMEOUTS timeouts; - OVERLAPPED write_ovl; - OVERLAPPED read_ovl; - OVERLAPPED wait_ovl; - DWORD events; - BYTE pending_byte; - BOOL writing; -#else - int fd; -#endif -}; - -struct sp_port_config { - int baudrate; - int bits; - enum sp_parity parity; - int stopbits; - enum sp_rts rts; - enum sp_cts cts; - enum sp_dtr dtr; - enum sp_dsr dsr; - enum sp_xonxoff xon_xoff; -}; - -struct port_data { -#ifdef _WIN32 - DCB dcb; -#else - struct termios term; - int controlbits; - int termiox_supported; - int rts_flow; - int cts_flow; - int dtr_flow; - int dsr_flow; -#endif -}; - -#ifdef _WIN32 -typedef HANDLE event_handle; -#else -typedef int event_handle; -#endif - -/* Standard baud rates. */ -#ifdef _WIN32 -#define BAUD_TYPE DWORD -#define BAUD(n) {CBR_##n, n} -#else -#define BAUD_TYPE speed_t -#define BAUD(n) {B##n, n} -#endif - -struct std_baudrate { - BAUD_TYPE index; - int value; -}; - -const struct std_baudrate std_baudrates[] = { +static const struct std_baudrate std_baudrates[] = { #ifdef _WIN32 /* * The baudrates 50/75/134/150/200/1800/230400/460800 do not seem to @@ -172,782 +44,22 @@ const struct std_baudrate std_baudrates[] = { #endif }; -void (*sp_debug_handler)(const char *format, ...) = sp_default_debug_handler; - -#define ARRAY_SIZE(x) (sizeof(x) / sizeof(x[0])) #define NUM_STD_BAUDRATES ARRAY_SIZE(std_baudrates) -/* Debug output macros. */ -#define DEBUG(fmt, ...) do { if (sp_debug_handler) sp_debug_handler(fmt ".\n", ##__VA_ARGS__); } while (0) -#define DEBUG_ERROR(err, fmt, ...) DEBUG("%s returning " #err ": " fmt, __func__, ##__VA_ARGS__) -#define DEBUG_FAIL(fmt, ...) do { \ - char *errmsg = sp_last_error_message(); \ - DEBUG("%s returning SP_ERR_FAIL: "fmt": %s", __func__,##__VA_ARGS__,errmsg); \ - sp_free_error_message(errmsg); \ -} while (0); -#define RETURN() do { DEBUG("%s returning", __func__); return; } while(0) -#define RETURN_CODE(x) do { DEBUG("%s returning " #x, __func__); return x; } while (0) -#define RETURN_CODEVAL(x) do { \ - switch (x) { \ - case SP_OK: RETURN_CODE(SP_OK); \ - case SP_ERR_ARG: RETURN_CODE(SP_ERR_ARG); \ - case SP_ERR_FAIL: RETURN_CODE(SP_ERR_FAIL); \ - case SP_ERR_MEM: RETURN_CODE(SP_ERR_MEM); \ - case SP_ERR_SUPP: RETURN_CODE(SP_ERR_SUPP); \ - } \ -} while (0) -#define RETURN_OK() RETURN_CODE(SP_OK); -#define RETURN_ERROR(err, ...) do { DEBUG_ERROR(err, __VA_ARGS__); return err; } while (0) -#define RETURN_FAIL(...) do { DEBUG_FAIL(__VA_ARGS__); return SP_ERR_FAIL; } while (0) -#define RETURN_VALUE(fmt, x) do { \ - typeof(x) _x = x; \ - DEBUG("%s returning " fmt, __func__, _x); \ - return _x; \ -} while (0) -#define SET_ERROR(val, err, msg) do { DEBUG_ERROR(err, msg); val = err; } while (0) -#define SET_FAIL(val, msg) do { DEBUG_FAIL(msg); val = SP_ERR_FAIL; } while (0) -#define TRACE(fmt, ...) DEBUG("%s(" fmt ") called", __func__, ##__VA_ARGS__) - -#define TRY(x) do { int ret = x; if (ret != SP_OK) RETURN_CODEVAL(ret); } while (0) +void (*sp_debug_handler)(const char *format, ...) = sp_default_debug_handler; -/* Helper functions. */ static enum sp_return get_config(struct sp_port *port, struct port_data *data, struct sp_port_config *config); + static enum sp_return set_config(struct sp_port *port, struct port_data *data, const struct sp_port_config *config); -#ifdef _WIN32 - -/* USB path is a string of at most 8 decimal numbers < 128 separated by dots */ -#define MAX_USB_PATH (8*3 + 7*1 + 1) - -static char *wc_to_utf8(PWCHAR wc_buffer, ULONG size) -{ - WCHAR wc_str[size/sizeof(WCHAR)+1]; - char *utf8_str; - - /* zero terminate the wide char string */ - memcpy(wc_str, wc_buffer, size); - wc_str[sizeof(wc_str)-1] = 0; - - /* compute the size of the utf8 converted string */ - if (!(size = WideCharToMultiByte(CP_ACP, WC_NO_BEST_FIT_CHARS, wc_str, -1, - NULL, 0, NULL, NULL))) - return NULL; - - /* allocate utf8 output buffer */ - if (!(utf8_str = malloc(size))) - return NULL; - - /* actually converted to utf8 */ - if (!WideCharToMultiByte(CP_ACP, WC_NO_BEST_FIT_CHARS, wc_str, -1, - utf8_str, size, NULL, NULL)) { - free(utf8_str); - return NULL; - } - - return utf8_str; -} - -static char *get_root_hub_name(HANDLE host_controller) -{ - USB_ROOT_HUB_NAME root_hub_name; - PUSB_ROOT_HUB_NAME root_hub_name_wc; - char *root_hub_name_utf8; - ULONG size = 0; - - /* compute the size of the root hub name string */ - if (!DeviceIoControl(host_controller, IOCTL_USB_GET_ROOT_HUB_NAME, 0, 0, - &root_hub_name, sizeof(root_hub_name), &size, NULL)) - return NULL; - - /* allocate wide char root hub name string */ - size = root_hub_name.ActualLength; - if (!(root_hub_name_wc = malloc(size))) - return NULL; - - /* actually get the root hub name string */ - if (!DeviceIoControl(host_controller, IOCTL_USB_GET_ROOT_HUB_NAME, - NULL, 0, root_hub_name_wc, size, &size, NULL)) { - free(root_hub_name_wc); - return NULL; - } - - /* convert the root hub name string to utf8 */ - root_hub_name_utf8 = wc_to_utf8(root_hub_name_wc->RootHubName, size); - free(root_hub_name_wc); - return root_hub_name_utf8; -} - -static char *get_external_hub_name(HANDLE hub, ULONG connection_index) -{ - USB_NODE_CONNECTION_NAME ext_hub_name; - PUSB_NODE_CONNECTION_NAME ext_hub_name_wc; - char *ext_hub_name_utf8; - ULONG size; - - /* compute the size of the external hub name string */ - ext_hub_name.ConnectionIndex = connection_index; - if (!DeviceIoControl(hub, IOCTL_USB_GET_NODE_CONNECTION_NAME, - &ext_hub_name, sizeof(ext_hub_name), - &ext_hub_name, sizeof(ext_hub_name), &size, NULL)) - return NULL; - - /* allocate wide char external hub name string */ - size = ext_hub_name.ActualLength; - if (size <= sizeof(ext_hub_name) - || !(ext_hub_name_wc = malloc(size))) - return NULL; - - /* get the name of the external hub attached to the specified port */ - ext_hub_name_wc->ConnectionIndex = connection_index; - if (!DeviceIoControl(hub, IOCTL_USB_GET_NODE_CONNECTION_NAME, - ext_hub_name_wc, size, - ext_hub_name_wc, size, &size, NULL)) { - free(ext_hub_name_wc); - return NULL; - } - - /* convert the external hub name string to utf8 */ - ext_hub_name_utf8 = wc_to_utf8(ext_hub_name_wc->NodeName, size); - free(ext_hub_name_wc); - return ext_hub_name_utf8; -} - -static char *get_string_descriptor(HANDLE hub_device, ULONG connection_index, - UCHAR descriptor_index) -{ - char desc_req_buf[sizeof(USB_DESCRIPTOR_REQUEST) + - MAXIMUM_USB_STRING_LENGTH] = { 0 }; - PUSB_DESCRIPTOR_REQUEST desc_req = (void *) desc_req_buf; - PUSB_STRING_DESCRIPTOR desc = (void *) (desc_req + 1); - ULONG size = sizeof(desc_req_buf); - - desc_req->ConnectionIndex = connection_index; - desc_req->SetupPacket.wValue = (USB_STRING_DESCRIPTOR_TYPE << 8) - | descriptor_index; - desc_req->SetupPacket.wIndex = 0; - desc_req->SetupPacket.wLength = size - sizeof(*desc_req); - - if (!DeviceIoControl(hub_device, - IOCTL_USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION, - desc_req, size, desc_req, size, &size, NULL) - || size < 2 - || desc->bDescriptorType != USB_STRING_DESCRIPTOR_TYPE - || desc->bLength != size - sizeof(*desc_req) - || desc->bLength % 2) - return NULL; - - return wc_to_utf8(desc->bString, desc->bLength); -} - -static void enumerate_hub(struct sp_port *port, char *hub_name, - char *parent_path); - -static void enumerate_hub_ports(struct sp_port *port, HANDLE hub_device, - ULONG nb_ports, char *parent_path) -{ - char path[MAX_USB_PATH]; - ULONG index = 0; - - for (index = 1; index <= nb_ports; index++) { - PUSB_NODE_CONNECTION_INFORMATION_EX connection_info_ex; - ULONG size = sizeof(*connection_info_ex) + 30*sizeof(USB_PIPE_INFO); - - if (!(connection_info_ex = malloc(size))) - break; - - connection_info_ex->ConnectionIndex = index; - if (!DeviceIoControl(hub_device, - IOCTL_USB_GET_NODE_CONNECTION_INFORMATION_EX, - connection_info_ex, size, - connection_info_ex, size, &size, NULL)) { - /* try to get CONNECTION_INFORMATION if CONNECTION_INFORMATION_EX - did not work */ - PUSB_NODE_CONNECTION_INFORMATION connection_info; - - size = sizeof(*connection_info) + 30*sizeof(USB_PIPE_INFO); - if (!(connection_info = malloc(size))) { - free(connection_info_ex); - continue; - } - connection_info->ConnectionIndex = index; - if (!DeviceIoControl(hub_device, - IOCTL_USB_GET_NODE_CONNECTION_INFORMATION, - connection_info, size, - connection_info, size, &size, NULL)) { - free(connection_info); - free(connection_info_ex); - continue; - } - - connection_info_ex->ConnectionIndex = connection_info->ConnectionIndex; - connection_info_ex->DeviceDescriptor = connection_info->DeviceDescriptor; - connection_info_ex->DeviceIsHub = connection_info->DeviceIsHub; - connection_info_ex->DeviceAddress = connection_info->DeviceAddress; - free(connection_info); - } - - if (connection_info_ex->DeviceIsHub) { - /* recursively enumerate external hub */ - PCHAR ext_hub_name; - if ((ext_hub_name = get_external_hub_name(hub_device, index))) { - snprintf(path, sizeof(path), "%s%d.", - parent_path, connection_info_ex->ConnectionIndex); - enumerate_hub(port, ext_hub_name, path); - } - free(connection_info_ex); - } else { - snprintf(path, sizeof(path), "%s%d", - parent_path, connection_info_ex->ConnectionIndex); - - /* check if this device is the one we search for */ - if (strcmp(path, port->usb_path)) { - free(connection_info_ex); - continue; - } - - /* finally grab detailed informations regarding the device */ - port->usb_address = connection_info_ex->DeviceAddress + 1; - port->usb_vid = connection_info_ex->DeviceDescriptor.idVendor; - port->usb_pid = connection_info_ex->DeviceDescriptor.idProduct; - - if (connection_info_ex->DeviceDescriptor.iManufacturer) - port->usb_manufacturer = get_string_descriptor(hub_device,index, - connection_info_ex->DeviceDescriptor.iManufacturer); - if (connection_info_ex->DeviceDescriptor.iProduct) - port->usb_product = get_string_descriptor(hub_device, index, - connection_info_ex->DeviceDescriptor.iProduct); - if (connection_info_ex->DeviceDescriptor.iSerialNumber) - port->usb_serial = get_string_descriptor(hub_device, index, - connection_info_ex->DeviceDescriptor.iSerialNumber); - - free(connection_info_ex); - break; - } - } -} - -static void enumerate_hub(struct sp_port *port, char *hub_name, - char *parent_path) -{ - USB_NODE_INFORMATION hub_info; - HANDLE hub_device; - ULONG size = sizeof(hub_info); - char *device_name; - - /* open the hub with its full name */ - if (!(device_name = malloc(strlen("\\\\.\\") + strlen(hub_name) + 1))) - return; - strcpy(device_name, "\\\\.\\"); - strcat(device_name, hub_name); - hub_device = CreateFile(device_name, GENERIC_WRITE, FILE_SHARE_WRITE, - NULL, OPEN_EXISTING, 0, NULL); - free(device_name); - if (hub_device == INVALID_HANDLE_VALUE) - return; - - /* get the number of ports of the hub */ - if (DeviceIoControl(hub_device, IOCTL_USB_GET_NODE_INFORMATION, - &hub_info, size, &hub_info, size, &size, NULL)) - /* enumarate the ports of the hub */ - enumerate_hub_ports(port, hub_device, - hub_info.u.HubInformation.HubDescriptor.bNumberOfPorts, parent_path); - - CloseHandle(hub_device); -} - -static void enumerate_host_controller(struct sp_port *port, - HANDLE host_controller_device) -{ - char *root_hub_name; - - if ((root_hub_name = get_root_hub_name(host_controller_device))) { - enumerate_hub(port, root_hub_name, ""); - free(root_hub_name); - } -} - -static void get_usb_details(struct sp_port *port, DEVINST dev_inst_match) -{ - HDEVINFO device_info; - SP_DEVINFO_DATA device_info_data; - ULONG i, size = 0; - - device_info = SetupDiGetClassDevs(&GUID_CLASS_USB_HOST_CONTROLLER,NULL,NULL, - DIGCF_PRESENT | DIGCF_DEVICEINTERFACE); - device_info_data.cbSize = sizeof(device_info_data); - - for (i=0; SetupDiEnumDeviceInfo(device_info, i, &device_info_data); i++) { - SP_DEVICE_INTERFACE_DATA device_interface_data; - PSP_DEVICE_INTERFACE_DETAIL_DATA device_detail_data; - DEVINST dev_inst = dev_inst_match; - HANDLE host_controller_device; - - device_interface_data.cbSize = sizeof(device_interface_data); - if (!SetupDiEnumDeviceInterfaces(device_info, 0, - &GUID_CLASS_USB_HOST_CONTROLLER, - i, &device_interface_data)) - continue; - - if (!SetupDiGetDeviceInterfaceDetail(device_info,&device_interface_data, - NULL, 0, &size, NULL) - && GetLastError() != ERROR_INSUFFICIENT_BUFFER) - continue; - - if (!(device_detail_data = malloc(size))) - continue; - device_detail_data->cbSize = sizeof(*device_detail_data); - if (!SetupDiGetDeviceInterfaceDetail(device_info,&device_interface_data, - device_detail_data, size, &size, - NULL)) { - free(device_detail_data); - continue; - } - - while (CM_Get_Parent(&dev_inst, dev_inst, 0) == CR_SUCCESS - && dev_inst != device_info_data.DevInst) { } - if (dev_inst != device_info_data.DevInst) { - free(device_detail_data); - continue; - } - - port->usb_bus = i + 1; - - host_controller_device = CreateFile(device_detail_data->DevicePath, - GENERIC_WRITE, FILE_SHARE_WRITE, - NULL, OPEN_EXISTING, 0, NULL); - if (host_controller_device != INVALID_HANDLE_VALUE) { - enumerate_host_controller(port, host_controller_device); - CloseHandle(host_controller_device); - } - free(device_detail_data); - } - - SetupDiDestroyDeviceInfoList(device_info); - return; -} - -#endif /* _WIN32 */ - -static enum sp_return sp_get_port_details(struct sp_port *port) -{ - /* Description limited to 127 char, - anything longer would not be user friendly anyway */ - char description[128]; -#ifndef _WIN32 - int bus, address, vid, pid = -1; - char manufacturer[128], product[128], serial[128]; - char baddr[32]; -#endif - - port->description = NULL; - port->transport = SP_TRANSPORT_NATIVE; - port->usb_bus = -1; - port->usb_address = -1; - port->usb_vid = -1; - port->usb_pid = -1; - port->usb_manufacturer = NULL; - port->usb_product = NULL; - port->usb_serial = NULL; - port->bluetooth_address = NULL; - -#ifdef _WIN32 - SP_DEVINFO_DATA device_info_data = { .cbSize = sizeof(device_info_data) }; - HDEVINFO device_info; - int i; - - device_info = SetupDiGetClassDevs(NULL, 0, 0, - DIGCF_PRESENT | DIGCF_ALLCLASSES); - if (device_info == INVALID_HANDLE_VALUE) - RETURN_FAIL("SetupDiGetClassDevs() failed"); - - for (i=0; SetupDiEnumDeviceInfo(device_info, i, &device_info_data); i++) { - HKEY device_key; - DEVINST dev_inst; - char value[8], class[16]; - DWORD size, type; - CONFIGRET cr; - - /* check if this is the device we are looking for */ - if (!(device_key = SetupDiOpenDevRegKey(device_info, &device_info_data, - DICS_FLAG_GLOBAL, 0, - DIREG_DEV, KEY_QUERY_VALUE))) - continue; - size = sizeof(value); - if (RegQueryValueExA(device_key, "PortName", NULL, &type, (LPBYTE)value, - &size) != ERROR_SUCCESS || type != REG_SZ) - continue; - RegCloseKey(device_key); - value[sizeof(value)-1] = 0; - if (strcmp(value, port->name)) - continue; - - /* check port transport type */ - dev_inst = device_info_data.DevInst; - size = sizeof(class); - cr = CR_FAILURE; - while (CM_Get_Parent(&dev_inst, dev_inst, 0) == CR_SUCCESS && - (cr = CM_Get_DevNode_Registry_PropertyA(dev_inst, - CM_DRP_CLASS, 0, class, &size, 0)) != CR_SUCCESS) { } - if (cr == CR_SUCCESS) { - if (!strcmp(class, "USB")) - port->transport = SP_TRANSPORT_USB; - } - - /* get port description (friendly name) */ - dev_inst = device_info_data.DevInst; - size = sizeof(description); - while ((cr = CM_Get_DevNode_Registry_PropertyA(dev_inst, - CM_DRP_FRIENDLYNAME, 0, description, &size, 0)) != CR_SUCCESS - && CM_Get_Parent(&dev_inst, dev_inst, 0) == CR_SUCCESS) { } - if (cr == CR_SUCCESS) - port->description = strdup(description); - - /* get more informations for USB connected ports */ - if (port->transport == SP_TRANSPORT_USB) { - char usb_path[MAX_USB_PATH] = "", tmp[MAX_USB_PATH]; - char device_id[MAX_DEVICE_ID_LEN]; - - /* recurse over parents to build the USB device path */ - dev_inst = device_info_data.DevInst; - do { - /* verify that this layer of the tree is USB related */ - if (CM_Get_Device_IDA(dev_inst, device_id, - sizeof(device_id), 0) != CR_SUCCESS - || strncmp(device_id, "USB\\", 4)) - continue; - - /* discard one layer for composite devices */ - char compat_ids[512], *p = compat_ids; - size = sizeof(compat_ids); - if (CM_Get_DevNode_Registry_PropertyA(dev_inst, - CM_DRP_COMPATIBLEIDS, 0, - &compat_ids, - &size, 0) == CR_SUCCESS) { - while (*p) { - if (!strncmp(p, "USB\\COMPOSITE", 13)) - break; - p += strlen(p) + 1; - } - if (*p) - continue; - } - - /* stop the recursion when reaching the USB root */ - if (!strncmp(device_id, "USB\\ROOT", 8)) - break; - - /* prepend the address of current USB layer to the USB path */ - DWORD address; - size = sizeof(address); - if (CM_Get_DevNode_Registry_PropertyA(dev_inst, CM_DRP_ADDRESS, - 0, &address, &size, 0) == CR_SUCCESS) { - strcpy(tmp, usb_path); - snprintf(usb_path, sizeof(usb_path), "%d%s%s", - (int)address, *tmp ? "." : "", tmp); - } - } while (CM_Get_Parent(&dev_inst, dev_inst, 0) == CR_SUCCESS); - - port->usb_path = strdup(usb_path); - - /* wake up the USB device to be able to read string descriptor */ - char *escaped_port_name; - HANDLE handle; - if (!(escaped_port_name = malloc(strlen(port->name) + 5))) - RETURN_ERROR(SP_ERR_MEM, "Escaped port name malloc failed"); - sprintf(escaped_port_name, "\\\\.\\%s", port->name); - handle = CreateFile(escaped_port_name, GENERIC_READ, 0, 0, - OPEN_EXISTING, - FILE_ATTRIBUTE_NORMAL|FILE_FLAG_OVERLAPPED, 0); - free(escaped_port_name); - CloseHandle(handle); - - /* retrive USB device details from the device descriptor */ - get_usb_details(port, device_info_data.DevInst); - } - break; - } -#elif defined(__APPLE__) - CFMutableDictionaryRef classes; - io_iterator_t iter; - io_object_t ioport; - CFTypeRef cf_property, cf_bus, cf_address, cf_vendor, cf_product; - Boolean result; - char path[PATH_MAX]; - - DEBUG("Getting serial port list"); - if (!(classes = IOServiceMatching(kIOSerialBSDServiceValue))) - RETURN_FAIL("IOServiceMatching() failed"); - - if (IOServiceGetMatchingServices(kIOMasterPortDefault, classes, - &iter) != KERN_SUCCESS) - RETURN_FAIL("IOServiceGetMatchingServices() failed"); - - DEBUG("Iterating over results"); - while ((ioport = IOIteratorNext(iter))) { - if (!(cf_property = IORegistryEntryCreateCFProperty(ioport, - CFSTR(kIOCalloutDeviceKey), kCFAllocatorDefault, 0))) { - IOObjectRelease(ioport); - continue; - } - result = CFStringGetCString(cf_property, path, sizeof(path), - kCFStringEncodingASCII); - CFRelease(cf_property); - if (!result || strcmp(path, port->name)) { - IOObjectRelease(ioport); - continue; - } - DEBUG("Found port %s", path); - - IORegistryEntryGetParentEntry(ioport, kIOServicePlane, &ioparent); - if ((cf_property=IORegistryEntrySearchCFProperty(ioparent,kIOServicePlane, - CFSTR("IOProviderClass"), kCFAllocatorDefault, - kIORegistryIterateRecursively | kIORegistryIterateParents))) { - if (CFStringGetCString(cf_property, class, sizeof(class), - kCFStringEncodingASCII) && - strstr(class, "USB")) { - DEBUG("Found USB class device"); - port->transport = SP_TRANSPORT_USB; - } - CFRelease(cf_property); - } - IOObjectRelease(ioparent); - - if ((cf_property = IORegistryEntrySearchCFProperty(ioport,kIOServicePlane, - CFSTR("USB Interface Name"), kCFAllocatorDefault, - kIORegistryIterateRecursively | kIORegistryIterateParents)) || - (cf_property = IORegistryEntrySearchCFProperty(ioport,kIOServicePlane, - CFSTR("USB Product Name"), kCFAllocatorDefault, - kIORegistryIterateRecursively | kIORegistryIterateParents)) || - (cf_property = IORegistryEntrySearchCFProperty(ioport,kIOServicePlane, - CFSTR("Product Name"), kCFAllocatorDefault, - kIORegistryIterateRecursively | kIORegistryIterateParents)) || - (cf_property = IORegistryEntryCreateCFProperty(ioport, - CFSTR(kIOTTYDeviceKey), kCFAllocatorDefault, 0))) { - if (CFStringGetCString(cf_property, description, sizeof(description), - kCFStringEncodingASCII)) { - DEBUG("Found description %s", description); - port->description = strdup(description); - } - CFRelease(cf_property); - } else { - DEBUG("No description for this device"); - } - - cf_bus = IORegistryEntrySearchCFProperty(ioport, kIOServicePlane, - CFSTR("USBBusNumber"), - kCFAllocatorDefault, - kIORegistryIterateRecursively - | kIORegistryIterateParents); - cf_address = IORegistryEntrySearchCFProperty(ioport, kIOServicePlane, - CFSTR("USB Address"), - kCFAllocatorDefault, - kIORegistryIterateRecursively - | kIORegistryIterateParents); - if (cf_bus && cf_address && - CFNumberGetValue(cf_bus , kCFNumberIntType, &bus) && - CFNumberGetValue(cf_address, kCFNumberIntType, &address)) { - DEBUG("Found matching USB bus:address %03d:%03d", bus, address); - port->usb_bus = bus; - port->usb_address = address; - } - if (cf_bus ) CFRelease(cf_bus); - if (cf_address) CFRelease(cf_address); - - cf_vendor = IORegistryEntrySearchCFProperty(ioport, kIOServicePlane, - CFSTR("idVendor"), - kCFAllocatorDefault, - kIORegistryIterateRecursively - | kIORegistryIterateParents); - cf_product = IORegistryEntrySearchCFProperty(ioport, kIOServicePlane, - CFSTR("idProduct"), - kCFAllocatorDefault, - kIORegistryIterateRecursively - | kIORegistryIterateParents); - if (cf_vendor && cf_product && - CFNumberGetValue(cf_vendor , kCFNumberIntType, &vid) && - CFNumberGetValue(cf_product, kCFNumberIntType, &pid)) { - DEBUG("Found matching USB vid:pid %04X:%04X", vid, pid); - port->usb_vid = vid; - port->usb_pid = pid; - } - if (cf_vendor ) CFRelease(cf_vendor); - if (cf_product) CFRelease(cf_product); - - if ((cf_property = IORegistryEntrySearchCFProperty(ioport,kIOServicePlane, - CFSTR("USB Vendor Name"), kCFAllocatorDefault, - kIORegistryIterateRecursively | kIORegistryIterateParents))) { - if (CFStringGetCString(cf_property, manufacturer, sizeof(manufacturer), - kCFStringEncodingASCII)) { - DEBUG("Found manufacturer %s", manufacturer); - port->usb_manufacturer = strdup(manufacturer); - } - CFRelease(cf_property); - } - - if ((cf_property = IORegistryEntrySearchCFProperty(ioport,kIOServicePlane, - CFSTR("USB Product Name"), kCFAllocatorDefault, - kIORegistryIterateRecursively | kIORegistryIterateParents))) { - if (CFStringGetCString(cf_property, product, sizeof(product), - kCFStringEncodingASCII)) { - DEBUG("Found product name %s", product); - port->usb_product = strdup(product); - } - CFRelease(cf_property); - } - - if ((cf_property = IORegistryEntrySearchCFProperty(ioport,kIOServicePlane, - CFSTR("USB Serial Number"), kCFAllocatorDefault, - kIORegistryIterateRecursively | kIORegistryIterateParents))) { - if (CFStringGetCString(cf_property, serial, sizeof(serial), - kCFStringEncodingASCII)) { - DEBUG("Found serial number %s", serial); - port->usb_serial = strdup(serial); - } - CFRelease(cf_property); - } - - IOObjectRelease(ioport); - break; - } - IOObjectRelease(iter); -#elif defined(__linux__) - const char dir_name[] = "/sys/class/tty/%s/device/%s%s"; - char sub_dir[32] = "", file_name[PATH_MAX]; - char *ptr, *dev = port->name + 5; - FILE *file; - int i, count; - - if (strncmp(port->name, "/dev/", 5)) - RETURN_ERROR(SP_ERR_ARG, "Device name not recognized (%s)", port->name); - - snprintf(file_name, sizeof(file_name), "/sys/class/tty/%s", dev); - count = readlink(file_name, file_name, sizeof(file_name)); - if (count <= 0 || count >= (int) sizeof(file_name)-1) - RETURN_ERROR(SP_ERR_ARG, "Device not found (%s)", port->name); - file_name[count] = 0; - if (strstr(file_name, "bluetooth")) - port->transport = SP_TRANSPORT_BLUETOOTH; - else if (strstr(file_name, "usb")) - port->transport = SP_TRANSPORT_USB; - - if (port->transport == SP_TRANSPORT_USB) { - for (i=0; i<5; i++) { - strcat(sub_dir, "../"); - - snprintf(file_name,sizeof(file_name),dir_name,dev,sub_dir,"busnum"); - if (!(file = fopen(file_name, "r"))) - continue; - count = fscanf(file, "%d", &bus); - fclose(file); - if (count != 1) - continue; - - snprintf(file_name,sizeof(file_name),dir_name,dev,sub_dir,"devnum"); - if (!(file = fopen(file_name, "r"))) - continue; - count = fscanf(file, "%d", &address); - fclose(file); - if (count != 1) - continue; - - snprintf(file_name,sizeof(file_name),dir_name,dev,sub_dir,"idVendor"); - if (!(file = fopen(file_name, "r"))) - continue; - count = fscanf(file, "%4x", &vid); - fclose(file); - if (count != 1) - continue; - - snprintf(file_name,sizeof(file_name),dir_name,dev,sub_dir,"idProduct"); - if (!(file = fopen(file_name, "r"))) - continue; - count = fscanf(file, "%4x", &pid); - fclose(file); - if (count != 1) - continue; - - port->usb_bus = bus; - port->usb_address = address; - port->usb_vid = vid; - port->usb_pid = pid; - - snprintf(file_name,sizeof(file_name),dir_name,dev,sub_dir,"product"); - if ((file = fopen(file_name, "r"))) { - if ((ptr = fgets(description, sizeof(description), file))) { - ptr = description + strlen(description) - 1; - if (ptr >= description && *ptr == '\n') - *ptr = 0; - port->description = strdup(description); - } - fclose(file); - } - if (!file || !ptr) - port->description = strdup(dev); - - snprintf(file_name,sizeof(file_name),dir_name,dev,sub_dir,"manufacturer"); - if ((file = fopen(file_name, "r"))) { - if ((ptr = fgets(manufacturer, sizeof(manufacturer), file))) { - ptr = manufacturer + strlen(manufacturer) - 1; - if (ptr >= manufacturer && *ptr == '\n') - *ptr = 0; - port->usb_manufacturer = strdup(manufacturer); - } - fclose(file); - } - - snprintf(file_name,sizeof(file_name),dir_name,dev,sub_dir,"product"); - if ((file = fopen(file_name, "r"))) { - if ((ptr = fgets(product, sizeof(product), file))) { - ptr = product + strlen(product) - 1; - if (ptr >= product && *ptr == '\n') - *ptr = 0; - port->usb_product = strdup(product); - } - fclose(file); - } - - snprintf(file_name,sizeof(file_name),dir_name,dev,sub_dir,"serial"); - if ((file = fopen(file_name, "r"))) { - if ((ptr = fgets(serial, sizeof(serial), file))) { - ptr = serial + strlen(serial) - 1; - if (ptr >= serial && *ptr == '\n') - *ptr = 0; - port->usb_serial = strdup(serial); - } - fclose(file); - } - - break; - } - } else { - port->description = strdup(dev); - - if (port->transport == SP_TRANSPORT_BLUETOOTH) { - snprintf(file_name, sizeof(file_name), dir_name, dev, "", "address"); - if ((file = fopen(file_name, "r"))) { - if ((ptr = fgets(baddr, sizeof(baddr), file))) { - ptr = baddr + strlen(baddr) - 1; - if (ptr >= baddr && *ptr == '\n') - *ptr = 0; - port->bluetooth_address = strdup(baddr); - } - fclose(file); - } - } - } -#else - DEBUG("Port details not supported on this platform"); -#endif - - RETURN_OK(); -} - -enum sp_return sp_get_port_by_name(const char *portname, struct sp_port **port_ptr) +SP_API enum sp_return sp_get_port_by_name(const char *portname, struct sp_port **port_ptr) { struct sp_port *port; +#ifndef NO_PORT_METADATA enum sp_return ret; +#endif int len; TRACE("%s, %p", portname, port_ptr); @@ -960,7 +72,7 @@ enum sp_return sp_get_port_by_name(const char *portname, struct sp_port **port_p if (!portname) RETURN_ERROR(SP_ERR_ARG, "Null port name"); - DEBUG("Building structure for port %s", portname); + DEBUG_FMT("Building structure for port %s", portname); if (!(port = malloc(sizeof(struct sp_port)))) RETURN_ERROR(SP_ERR_MEM, "Port structure malloc failed"); @@ -975,53 +87,67 @@ enum sp_return sp_get_port_by_name(const char *portname, struct sp_port **port_p memcpy(port->name, portname, len); #ifdef _WIN32 + port->usb_path = NULL; port->hdl = INVALID_HANDLE_VALUE; #else port->fd = -1; #endif - if ((ret = sp_get_port_details(port)) != SP_OK) { + port->description = NULL; + port->transport = SP_TRANSPORT_NATIVE; + port->usb_bus = -1; + port->usb_address = -1; + port->usb_vid = -1; + port->usb_pid = -1; + port->usb_manufacturer = NULL; + port->usb_product = NULL; + port->usb_serial = NULL; + port->bluetooth_address = NULL; + +#ifndef NO_PORT_METADATA + if ((ret = get_port_details(port)) != SP_OK) { sp_free_port(port); return ret; } +#endif *port_ptr = port; RETURN_OK(); } -char *sp_get_port_name(const struct sp_port *port) +SP_API char *sp_get_port_name(const struct sp_port *port) { TRACE("%p", port); if (!port) return NULL; - RETURN_VALUE("%s", port->name); + RETURN_STRING(port->name); } -char *sp_get_port_description(struct sp_port *port) +SP_API char *sp_get_port_description(const struct sp_port *port) { TRACE("%p", port); if (!port || !port->description) return NULL; - RETURN_VALUE("%s", port->description); + RETURN_STRING(port->description); } -enum sp_transport sp_get_port_transport(struct sp_port *port) +SP_API enum sp_transport sp_get_port_transport(const struct sp_port *port) { TRACE("%p", port); if (!port) RETURN_ERROR(SP_ERR_ARG, "Null port"); - RETURN_VALUE("%d", port->transport); + RETURN_INT(port->transport); } -enum sp_return sp_get_port_usb_bus_address(const struct sp_port *port, - int *usb_bus, int *usb_address) +SP_API enum sp_return sp_get_port_usb_bus_address(const struct sp_port *port, + int *usb_bus,int *usb_address) { TRACE("%p", port); @@ -1029,15 +155,19 @@ enum sp_return sp_get_port_usb_bus_address(const struct sp_port *port, RETURN_ERROR(SP_ERR_ARG, "Null port"); if (port->transport != SP_TRANSPORT_USB) RETURN_ERROR(SP_ERR_ARG, "Port does not use USB transport"); + if (port->usb_bus < 0 || port->usb_address < 0) + RETURN_ERROR(SP_ERR_SUPP, "Bus and address values are not available"); - if (usb_bus) *usb_bus = port->usb_bus; - if (usb_address) *usb_address = port->usb_address; + if (usb_bus) + *usb_bus = port->usb_bus; + if (usb_address) + *usb_address = port->usb_address; RETURN_OK(); } -enum sp_return sp_get_port_usb_vid_pid(const struct sp_port *port, - int *usb_vid, int *usb_pid) +SP_API enum sp_return sp_get_port_usb_vid_pid(const struct sp_port *port, + int *usb_vid, int *usb_pid) { TRACE("%p", port); @@ -1045,44 +175,48 @@ enum sp_return sp_get_port_usb_vid_pid(const struct sp_port *port, RETURN_ERROR(SP_ERR_ARG, "Null port"); if (port->transport != SP_TRANSPORT_USB) RETURN_ERROR(SP_ERR_ARG, "Port does not use USB transport"); + if (port->usb_vid < 0 || port->usb_pid < 0) + RETURN_ERROR(SP_ERR_SUPP, "VID:PID values are not available"); - if (usb_vid) *usb_vid = port->usb_vid; - if (usb_pid) *usb_pid = port->usb_pid; + if (usb_vid) + *usb_vid = port->usb_vid; + if (usb_pid) + *usb_pid = port->usb_pid; RETURN_OK(); } -char *sp_get_port_usb_manufacturer(const struct sp_port *port) +SP_API char *sp_get_port_usb_manufacturer(const struct sp_port *port) { TRACE("%p", port); if (!port || port->transport != SP_TRANSPORT_USB || !port->usb_manufacturer) return NULL; - RETURN_VALUE("%s", port->usb_manufacturer); + RETURN_STRING(port->usb_manufacturer); } -char *sp_get_port_usb_product(const struct sp_port *port) +SP_API char *sp_get_port_usb_product(const struct sp_port *port) { TRACE("%p", port); if (!port || port->transport != SP_TRANSPORT_USB || !port->usb_product) return NULL; - RETURN_VALUE("%s", port->usb_product); + RETURN_STRING(port->usb_product); } -char *sp_get_port_usb_serial(const struct sp_port *port) +SP_API char *sp_get_port_usb_serial(const struct sp_port *port) { TRACE("%p", port); if (!port || port->transport != SP_TRANSPORT_USB || !port->usb_serial) return NULL; - RETURN_VALUE("%s", port->usb_serial); + RETURN_STRING(port->usb_serial); } -char *sp_get_port_bluetooth_address(const struct sp_port *port) +SP_API char *sp_get_port_bluetooth_address(const struct sp_port *port) { TRACE("%p", port); @@ -1090,10 +224,11 @@ char *sp_get_port_bluetooth_address(const struct sp_port *port) || !port->bluetooth_address) return NULL; - RETURN_VALUE("%s", port->bluetooth_address); + RETURN_STRING(port->bluetooth_address); } -enum sp_return sp_get_port_handle(const struct sp_port *port, void *result_ptr) +SP_API enum sp_return sp_get_port_handle(const struct sp_port *port, + void *result_ptr) { TRACE("%p, %p", port, result_ptr); @@ -1111,7 +246,8 @@ enum sp_return sp_get_port_handle(const struct sp_port *port, void *result_ptr) RETURN_OK(); } -enum sp_return sp_copy_port(const struct sp_port *port, struct sp_port **copy_ptr) +SP_API enum sp_return sp_copy_port(const struct sp_port *port, + struct sp_port **copy_ptr) { TRACE("%p, %p", port, copy_ptr); @@ -1128,10 +264,10 @@ enum sp_return sp_copy_port(const struct sp_port *port, struct sp_port **copy_pt DEBUG("Copying port structure"); - RETURN_VALUE("%p", sp_get_port_by_name(port->name, copy_ptr)); + RETURN_INT(sp_get_port_by_name(port->name, copy_ptr)); } -void sp_free_port(struct sp_port *port) +SP_API void sp_free_port(struct sp_port *port) { TRACE("%p", port); @@ -1164,7 +300,8 @@ void sp_free_port(struct sp_port *port) RETURN(); } -static struct sp_port **list_append(struct sp_port **list, const char *portname) +SP_PRIV struct sp_port **list_append(struct sp_port **list, + const char *portname) { void *tmp; unsigned int count; @@ -1183,209 +320,42 @@ fail: return NULL; } -enum sp_return sp_list_ports(struct sp_port ***list_ptr) +SP_API enum sp_return sp_list_ports(struct sp_port ***list_ptr) { +#ifndef NO_ENUMERATION struct sp_port **list; - int ret = SP_ERR_SUPP; + int ret; +#endif TRACE("%p", list_ptr); if (!list_ptr) RETURN_ERROR(SP_ERR_ARG, "Null result pointer"); +#ifdef NO_ENUMERATION + RETURN_ERROR(SP_ERR_SUPP, "Enumeration not supported on this platform"); +#else DEBUG("Enumerating ports"); - if (!(list = malloc(sizeof(struct sp_port **)))) + if (!(list = malloc(sizeof(struct sp_port *)))) RETURN_ERROR(SP_ERR_MEM, "Port list malloc failed"); 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: + if (ret == SP_OK) { *list_ptr = list; - RETURN_OK(); - case SP_ERR_SUPP: - DEBUG_ERROR(SP_ERR_SUPP, "Enumeration not supported on this platform"); - default: - if (list) - sp_free_port_list(list); + } else { + sp_free_port_list(list); *list_ptr = NULL; - return ret; } + + RETURN_CODEVAL(ret); +#endif } -void sp_free_port_list(struct sp_port **list) +SP_API void sp_free_port_list(struct sp_port **list) { unsigned int i; @@ -1406,9 +376,9 @@ void sp_free_port_list(struct sp_port **list) } #define CHECK_PORT() do { \ - if (port == NULL) \ + if (!port) \ RETURN_ERROR(SP_ERR_ARG, "Null port"); \ - if (port->name == NULL) \ + if (!port->name) \ RETURN_ERROR(SP_ERR_ARG, "Null port name"); \ } while (0) #ifdef _WIN32 @@ -1427,7 +397,44 @@ void sp_free_port_list(struct sp_port **list) CHECK_PORT_HANDLE(); \ } while (0) -enum sp_return sp_open(struct sp_port *port, enum sp_mode flags) +#ifdef WIN32 +/** To be called after port receive buffer is emptied. */ +static enum sp_return restart_wait(struct sp_port *port) +{ + DWORD wait_result; + + if (port->wait_running) { + /* Check status of running wait operation. */ + if (GetOverlappedResult(port->hdl, &port->wait_ovl, + &wait_result, FALSE)) { + DEBUG("Previous wait completed"); + port->wait_running = FALSE; + } else if (GetLastError() == ERROR_IO_INCOMPLETE) { + DEBUG("Previous wait still running"); + RETURN_OK(); + } else { + RETURN_FAIL("GetOverlappedResult() failed"); + } + } + + if (!port->wait_running) { + /* Start new wait operation. */ + if (WaitCommEvent(port->hdl, &port->events, + &port->wait_ovl)) { + DEBUG("New wait returned, events already pending"); + } else if (GetLastError() == ERROR_IO_PENDING) { + DEBUG("New wait running in background"); + port->wait_running = TRUE; + } else { + RETURN_FAIL("WaitCommEvent() failed"); + } + } + + RETURN_OK(); +} +#endif + +SP_API enum sp_return sp_open(struct sp_port *port, enum sp_mode flags) { struct port_data data; struct sp_port_config config; @@ -1437,10 +444,10 @@ enum sp_return sp_open(struct sp_port *port, enum sp_mode flags) CHECK_PORT(); - if (flags > (SP_MODE_READ | SP_MODE_WRITE)) + if (flags > SP_MODE_READ_WRITE) RETURN_ERROR(SP_ERR_ARG, "Invalid flags"); - DEBUG("Opening port %s", port->name); + DEBUG_FMT("Opening port %s", port->name); #ifdef _WIN32 DWORD desired_access = 0, flags_and_attributes = 0, errors; @@ -1465,7 +472,7 @@ enum sp_return sp_open(struct sp_port *port, enum sp_mode flags) free(escaped_port_name); if (port->hdl == INVALID_HANDLE_VALUE) - RETURN_FAIL("port CreateFile() failed"); + RETURN_FAIL("Port CreateFile() failed"); /* All timeouts initially disabled. */ port->timeouts.ReadIntervalTimeout = 0; @@ -1500,21 +507,20 @@ enum sp_return sp_open(struct sp_port *port, enum sp_mode flags) RETURN_FAIL("SetCommMask() failed"); } - /* Start background operation for RX and error events. */ - if (WaitCommEvent(port->hdl, &port->events, &port->wait_ovl) == 0) { - if (GetLastError() != ERROR_IO_PENDING) { - sp_close(port); - RETURN_FAIL("WaitCommEvent() failed"); - } - } - port->writing = FALSE; + port->wait_running = FALSE; + + ret = restart_wait(port); + if (ret < 0) { + sp_close(port); + RETURN_CODEVAL(ret); + } #else int flags_local = O_NONBLOCK | O_NOCTTY; /* Map 'flags' to the OS-specific settings. */ - if (flags & (SP_MODE_READ | SP_MODE_WRITE)) + if ((flags & SP_MODE_READ_WRITE) == SP_MODE_READ_WRITE) flags_local |= O_RDWR; else if (flags & SP_MODE_READ) flags_local |= O_RDONLY; @@ -1538,7 +544,7 @@ enum sp_return sp_open(struct sp_port *port, enum sp_mode flags) data.dcb.fDsrSensitivity = FALSE; data.dcb.fErrorChar = FALSE; data.dcb.fNull = FALSE; - data.dcb.fAbortOnError = TRUE; + data.dcb.fAbortOnError = FALSE; #else /* Turn off all fancy termios tricks, give us a raw channel. */ data.term.c_iflag &= ~(IGNBRK | BRKINT | PARMRK | ISTRIP | INLCR | IGNCR | ICRNL | IMAXBEL); @@ -1593,18 +599,18 @@ enum sp_return sp_open(struct sp_port *port, enum sp_mode flags) RETURN_OK(); } -enum sp_return sp_close(struct sp_port *port) +SP_API enum sp_return sp_close(struct sp_port *port) { TRACE("%p", port); CHECK_OPEN_PORT(); - DEBUG("Closing port %s", port->name); + DEBUG_FMT("Closing port %s", port->name); #ifdef _WIN32 /* Returns non-zero upon success, 0 upon failure. */ if (CloseHandle(port->hdl) == 0) - RETURN_FAIL("port CloseHandle() failed"); + RETURN_FAIL("Port CloseHandle() failed"); port->hdl = INVALID_HANDLE_VALUE; /* Close event handles for overlapped structures. */ @@ -1627,7 +633,7 @@ enum sp_return sp_close(struct sp_port *port) RETURN_OK(); } -enum sp_return sp_flush(struct sp_port *port, enum sp_buffer buffers) +SP_API enum sp_return sp_flush(struct sp_port *port, enum sp_buffer buffers) { TRACE("%p, 0x%x", port, buffers); @@ -1638,7 +644,8 @@ enum sp_return sp_flush(struct sp_port *port, enum sp_buffer buffers) const char *buffer_names[] = {"no", "input", "output", "both"}; - DEBUG("Flushing %s buffers on port %s", buffer_names[buffers], port->name); + DEBUG_FMT("Flushing %s buffers on port %s", + buffer_names[buffers], port->name); #ifdef _WIN32 DWORD flags = 0; @@ -1650,13 +657,16 @@ enum sp_return sp_flush(struct sp_port *port, enum sp_buffer buffers) /* Returns non-zero upon success, 0 upon failure. */ if (PurgeComm(port->hdl, flags) == 0) RETURN_FAIL("PurgeComm() failed"); + + if (buffers & SP_BUF_INPUT) + TRY(restart_wait(port)); #else int flags = 0; - if (buffers & SP_BUF_BOTH) + if (buffers == SP_BUF_BOTH) flags = TCIOFLUSH; - else if (buffers & SP_BUF_INPUT) + else if (buffers == SP_BUF_INPUT) flags = TCIFLUSH; - else if (buffers & SP_BUF_OUTPUT) + else if (buffers == SP_BUF_OUTPUT) flags = TCOFLUSH; /* Returns 0 upon success, -1 upon failure. */ @@ -1666,13 +676,13 @@ enum sp_return sp_flush(struct sp_port *port, enum sp_buffer buffers) RETURN_OK(); } -enum sp_return sp_drain(struct sp_port *port) +SP_API enum sp_return sp_drain(struct sp_port *port) { TRACE("%p", port); CHECK_OPEN_PORT(); - DEBUG("Draining port %s", port->name); + DEBUG_FMT("Draining port %s", port->name); #ifdef _WIN32 /* Returns non-zero upon success, 0 upon failure. */ @@ -1702,7 +712,8 @@ enum sp_return sp_drain(struct sp_port *port) #endif } -enum sp_return sp_blocking_write(struct sp_port *port, const void *buf, size_t count, unsigned int timeout) +SP_API enum sp_return sp_blocking_write(struct sp_port *port, const void *buf, + size_t count, unsigned int timeout) { TRACE("%p, %p, %d, %d", port, buf, count, timeout); @@ -1712,12 +723,14 @@ enum sp_return sp_blocking_write(struct sp_port *port, const void *buf, size_t c RETURN_ERROR(SP_ERR_ARG, "Null buffer"); if (timeout) - DEBUG("Writing %d bytes to port %s, timeout %d ms", count, port->name, timeout); + DEBUG_FMT("Writing %d bytes to port %s, timeout %d ms", + count, port->name, timeout); else - DEBUG("Writing %d bytes to port %s, no timeout", count, port->name); + DEBUG_FMT("Writing %d bytes to port %s, no timeout", + count, port->name); if (count == 0) - RETURN_VALUE("0", 0); + RETURN_INT(0); #ifdef _WIN32 DWORD bytes_written = 0; @@ -1743,14 +756,14 @@ enum sp_return sp_blocking_write(struct sp_port *port, const void *buf, size_t c if (GetLastError() == ERROR_IO_PENDING) { DEBUG("Waiting for write to complete"); GetOverlappedResult(port->hdl, &port->write_ovl, &bytes_written, TRUE); - DEBUG("Write completed, %d/%d bytes written", bytes_written, count); - RETURN_VALUE("%d", bytes_written); + DEBUG_FMT("Write completed, %d/%d bytes written", bytes_written, count); + RETURN_INT(bytes_written); } else { RETURN_FAIL("WriteFile() failed"); } } else { DEBUG("Write completed immediately"); - RETURN_VALUE("%d", count); + RETURN_INT(count); } #else size_t bytes_written = 0; @@ -1770,16 +783,15 @@ enum sp_return sp_blocking_write(struct sp_port *port, const void *buf, size_t c } /* Loop until we have written the requested number of bytes. */ - while (bytes_written < count) - { + while (bytes_written < count) { /* Wait until space is available. */ FD_ZERO(&fds); FD_SET(port->fd, &fds); if (timeout) { gettimeofday(&now, NULL); if (timercmp(&now, &end, >)) { - DEBUG("write timed out"); - RETURN_VALUE("%d", bytes_written); + DEBUG("Write timed out"); + RETURN_INT(bytes_written); } timersub(&end, &now, &delta); } @@ -1792,8 +804,8 @@ enum sp_return sp_blocking_write(struct sp_port *port, const void *buf, size_t c RETURN_FAIL("select() failed"); } } else if (result == 0) { - DEBUG("write timed out"); - RETURN_VALUE("%d", bytes_written); + DEBUG("Write timed out"); + RETURN_INT(bytes_written); } /* Do write. */ @@ -1812,11 +824,12 @@ enum sp_return sp_blocking_write(struct sp_port *port, const void *buf, size_t c ptr += result; } - RETURN_VALUE("%d", bytes_written); + RETURN_INT(bytes_written); #endif } -enum sp_return sp_nonblocking_write(struct sp_port *port, const void *buf, size_t count) +SP_API enum sp_return sp_nonblocking_write(struct sp_port *port, + const void *buf, size_t count) { TRACE("%p, %p, %d", port, buf, count); @@ -1825,10 +838,10 @@ enum sp_return sp_nonblocking_write(struct sp_port *port, const void *buf, size_ if (!buf) RETURN_ERROR(SP_ERR_ARG, "Null buffer"); - DEBUG("Writing up to %d bytes to port %s", count, port->name); + DEBUG_FMT("Writing up to %d bytes to port %s", count, port->name); if (count == 0) - RETURN_VALUE("0", 0); + RETURN_INT(0); #ifdef _WIN32 DWORD written = 0; @@ -1842,7 +855,7 @@ enum sp_return sp_nonblocking_write(struct sp_port *port, const void *buf, size_ } else { DEBUG("Previous write not complete"); /* Can't take a new write until the previous one finishes. */ - RETURN_VALUE("0", 0); + RETURN_INT(0); } } @@ -1851,10 +864,11 @@ enum sp_return sp_nonblocking_write(struct sp_port *port, const void *buf, size_ if (SetCommTimeouts(port->hdl, &port->timeouts) == 0) RETURN_FAIL("SetCommTimeouts() failed"); - /* Keep writing data until the OS has to actually start an async IO for it. - * At that point we know the buffer is full. */ - while (written < count) - { + /* + * Keep writing data until the OS has to actually start an async IO + * for it. At that point we know the buffer is full. + */ + while (written < count) { /* Copy first byte of user buffer. */ port->pending_byte = *ptr++; @@ -1869,7 +883,7 @@ enum sp_return sp_nonblocking_write(struct sp_port *port, const void *buf, size_ } else { DEBUG("Asynchronous write running"); port->writing = 1; - RETURN_VALUE("%d", ++written); + RETURN_INT(++written); } } else { /* Actual failure of some kind. */ @@ -1883,7 +897,7 @@ enum sp_return sp_nonblocking_write(struct sp_port *port, const void *buf, size_ DEBUG("All bytes written immediately"); - RETURN_VALUE("%d", written); + RETURN_INT(written); #else /* Returns the number of bytes written, or -1 upon failure. */ ssize_t written = write(port->fd, buf, count); @@ -1891,11 +905,12 @@ enum sp_return sp_nonblocking_write(struct sp_port *port, const void *buf, size_ if (written < 0) RETURN_FAIL("write() failed"); else - RETURN_VALUE("%d", written); + RETURN_INT(written); #endif } -enum sp_return sp_blocking_read(struct sp_port *port, void *buf, size_t count, unsigned int timeout) +SP_API enum sp_return sp_blocking_read(struct sp_port *port, void *buf, + size_t count, unsigned int timeout) { TRACE("%p, %p, %d, %d", port, buf, count, timeout); @@ -1905,15 +920,19 @@ enum sp_return sp_blocking_read(struct sp_port *port, void *buf, size_t count, u RETURN_ERROR(SP_ERR_ARG, "Null buffer"); if (timeout) - DEBUG("Reading %d bytes from port %s, timeout %d ms", count, port->name, timeout); + DEBUG_FMT("Reading %d bytes from port %s, timeout %d ms", + count, port->name, timeout); else - DEBUG("Reading %d bytes from port %s, no timeout", count, port->name); + DEBUG_FMT("Reading %d bytes from port %s, no timeout", + count, port->name); if (count == 0) - RETURN_VALUE("0", 0); + RETURN_INT(0); #ifdef _WIN32 DWORD bytes_read = 0; + DWORD bytes_remaining; + int ret; /* Set timeout. */ port->timeouts.ReadIntervalTimeout = 0; @@ -1926,7 +945,7 @@ enum sp_return sp_blocking_read(struct sp_port *port, void *buf, size_t count, u if (GetLastError() == ERROR_IO_PENDING) { DEBUG("Waiting for read to complete"); GetOverlappedResult(port->hdl, &port->read_ovl, &bytes_read, TRUE); - DEBUG("Read completed, %d/%d bytes read", bytes_read, count); + DEBUG_FMT("Read completed, %d/%d bytes read", bytes_read, count); } else { RETURN_FAIL("ReadFile() failed"); } @@ -1935,13 +954,18 @@ enum sp_return sp_blocking_read(struct sp_port *port, void *buf, size_t count, u bytes_read = count; } - /* Start background operation for subsequent events. */ - if (WaitCommEvent(port->hdl, &port->events, &port->wait_ovl) == 0) { - if (GetLastError() != ERROR_IO_PENDING) - RETURN_FAIL("WaitCommEvent() failed"); - } + ret = sp_input_waiting(port); - RETURN_VALUE("%d", bytes_read); + if (ret < 0) + RETURN_CODEVAL(ret); + + bytes_remaining = ret; + + /* Restart wait operation if buffer was emptied. */ + if (bytes_read > 0 && bytes_remaining == 0) + TRY(restart_wait(port)); + + RETURN_INT(bytes_read); #else size_t bytes_read = 0; @@ -1961,8 +985,7 @@ enum sp_return sp_blocking_read(struct sp_port *port, void *buf, size_t count, u } /* Loop until we have the requested number of bytes. */ - while (bytes_read < count) - { + while (bytes_read < count) { /* Wait until data is available. */ FD_ZERO(&fds); FD_SET(port->fd, &fds); @@ -1970,7 +993,7 @@ enum sp_return sp_blocking_read(struct sp_port *port, void *buf, size_t count, u gettimeofday(&now, NULL); if (timercmp(&now, &end, >)) /* Timeout has expired. */ - RETURN_VALUE("%d", bytes_read); + RETURN_INT(bytes_read); timersub(&end, &now, &delta); } result = select(port->fd + 1, &fds, NULL, NULL, timeout ? &delta : NULL); @@ -1982,8 +1005,8 @@ enum sp_return sp_blocking_read(struct sp_port *port, void *buf, size_t count, u RETURN_FAIL("select() failed"); } } else if (result == 0) { - DEBUG("read timed out"); - RETURN_VALUE("%d", bytes_read); + DEBUG("Read timed out"); + RETURN_INT(bytes_read); } /* Do read. */ @@ -2002,11 +1025,12 @@ enum sp_return sp_blocking_read(struct sp_port *port, void *buf, size_t count, u ptr += result; } - RETURN_VALUE("%d", bytes_read); + RETURN_INT(bytes_read); #endif } -enum sp_return sp_nonblocking_read(struct sp_port *port, void *buf, size_t count) +SP_API enum sp_return sp_nonblocking_read(struct sp_port *port, void *buf, + size_t count) { TRACE("%p, %p, %d", port, buf, count); @@ -2015,10 +1039,12 @@ enum sp_return sp_nonblocking_read(struct sp_port *port, void *buf, size_t count if (!buf) RETURN_ERROR(SP_ERR_ARG, "Null buffer"); - DEBUG("Reading up to %d bytes from port %s", count, port->name); + DEBUG_FMT("Reading up to %d bytes from port %s", count, port->name); #ifdef _WIN32 DWORD bytes_read; + DWORD bytes_remaining; + int ret; /* Set timeout. */ port->timeouts.ReadIntervalTimeout = MAXDWORD; @@ -2034,15 +1060,18 @@ enum sp_return sp_nonblocking_read(struct sp_port *port, void *buf, size_t count if (GetOverlappedResult(port->hdl, &port->read_ovl, &bytes_read, TRUE) == 0) RETURN_FAIL("GetOverlappedResult() failed"); - if (bytes_read > 0) { - /* Start background operation for subsequent events. */ - if (WaitCommEvent(port->hdl, &port->events, &port->wait_ovl) == 0) { - if (GetLastError() != ERROR_IO_PENDING) - RETURN_FAIL("WaitCommEvent() failed"); - } - } + ret = sp_input_waiting(port); + + if (ret < 0) + RETURN_CODEVAL(ret); + + bytes_remaining = ret; + + /* Restart wait operation if buffer was emptied. */ + if (bytes_read > 0 && bytes_remaining == 0) + TRY(restart_wait(port)); - RETURN_VALUE("%d", bytes_read); + RETURN_INT(bytes_read); #else ssize_t bytes_read; @@ -2055,17 +1084,17 @@ enum sp_return sp_nonblocking_read(struct sp_port *port, void *buf, size_t count /* This is an actual failure. */ RETURN_FAIL("read() failed"); } - RETURN_VALUE("%d", bytes_read); + RETURN_INT(bytes_read); #endif } -enum sp_return sp_input_waiting(struct sp_port *port) +SP_API enum sp_return sp_input_waiting(struct sp_port *port) { TRACE("%p", port); CHECK_OPEN_PORT(); - DEBUG("Checking input bytes waiting on port %s", port->name); + DEBUG_FMT("Checking input bytes waiting on port %s", port->name); #ifdef _WIN32 DWORD errors; @@ -2073,22 +1102,22 @@ enum sp_return sp_input_waiting(struct sp_port *port) if (ClearCommError(port->hdl, &errors, &comstat) == 0) RETURN_FAIL("ClearCommError() failed"); - RETURN_VALUE("%d", comstat.cbInQue); + RETURN_INT(comstat.cbInQue); #else int bytes_waiting; if (ioctl(port->fd, TIOCINQ, &bytes_waiting) < 0) RETURN_FAIL("TIOCINQ ioctl failed"); - RETURN_VALUE("%d", bytes_waiting); + RETURN_INT(bytes_waiting); #endif } -enum sp_return sp_output_waiting(struct sp_port *port) +SP_API enum sp_return sp_output_waiting(struct sp_port *port) { TRACE("%p", port); CHECK_OPEN_PORT(); - DEBUG("Checking output bytes waiting on port %s", port->name); + DEBUG_FMT("Checking output bytes waiting on port %s", port->name); #ifdef _WIN32 DWORD errors; @@ -2096,16 +1125,16 @@ enum sp_return sp_output_waiting(struct sp_port *port) if (ClearCommError(port->hdl, &errors, &comstat) == 0) RETURN_FAIL("ClearCommError() failed"); - RETURN_VALUE("%d", comstat.cbOutQue); + RETURN_INT(comstat.cbOutQue); #else int bytes_waiting; if (ioctl(port->fd, TIOCOUTQ, &bytes_waiting) < 0) RETURN_FAIL("TIOCOUTQ ioctl failed"); - RETURN_VALUE("%d", bytes_waiting); + RETURN_INT(bytes_waiting); #endif } -enum sp_return sp_new_event_set(struct sp_event_set **result_ptr) +SP_API enum sp_return sp_new_event_set(struct sp_event_set **result_ptr) { struct sp_event_set *result; @@ -2136,13 +1165,14 @@ static enum sp_return add_handle(struct sp_event_set *event_set, if (!(new_handles = realloc(event_set->handles, sizeof(event_handle) * (event_set->count + 1)))) - RETURN_ERROR(SP_ERR_MEM, "handle array realloc() failed"); + RETURN_ERROR(SP_ERR_MEM, "Handle array realloc() failed"); + + event_set->handles = new_handles; if (!(new_masks = realloc(event_set->masks, sizeof(enum sp_event) * (event_set->count + 1)))) - RETURN_ERROR(SP_ERR_MEM, "mask array realloc() failed"); + RETURN_ERROR(SP_ERR_MEM, "Mask array realloc() failed"); - event_set->handles = new_handles; event_set->masks = new_masks; ((event_handle *) event_set->handles)[event_set->count] = handle; @@ -2153,7 +1183,7 @@ static enum sp_return add_handle(struct sp_event_set *event_set, RETURN_OK(); } -enum sp_return sp_add_port_events(struct sp_event_set *event_set, +SP_API enum sp_return sp_add_port_events(struct sp_event_set *event_set, const struct sp_port *port, enum sp_event mask) { TRACE("%p, %p, %d", event_set, port, mask); @@ -2183,7 +1213,7 @@ enum sp_return sp_add_port_events(struct sp_event_set *event_set, RETURN_OK(); } -void sp_free_event_set(struct sp_event_set *event_set) +SP_API void sp_free_event_set(struct sp_event_set *event_set) { TRACE("%p", event_set); @@ -2204,7 +1234,8 @@ void sp_free_event_set(struct sp_event_set *event_set) RETURN(); } -enum sp_return sp_wait(struct sp_event_set *event_set, unsigned int timeout) +SP_API enum sp_return sp_wait(struct sp_event_set *event_set, + unsigned int timeout) { TRACE("%p, %d", event_set, timeout); @@ -2249,12 +1280,11 @@ enum sp_return sp_wait(struct sp_event_set *event_set, unsigned int timeout) } /* Loop until an event occurs. */ - while (1) - { + while (1) { if (timeout) { gettimeofday(&now, NULL); if (timercmp(&now, &end, >)) { - DEBUG("wait timed out"); + DEBUG("Wait timed out"); break; } timersub(&end, &now, &delta); @@ -2299,7 +1329,7 @@ static enum sp_return get_baudrate(int fd, int *baudrate) if (ioctl(fd, get_termios_get_ioctl(), data) < 0) { free(data); - RETURN_FAIL("getting termios failed"); + RETURN_FAIL("Getting termios failed"); } *baudrate = get_termios_speed(data); @@ -2322,7 +1352,7 @@ static enum sp_return set_baudrate(int fd, int baudrate) if (ioctl(fd, get_termios_get_ioctl(), data) < 0) { free(data); - RETURN_FAIL("getting termios failed"); + RETURN_FAIL("Getting termios failed"); } DEBUG("Setting baud rate"); @@ -2331,7 +1361,7 @@ static enum sp_return set_baudrate(int fd, int baudrate) if (ioctl(fd, get_termios_set_ioctl(), data) < 0) { free(data); - RETURN_FAIL("setting termios failed"); + RETURN_FAIL("Setting termios failed"); } free(data); @@ -2354,7 +1384,7 @@ static enum sp_return get_flow(int fd, struct port_data *data) if (ioctl(fd, TCGETX, termx) < 0) { free(termx); - RETURN_FAIL("getting termiox failed"); + RETURN_FAIL("Getting termiox failed"); } get_termiox_flow(termx, &data->rts_flow, &data->cts_flow, @@ -2378,7 +1408,7 @@ static enum sp_return set_flow(int fd, struct port_data *data) if (ioctl(fd, TCGETX, termx) < 0) { free(termx); - RETURN_FAIL("getting termiox failed"); + RETURN_FAIL("Getting termiox failed"); } DEBUG("Setting advanced flow control"); @@ -2388,7 +1418,7 @@ static enum sp_return set_flow(int fd, struct port_data *data) if (ioctl(fd, TCSETX, termx) < 0) { free(termx); - RETURN_FAIL("setting termiox failed"); + RETURN_FAIL("Setting termiox failed"); } free(termx); @@ -2404,7 +1434,7 @@ static enum sp_return get_config(struct sp_port *port, struct port_data *data, TRACE("%p, %p, %p", port, data, config); - DEBUG("Getting configuration for port %s", port->name); + DEBUG_FMT("Getting configuration for port %s", port->name); #ifdef _WIN32 if (!GetCommState(port->hdl, &data->dcb)) @@ -2621,7 +1651,7 @@ static enum sp_return set_config(struct sp_port *port, struct port_data *data, TRACE("%p, %p, %p", port, data, config); - DEBUG("Setting configuration for port %s", port->name); + DEBUG_FMT("Setting configuration for port %s", port->name); #ifdef _WIN32 if (config->baudrate >= 0) { @@ -2972,8 +2002,10 @@ static enum sp_return set_config(struct sp_port *port, struct port_data *data, if (baud_nonstd != B0) { if (ioctl(port->fd, IOSSIOSPEED, &baud_nonstd) == -1) RETURN_FAIL("IOSSIOSPEED ioctl failed"); - /* Set baud rates in data->term to correct, but incompatible - * with tcsetattr() value, same as delivered by tcgetattr(). */ + /* + * Set baud rates in data->term to correct, but incompatible + * with tcsetattr() value, same as delivered by tcgetattr(). + */ if (cfsetspeed(&data->term, baud_nonstd) < 0) RETURN_FAIL("cfsetspeed() failed"); } @@ -2993,7 +2025,7 @@ static enum sp_return set_config(struct sp_port *port, struct port_data *data, RETURN_OK(); } -enum sp_return sp_new_config(struct sp_port_config **config_ptr) +SP_API enum sp_return sp_new_config(struct sp_port_config **config_ptr) { struct sp_port_config *config; @@ -3005,7 +2037,7 @@ enum sp_return sp_new_config(struct sp_port_config **config_ptr) *config_ptr = NULL; if (!(config = malloc(sizeof(struct sp_port_config)))) - RETURN_ERROR(SP_ERR_MEM, "config malloc failed"); + RETURN_ERROR(SP_ERR_MEM, "Config malloc failed"); config->baudrate = -1; config->bits = -1; @@ -3021,7 +2053,7 @@ enum sp_return sp_new_config(struct sp_port_config **config_ptr) RETURN_OK(); } -void sp_free_config(struct sp_port_config *config) +SP_API void sp_free_config(struct sp_port_config *config) { TRACE("%p", config); @@ -3033,7 +2065,8 @@ void sp_free_config(struct sp_port_config *config) RETURN(); } -enum sp_return sp_get_config(struct sp_port *port, struct sp_port_config *config) +SP_API enum sp_return sp_get_config(struct sp_port *port, + struct sp_port_config *config) { struct port_data data; @@ -3049,7 +2082,8 @@ enum sp_return sp_get_config(struct sp_port *port, struct sp_port_config *config RETURN_OK(); } -enum sp_return sp_set_config(struct sp_port *port, const struct sp_port_config *config) +SP_API enum sp_return sp_set_config(struct sp_port *port, + const struct sp_port_config *config) { struct port_data data; struct sp_port_config prev_config; @@ -3068,7 +2102,7 @@ enum sp_return sp_set_config(struct sp_port *port, const struct sp_port_config * } #define CREATE_ACCESSORS(x, type) \ -enum sp_return sp_set_##x(struct sp_port *port, type x) { \ +SP_API enum sp_return sp_set_##x(struct sp_port *port, type x) { \ struct port_data data; \ struct sp_port_config config; \ TRACE("%p, %d", port, x); \ @@ -3078,14 +2112,16 @@ enum sp_return sp_set_##x(struct sp_port *port, type x) { \ TRY(set_config(port, &data, &config)); \ RETURN_OK(); \ } \ -enum sp_return sp_get_config_##x(const struct sp_port_config *config, type *x) { \ +SP_API enum sp_return sp_get_config_##x(const struct sp_port_config *config, \ + type *x) { \ TRACE("%p, %p", config, x); \ if (!config) \ RETURN_ERROR(SP_ERR_ARG, "Null config"); \ *x = config->x; \ RETURN_OK(); \ } \ -enum sp_return sp_set_config_##x(struct sp_port_config *config, type x) { \ +SP_API enum sp_return sp_set_config_##x(struct sp_port_config *config, \ + type x) { \ TRACE("%p, %d", config, x); \ if (!config) \ RETURN_ERROR(SP_ERR_ARG, "Null config"); \ @@ -3103,7 +2139,8 @@ CREATE_ACCESSORS(dtr, enum sp_dtr) CREATE_ACCESSORS(dsr, enum sp_dsr) CREATE_ACCESSORS(xon_xoff, enum sp_xonxoff) -enum sp_return sp_set_config_flowcontrol(struct sp_port_config *config, enum sp_flowcontrol flowcontrol) +SP_API enum sp_return sp_set_config_flowcontrol(struct sp_port_config *config, + enum sp_flowcontrol flowcontrol) { if (!config) RETURN_ERROR(SP_ERR_ARG, "Null configuration"); @@ -3137,7 +2174,8 @@ enum sp_return sp_set_config_flowcontrol(struct sp_port_config *config, enum sp_ RETURN_OK(); } -enum sp_return sp_set_flowcontrol(struct sp_port *port, enum sp_flowcontrol flowcontrol) +SP_API enum sp_return sp_set_flowcontrol(struct sp_port *port, + enum sp_flowcontrol flowcontrol) { struct port_data data; struct sp_port_config config; @@ -3155,7 +2193,8 @@ enum sp_return sp_set_flowcontrol(struct sp_port *port, enum sp_flowcontrol flow RETURN_OK(); } -enum sp_return sp_get_signals(struct sp_port *port, enum sp_signal *signals) +SP_API enum sp_return sp_get_signals(struct sp_port *port, + enum sp_signal *signals) { TRACE("%p, %p", port, signals); @@ -3164,7 +2203,7 @@ enum sp_return sp_get_signals(struct sp_port *port, enum sp_signal *signals) if (!signals) RETURN_ERROR(SP_ERR_ARG, "Null result pointer"); - DEBUG("Getting control signals for port %s", port->name); + DEBUG_FMT("Getting control signals for port %s", port->name); *signals = 0; #ifdef _WIN32 @@ -3195,7 +2234,7 @@ enum sp_return sp_get_signals(struct sp_port *port, enum sp_signal *signals) RETURN_OK(); } -enum sp_return sp_start_break(struct sp_port *port) +SP_API enum sp_return sp_start_break(struct sp_port *port) { TRACE("%p", port); @@ -3211,7 +2250,7 @@ enum sp_return sp_start_break(struct sp_port *port) RETURN_OK(); } -enum sp_return sp_end_break(struct sp_port *port) +SP_API enum sp_return sp_end_break(struct sp_port *port) { TRACE("%p", port); @@ -3227,19 +2266,19 @@ enum sp_return sp_end_break(struct sp_port *port) RETURN_OK(); } -int sp_last_error_code(void) +SP_API int sp_last_error_code(void) { - TRACE(""); + TRACE_VOID(); #ifdef _WIN32 - RETURN_VALUE("%d", GetLastError()); + RETURN_INT(GetLastError()); #else - RETURN_VALUE("%d", errno); + RETURN_INT(errno); #endif } -char *sp_last_error_message(void) +SP_API char *sp_last_error_message(void) { - TRACE(""); + TRACE_VOID(); #ifdef _WIN32 LPVOID message; @@ -3255,13 +2294,13 @@ char *sp_last_error_message(void) (LPTSTR) &message, 0, NULL ); - RETURN_VALUE("%s", message); + RETURN_STRING(message); #else - RETURN_VALUE("%s", strerror(errno)); + RETURN_STRING(strerror(errno)); #endif } -void sp_free_error_message(char *message) +SP_API void sp_free_error_message(char *message) { TRACE("%s", message); @@ -3274,7 +2313,7 @@ void sp_free_error_message(char *message) RETURN(); } -void sp_set_debug_handler(void (*handler)(const char *format, ...)) +SP_API void sp_set_debug_handler(void (*handler)(const char *format, ...)) { TRACE("%p", handler); @@ -3283,7 +2322,7 @@ void sp_set_debug_handler(void (*handler)(const char *format, ...)) RETURN(); } -void sp_default_debug_handler(const char *format, ...) +SP_API void sp_default_debug_handler(const char *format, ...) { va_list args; va_start(args, format); @@ -3294,42 +2333,42 @@ void sp_default_debug_handler(const char *format, ...) va_end(args); } -int sp_get_major_package_version(void) +SP_API int sp_get_major_package_version(void) { return SP_PACKAGE_VERSION_MAJOR; } -int sp_get_minor_package_version(void) +SP_API int sp_get_minor_package_version(void) { return SP_PACKAGE_VERSION_MINOR; } -int sp_get_micro_package_version(void) +SP_API int sp_get_micro_package_version(void) { return SP_PACKAGE_VERSION_MICRO; } -const char *sp_get_package_version_string(void) +SP_API const char *sp_get_package_version_string(void) { return SP_PACKAGE_VERSION_STRING; } -int sp_get_current_lib_version(void) +SP_API int sp_get_current_lib_version(void) { return SP_LIB_VERSION_CURRENT; } -int sp_get_revision_lib_version(void) +SP_API int sp_get_revision_lib_version(void) { return SP_LIB_VERSION_REVISION; } -int sp_get_age_lib_version(void) +SP_API int sp_get_age_lib_version(void) { return SP_LIB_VERSION_AGE; } -const char *sp_get_lib_version_string(void) +SP_API const char *sp_get_lib_version_string(void) { return SP_LIB_VERSION_STRING; }