2 * This file is part of the libserialport project.
4 * Copyright (C) 2010-2012 Bert Vermeulen <bert@biot.com>
5 * Copyright (C) 2010-2012 Uwe Hermann <uwe@hermann-uwe.de>
6 * Copyright (C) 2013 Martin Ling <martin-libserialport@earth.li>
7 * Copyright (C) 2013 Matthias Heidbrink <m-sigrok@heidbrink.biz>
8 * Copyright (C) 2014 Aurelien Jacobs <aurel@gnuage.org>
10 * This program is free software: you can redistribute it and/or modify
11 * it under the terms of the GNU Lesser General Public License as
12 * published by the Free Software Foundation, either version 3 of the
13 * License, or (at your option) any later version.
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
20 * You should have received a copy of the GNU Lesser General Public License
21 * along with this program. If not, see <http://www.gnu.org/licenses/>.
25 #include <sys/types.h>
42 #include <sys/ioctl.h>
48 #include <CoreFoundation/CoreFoundation.h>
49 #include <IOKit/IOKitLib.h>
50 #include <IOKit/serial/IOSerialKeys.h>
51 #include <IOKit/serial/ioss.h>
52 #include <sys/syslimits.h>
57 #include "linux/serial.h"
59 #include "linux_termios.h"
61 /* TCGETX/TCSETX is not available everywhere. */
62 #if defined(TCGETX) && defined(TCSETX) && defined(HAVE_TERMIOX)
67 /* TIOCINQ/TIOCOUTQ is not available everywhere. */
68 #if !defined(TIOCINQ) && defined(FIONREAD)
69 #define TIOCINQ FIONREAD
71 #if !defined(TIOCOUTQ) && defined(FIONWRITE)
72 #define TIOCOUTQ FIONWRITE
75 /* Non-standard baudrates are not available everywhere. */
76 #if defined(HAVE_TERMIOS_SPEED) || defined(HAVE_TERMIOS2_SPEED)
77 #define USE_TERMIOS_SPEED
80 #include "libserialport.h"
85 enum sp_transport transport;
90 char *usb_manufacturer;
93 char *bluetooth_address;
97 COMMTIMEOUTS timeouts;
109 struct sp_port_config {
112 enum sp_parity parity;
118 enum sp_xonxoff xon_xoff;
127 int termiox_supported;
136 typedef HANDLE event_handle;
138 typedef int event_handle;
141 /* Standard baud rates. */
143 #define BAUD_TYPE DWORD
144 #define BAUD(n) {CBR_##n, n}
146 #define BAUD_TYPE speed_t
147 #define BAUD(n) {B##n, n}
150 struct std_baudrate {
155 const struct std_baudrate std_baudrates[] = {
158 * The baudrates 50/75/134/150/200/1800/230400/460800 do not seem to
159 * have documented CBR_* macros.
161 BAUD(110), BAUD(300), BAUD(600), BAUD(1200), BAUD(2400), BAUD(4800),
162 BAUD(9600), BAUD(14400), BAUD(19200), BAUD(38400), BAUD(57600),
163 BAUD(115200), BAUD(128000), BAUD(256000),
165 BAUD(50), BAUD(75), BAUD(110), BAUD(134), BAUD(150), BAUD(200),
166 BAUD(300), BAUD(600), BAUD(1200), BAUD(1800), BAUD(2400), BAUD(4800),
167 BAUD(9600), BAUD(19200), BAUD(38400), BAUD(57600), BAUD(115200),
169 #if !defined(__APPLE__) && !defined(__OpenBSD__)
175 void (*sp_debug_handler)(const char *format, ...) = sp_default_debug_handler;
177 #define ARRAY_SIZE(x) (sizeof(x) / sizeof(x[0]))
178 #define NUM_STD_BAUDRATES ARRAY_SIZE(std_baudrates)
180 /* Debug output macros. */
181 #define DEBUG(fmt, ...) do { if (sp_debug_handler) sp_debug_handler(fmt ".\n", ##__VA_ARGS__); } while (0)
182 #define DEBUG_ERROR(err, fmt, ...) DEBUG("%s returning " #err ": " fmt, __func__, ##__VA_ARGS__)
183 #define DEBUG_FAIL(fmt, ...) do { \
184 char *errmsg = sp_last_error_message(); \
185 DEBUG("%s returning SP_ERR_FAIL: "fmt": %s", __func__,##__VA_ARGS__,errmsg); \
186 sp_free_error_message(errmsg); \
188 #define RETURN() do { DEBUG("%s returning", __func__); return; } while(0)
189 #define RETURN_CODE(x) do { DEBUG("%s returning " #x, __func__); return x; } while (0)
190 #define RETURN_CODEVAL(x) do { \
192 case SP_OK: RETURN_CODE(SP_OK); \
193 case SP_ERR_ARG: RETURN_CODE(SP_ERR_ARG); \
194 case SP_ERR_FAIL: RETURN_CODE(SP_ERR_FAIL); \
195 case SP_ERR_MEM: RETURN_CODE(SP_ERR_MEM); \
196 case SP_ERR_SUPP: RETURN_CODE(SP_ERR_SUPP); \
199 #define RETURN_OK() RETURN_CODE(SP_OK);
200 #define RETURN_ERROR(err, ...) do { DEBUG_ERROR(err, __VA_ARGS__); return err; } while (0)
201 #define RETURN_FAIL(...) do { DEBUG_FAIL(__VA_ARGS__); return SP_ERR_FAIL; } while (0)
202 #define RETURN_VALUE(fmt, x) do { \
204 DEBUG("%s returning " fmt, __func__, _x); \
207 #define SET_ERROR(val, err, msg) do { DEBUG_ERROR(err, msg); val = err; } while (0)
208 #define SET_FAIL(val, msg) do { DEBUG_FAIL(msg); val = SP_ERR_FAIL; } while (0)
209 #define TRACE(fmt, ...) DEBUG("%s(" fmt ") called", __func__, ##__VA_ARGS__)
211 #define TRY(x) do { int ret = x; if (ret != SP_OK) RETURN_CODEVAL(ret); } while (0)
213 /* Helper functions. */
214 static enum sp_return get_config(struct sp_port *port, struct port_data *data,
215 struct sp_port_config *config);
216 static enum sp_return set_config(struct sp_port *port, struct port_data *data,
217 const struct sp_port_config *config);
221 /* USB path is a string of at most 8 decimal numbers < 128 separated by dots */
222 #define MAX_USB_PATH (8*3 + 7*1 + 1)
224 static char *wc_to_utf8(PWCHAR wc_buffer, ULONG size)
226 WCHAR wc_str[size/sizeof(WCHAR)+1];
229 /* zero terminate the wide char string */
230 memcpy(wc_str, wc_buffer, size);
231 wc_str[sizeof(wc_str)-1] = 0;
233 /* compute the size of the utf8 converted string */
234 if (!(size = WideCharToMultiByte(CP_ACP, WC_NO_BEST_FIT_CHARS, wc_str, -1,
235 NULL, 0, NULL, NULL)))
238 /* allocate utf8 output buffer */
239 if (!(utf8_str = malloc(size)))
242 /* actually converted to utf8 */
243 if (!WideCharToMultiByte(CP_ACP, WC_NO_BEST_FIT_CHARS, wc_str, -1,
244 utf8_str, size, NULL, NULL)) {
252 static char *get_root_hub_name(HANDLE host_controller)
254 USB_ROOT_HUB_NAME root_hub_name;
255 PUSB_ROOT_HUB_NAME root_hub_name_wc;
256 char *root_hub_name_utf8;
259 /* compute the size of the root hub name string */
260 if (!DeviceIoControl(host_controller, IOCTL_USB_GET_ROOT_HUB_NAME, 0, 0,
261 &root_hub_name, sizeof(root_hub_name), &size, NULL))
264 /* allocate wide char root hub name string */
265 size = root_hub_name.ActualLength;
266 if (!(root_hub_name_wc = malloc(size)))
269 /* actually get the root hub name string */
270 if (!DeviceIoControl(host_controller, IOCTL_USB_GET_ROOT_HUB_NAME,
271 NULL, 0, root_hub_name_wc, size, &size, NULL)) {
272 free(root_hub_name_wc);
276 /* convert the root hub name string to utf8 */
277 root_hub_name_utf8 = wc_to_utf8(root_hub_name_wc->RootHubName, size);
278 free(root_hub_name_wc);
279 return root_hub_name_utf8;
282 static char *get_external_hub_name(HANDLE hub, ULONG connection_index)
284 USB_NODE_CONNECTION_NAME ext_hub_name;
285 PUSB_NODE_CONNECTION_NAME ext_hub_name_wc;
286 char *ext_hub_name_utf8;
289 /* compute the size of the external hub name string */
290 ext_hub_name.ConnectionIndex = connection_index;
291 if (!DeviceIoControl(hub, IOCTL_USB_GET_NODE_CONNECTION_NAME,
292 &ext_hub_name, sizeof(ext_hub_name),
293 &ext_hub_name, sizeof(ext_hub_name), &size, NULL))
296 /* allocate wide char external hub name string */
297 size = ext_hub_name.ActualLength;
298 if (size <= sizeof(ext_hub_name)
299 || !(ext_hub_name_wc = malloc(size)))
302 /* get the name of the external hub attached to the specified port */
303 ext_hub_name_wc->ConnectionIndex = connection_index;
304 if (!DeviceIoControl(hub, IOCTL_USB_GET_NODE_CONNECTION_NAME,
305 ext_hub_name_wc, size,
306 ext_hub_name_wc, size, &size, NULL)) {
307 free(ext_hub_name_wc);
311 /* convert the external hub name string to utf8 */
312 ext_hub_name_utf8 = wc_to_utf8(ext_hub_name_wc->NodeName, size);
313 free(ext_hub_name_wc);
314 return ext_hub_name_utf8;
317 static char *get_string_descriptor(HANDLE hub_device, ULONG connection_index,
318 UCHAR descriptor_index)
320 char desc_req_buf[sizeof(USB_DESCRIPTOR_REQUEST) +
321 MAXIMUM_USB_STRING_LENGTH] = { 0 };
322 PUSB_DESCRIPTOR_REQUEST desc_req = (void *) desc_req_buf;
323 PUSB_STRING_DESCRIPTOR desc = (void *) (desc_req + 1);
324 ULONG size = sizeof(desc_req_buf);
326 desc_req->ConnectionIndex = connection_index;
327 desc_req->SetupPacket.wValue = (USB_STRING_DESCRIPTOR_TYPE << 8)
329 desc_req->SetupPacket.wIndex = 0;
330 desc_req->SetupPacket.wLength = size - sizeof(*desc_req);
332 if (!DeviceIoControl(hub_device,
333 IOCTL_USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION,
334 desc_req, size, desc_req, size, &size, NULL)
336 || desc->bDescriptorType != USB_STRING_DESCRIPTOR_TYPE
337 || desc->bLength != size - sizeof(*desc_req)
338 || desc->bLength % 2)
341 return wc_to_utf8(desc->bString, desc->bLength);
344 static void enumerate_hub(struct sp_port *port, char *hub_name,
347 static void enumerate_hub_ports(struct sp_port *port, HANDLE hub_device,
348 ULONG nb_ports, char *parent_path)
350 char path[MAX_USB_PATH];
353 for (index = 1; index <= nb_ports; index++) {
354 PUSB_NODE_CONNECTION_INFORMATION_EX connection_info_ex;
355 ULONG size = sizeof(*connection_info_ex) + 30*sizeof(USB_PIPE_INFO);
357 if (!(connection_info_ex = malloc(size)))
360 connection_info_ex->ConnectionIndex = index;
361 if (!DeviceIoControl(hub_device,
362 IOCTL_USB_GET_NODE_CONNECTION_INFORMATION_EX,
363 connection_info_ex, size,
364 connection_info_ex, size, &size, NULL)) {
365 /* try to get CONNECTION_INFORMATION if CONNECTION_INFORMATION_EX
367 PUSB_NODE_CONNECTION_INFORMATION connection_info;
369 size = sizeof(*connection_info) + 30*sizeof(USB_PIPE_INFO);
370 if (!(connection_info = malloc(size))) {
371 free(connection_info_ex);
374 connection_info->ConnectionIndex = index;
375 if (!DeviceIoControl(hub_device,
376 IOCTL_USB_GET_NODE_CONNECTION_INFORMATION,
377 connection_info, size,
378 connection_info, size, &size, NULL)) {
379 free(connection_info);
380 free(connection_info_ex);
384 connection_info_ex->ConnectionIndex = connection_info->ConnectionIndex;
385 connection_info_ex->DeviceDescriptor = connection_info->DeviceDescriptor;
386 connection_info_ex->DeviceIsHub = connection_info->DeviceIsHub;
387 connection_info_ex->DeviceAddress = connection_info->DeviceAddress;
388 free(connection_info);
391 if (connection_info_ex->DeviceIsHub) {
392 /* recursively enumerate external hub */
394 if ((ext_hub_name = get_external_hub_name(hub_device, index))) {
395 snprintf(path, sizeof(path), "%s%d.",
396 parent_path, connection_info_ex->ConnectionIndex);
397 enumerate_hub(port, ext_hub_name, path);
399 free(connection_info_ex);
401 snprintf(path, sizeof(path), "%s%d",
402 parent_path, connection_info_ex->ConnectionIndex);
404 /* check if this device is the one we search for */
405 if (strcmp(path, port->usb_path)) {
406 free(connection_info_ex);
410 /* finally grab detailed informations regarding the device */
411 port->usb_address = connection_info_ex->DeviceAddress + 1;
412 port->usb_vid = connection_info_ex->DeviceDescriptor.idVendor;
413 port->usb_pid = connection_info_ex->DeviceDescriptor.idProduct;
415 if (connection_info_ex->DeviceDescriptor.iManufacturer)
416 port->usb_manufacturer = get_string_descriptor(hub_device,index,
417 connection_info_ex->DeviceDescriptor.iManufacturer);
418 if (connection_info_ex->DeviceDescriptor.iProduct)
419 port->usb_product = get_string_descriptor(hub_device, index,
420 connection_info_ex->DeviceDescriptor.iProduct);
421 if (connection_info_ex->DeviceDescriptor.iSerialNumber)
422 port->usb_serial = get_string_descriptor(hub_device, index,
423 connection_info_ex->DeviceDescriptor.iSerialNumber);
425 free(connection_info_ex);
431 static void enumerate_hub(struct sp_port *port, char *hub_name,
434 USB_NODE_INFORMATION hub_info;
436 ULONG size = sizeof(hub_info);
439 /* open the hub with its full name */
440 if (!(device_name = malloc(strlen("\\\\.\\") + strlen(hub_name) + 1)))
442 strcpy(device_name, "\\\\.\\");
443 strcat(device_name, hub_name);
444 hub_device = CreateFile(device_name, GENERIC_WRITE, FILE_SHARE_WRITE,
445 NULL, OPEN_EXISTING, 0, NULL);
447 if (hub_device == INVALID_HANDLE_VALUE)
450 /* get the number of ports of the hub */
451 if (DeviceIoControl(hub_device, IOCTL_USB_GET_NODE_INFORMATION,
452 &hub_info, size, &hub_info, size, &size, NULL))
453 /* enumarate the ports of the hub */
454 enumerate_hub_ports(port, hub_device,
455 hub_info.u.HubInformation.HubDescriptor.bNumberOfPorts, parent_path);
457 CloseHandle(hub_device);
460 static void enumerate_host_controller(struct sp_port *port,
461 HANDLE host_controller_device)
465 if ((root_hub_name = get_root_hub_name(host_controller_device))) {
466 enumerate_hub(port, root_hub_name, "");
471 static void get_usb_details(struct sp_port *port, DEVINST dev_inst_match)
473 HDEVINFO device_info;
474 SP_DEVINFO_DATA device_info_data;
477 device_info = SetupDiGetClassDevs(&GUID_CLASS_USB_HOST_CONTROLLER,NULL,NULL,
478 DIGCF_PRESENT | DIGCF_DEVICEINTERFACE);
479 device_info_data.cbSize = sizeof(device_info_data);
481 for (i=0; SetupDiEnumDeviceInfo(device_info, i, &device_info_data); i++) {
482 SP_DEVICE_INTERFACE_DATA device_interface_data;
483 PSP_DEVICE_INTERFACE_DETAIL_DATA device_detail_data;
484 DEVINST dev_inst = dev_inst_match;
485 HANDLE host_controller_device;
487 device_interface_data.cbSize = sizeof(device_interface_data);
488 if (!SetupDiEnumDeviceInterfaces(device_info, 0,
489 &GUID_CLASS_USB_HOST_CONTROLLER,
490 i, &device_interface_data))
493 if (!SetupDiGetDeviceInterfaceDetail(device_info,&device_interface_data,
494 NULL, 0, &size, NULL)
495 && GetLastError() != ERROR_INSUFFICIENT_BUFFER)
498 if (!(device_detail_data = malloc(size)))
500 device_detail_data->cbSize = sizeof(*device_detail_data);
501 if (!SetupDiGetDeviceInterfaceDetail(device_info,&device_interface_data,
502 device_detail_data, size, &size,
504 free(device_detail_data);
508 while (CM_Get_Parent(&dev_inst, dev_inst, 0) == CR_SUCCESS
509 && dev_inst != device_info_data.DevInst) { }
510 if (dev_inst != device_info_data.DevInst) {
511 free(device_detail_data);
515 port->usb_bus = i + 1;
517 host_controller_device = CreateFile(device_detail_data->DevicePath,
518 GENERIC_WRITE, FILE_SHARE_WRITE,
519 NULL, OPEN_EXISTING, 0, NULL);
520 if (host_controller_device != INVALID_HANDLE_VALUE) {
521 enumerate_host_controller(port, host_controller_device);
522 CloseHandle(host_controller_device);
524 free(device_detail_data);
527 SetupDiDestroyDeviceInfoList(device_info);
533 static enum sp_return sp_get_port_details(struct sp_port *port)
535 /* Description limited to 127 char,
536 anything longer would not be user friendly anyway */
537 char description[128];
539 int bus, address, vid, pid = -1;
540 char manufacturer[128], product[128], serial[128];
544 port->description = NULL;
545 port->transport = SP_TRANSPORT_NATIVE;
547 port->usb_address = -1;
550 port->usb_manufacturer = NULL;
551 port->usb_product = NULL;
552 port->usb_serial = NULL;
553 port->bluetooth_address = NULL;
556 SP_DEVINFO_DATA device_info_data = { .cbSize = sizeof(device_info_data) };
557 HDEVINFO device_info;
560 device_info = SetupDiGetClassDevs(NULL, 0, 0,
561 DIGCF_PRESENT | DIGCF_ALLCLASSES);
562 if (device_info == INVALID_HANDLE_VALUE)
563 RETURN_FAIL("SetupDiGetClassDevs() failed");
565 for (i=0; SetupDiEnumDeviceInfo(device_info, i, &device_info_data); i++) {
568 char value[8], class[16];
572 /* check if this is the device we are looking for */
573 if (!(device_key = SetupDiOpenDevRegKey(device_info, &device_info_data,
575 DIREG_DEV, KEY_QUERY_VALUE)))
577 size = sizeof(value);
578 if (RegQueryValueExA(device_key, "PortName", NULL, &type, (LPBYTE)value,
579 &size) != ERROR_SUCCESS || type != REG_SZ)
581 RegCloseKey(device_key);
582 value[sizeof(value)-1] = 0;
583 if (strcmp(value, port->name))
586 /* check port transport type */
587 dev_inst = device_info_data.DevInst;
588 size = sizeof(class);
590 while (CM_Get_Parent(&dev_inst, dev_inst, 0) == CR_SUCCESS &&
591 (cr = CM_Get_DevNode_Registry_PropertyA(dev_inst,
592 CM_DRP_CLASS, 0, class, &size, 0)) != CR_SUCCESS) { }
593 if (cr == CR_SUCCESS) {
594 if (!strcmp(class, "USB"))
595 port->transport = SP_TRANSPORT_USB;
598 /* get port description (friendly name) */
599 dev_inst = device_info_data.DevInst;
600 size = sizeof(description);
601 while ((cr = CM_Get_DevNode_Registry_PropertyA(dev_inst,
602 CM_DRP_FRIENDLYNAME, 0, description, &size, 0)) != CR_SUCCESS
603 && CM_Get_Parent(&dev_inst, dev_inst, 0) == CR_SUCCESS) { }
604 if (cr == CR_SUCCESS)
605 port->description = strdup(description);
607 /* get more informations for USB connected ports */
608 if (port->transport == SP_TRANSPORT_USB) {
609 char usb_path[MAX_USB_PATH] = "", tmp[MAX_USB_PATH];
610 char device_id[MAX_DEVICE_ID_LEN];
612 /* recurse over parents to build the USB device path */
613 dev_inst = device_info_data.DevInst;
615 /* verify that this layer of the tree is USB related */
616 if (CM_Get_Device_IDA(dev_inst, device_id,
617 sizeof(device_id), 0) != CR_SUCCESS
618 || strncmp(device_id, "USB\\", 4))
621 /* discard one layer for composite devices */
622 char compat_ids[512], *p = compat_ids;
623 size = sizeof(compat_ids);
624 if (CM_Get_DevNode_Registry_PropertyA(dev_inst,
625 CM_DRP_COMPATIBLEIDS, 0,
627 &size, 0) == CR_SUCCESS) {
629 if (!strncmp(p, "USB\\COMPOSITE", 13))
637 /* stop the recursion when reaching the USB root */
638 if (!strncmp(device_id, "USB\\ROOT", 8))
641 /* prepend the address of current USB layer to the USB path */
643 size = sizeof(address);
644 if (CM_Get_DevNode_Registry_PropertyA(dev_inst, CM_DRP_ADDRESS,
645 0, &address, &size, 0) == CR_SUCCESS) {
646 strcpy(tmp, usb_path);
647 snprintf(usb_path, sizeof(usb_path), "%d%s%s",
648 (int)address, *tmp ? "." : "", tmp);
650 } while (CM_Get_Parent(&dev_inst, dev_inst, 0) == CR_SUCCESS);
652 port->usb_path = strdup(usb_path);
654 /* wake up the USB device to be able to read string descriptor */
655 char *escaped_port_name;
657 if (!(escaped_port_name = malloc(strlen(port->name) + 5)))
658 RETURN_ERROR(SP_ERR_MEM, "Escaped port name malloc failed");
659 sprintf(escaped_port_name, "\\\\.\\%s", port->name);
660 handle = CreateFile(escaped_port_name, GENERIC_READ, 0, 0,
662 FILE_ATTRIBUTE_NORMAL|FILE_FLAG_OVERLAPPED, 0);
663 free(escaped_port_name);
666 /* retrive USB device details from the device descriptor */
667 get_usb_details(port, device_info_data.DevInst);
671 #elif defined(__APPLE__)
672 CFMutableDictionaryRef classes;
675 CFTypeRef cf_property, cf_bus, cf_address, cf_vendor, cf_product;
679 DEBUG("Getting serial port list");
680 if (!(classes = IOServiceMatching(kIOSerialBSDServiceValue)))
681 RETURN_FAIL("IOServiceMatching() failed");
683 if (IOServiceGetMatchingServices(kIOMasterPortDefault, classes,
684 &iter) != KERN_SUCCESS)
685 RETURN_FAIL("IOServiceGetMatchingServices() failed");
687 DEBUG("Iterating over results");
688 while ((ioport = IOIteratorNext(iter))) {
689 if (!(cf_property = IORegistryEntryCreateCFProperty(ioport,
690 CFSTR(kIOCalloutDeviceKey), kCFAllocatorDefault, 0))) {
691 IOObjectRelease(ioport);
694 result = CFStringGetCString(cf_property, path, sizeof(path),
695 kCFStringEncodingASCII);
696 CFRelease(cf_property);
697 if (!result || strcmp(path, port->name)) {
698 IOObjectRelease(ioport);
701 DEBUG("Found port %s", path);
703 IORegistryEntryGetParentEntry(ioport, kIOServicePlane, &ioparent);
704 if ((cf_property=IORegistryEntrySearchCFProperty(ioparent,kIOServicePlane,
705 CFSTR("IOProviderClass"), kCFAllocatorDefault,
706 kIORegistryIterateRecursively | kIORegistryIterateParents))) {
707 if (CFStringGetCString(cf_property, class, sizeof(class),
708 kCFStringEncodingASCII) &&
709 strstr(class, "USB")) {
710 DEBUG("Found USB class device");
711 port->transport = SP_TRANSPORT_USB;
713 CFRelease(cf_property);
715 IOObjectRelease(ioparent);
717 if ((cf_property = IORegistryEntrySearchCFProperty(ioport,kIOServicePlane,
718 CFSTR("USB Interface Name"), kCFAllocatorDefault,
719 kIORegistryIterateRecursively | kIORegistryIterateParents)) ||
720 (cf_property = IORegistryEntrySearchCFProperty(ioport,kIOServicePlane,
721 CFSTR("USB Product Name"), kCFAllocatorDefault,
722 kIORegistryIterateRecursively | kIORegistryIterateParents)) ||
723 (cf_property = IORegistryEntrySearchCFProperty(ioport,kIOServicePlane,
724 CFSTR("Product Name"), kCFAllocatorDefault,
725 kIORegistryIterateRecursively | kIORegistryIterateParents)) ||
726 (cf_property = IORegistryEntryCreateCFProperty(ioport,
727 CFSTR(kIOTTYDeviceKey), kCFAllocatorDefault, 0))) {
728 if (CFStringGetCString(cf_property, description, sizeof(description),
729 kCFStringEncodingASCII)) {
730 DEBUG("Found description %s", description);
731 port->description = strdup(description);
733 CFRelease(cf_property);
735 DEBUG("No description for this device");
738 cf_bus = IORegistryEntrySearchCFProperty(ioport, kIOServicePlane,
739 CFSTR("USBBusNumber"),
741 kIORegistryIterateRecursively
742 | kIORegistryIterateParents);
743 cf_address = IORegistryEntrySearchCFProperty(ioport, kIOServicePlane,
744 CFSTR("USB Address"),
746 kIORegistryIterateRecursively
747 | kIORegistryIterateParents);
748 if (cf_bus && cf_address &&
749 CFNumberGetValue(cf_bus , kCFNumberIntType, &bus) &&
750 CFNumberGetValue(cf_address, kCFNumberIntType, &address)) {
751 DEBUG("Found matching USB bus:address %03d:%03d", bus, address);
753 port->usb_address = address;
755 if (cf_bus ) CFRelease(cf_bus);
756 if (cf_address) CFRelease(cf_address);
758 cf_vendor = IORegistryEntrySearchCFProperty(ioport, kIOServicePlane,
761 kIORegistryIterateRecursively
762 | kIORegistryIterateParents);
763 cf_product = IORegistryEntrySearchCFProperty(ioport, kIOServicePlane,
766 kIORegistryIterateRecursively
767 | kIORegistryIterateParents);
768 if (cf_vendor && cf_product &&
769 CFNumberGetValue(cf_vendor , kCFNumberIntType, &vid) &&
770 CFNumberGetValue(cf_product, kCFNumberIntType, &pid)) {
771 DEBUG("Found matching USB vid:pid %04X:%04X", vid, pid);
775 if (cf_vendor ) CFRelease(cf_vendor);
776 if (cf_product) CFRelease(cf_product);
778 if ((cf_property = IORegistryEntrySearchCFProperty(ioport,kIOServicePlane,
779 CFSTR("USB Vendor Name"), kCFAllocatorDefault,
780 kIORegistryIterateRecursively | kIORegistryIterateParents))) {
781 if (CFStringGetCString(cf_property, manufacturer, sizeof(manufacturer),
782 kCFStringEncodingASCII)) {
783 DEBUG("Found manufacturer %s", manufacturer);
784 port->usb_manufacturer = strdup(manufacturer);
786 CFRelease(cf_property);
789 if ((cf_property = IORegistryEntrySearchCFProperty(ioport,kIOServicePlane,
790 CFSTR("USB Product Name"), kCFAllocatorDefault,
791 kIORegistryIterateRecursively | kIORegistryIterateParents))) {
792 if (CFStringGetCString(cf_property, product, sizeof(product),
793 kCFStringEncodingASCII)) {
794 DEBUG("Found product name %s", product);
795 port->usb_product = strdup(product);
797 CFRelease(cf_property);
800 if ((cf_property = IORegistryEntrySearchCFProperty(ioport,kIOServicePlane,
801 CFSTR("USB Serial Number"), kCFAllocatorDefault,
802 kIORegistryIterateRecursively | kIORegistryIterateParents))) {
803 if (CFStringGetCString(cf_property, serial, sizeof(serial),
804 kCFStringEncodingASCII)) {
805 DEBUG("Found serial number %s", serial);
806 port->usb_serial = strdup(serial);
808 CFRelease(cf_property);
811 IOObjectRelease(ioport);
814 IOObjectRelease(iter);
815 #elif defined(__linux__)
816 const char dir_name[] = "/sys/class/tty/%s/device/%s%s";
817 char sub_dir[32] = "", file_name[PATH_MAX];
818 char *ptr, *dev = port->name + 5;
822 if (strncmp(port->name, "/dev/", 5))
823 RETURN_ERROR(SP_ERR_ARG, "Device name not recognized (%s)", port->name);
825 snprintf(file_name, sizeof(file_name), "/sys/class/tty/%s", dev);
826 count = readlink(file_name, file_name, sizeof(file_name));
827 if (count <= 0 || count >= (int) sizeof(file_name)-1)
828 RETURN_ERROR(SP_ERR_ARG, "Device not found (%s)", port->name);
829 file_name[count] = 0;
830 if (strstr(file_name, "bluetooth"))
831 port->transport = SP_TRANSPORT_BLUETOOTH;
832 else if (strstr(file_name, "usb"))
833 port->transport = SP_TRANSPORT_USB;
835 if (port->transport == SP_TRANSPORT_USB) {
836 for (i=0; i<5; i++) {
837 strcat(sub_dir, "../");
839 snprintf(file_name,sizeof(file_name),dir_name,dev,sub_dir,"busnum");
840 if (!(file = fopen(file_name, "r")))
842 count = fscanf(file, "%d", &bus);
847 snprintf(file_name,sizeof(file_name),dir_name,dev,sub_dir,"devnum");
848 if (!(file = fopen(file_name, "r")))
850 count = fscanf(file, "%d", &address);
855 snprintf(file_name,sizeof(file_name),dir_name,dev,sub_dir,"idVendor");
856 if (!(file = fopen(file_name, "r")))
858 count = fscanf(file, "%4x", &vid);
863 snprintf(file_name,sizeof(file_name),dir_name,dev,sub_dir,"idProduct");
864 if (!(file = fopen(file_name, "r")))
866 count = fscanf(file, "%4x", &pid);
872 port->usb_address = address;
876 snprintf(file_name,sizeof(file_name),dir_name,dev,sub_dir,"product");
877 if ((file = fopen(file_name, "r"))) {
878 if ((ptr = fgets(description, sizeof(description), file))) {
879 ptr = description + strlen(description) - 1;
880 if (ptr >= description && *ptr == '\n')
882 port->description = strdup(description);
887 port->description = strdup(dev);
889 snprintf(file_name,sizeof(file_name),dir_name,dev,sub_dir,"manufacturer");
890 if ((file = fopen(file_name, "r"))) {
891 if ((ptr = fgets(manufacturer, sizeof(manufacturer), file))) {
892 ptr = manufacturer + strlen(manufacturer) - 1;
893 if (ptr >= manufacturer && *ptr == '\n')
895 port->usb_manufacturer = strdup(manufacturer);
900 snprintf(file_name,sizeof(file_name),dir_name,dev,sub_dir,"product");
901 if ((file = fopen(file_name, "r"))) {
902 if ((ptr = fgets(product, sizeof(product), file))) {
903 ptr = product + strlen(product) - 1;
904 if (ptr >= product && *ptr == '\n')
906 port->usb_product = strdup(product);
911 snprintf(file_name,sizeof(file_name),dir_name,dev,sub_dir,"serial");
912 if ((file = fopen(file_name, "r"))) {
913 if ((ptr = fgets(serial, sizeof(serial), file))) {
914 ptr = serial + strlen(serial) - 1;
915 if (ptr >= serial && *ptr == '\n')
917 port->usb_serial = strdup(serial);
925 port->description = strdup(dev);
927 if (port->transport == SP_TRANSPORT_BLUETOOTH) {
928 snprintf(file_name, sizeof(file_name), dir_name, dev, "", "address");
929 if ((file = fopen(file_name, "r"))) {
930 if ((ptr = fgets(baddr, sizeof(baddr), file))) {
931 ptr = baddr + strlen(baddr) - 1;
932 if (ptr >= baddr && *ptr == '\n')
934 port->bluetooth_address = strdup(baddr);
941 DEBUG("Port details not supported on this platform");
947 enum sp_return sp_get_port_by_name(const char *portname, struct sp_port **port_ptr)
949 struct sp_port *port;
953 TRACE("%s, %p", portname, port_ptr);
956 RETURN_ERROR(SP_ERR_ARG, "Null result pointer");
961 RETURN_ERROR(SP_ERR_ARG, "Null port name");
963 DEBUG("Building structure for port %s", portname);
965 if (!(port = malloc(sizeof(struct sp_port))))
966 RETURN_ERROR(SP_ERR_MEM, "Port structure malloc failed");
968 len = strlen(portname) + 1;
970 if (!(port->name = malloc(len))) {
972 RETURN_ERROR(SP_ERR_MEM, "Port name malloc failed");
975 memcpy(port->name, portname, len);
978 port->hdl = INVALID_HANDLE_VALUE;
983 if ((ret = sp_get_port_details(port)) != SP_OK) {
993 char *sp_get_port_name(const struct sp_port *port)
1000 RETURN_VALUE("%s", port->name);
1003 char *sp_get_port_description(struct sp_port *port)
1007 if (!port || !port->description)
1010 RETURN_VALUE("%s", port->description);
1013 enum sp_transport sp_get_port_transport(struct sp_port *port)
1018 RETURN_ERROR(SP_ERR_ARG, "Null port");
1020 RETURN_VALUE("%d", port->transport);
1023 enum sp_return sp_get_port_usb_bus_address(const struct sp_port *port,
1024 int *usb_bus, int *usb_address)
1029 RETURN_ERROR(SP_ERR_ARG, "Null port");
1030 if (port->transport != SP_TRANSPORT_USB)
1031 RETURN_ERROR(SP_ERR_ARG, "Port does not use USB transport");
1033 if (usb_bus) *usb_bus = port->usb_bus;
1034 if (usb_address) *usb_address = port->usb_address;
1039 enum sp_return sp_get_port_usb_vid_pid(const struct sp_port *port,
1040 int *usb_vid, int *usb_pid)
1045 RETURN_ERROR(SP_ERR_ARG, "Null port");
1046 if (port->transport != SP_TRANSPORT_USB)
1047 RETURN_ERROR(SP_ERR_ARG, "Port does not use USB transport");
1049 if (usb_vid) *usb_vid = port->usb_vid;
1050 if (usb_pid) *usb_pid = port->usb_pid;
1055 char *sp_get_port_usb_manufacturer(const struct sp_port *port)
1059 if (!port || port->transport != SP_TRANSPORT_USB || !port->usb_manufacturer)
1062 RETURN_VALUE("%s", port->usb_manufacturer);
1065 char *sp_get_port_usb_product(const struct sp_port *port)
1069 if (!port || port->transport != SP_TRANSPORT_USB || !port->usb_product)
1072 RETURN_VALUE("%s", port->usb_product);
1075 char *sp_get_port_usb_serial(const struct sp_port *port)
1079 if (!port || port->transport != SP_TRANSPORT_USB || !port->usb_serial)
1082 RETURN_VALUE("%s", port->usb_serial);
1085 char *sp_get_port_bluetooth_address(const struct sp_port *port)
1089 if (!port || port->transport != SP_TRANSPORT_BLUETOOTH
1090 || !port->bluetooth_address)
1093 RETURN_VALUE("%s", port->bluetooth_address);
1096 enum sp_return sp_get_port_handle(const struct sp_port *port, void *result_ptr)
1098 TRACE("%p, %p", port, result_ptr);
1101 RETURN_ERROR(SP_ERR_ARG, "Null port");
1104 HANDLE *handle_ptr = result_ptr;
1105 *handle_ptr = port->hdl;
1107 int *fd_ptr = result_ptr;
1114 enum sp_return sp_copy_port(const struct sp_port *port, struct sp_port **copy_ptr)
1116 TRACE("%p, %p", port, copy_ptr);
1119 RETURN_ERROR(SP_ERR_ARG, "Null result pointer");
1124 RETURN_ERROR(SP_ERR_ARG, "Null port");
1127 RETURN_ERROR(SP_ERR_ARG, "Null port name");
1129 DEBUG("Copying port structure");
1131 RETURN_VALUE("%p", sp_get_port_by_name(port->name, copy_ptr));
1134 void sp_free_port(struct sp_port *port)
1143 DEBUG("Freeing port structure");
1147 if (port->description)
1148 free(port->description);
1149 if (port->usb_manufacturer)
1150 free(port->usb_manufacturer);
1151 if (port->usb_product)
1152 free(port->usb_product);
1153 if (port->usb_serial)
1154 free(port->usb_serial);
1155 if (port->bluetooth_address)
1156 free(port->bluetooth_address);
1159 free(port->usb_path);
1167 static struct sp_port **list_append(struct sp_port **list, const char *portname)
1172 for (count = 0; list[count]; count++);
1173 if (!(tmp = realloc(list, sizeof(struct sp_port *) * (count + 2))))
1176 if (sp_get_port_by_name(portname, &list[count]) != SP_OK)
1178 list[count + 1] = NULL;
1182 sp_free_port_list(list);
1186 enum sp_return sp_list_ports(struct sp_port ***list_ptr)
1188 struct sp_port **list;
1189 int ret = SP_ERR_SUPP;
1191 TRACE("%p", list_ptr);
1194 RETURN_ERROR(SP_ERR_ARG, "Null result pointer");
1196 DEBUG("Enumerating ports");
1198 if (!(list = malloc(sizeof(struct sp_port **))))
1199 RETURN_ERROR(SP_ERR_MEM, "Port list malloc failed");
1205 TCHAR *value, *data;
1206 DWORD max_value_len, max_data_size, max_data_len;
1207 DWORD value_len, data_size, data_len;
1208 DWORD type, index = 0;
1214 DEBUG("Opening registry key");
1215 if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, _T("HARDWARE\\DEVICEMAP\\SERIALCOMM"),
1216 0, KEY_QUERY_VALUE, &key) != ERROR_SUCCESS) {
1217 SET_FAIL(ret, "RegOpenKeyEx() failed");
1220 DEBUG("Querying registry key value and data sizes");
1221 if (RegQueryInfoKey(key, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1222 &max_value_len, &max_data_size, NULL, NULL) != ERROR_SUCCESS) {
1223 SET_FAIL(ret, "RegQueryInfoKey() failed");
1226 max_data_len = max_data_size / sizeof(TCHAR);
1227 if (!(value = malloc((max_value_len + 1) * sizeof(TCHAR)))) {
1228 SET_ERROR(ret, SP_ERR_MEM, "registry value malloc failed");
1231 if (!(data = malloc((max_data_len + 1) * sizeof(TCHAR)))) {
1232 SET_ERROR(ret, SP_ERR_MEM, "registry data malloc failed");
1233 goto out_free_value;
1235 DEBUG("Iterating over values");
1237 value_len = max_value_len + 1,
1238 data_size = max_data_size,
1239 RegEnumValue(key, index, value, &value_len,
1240 NULL, &type, (LPBYTE)data, &data_size) == ERROR_SUCCESS)
1242 data_len = data_size / sizeof(TCHAR);
1243 data[data_len] = '\0';
1245 name_len = WideCharToMultiByte(CP_ACP, 0, data, -1, NULL, 0, NULL, NULL);
1247 name_len = data_len + 1;
1249 if (!(name = malloc(name_len))) {
1250 SET_ERROR(ret, SP_ERR_MEM, "registry port name malloc failed");
1254 WideCharToMultiByte(CP_ACP, 0, data, -1, name, name_len, NULL, NULL);
1258 if (type == REG_SZ) {
1259 DEBUG("Found port %s", name);
1260 if (!(list = list_append(list, name))) {
1261 SET_ERROR(ret, SP_ERR_MEM, "list append failed");
1276 CFMutableDictionaryRef classes;
1278 char path[PATH_MAX];
1285 DEBUG("Creating matching dictionary");
1286 if (!(classes = IOServiceMatching(kIOSerialBSDServiceValue))) {
1287 SET_FAIL(ret, "IOServiceMatching() failed");
1291 DEBUG("Getting matching services");
1292 if (IOServiceGetMatchingServices(kIOMasterPortDefault, classes,
1293 &iter) != KERN_SUCCESS) {
1294 SET_FAIL(ret, "IOServiceGetMatchingServices() failed");
1298 DEBUG("Iterating over results");
1299 while ((port = IOIteratorNext(iter))) {
1300 cf_path = IORegistryEntryCreateCFProperty(port,
1301 CFSTR(kIOCalloutDeviceKey), kCFAllocatorDefault, 0);
1303 result = CFStringGetCString(cf_path, path, sizeof(path),
1304 kCFStringEncodingASCII);
1307 DEBUG("Found port %s", path);
1308 if (!(list = list_append(list, path))) {
1309 SET_ERROR(ret, SP_ERR_MEM, "list append failed");
1310 IOObjectRelease(port);
1315 IOObjectRelease(port);
1318 IOObjectRelease(iter);
1322 char name[PATH_MAX], target[PATH_MAX];
1323 struct dirent entry, *result;
1324 struct serial_struct serial_info;
1325 int len, fd, ioctl_result;
1330 DEBUG("Enumerating tty devices");
1331 if (!(dir = opendir("/sys/class/tty")))
1332 RETURN_FAIL("could not open /sys/class/tty");
1334 DEBUG("Iterating over results");
1335 while (!readdir_r(dir, &entry, &result) && result) {
1336 len = readlinkat(dirfd(dir), entry.d_name, target, sizeof(target));
1337 if (len <= 0 || len >= (int) sizeof(target)-1)
1340 if (strstr(target, "virtual"))
1342 snprintf(name, sizeof(name), "/dev/%s", entry.d_name);
1343 DEBUG("Found device %s", name);
1344 if (strstr(target, "serial8250")) {
1345 /* The serial8250 driver has a hardcoded number of ports.
1346 * The only way to tell which actually exist on a given system
1347 * is to try to open them and make an ioctl call. */
1348 DEBUG("serial8250 device, attempting to open");
1349 if ((fd = open(name, O_RDWR | O_NONBLOCK | O_NOCTTY)) < 0) {
1350 DEBUG("open failed, skipping");
1353 ioctl_result = ioctl(fd, TIOCGSERIAL, &serial_info);
1355 if (ioctl_result != 0) {
1356 DEBUG("ioctl failed, skipping");
1359 if (serial_info.type == PORT_UNKNOWN) {
1360 DEBUG("port type is unknown, skipping");
1364 DEBUG("Found port %s", name);
1365 list = list_append(list, name);
1367 SET_ERROR(ret, SP_ERR_MEM, "list append failed");
1379 DEBUG_ERROR(SP_ERR_SUPP, "Enumeration not supported on this platform");
1382 sp_free_port_list(list);
1388 void sp_free_port_list(struct sp_port **list)
1399 DEBUG("Freeing port list");
1401 for (i = 0; list[i]; i++)
1402 sp_free_port(list[i]);
1408 #define CHECK_PORT() do { \
1410 RETURN_ERROR(SP_ERR_ARG, "Null port"); \
1411 if (port->name == NULL) \
1412 RETURN_ERROR(SP_ERR_ARG, "Null port name"); \
1415 #define CHECK_PORT_HANDLE() do { \
1416 if (port->hdl == INVALID_HANDLE_VALUE) \
1417 RETURN_ERROR(SP_ERR_ARG, "Invalid port handle"); \
1420 #define CHECK_PORT_HANDLE() do { \
1422 RETURN_ERROR(SP_ERR_ARG, "Invalid port fd"); \
1425 #define CHECK_OPEN_PORT() do { \
1427 CHECK_PORT_HANDLE(); \
1430 enum sp_return sp_open(struct sp_port *port, enum sp_mode flags)
1432 struct port_data data;
1433 struct sp_port_config config;
1436 TRACE("%p, 0x%x", port, flags);
1440 if (flags > (SP_MODE_READ | SP_MODE_WRITE))
1441 RETURN_ERROR(SP_ERR_ARG, "Invalid flags");
1443 DEBUG("Opening port %s", port->name);
1446 DWORD desired_access = 0, flags_and_attributes = 0, errors;
1447 char *escaped_port_name;
1450 /* Prefix port name with '\\.\' to work with ports above COM9. */
1451 if (!(escaped_port_name = malloc(strlen(port->name) + 5)))
1452 RETURN_ERROR(SP_ERR_MEM, "Escaped port name malloc failed");
1453 sprintf(escaped_port_name, "\\\\.\\%s", port->name);
1455 /* Map 'flags' to the OS-specific settings. */
1456 flags_and_attributes = FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED;
1457 if (flags & SP_MODE_READ)
1458 desired_access |= GENERIC_READ;
1459 if (flags & SP_MODE_WRITE)
1460 desired_access |= GENERIC_WRITE;
1462 port->hdl = CreateFile(escaped_port_name, desired_access, 0, 0,
1463 OPEN_EXISTING, flags_and_attributes, 0);
1465 free(escaped_port_name);
1467 if (port->hdl == INVALID_HANDLE_VALUE)
1468 RETURN_FAIL("port CreateFile() failed");
1470 /* All timeouts initially disabled. */
1471 port->timeouts.ReadIntervalTimeout = 0;
1472 port->timeouts.ReadTotalTimeoutMultiplier = 0;
1473 port->timeouts.ReadTotalTimeoutConstant = 0;
1474 port->timeouts.WriteTotalTimeoutMultiplier = 0;
1475 port->timeouts.WriteTotalTimeoutConstant = 0;
1477 if (SetCommTimeouts(port->hdl, &port->timeouts) == 0) {
1479 RETURN_FAIL("SetCommTimeouts() failed");
1482 /* Prepare OVERLAPPED structures. */
1483 #define INIT_OVERLAPPED(ovl) do { \
1484 memset(&port->ovl, 0, sizeof(port->ovl)); \
1485 port->ovl.hEvent = INVALID_HANDLE_VALUE; \
1486 if ((port->ovl.hEvent = CreateEvent(NULL, TRUE, TRUE, NULL)) \
1487 == INVALID_HANDLE_VALUE) { \
1489 RETURN_FAIL(#ovl "CreateEvent() failed"); \
1493 INIT_OVERLAPPED(read_ovl);
1494 INIT_OVERLAPPED(write_ovl);
1495 INIT_OVERLAPPED(wait_ovl);
1497 /* Set event mask for RX and error events. */
1498 if (SetCommMask(port->hdl, EV_RXCHAR | EV_ERR) == 0) {
1500 RETURN_FAIL("SetCommMask() failed");
1503 /* Start background operation for RX and error events. */
1504 if (WaitCommEvent(port->hdl, &port->events, &port->wait_ovl) == 0) {
1505 if (GetLastError() != ERROR_IO_PENDING) {
1507 RETURN_FAIL("WaitCommEvent() failed");
1511 port->writing = FALSE;
1514 int flags_local = O_NONBLOCK | O_NOCTTY;
1516 /* Map 'flags' to the OS-specific settings. */
1517 if (flags & (SP_MODE_READ | SP_MODE_WRITE))
1518 flags_local |= O_RDWR;
1519 else if (flags & SP_MODE_READ)
1520 flags_local |= O_RDONLY;
1521 else if (flags & SP_MODE_WRITE)
1522 flags_local |= O_WRONLY;
1524 if ((port->fd = open(port->name, flags_local)) < 0)
1525 RETURN_FAIL("open() failed");
1528 ret = get_config(port, &data, &config);
1532 RETURN_CODEVAL(ret);
1535 /* Set sane port settings. */
1537 data.dcb.fBinary = TRUE;
1538 data.dcb.fDsrSensitivity = FALSE;
1539 data.dcb.fErrorChar = FALSE;
1540 data.dcb.fNull = FALSE;
1541 data.dcb.fAbortOnError = TRUE;
1543 /* Turn off all fancy termios tricks, give us a raw channel. */
1544 data.term.c_iflag &= ~(IGNBRK | BRKINT | PARMRK | ISTRIP | INLCR | IGNCR | ICRNL | IMAXBEL);
1546 data.term.c_iflag &= ~IUCLC;
1548 data.term.c_oflag &= ~(OPOST | ONLCR | OCRNL | ONOCR | ONLRET);
1550 data.term.c_oflag &= ~OLCUC;
1553 data.term.c_oflag &= ~NLDLY;
1556 data.term.c_oflag &= ~CRDLY;
1559 data.term.c_oflag &= ~TABDLY;
1562 data.term.c_oflag &= ~BSDLY;
1565 data.term.c_oflag &= ~VTDLY;
1568 data.term.c_oflag &= ~FFDLY;
1571 data.term.c_oflag &= ~OFILL;
1573 data.term.c_lflag &= ~(ISIG | ICANON | ECHO | IEXTEN);
1574 data.term.c_cc[VMIN] = 0;
1575 data.term.c_cc[VTIME] = 0;
1577 /* Ignore modem status lines; enable receiver; leave control lines alone on close. */
1578 data.term.c_cflag |= (CLOCAL | CREAD | HUPCL);
1582 if (ClearCommError(port->hdl, &errors, &status) == 0)
1583 RETURN_FAIL("ClearCommError() failed");
1586 ret = set_config(port, &data, &config);
1590 RETURN_CODEVAL(ret);
1596 enum sp_return sp_close(struct sp_port *port)
1602 DEBUG("Closing port %s", port->name);
1605 /* Returns non-zero upon success, 0 upon failure. */
1606 if (CloseHandle(port->hdl) == 0)
1607 RETURN_FAIL("port CloseHandle() failed");
1608 port->hdl = INVALID_HANDLE_VALUE;
1610 /* Close event handles for overlapped structures. */
1611 #define CLOSE_OVERLAPPED(ovl) do { \
1612 if (port->ovl.hEvent != INVALID_HANDLE_VALUE && \
1613 CloseHandle(port->ovl.hEvent) == 0) \
1614 RETURN_FAIL(# ovl "event CloseHandle() failed"); \
1616 CLOSE_OVERLAPPED(read_ovl);
1617 CLOSE_OVERLAPPED(write_ovl);
1618 CLOSE_OVERLAPPED(wait_ovl);
1621 /* Returns 0 upon success, -1 upon failure. */
1622 if (close(port->fd) == -1)
1623 RETURN_FAIL("close() failed");
1630 enum sp_return sp_flush(struct sp_port *port, enum sp_buffer buffers)
1632 TRACE("%p, 0x%x", port, buffers);
1636 if (buffers > SP_BUF_BOTH)
1637 RETURN_ERROR(SP_ERR_ARG, "Invalid buffer selection");
1639 const char *buffer_names[] = {"no", "input", "output", "both"};
1641 DEBUG("Flushing %s buffers on port %s", buffer_names[buffers], port->name);
1645 if (buffers & SP_BUF_INPUT)
1646 flags |= PURGE_RXCLEAR;
1647 if (buffers & SP_BUF_OUTPUT)
1648 flags |= PURGE_TXCLEAR;
1650 /* Returns non-zero upon success, 0 upon failure. */
1651 if (PurgeComm(port->hdl, flags) == 0)
1652 RETURN_FAIL("PurgeComm() failed");
1655 if (buffers & SP_BUF_BOTH)
1657 else if (buffers & SP_BUF_INPUT)
1659 else if (buffers & SP_BUF_OUTPUT)
1662 /* Returns 0 upon success, -1 upon failure. */
1663 if (tcflush(port->fd, flags) < 0)
1664 RETURN_FAIL("tcflush() failed");
1669 enum sp_return sp_drain(struct sp_port *port)
1675 DEBUG("Draining port %s", port->name);
1678 /* Returns non-zero upon success, 0 upon failure. */
1679 if (FlushFileBuffers(port->hdl) == 0)
1680 RETURN_FAIL("FlushFileBuffers() failed");
1687 result = ioctl(port->fd, TCSBRK, &arg);
1689 result = tcdrain(port->fd);
1692 if (errno == EINTR) {
1693 DEBUG("tcdrain() was interrupted");
1696 RETURN_FAIL("tcdrain() failed");
1705 enum sp_return sp_blocking_write(struct sp_port *port, const void *buf, size_t count, unsigned int timeout)
1707 TRACE("%p, %p, %d, %d", port, buf, count, timeout);
1712 RETURN_ERROR(SP_ERR_ARG, "Null buffer");
1715 DEBUG("Writing %d bytes to port %s, timeout %d ms", count, port->name, timeout);
1717 DEBUG("Writing %d bytes to port %s, no timeout", count, port->name);
1720 RETURN_VALUE("0", 0);
1723 DWORD bytes_written = 0;
1726 /* Wait for previous non-blocking write to complete, if any. */
1727 if (port->writing) {
1728 DEBUG("Waiting for previous write to complete");
1729 result = GetOverlappedResult(port->hdl, &port->write_ovl, &bytes_written, TRUE);
1732 RETURN_FAIL("Previous write failed to complete");
1733 DEBUG("Previous write completed");
1737 port->timeouts.WriteTotalTimeoutConstant = timeout;
1738 if (SetCommTimeouts(port->hdl, &port->timeouts) == 0)
1739 RETURN_FAIL("SetCommTimeouts() failed");
1742 if (WriteFile(port->hdl, buf, count, NULL, &port->write_ovl) == 0) {
1743 if (GetLastError() == ERROR_IO_PENDING) {
1744 DEBUG("Waiting for write to complete");
1745 GetOverlappedResult(port->hdl, &port->write_ovl, &bytes_written, TRUE);
1746 DEBUG("Write completed, %d/%d bytes written", bytes_written, count);
1747 RETURN_VALUE("%d", bytes_written);
1749 RETURN_FAIL("WriteFile() failed");
1752 DEBUG("Write completed immediately");
1753 RETURN_VALUE("%d", count);
1756 size_t bytes_written = 0;
1757 unsigned char *ptr = (unsigned char *) buf;
1758 struct timeval start, delta, now, end = {0, 0};
1763 /* Get time at start of operation. */
1764 gettimeofday(&start, NULL);
1765 /* Define duration of timeout. */
1766 delta.tv_sec = timeout / 1000;
1767 delta.tv_usec = (timeout % 1000) * 1000;
1768 /* Calculate time at which we should give up. */
1769 timeradd(&start, &delta, &end);
1772 /* Loop until we have written the requested number of bytes. */
1773 while (bytes_written < count)
1775 /* Wait until space is available. */
1777 FD_SET(port->fd, &fds);
1779 gettimeofday(&now, NULL);
1780 if (timercmp(&now, &end, >)) {
1781 DEBUG("write timed out");
1782 RETURN_VALUE("%d", bytes_written);
1784 timersub(&end, &now, &delta);
1786 result = select(port->fd + 1, NULL, &fds, NULL, timeout ? &delta : NULL);
1788 if (errno == EINTR) {
1789 DEBUG("select() call was interrupted, repeating");
1792 RETURN_FAIL("select() failed");
1794 } else if (result == 0) {
1795 DEBUG("write timed out");
1796 RETURN_VALUE("%d", bytes_written);
1800 result = write(port->fd, ptr, count - bytes_written);
1803 if (errno == EAGAIN)
1804 /* This shouldn't happen because we did a select() first, but handle anyway. */
1807 /* This is an actual failure. */
1808 RETURN_FAIL("write() failed");
1811 bytes_written += result;
1815 RETURN_VALUE("%d", bytes_written);
1819 enum sp_return sp_nonblocking_write(struct sp_port *port, const void *buf, size_t count)
1821 TRACE("%p, %p, %d", port, buf, count);
1826 RETURN_ERROR(SP_ERR_ARG, "Null buffer");
1828 DEBUG("Writing up to %d bytes to port %s", count, port->name);
1831 RETURN_VALUE("0", 0);
1835 BYTE *ptr = (BYTE *) buf;
1837 /* Check whether previous write is complete. */
1838 if (port->writing) {
1839 if (HasOverlappedIoCompleted(&port->write_ovl)) {
1840 DEBUG("Previous write completed");
1843 DEBUG("Previous write not complete");
1844 /* Can't take a new write until the previous one finishes. */
1845 RETURN_VALUE("0", 0);
1850 port->timeouts.WriteTotalTimeoutConstant = 0;
1851 if (SetCommTimeouts(port->hdl, &port->timeouts) == 0)
1852 RETURN_FAIL("SetCommTimeouts() failed");
1854 /* Keep writing data until the OS has to actually start an async IO for it.
1855 * At that point we know the buffer is full. */
1856 while (written < count)
1858 /* Copy first byte of user buffer. */
1859 port->pending_byte = *ptr++;
1861 /* Start asynchronous write. */
1862 if (WriteFile(port->hdl, &port->pending_byte, 1, NULL, &port->write_ovl) == 0) {
1863 if (GetLastError() == ERROR_IO_PENDING) {
1864 if (HasOverlappedIoCompleted(&port->write_ovl)) {
1865 DEBUG("Asynchronous write completed immediately");
1870 DEBUG("Asynchronous write running");
1872 RETURN_VALUE("%d", ++written);
1875 /* Actual failure of some kind. */
1876 RETURN_FAIL("WriteFile() failed");
1879 DEBUG("Single byte written immediately");
1884 DEBUG("All bytes written immediately");
1886 RETURN_VALUE("%d", written);
1888 /* Returns the number of bytes written, or -1 upon failure. */
1889 ssize_t written = write(port->fd, buf, count);
1892 RETURN_FAIL("write() failed");
1894 RETURN_VALUE("%d", written);
1898 enum sp_return sp_blocking_read(struct sp_port *port, void *buf, size_t count, unsigned int timeout)
1900 TRACE("%p, %p, %d, %d", port, buf, count, timeout);
1905 RETURN_ERROR(SP_ERR_ARG, "Null buffer");
1908 DEBUG("Reading %d bytes from port %s, timeout %d ms", count, port->name, timeout);
1910 DEBUG("Reading %d bytes from port %s, no timeout", count, port->name);
1913 RETURN_VALUE("0", 0);
1916 DWORD bytes_read = 0;
1919 port->timeouts.ReadIntervalTimeout = 0;
1920 port->timeouts.ReadTotalTimeoutConstant = timeout;
1921 if (SetCommTimeouts(port->hdl, &port->timeouts) == 0)
1922 RETURN_FAIL("SetCommTimeouts() failed");
1925 if (ReadFile(port->hdl, buf, count, NULL, &port->read_ovl) == 0) {
1926 if (GetLastError() == ERROR_IO_PENDING) {
1927 DEBUG("Waiting for read to complete");
1928 GetOverlappedResult(port->hdl, &port->read_ovl, &bytes_read, TRUE);
1929 DEBUG("Read completed, %d/%d bytes read", bytes_read, count);
1931 RETURN_FAIL("ReadFile() failed");
1934 DEBUG("Read completed immediately");
1938 /* Start background operation for subsequent events. */
1939 if (WaitCommEvent(port->hdl, &port->events, &port->wait_ovl) == 0) {
1940 if (GetLastError() != ERROR_IO_PENDING)
1941 RETURN_FAIL("WaitCommEvent() failed");
1944 RETURN_VALUE("%d", bytes_read);
1947 size_t bytes_read = 0;
1948 unsigned char *ptr = (unsigned char *) buf;
1949 struct timeval start, delta, now, end = {0, 0};
1954 /* Get time at start of operation. */
1955 gettimeofday(&start, NULL);
1956 /* Define duration of timeout. */
1957 delta.tv_sec = timeout / 1000;
1958 delta.tv_usec = (timeout % 1000) * 1000;
1959 /* Calculate time at which we should give up. */
1960 timeradd(&start, &delta, &end);
1963 /* Loop until we have the requested number of bytes. */
1964 while (bytes_read < count)
1966 /* Wait until data is available. */
1968 FD_SET(port->fd, &fds);
1970 gettimeofday(&now, NULL);
1971 if (timercmp(&now, &end, >))
1972 /* Timeout has expired. */
1973 RETURN_VALUE("%d", bytes_read);
1974 timersub(&end, &now, &delta);
1976 result = select(port->fd + 1, &fds, NULL, NULL, timeout ? &delta : NULL);
1978 if (errno == EINTR) {
1979 DEBUG("select() call was interrupted, repeating");
1982 RETURN_FAIL("select() failed");
1984 } else if (result == 0) {
1985 DEBUG("read timed out");
1986 RETURN_VALUE("%d", bytes_read);
1990 result = read(port->fd, ptr, count - bytes_read);
1993 if (errno == EAGAIN)
1994 /* This shouldn't happen because we did a select() first, but handle anyway. */
1997 /* This is an actual failure. */
1998 RETURN_FAIL("read() failed");
2001 bytes_read += result;
2005 RETURN_VALUE("%d", bytes_read);
2009 enum sp_return sp_nonblocking_read(struct sp_port *port, void *buf, size_t count)
2011 TRACE("%p, %p, %d", port, buf, count);
2016 RETURN_ERROR(SP_ERR_ARG, "Null buffer");
2018 DEBUG("Reading up to %d bytes from port %s", count, port->name);
2024 port->timeouts.ReadIntervalTimeout = MAXDWORD;
2025 port->timeouts.ReadTotalTimeoutConstant = 0;
2026 if (SetCommTimeouts(port->hdl, &port->timeouts) == 0)
2027 RETURN_FAIL("SetCommTimeouts() failed");
2030 if (ReadFile(port->hdl, buf, count, NULL, &port->read_ovl) == 0)
2031 RETURN_FAIL("ReadFile() failed");
2033 /* Get number of bytes read. */
2034 if (GetOverlappedResult(port->hdl, &port->read_ovl, &bytes_read, TRUE) == 0)
2035 RETURN_FAIL("GetOverlappedResult() failed");
2037 if (bytes_read > 0) {
2038 /* Start background operation for subsequent events. */
2039 if (WaitCommEvent(port->hdl, &port->events, &port->wait_ovl) == 0) {
2040 if (GetLastError() != ERROR_IO_PENDING)
2041 RETURN_FAIL("WaitCommEvent() failed");
2045 RETURN_VALUE("%d", bytes_read);
2049 /* Returns the number of bytes read, or -1 upon failure. */
2050 if ((bytes_read = read(port->fd, buf, count)) < 0) {
2051 if (errno == EAGAIN)
2052 /* No bytes available. */
2055 /* This is an actual failure. */
2056 RETURN_FAIL("read() failed");
2058 RETURN_VALUE("%d", bytes_read);
2062 enum sp_return sp_input_waiting(struct sp_port *port)
2068 DEBUG("Checking input bytes waiting on port %s", port->name);
2074 if (ClearCommError(port->hdl, &errors, &comstat) == 0)
2075 RETURN_FAIL("ClearCommError() failed");
2076 RETURN_VALUE("%d", comstat.cbInQue);
2079 if (ioctl(port->fd, TIOCINQ, &bytes_waiting) < 0)
2080 RETURN_FAIL("TIOCINQ ioctl failed");
2081 RETURN_VALUE("%d", bytes_waiting);
2085 enum sp_return sp_output_waiting(struct sp_port *port)
2091 DEBUG("Checking output bytes waiting on port %s", port->name);
2097 if (ClearCommError(port->hdl, &errors, &comstat) == 0)
2098 RETURN_FAIL("ClearCommError() failed");
2099 RETURN_VALUE("%d", comstat.cbOutQue);
2102 if (ioctl(port->fd, TIOCOUTQ, &bytes_waiting) < 0)
2103 RETURN_FAIL("TIOCOUTQ ioctl failed");
2104 RETURN_VALUE("%d", bytes_waiting);
2108 enum sp_return sp_new_event_set(struct sp_event_set **result_ptr)
2110 struct sp_event_set *result;
2112 TRACE("%p", result_ptr);
2115 RETURN_ERROR(SP_ERR_ARG, "Null result");
2119 if (!(result = malloc(sizeof(struct sp_event_set))))
2120 RETURN_ERROR(SP_ERR_MEM, "sp_event_set malloc() failed");
2122 memset(result, 0, sizeof(struct sp_event_set));
2124 *result_ptr = result;
2129 static enum sp_return add_handle(struct sp_event_set *event_set,
2130 event_handle handle, enum sp_event mask)
2133 enum sp_event *new_masks;
2135 TRACE("%p, %d, %d", event_set, handle, mask);
2137 if (!(new_handles = realloc(event_set->handles,
2138 sizeof(event_handle) * (event_set->count + 1))))
2139 RETURN_ERROR(SP_ERR_MEM, "handle array realloc() failed");
2141 if (!(new_masks = realloc(event_set->masks,
2142 sizeof(enum sp_event) * (event_set->count + 1))))
2143 RETURN_ERROR(SP_ERR_MEM, "mask array realloc() failed");
2145 event_set->handles = new_handles;
2146 event_set->masks = new_masks;
2148 ((event_handle *) event_set->handles)[event_set->count] = handle;
2149 event_set->masks[event_set->count] = mask;
2156 enum sp_return sp_add_port_events(struct sp_event_set *event_set,
2157 const struct sp_port *port, enum sp_event mask)
2159 TRACE("%p, %p, %d", event_set, port, mask);
2162 RETURN_ERROR(SP_ERR_ARG, "Null event set");
2165 RETURN_ERROR(SP_ERR_ARG, "Null port");
2167 if (mask > (SP_EVENT_RX_READY | SP_EVENT_TX_READY | SP_EVENT_ERROR))
2168 RETURN_ERROR(SP_ERR_ARG, "Invalid event mask");
2174 enum sp_event handle_mask;
2175 if ((handle_mask = mask & SP_EVENT_TX_READY))
2176 TRY(add_handle(event_set, port->write_ovl.hEvent, handle_mask));
2177 if ((handle_mask = mask & (SP_EVENT_RX_READY | SP_EVENT_ERROR)))
2178 TRY(add_handle(event_set, port->wait_ovl.hEvent, handle_mask));
2180 TRY(add_handle(event_set, port->fd, mask));
2186 void sp_free_event_set(struct sp_event_set *event_set)
2188 TRACE("%p", event_set);
2191 DEBUG("Null event set");
2195 DEBUG("Freeing event set");
2197 if (event_set->handles)
2198 free(event_set->handles);
2199 if (event_set->masks)
2200 free(event_set->masks);
2207 enum sp_return sp_wait(struct sp_event_set *event_set, unsigned int timeout)
2209 TRACE("%p, %d", event_set, timeout);
2212 RETURN_ERROR(SP_ERR_ARG, "Null event set");
2215 if (WaitForMultipleObjects(event_set->count, event_set->handles, FALSE,
2216 timeout ? timeout : INFINITE) == WAIT_FAILED)
2217 RETURN_FAIL("WaitForMultipleObjects() failed");
2221 struct timeval start, delta, now, end = {0, 0};
2222 int result, timeout_remaining;
2223 struct pollfd *pollfds;
2226 if (!(pollfds = malloc(sizeof(struct pollfd) * event_set->count)))
2227 RETURN_ERROR(SP_ERR_MEM, "pollfds malloc() failed");
2229 for (i = 0; i < event_set->count; i++) {
2230 pollfds[i].fd = ((int *) event_set->handles)[i];
2231 pollfds[i].events = 0;
2232 pollfds[i].revents = 0;
2233 if (event_set->masks[i] & SP_EVENT_RX_READY)
2234 pollfds[i].events |= POLLIN;
2235 if (event_set->masks[i] & SP_EVENT_TX_READY)
2236 pollfds[i].events |= POLLOUT;
2237 if (event_set->masks[i] & SP_EVENT_ERROR)
2238 pollfds[i].events |= POLLERR;
2242 /* Get time at start of operation. */
2243 gettimeofday(&start, NULL);
2244 /* Define duration of timeout. */
2245 delta.tv_sec = timeout / 1000;
2246 delta.tv_usec = (timeout % 1000) * 1000;
2247 /* Calculate time at which we should give up. */
2248 timeradd(&start, &delta, &end);
2251 /* Loop until an event occurs. */
2255 gettimeofday(&now, NULL);
2256 if (timercmp(&now, &end, >)) {
2257 DEBUG("wait timed out");
2260 timersub(&end, &now, &delta);
2261 timeout_remaining = delta.tv_sec * 1000 + delta.tv_usec / 1000;
2264 result = poll(pollfds, event_set->count, timeout ? timeout_remaining : -1);
2267 if (errno == EINTR) {
2268 DEBUG("poll() call was interrupted, repeating");
2272 RETURN_FAIL("poll() failed");
2274 } else if (result == 0) {
2275 DEBUG("poll() timed out");
2278 DEBUG("poll() completed");
2288 #ifdef USE_TERMIOS_SPEED
2289 static enum sp_return get_baudrate(int fd, int *baudrate)
2293 TRACE("%d, %p", fd, baudrate);
2295 DEBUG("Getting baud rate");
2297 if (!(data = malloc(get_termios_size())))
2298 RETURN_ERROR(SP_ERR_MEM, "termios malloc failed");
2300 if (ioctl(fd, get_termios_get_ioctl(), data) < 0) {
2302 RETURN_FAIL("getting termios failed");
2305 *baudrate = get_termios_speed(data);
2312 static enum sp_return set_baudrate(int fd, int baudrate)
2316 TRACE("%d, %d", fd, baudrate);
2318 DEBUG("Getting baud rate");
2320 if (!(data = malloc(get_termios_size())))
2321 RETURN_ERROR(SP_ERR_MEM, "termios malloc failed");
2323 if (ioctl(fd, get_termios_get_ioctl(), data) < 0) {
2325 RETURN_FAIL("getting termios failed");
2328 DEBUG("Setting baud rate");
2330 set_termios_speed(data, baudrate);
2332 if (ioctl(fd, get_termios_set_ioctl(), data) < 0) {
2334 RETURN_FAIL("setting termios failed");
2341 #endif /* USE_TERMIOS_SPEED */
2344 static enum sp_return get_flow(int fd, struct port_data *data)
2348 TRACE("%d, %p", fd, data);
2350 DEBUG("Getting advanced flow control");
2352 if (!(termx = malloc(get_termiox_size())))
2353 RETURN_ERROR(SP_ERR_MEM, "termiox malloc failed");
2355 if (ioctl(fd, TCGETX, termx) < 0) {
2357 RETURN_FAIL("getting termiox failed");
2360 get_termiox_flow(termx, &data->rts_flow, &data->cts_flow,
2361 &data->dtr_flow, &data->dsr_flow);
2368 static enum sp_return set_flow(int fd, struct port_data *data)
2372 TRACE("%d, %p", fd, data);
2374 DEBUG("Getting advanced flow control");
2376 if (!(termx = malloc(get_termiox_size())))
2377 RETURN_ERROR(SP_ERR_MEM, "termiox malloc failed");
2379 if (ioctl(fd, TCGETX, termx) < 0) {
2381 RETURN_FAIL("getting termiox failed");
2384 DEBUG("Setting advanced flow control");
2386 set_termiox_flow(termx, data->rts_flow, data->cts_flow,
2387 data->dtr_flow, data->dsr_flow);
2389 if (ioctl(fd, TCSETX, termx) < 0) {
2391 RETURN_FAIL("setting termiox failed");
2398 #endif /* USE_TERMIOX */
2400 static enum sp_return get_config(struct sp_port *port, struct port_data *data,
2401 struct sp_port_config *config)
2405 TRACE("%p, %p, %p", port, data, config);
2407 DEBUG("Getting configuration for port %s", port->name);
2410 if (!GetCommState(port->hdl, &data->dcb))
2411 RETURN_FAIL("GetCommState() failed");
2413 for (i = 0; i < NUM_STD_BAUDRATES; i++) {
2414 if (data->dcb.BaudRate == std_baudrates[i].index) {
2415 config->baudrate = std_baudrates[i].value;
2420 if (i == NUM_STD_BAUDRATES)
2421 /* BaudRate field can be either an index or a custom baud rate. */
2422 config->baudrate = data->dcb.BaudRate;
2424 config->bits = data->dcb.ByteSize;
2426 if (data->dcb.fParity)
2427 switch (data->dcb.Parity) {
2429 config->parity = SP_PARITY_NONE;
2432 config->parity = SP_PARITY_ODD;
2435 config->parity = SP_PARITY_EVEN;
2438 config->parity = SP_PARITY_MARK;
2441 config->parity = SP_PARITY_SPACE;
2444 config->parity = -1;
2447 config->parity = SP_PARITY_NONE;
2449 switch (data->dcb.StopBits) {
2451 config->stopbits = 1;
2454 config->stopbits = 2;
2457 config->stopbits = -1;
2460 switch (data->dcb.fRtsControl) {
2461 case RTS_CONTROL_DISABLE:
2462 config->rts = SP_RTS_OFF;
2464 case RTS_CONTROL_ENABLE:
2465 config->rts = SP_RTS_ON;
2467 case RTS_CONTROL_HANDSHAKE:
2468 config->rts = SP_RTS_FLOW_CONTROL;
2474 config->cts = data->dcb.fOutxCtsFlow ? SP_CTS_FLOW_CONTROL : SP_CTS_IGNORE;
2476 switch (data->dcb.fDtrControl) {
2477 case DTR_CONTROL_DISABLE:
2478 config->dtr = SP_DTR_OFF;
2480 case DTR_CONTROL_ENABLE:
2481 config->dtr = SP_DTR_ON;
2483 case DTR_CONTROL_HANDSHAKE:
2484 config->dtr = SP_DTR_FLOW_CONTROL;
2490 config->dsr = data->dcb.fOutxDsrFlow ? SP_DSR_FLOW_CONTROL : SP_DSR_IGNORE;
2492 if (data->dcb.fInX) {
2493 if (data->dcb.fOutX)
2494 config->xon_xoff = SP_XONXOFF_INOUT;
2496 config->xon_xoff = SP_XONXOFF_IN;
2498 if (data->dcb.fOutX)
2499 config->xon_xoff = SP_XONXOFF_OUT;
2501 config->xon_xoff = SP_XONXOFF_DISABLED;
2506 if (tcgetattr(port->fd, &data->term) < 0)
2507 RETURN_FAIL("tcgetattr() failed");
2509 if (ioctl(port->fd, TIOCMGET, &data->controlbits) < 0)
2510 RETURN_FAIL("TIOCMGET ioctl failed");
2513 int ret = get_flow(port->fd, data);
2515 if (ret == SP_ERR_FAIL && errno == EINVAL)
2516 data->termiox_supported = 0;
2518 RETURN_CODEVAL(ret);
2520 data->termiox_supported = 1;
2522 data->termiox_supported = 0;
2525 for (i = 0; i < NUM_STD_BAUDRATES; i++) {
2526 if (cfgetispeed(&data->term) == std_baudrates[i].index) {
2527 config->baudrate = std_baudrates[i].value;
2532 if (i == NUM_STD_BAUDRATES) {
2534 config->baudrate = (int)data->term.c_ispeed;
2535 #elif defined(USE_TERMIOS_SPEED)
2536 TRY(get_baudrate(port->fd, &config->baudrate));
2538 config->baudrate = -1;
2542 switch (data->term.c_cflag & CSIZE) {
2559 if (!(data->term.c_cflag & PARENB) && (data->term.c_iflag & IGNPAR))
2560 config->parity = SP_PARITY_NONE;
2561 else if (!(data->term.c_cflag & PARENB) || (data->term.c_iflag & IGNPAR))
2562 config->parity = -1;
2564 else if (data->term.c_cflag & CMSPAR)
2565 config->parity = (data->term.c_cflag & PARODD) ? SP_PARITY_MARK : SP_PARITY_SPACE;
2568 config->parity = (data->term.c_cflag & PARODD) ? SP_PARITY_ODD : SP_PARITY_EVEN;
2570 config->stopbits = (data->term.c_cflag & CSTOPB) ? 2 : 1;
2572 if (data->term.c_cflag & CRTSCTS) {
2573 config->rts = SP_RTS_FLOW_CONTROL;
2574 config->cts = SP_CTS_FLOW_CONTROL;
2576 if (data->termiox_supported && data->rts_flow)
2577 config->rts = SP_RTS_FLOW_CONTROL;
2579 config->rts = (data->controlbits & TIOCM_RTS) ? SP_RTS_ON : SP_RTS_OFF;
2581 config->cts = (data->termiox_supported && data->cts_flow) ?
2582 SP_CTS_FLOW_CONTROL : SP_CTS_IGNORE;
2585 if (data->termiox_supported && data->dtr_flow)
2586 config->dtr = SP_DTR_FLOW_CONTROL;
2588 config->dtr = (data->controlbits & TIOCM_DTR) ? SP_DTR_ON : SP_DTR_OFF;
2590 config->dsr = (data->termiox_supported && data->dsr_flow) ?
2591 SP_DSR_FLOW_CONTROL : SP_DSR_IGNORE;
2593 if (data->term.c_iflag & IXOFF) {
2594 if (data->term.c_iflag & IXON)
2595 config->xon_xoff = SP_XONXOFF_INOUT;
2597 config->xon_xoff = SP_XONXOFF_IN;
2599 if (data->term.c_iflag & IXON)
2600 config->xon_xoff = SP_XONXOFF_OUT;
2602 config->xon_xoff = SP_XONXOFF_DISABLED;
2609 static enum sp_return set_config(struct sp_port *port, struct port_data *data,
2610 const struct sp_port_config *config)
2614 BAUD_TYPE baud_nonstd;
2618 #ifdef USE_TERMIOS_SPEED
2619 int baud_nonstd = 0;
2622 TRACE("%p, %p, %p", port, data, config);
2624 DEBUG("Setting configuration for port %s", port->name);
2627 if (config->baudrate >= 0) {
2628 for (i = 0; i < NUM_STD_BAUDRATES; i++) {
2629 if (config->baudrate == std_baudrates[i].value) {
2630 data->dcb.BaudRate = std_baudrates[i].index;
2635 if (i == NUM_STD_BAUDRATES)
2636 data->dcb.BaudRate = config->baudrate;
2639 if (config->bits >= 0)
2640 data->dcb.ByteSize = config->bits;
2642 if (config->parity >= 0) {
2643 switch (config->parity) {
2644 case SP_PARITY_NONE:
2645 data->dcb.Parity = NOPARITY;
2648 data->dcb.Parity = ODDPARITY;
2650 case SP_PARITY_EVEN:
2651 data->dcb.Parity = EVENPARITY;
2653 case SP_PARITY_MARK:
2654 data->dcb.Parity = MARKPARITY;
2656 case SP_PARITY_SPACE:
2657 data->dcb.Parity = SPACEPARITY;
2660 RETURN_ERROR(SP_ERR_ARG, "Invalid parity setting");
2664 if (config->stopbits >= 0) {
2665 switch (config->stopbits) {
2666 /* Note: There's also ONE5STOPBITS == 1.5 (unneeded so far). */
2668 data->dcb.StopBits = ONESTOPBIT;
2671 data->dcb.StopBits = TWOSTOPBITS;
2674 RETURN_ERROR(SP_ERR_ARG, "Invalid stop bit setting");
2678 if (config->rts >= 0) {
2679 switch (config->rts) {
2681 data->dcb.fRtsControl = RTS_CONTROL_DISABLE;
2684 data->dcb.fRtsControl = RTS_CONTROL_ENABLE;
2686 case SP_RTS_FLOW_CONTROL:
2687 data->dcb.fRtsControl = RTS_CONTROL_HANDSHAKE;
2690 RETURN_ERROR(SP_ERR_ARG, "Invalid RTS setting");
2694 if (config->cts >= 0) {
2695 switch (config->cts) {
2697 data->dcb.fOutxCtsFlow = FALSE;
2699 case SP_CTS_FLOW_CONTROL:
2700 data->dcb.fOutxCtsFlow = TRUE;
2703 RETURN_ERROR(SP_ERR_ARG, "Invalid CTS setting");
2707 if (config->dtr >= 0) {
2708 switch (config->dtr) {
2710 data->dcb.fDtrControl = DTR_CONTROL_DISABLE;
2713 data->dcb.fDtrControl = DTR_CONTROL_ENABLE;
2715 case SP_DTR_FLOW_CONTROL:
2716 data->dcb.fDtrControl = DTR_CONTROL_HANDSHAKE;
2719 RETURN_ERROR(SP_ERR_ARG, "Invalid DTR setting");
2723 if (config->dsr >= 0) {
2724 switch (config->dsr) {
2726 data->dcb.fOutxDsrFlow = FALSE;
2728 case SP_DSR_FLOW_CONTROL:
2729 data->dcb.fOutxDsrFlow = TRUE;
2732 RETURN_ERROR(SP_ERR_ARG, "Invalid DSR setting");
2736 if (config->xon_xoff >= 0) {
2737 switch (config->xon_xoff) {
2738 case SP_XONXOFF_DISABLED:
2739 data->dcb.fInX = FALSE;
2740 data->dcb.fOutX = FALSE;
2743 data->dcb.fInX = TRUE;
2744 data->dcb.fOutX = FALSE;
2746 case SP_XONXOFF_OUT:
2747 data->dcb.fInX = FALSE;
2748 data->dcb.fOutX = TRUE;
2750 case SP_XONXOFF_INOUT:
2751 data->dcb.fInX = TRUE;
2752 data->dcb.fOutX = TRUE;
2755 RETURN_ERROR(SP_ERR_ARG, "Invalid XON/XOFF setting");
2759 if (!SetCommState(port->hdl, &data->dcb))
2760 RETURN_FAIL("SetCommState() failed");
2766 if (config->baudrate >= 0) {
2767 for (i = 0; i < NUM_STD_BAUDRATES; i++) {
2768 if (config->baudrate == std_baudrates[i].value) {
2769 if (cfsetospeed(&data->term, std_baudrates[i].index) < 0)
2770 RETURN_FAIL("cfsetospeed() failed");
2772 if (cfsetispeed(&data->term, std_baudrates[i].index) < 0)
2773 RETURN_FAIL("cfsetispeed() failed");
2778 /* Non-standard baud rate */
2779 if (i == NUM_STD_BAUDRATES) {
2781 /* Set "dummy" baud rate. */
2782 if (cfsetspeed(&data->term, B9600) < 0)
2783 RETURN_FAIL("cfsetspeed() failed");
2784 baud_nonstd = config->baudrate;
2785 #elif defined(USE_TERMIOS_SPEED)
2788 RETURN_ERROR(SP_ERR_SUPP, "Non-standard baudrate not supported");
2793 if (config->bits >= 0) {
2794 data->term.c_cflag &= ~CSIZE;
2795 switch (config->bits) {
2797 data->term.c_cflag |= CS8;
2800 data->term.c_cflag |= CS7;
2803 data->term.c_cflag |= CS6;
2806 data->term.c_cflag |= CS5;
2809 RETURN_ERROR(SP_ERR_ARG, "Invalid data bits setting");
2813 if (config->parity >= 0) {
2814 data->term.c_iflag &= ~IGNPAR;
2815 data->term.c_cflag &= ~(PARENB | PARODD);
2817 data->term.c_cflag &= ~CMSPAR;
2819 switch (config->parity) {
2820 case SP_PARITY_NONE:
2821 data->term.c_iflag |= IGNPAR;
2823 case SP_PARITY_EVEN:
2824 data->term.c_cflag |= PARENB;
2827 data->term.c_cflag |= PARENB | PARODD;
2830 case SP_PARITY_MARK:
2831 data->term.c_cflag |= PARENB | PARODD;
2832 data->term.c_cflag |= CMSPAR;
2834 case SP_PARITY_SPACE:
2835 data->term.c_cflag |= PARENB;
2836 data->term.c_cflag |= CMSPAR;
2839 case SP_PARITY_MARK:
2840 case SP_PARITY_SPACE:
2841 RETURN_ERROR(SP_ERR_SUPP, "Mark/space parity not supported");
2844 RETURN_ERROR(SP_ERR_ARG, "Invalid parity setting");
2848 if (config->stopbits >= 0) {
2849 data->term.c_cflag &= ~CSTOPB;
2850 switch (config->stopbits) {
2852 data->term.c_cflag &= ~CSTOPB;
2855 data->term.c_cflag |= CSTOPB;
2858 RETURN_ERROR(SP_ERR_ARG, "Invalid stop bits setting");
2862 if (config->rts >= 0 || config->cts >= 0) {
2863 if (data->termiox_supported) {
2864 data->rts_flow = data->cts_flow = 0;
2865 switch (config->rts) {
2868 controlbits = TIOCM_RTS;
2869 if (ioctl(port->fd, config->rts == SP_RTS_ON ? TIOCMBIS : TIOCMBIC, &controlbits) < 0)
2870 RETURN_FAIL("Setting RTS signal level failed");
2872 case SP_RTS_FLOW_CONTROL:
2878 if (config->cts == SP_CTS_FLOW_CONTROL)
2881 if (data->rts_flow && data->cts_flow)
2882 data->term.c_iflag |= CRTSCTS;
2884 data->term.c_iflag &= ~CRTSCTS;
2886 /* Asymmetric use of RTS/CTS not supported. */
2887 if (data->term.c_iflag & CRTSCTS) {
2888 /* Flow control can only be disabled for both RTS & CTS together. */
2889 if (config->rts >= 0 && config->rts != SP_RTS_FLOW_CONTROL) {
2890 if (config->cts != SP_CTS_IGNORE)
2891 RETURN_ERROR(SP_ERR_SUPP, "RTS & CTS flow control must be disabled together");
2893 if (config->cts >= 0 && config->cts != SP_CTS_FLOW_CONTROL) {
2894 if (config->rts <= 0 || config->rts == SP_RTS_FLOW_CONTROL)
2895 RETURN_ERROR(SP_ERR_SUPP, "RTS & CTS flow control must be disabled together");
2898 /* Flow control can only be enabled for both RTS & CTS together. */
2899 if (((config->rts == SP_RTS_FLOW_CONTROL) && (config->cts != SP_CTS_FLOW_CONTROL)) ||
2900 ((config->cts == SP_CTS_FLOW_CONTROL) && (config->rts != SP_RTS_FLOW_CONTROL)))
2901 RETURN_ERROR(SP_ERR_SUPP, "RTS & CTS flow control must be enabled together");
2904 if (config->rts >= 0) {
2905 if (config->rts == SP_RTS_FLOW_CONTROL) {
2906 data->term.c_iflag |= CRTSCTS;
2908 controlbits = TIOCM_RTS;
2909 if (ioctl(port->fd, config->rts == SP_RTS_ON ? TIOCMBIS : TIOCMBIC,
2911 RETURN_FAIL("Setting RTS signal level failed");
2917 if (config->dtr >= 0 || config->dsr >= 0) {
2918 if (data->termiox_supported) {
2919 data->dtr_flow = data->dsr_flow = 0;
2920 switch (config->dtr) {
2923 controlbits = TIOCM_DTR;
2924 if (ioctl(port->fd, config->dtr == SP_DTR_ON ? TIOCMBIS : TIOCMBIC, &controlbits) < 0)
2925 RETURN_FAIL("Setting DTR signal level failed");
2927 case SP_DTR_FLOW_CONTROL:
2933 if (config->dsr == SP_DSR_FLOW_CONTROL)
2936 /* DTR/DSR flow control not supported. */
2937 if (config->dtr == SP_DTR_FLOW_CONTROL || config->dsr == SP_DSR_FLOW_CONTROL)
2938 RETURN_ERROR(SP_ERR_SUPP, "DTR/DSR flow control not supported");
2940 if (config->dtr >= 0) {
2941 controlbits = TIOCM_DTR;
2942 if (ioctl(port->fd, config->dtr == SP_DTR_ON ? TIOCMBIS : TIOCMBIC,
2944 RETURN_FAIL("Setting DTR signal level failed");
2949 if (config->xon_xoff >= 0) {
2950 data->term.c_iflag &= ~(IXON | IXOFF | IXANY);
2951 switch (config->xon_xoff) {
2952 case SP_XONXOFF_DISABLED:
2955 data->term.c_iflag |= IXOFF;
2957 case SP_XONXOFF_OUT:
2958 data->term.c_iflag |= IXON | IXANY;
2960 case SP_XONXOFF_INOUT:
2961 data->term.c_iflag |= IXON | IXOFF | IXANY;
2964 RETURN_ERROR(SP_ERR_ARG, "Invalid XON/XOFF setting");
2968 if (tcsetattr(port->fd, TCSANOW, &data->term) < 0)
2969 RETURN_FAIL("tcsetattr() failed");
2972 if (baud_nonstd != B0) {
2973 if (ioctl(port->fd, IOSSIOSPEED, &baud_nonstd) == -1)
2974 RETURN_FAIL("IOSSIOSPEED ioctl failed");
2975 /* Set baud rates in data->term to correct, but incompatible
2976 * with tcsetattr() value, same as delivered by tcgetattr(). */
2977 if (cfsetspeed(&data->term, baud_nonstd) < 0)
2978 RETURN_FAIL("cfsetspeed() failed");
2980 #elif defined(__linux__)
2981 #ifdef USE_TERMIOS_SPEED
2983 TRY(set_baudrate(port->fd, config->baudrate));
2986 if (data->termiox_supported)
2987 TRY(set_flow(port->fd, data));
2991 #endif /* !_WIN32 */
2996 enum sp_return sp_new_config(struct sp_port_config **config_ptr)
2998 struct sp_port_config *config;
3000 TRACE("%p", config_ptr);
3003 RETURN_ERROR(SP_ERR_ARG, "Null result pointer");
3007 if (!(config = malloc(sizeof(struct sp_port_config))))
3008 RETURN_ERROR(SP_ERR_MEM, "config malloc failed");
3010 config->baudrate = -1;
3012 config->parity = -1;
3013 config->stopbits = -1;
3019 *config_ptr = config;
3024 void sp_free_config(struct sp_port_config *config)
3026 TRACE("%p", config);
3029 DEBUG("Null config");
3036 enum sp_return sp_get_config(struct sp_port *port, struct sp_port_config *config)
3038 struct port_data data;
3040 TRACE("%p, %p", port, config);
3045 RETURN_ERROR(SP_ERR_ARG, "Null config");
3047 TRY(get_config(port, &data, config));
3052 enum sp_return sp_set_config(struct sp_port *port, const struct sp_port_config *config)
3054 struct port_data data;
3055 struct sp_port_config prev_config;
3057 TRACE("%p, %p", port, config);
3062 RETURN_ERROR(SP_ERR_ARG, "Null config");
3064 TRY(get_config(port, &data, &prev_config));
3065 TRY(set_config(port, &data, config));
3070 #define CREATE_ACCESSORS(x, type) \
3071 enum sp_return sp_set_##x(struct sp_port *port, type x) { \
3072 struct port_data data; \
3073 struct sp_port_config config; \
3074 TRACE("%p, %d", port, x); \
3075 CHECK_OPEN_PORT(); \
3076 TRY(get_config(port, &data, &config)); \
3078 TRY(set_config(port, &data, &config)); \
3081 enum sp_return sp_get_config_##x(const struct sp_port_config *config, type *x) { \
3082 TRACE("%p, %p", config, x); \
3084 RETURN_ERROR(SP_ERR_ARG, "Null config"); \
3088 enum sp_return sp_set_config_##x(struct sp_port_config *config, type x) { \
3089 TRACE("%p, %d", config, x); \
3091 RETURN_ERROR(SP_ERR_ARG, "Null config"); \
3096 CREATE_ACCESSORS(baudrate, int)
3097 CREATE_ACCESSORS(bits, int)
3098 CREATE_ACCESSORS(parity, enum sp_parity)
3099 CREATE_ACCESSORS(stopbits, int)
3100 CREATE_ACCESSORS(rts, enum sp_rts)
3101 CREATE_ACCESSORS(cts, enum sp_cts)
3102 CREATE_ACCESSORS(dtr, enum sp_dtr)
3103 CREATE_ACCESSORS(dsr, enum sp_dsr)
3104 CREATE_ACCESSORS(xon_xoff, enum sp_xonxoff)
3106 enum sp_return sp_set_config_flowcontrol(struct sp_port_config *config, enum sp_flowcontrol flowcontrol)
3109 RETURN_ERROR(SP_ERR_ARG, "Null configuration");
3111 if (flowcontrol > SP_FLOWCONTROL_DTRDSR)
3112 RETURN_ERROR(SP_ERR_ARG, "Invalid flow control setting");
3114 if (flowcontrol == SP_FLOWCONTROL_XONXOFF)
3115 config->xon_xoff = SP_XONXOFF_INOUT;
3117 config->xon_xoff = SP_XONXOFF_DISABLED;
3119 if (flowcontrol == SP_FLOWCONTROL_RTSCTS) {
3120 config->rts = SP_RTS_FLOW_CONTROL;
3121 config->cts = SP_CTS_FLOW_CONTROL;
3123 if (config->rts == SP_RTS_FLOW_CONTROL)
3124 config->rts = SP_RTS_ON;
3125 config->cts = SP_CTS_IGNORE;
3128 if (flowcontrol == SP_FLOWCONTROL_DTRDSR) {
3129 config->dtr = SP_DTR_FLOW_CONTROL;
3130 config->dsr = SP_DSR_FLOW_CONTROL;
3132 if (config->dtr == SP_DTR_FLOW_CONTROL)
3133 config->dtr = SP_DTR_ON;
3134 config->dsr = SP_DSR_IGNORE;
3140 enum sp_return sp_set_flowcontrol(struct sp_port *port, enum sp_flowcontrol flowcontrol)
3142 struct port_data data;
3143 struct sp_port_config config;
3145 TRACE("%p, %d", port, flowcontrol);
3149 TRY(get_config(port, &data, &config));
3151 TRY(sp_set_config_flowcontrol(&config, flowcontrol));
3153 TRY(set_config(port, &data, &config));
3158 enum sp_return sp_get_signals(struct sp_port *port, enum sp_signal *signals)
3160 TRACE("%p, %p", port, signals);
3165 RETURN_ERROR(SP_ERR_ARG, "Null result pointer");
3167 DEBUG("Getting control signals for port %s", port->name);
3172 if (GetCommModemStatus(port->hdl, &bits) == 0)
3173 RETURN_FAIL("GetCommModemStatus() failed");
3174 if (bits & MS_CTS_ON)
3175 *signals |= SP_SIG_CTS;
3176 if (bits & MS_DSR_ON)
3177 *signals |= SP_SIG_DSR;
3178 if (bits & MS_RLSD_ON)
3179 *signals |= SP_SIG_DCD;
3180 if (bits & MS_RING_ON)
3181 *signals |= SP_SIG_RI;
3184 if (ioctl(port->fd, TIOCMGET, &bits) < 0)
3185 RETURN_FAIL("TIOCMGET ioctl failed");
3186 if (bits & TIOCM_CTS)
3187 *signals |= SP_SIG_CTS;
3188 if (bits & TIOCM_DSR)
3189 *signals |= SP_SIG_DSR;
3190 if (bits & TIOCM_CAR)
3191 *signals |= SP_SIG_DCD;
3192 if (bits & TIOCM_RNG)
3193 *signals |= SP_SIG_RI;
3198 enum sp_return sp_start_break(struct sp_port *port)
3204 if (SetCommBreak(port->hdl) == 0)
3205 RETURN_FAIL("SetCommBreak() failed");
3207 if (ioctl(port->fd, TIOCSBRK, 1) < 0)
3208 RETURN_FAIL("TIOCSBRK ioctl failed");
3214 enum sp_return sp_end_break(struct sp_port *port)
3220 if (ClearCommBreak(port->hdl) == 0)
3221 RETURN_FAIL("ClearCommBreak() failed");
3223 if (ioctl(port->fd, TIOCCBRK, 1) < 0)
3224 RETURN_FAIL("TIOCCBRK ioctl failed");
3230 int sp_last_error_code(void)
3234 RETURN_VALUE("%d", GetLastError());
3236 RETURN_VALUE("%d", errno);
3240 char *sp_last_error_message(void)
3246 DWORD error = GetLastError();
3249 FORMAT_MESSAGE_ALLOCATE_BUFFER |
3250 FORMAT_MESSAGE_FROM_SYSTEM |
3251 FORMAT_MESSAGE_IGNORE_INSERTS,
3254 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
3258 RETURN_VALUE("%s", message);
3260 RETURN_VALUE("%s", strerror(errno));
3264 void sp_free_error_message(char *message)
3266 TRACE("%s", message);
3277 void sp_set_debug_handler(void (*handler)(const char *format, ...))
3279 TRACE("%p", handler);
3281 sp_debug_handler = handler;
3286 void sp_default_debug_handler(const char *format, ...)
3289 va_start(args, format);
3290 if (getenv("LIBSERIALPORT_DEBUG")) {
3291 fputs("sp: ", stderr);
3292 vfprintf(stderr, format, args);
3297 int sp_get_major_package_version(void)
3299 return SP_PACKAGE_VERSION_MAJOR;
3302 int sp_get_minor_package_version(void)
3304 return SP_PACKAGE_VERSION_MINOR;
3307 int sp_get_micro_package_version(void)
3309 return SP_PACKAGE_VERSION_MICRO;
3312 const char *sp_get_package_version_string(void)
3314 return SP_PACKAGE_VERSION_STRING;
3317 int sp_get_current_lib_version(void)
3319 return SP_LIB_VERSION_CURRENT;
3322 int sp_get_revision_lib_version(void)
3324 return SP_LIB_VERSION_REVISION;
3327 int sp_get_age_lib_version(void)
3329 return SP_LIB_VERSION_AGE;
3332 const char *sp_get_lib_version_string(void)
3334 return SP_LIB_VERSION_STRING;