]> sigrok.org Git - libserialport.git/blob - serialport.c
Add new APIs to get some USB descriptor details for USB serial ports.
[libserialport.git] / serialport.c
1 /*
2  * This file is part of the libserialport project.
3  *
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>
9  *
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.
14  *
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.
19  *
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/>.
22  */
23
24 #include <string.h>
25 #include <sys/types.h>
26 #include <sys/stat.h>
27 #include <fcntl.h>
28 #include <unistd.h>
29 #include <stdlib.h>
30 #include <errno.h>
31 #include <stdio.h>
32 #include <stdarg.h>
33 #ifdef _WIN32
34 #include <windows.h>
35 #include <setupapi.h>
36 #include <cfgmgr32.h>
37 #include <usbioctl.h>
38 #include <tchar.h>
39 #else
40 #include <limits.h>
41 #include <termios.h>
42 #include <sys/ioctl.h>
43 #include <sys/time.h>
44 #include <limits.h>
45 #include <poll.h>
46 #endif
47 #ifdef __APPLE__
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>
53 #endif
54 #ifdef __linux__
55 #include <dirent.h>
56 #ifndef __ANDROID__
57 #include "linux/serial.h"
58 #endif
59 #include "linux_termios.h"
60
61 /* TCGETX/TCSETX is not available everywhere. */
62 #if defined(TCGETX) && defined(TCSETX) && defined(HAVE_TERMIOX)
63 #define USE_TERMIOX
64 #endif
65 #endif
66
67 /* TIOCINQ/TIOCOUTQ is not available everywhere. */
68 #if !defined(TIOCINQ) && defined(FIONREAD)
69 #define TIOCINQ FIONREAD
70 #endif
71 #if !defined(TIOCOUTQ) && defined(FIONWRITE)
72 #define TIOCOUTQ FIONWRITE
73 #endif
74
75 /* Non-standard baudrates are not available everywhere. */
76 #if defined(HAVE_TERMIOS_SPEED) || defined(HAVE_TERMIOS2_SPEED)
77 #define USE_TERMIOS_SPEED
78 #endif
79
80 #include "libserialport.h"
81
82 struct sp_port {
83         char *name;
84         char *description;
85         enum sp_transport transport;
86         int usb_bus;
87         int usb_address;
88         int usb_vid;
89         int usb_pid;
90         char *usb_manufacturer;
91         char *usb_product;
92         char *usb_serial;
93         char *bluetooth_address;
94 #ifdef _WIN32
95         char *usb_path;
96         HANDLE hdl;
97         COMMTIMEOUTS timeouts;
98         OVERLAPPED write_ovl;
99         OVERLAPPED read_ovl;
100         OVERLAPPED wait_ovl;
101         DWORD events;
102         BYTE pending_byte;
103         BOOL writing;
104 #else
105         int fd;
106 #endif
107 };
108
109 struct sp_port_config {
110         int baudrate;
111         int bits;
112         enum sp_parity parity;
113         int stopbits;
114         enum sp_rts rts;
115         enum sp_cts cts;
116         enum sp_dtr dtr;
117         enum sp_dsr dsr;
118         enum sp_xonxoff xon_xoff;
119 };
120
121 struct port_data {
122 #ifdef _WIN32
123         DCB dcb;
124 #else
125         struct termios term;
126         int controlbits;
127         int termiox_supported;
128         int rts_flow;
129         int cts_flow;
130         int dtr_flow;
131         int dsr_flow;
132 #endif
133 };
134
135 #ifdef _WIN32
136 typedef HANDLE event_handle;
137 #else
138 typedef int event_handle;
139 #endif
140
141 /* Standard baud rates. */
142 #ifdef _WIN32
143 #define BAUD_TYPE DWORD
144 #define BAUD(n) {CBR_##n, n}
145 #else
146 #define BAUD_TYPE speed_t
147 #define BAUD(n) {B##n, n}
148 #endif
149
150 struct std_baudrate {
151         BAUD_TYPE index;
152         int value;
153 };
154
155 const struct std_baudrate std_baudrates[] = {
156 #ifdef _WIN32
157         /*
158          * The baudrates 50/75/134/150/200/1800/230400/460800 do not seem to
159          * have documented CBR_* macros.
160          */
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),
164 #else
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),
168         BAUD(230400),
169 #if !defined(__APPLE__) && !defined(__OpenBSD__)
170         BAUD(460800),
171 #endif
172 #endif
173 };
174
175 void (*sp_debug_handler)(const char *format, ...) = sp_default_debug_handler;
176
177 #define ARRAY_SIZE(x) (sizeof(x) / sizeof(x[0]))
178 #define NUM_STD_BAUDRATES ARRAY_SIZE(std_baudrates)
179
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); \
187 } while (0);
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 { \
191         switch (x) { \
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); \
197         } \
198 } while (0)
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 { \
203         typeof(x) _x = x; \
204         DEBUG("%s returning " fmt, __func__, _x); \
205         return _x; \
206 } while (0)
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__)
210
211 #define TRY(x) do { int ret = x; if (ret != SP_OK) RETURN_CODEVAL(ret); } while (0)
212
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);
218
219 #ifdef _WIN32
220
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)
223
224 static char *wc_to_utf8(PWCHAR wc_buffer, ULONG size)
225 {
226         WCHAR wc_str[size/sizeof(WCHAR)+1];
227         char *utf8_str;
228
229         /* zero terminate the wide char string */
230         memcpy(wc_str, wc_buffer, size);
231         wc_str[sizeof(wc_str)-1] = 0;
232
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)))
236                 return NULL;
237
238         /* allocate utf8 output buffer */
239         if (!(utf8_str = malloc(size)))
240                 return NULL;
241
242         /* actually converted to utf8 */
243         if (!WideCharToMultiByte(CP_ACP, WC_NO_BEST_FIT_CHARS, wc_str, -1,
244                                  utf8_str, size, NULL, NULL)) {
245                 free(utf8_str);
246                 return NULL;
247         }
248
249         return utf8_str;
250 }
251
252 static char *get_root_hub_name(HANDLE host_controller)
253 {
254         USB_ROOT_HUB_NAME  root_hub_name;
255         PUSB_ROOT_HUB_NAME root_hub_name_wc;
256         char *root_hub_name_utf8;
257         ULONG size = 0;
258
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))
262                 return NULL;
263
264         /* allocate wide char root hub name string */
265         size = root_hub_name.ActualLength;
266         if (!(root_hub_name_wc = malloc(size)))
267                 return NULL;
268
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);
273                 return NULL;
274         }
275
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;
280 }
281
282 static char *get_external_hub_name(HANDLE hub, ULONG connection_index)
283 {
284         USB_NODE_CONNECTION_NAME  ext_hub_name;
285         PUSB_NODE_CONNECTION_NAME ext_hub_name_wc;
286         char *ext_hub_name_utf8;
287         ULONG size;
288
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))
294                 return NULL;
295
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)))
300                 return NULL;
301
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);
308                 return NULL;
309         }
310
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;
315 }
316
317 static char *get_string_descriptor(HANDLE hub_device, ULONG connection_index,
318                                    UCHAR descriptor_index)
319 {
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);
325
326         desc_req->ConnectionIndex     = connection_index;
327         desc_req->SetupPacket.wValue  = (USB_STRING_DESCRIPTOR_TYPE << 8)
328                                         | descriptor_index;
329         desc_req->SetupPacket.wIndex  = 0;
330         desc_req->SetupPacket.wLength = size - sizeof(*desc_req);
331
332         if (!DeviceIoControl(hub_device,
333                              IOCTL_USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION,
334                              desc_req, size, desc_req, size, &size, NULL)
335             || size < 2
336             || desc->bDescriptorType != USB_STRING_DESCRIPTOR_TYPE
337             || desc->bLength != size - sizeof(*desc_req)
338             || desc->bLength % 2)
339                 return NULL;
340
341         return wc_to_utf8(desc->bString, desc->bLength);
342 }
343
344 static void enumerate_hub(struct sp_port *port, char *hub_name,
345                           char *parent_path);
346
347 static void enumerate_hub_ports(struct sp_port *port, HANDLE hub_device,
348                                 ULONG nb_ports, char *parent_path)
349 {
350         char path[MAX_USB_PATH];
351         ULONG index = 0;
352
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);
356
357                 if (!(connection_info_ex = malloc(size)))
358                         break;
359
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
366                            did not work */
367                         PUSB_NODE_CONNECTION_INFORMATION connection_info;
368
369                         size = sizeof(*connection_info) + 30*sizeof(USB_PIPE_INFO);
370                         if (!(connection_info = malloc(size))) {
371                                 free(connection_info_ex);
372                                 continue;
373                         }
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);
381                                 continue;
382                         }
383
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);
389                 }
390
391                 if (connection_info_ex->DeviceIsHub) {
392                         /* recursively enumerate external hub */
393                         PCHAR ext_hub_name;
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);
398                         }
399                         free(connection_info_ex);
400                 } else {
401                         snprintf(path, sizeof(path), "%s%d",
402                                  parent_path, connection_info_ex->ConnectionIndex);
403
404                         /* check if this device is the one we search for */
405                         if (strcmp(path, port->usb_path)) {
406                                 free(connection_info_ex);
407                                 continue;
408                         }
409
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;
414
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);
424
425                         free(connection_info_ex);
426                         break;
427                 }
428         }
429 }
430
431 static void enumerate_hub(struct sp_port *port, char *hub_name,
432                           char *parent_path)
433 {
434         USB_NODE_INFORMATION hub_info;
435         HANDLE hub_device;
436         ULONG size = sizeof(hub_info);
437         char *device_name;
438
439         /* open the hub with its full name */
440         if (!(device_name = malloc(strlen("\\\\.\\") + strlen(hub_name) + 1)))
441                 return;
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);
446         free(device_name);
447         if (hub_device == INVALID_HANDLE_VALUE)
448                 return;
449
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);
456
457         CloseHandle(hub_device);
458 }
459
460 static void enumerate_host_controller(struct sp_port *port,
461                                       HANDLE host_controller_device)
462 {
463         char *root_hub_name;
464
465         if ((root_hub_name = get_root_hub_name(host_controller_device))) {
466                 enumerate_hub(port, root_hub_name, "");
467                 free(root_hub_name);
468         }
469 }
470
471 static void get_usb_details(struct sp_port *port, DEVINST dev_inst_match)
472 {
473         HDEVINFO device_info;
474         SP_DEVINFO_DATA device_info_data;
475         ULONG i, size = 0;
476
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);
480
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;
486
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))
491                         continue;
492
493                 if (!SetupDiGetDeviceInterfaceDetail(device_info,&device_interface_data,
494                                                      NULL, 0, &size, NULL)
495                     && GetLastError() != ERROR_INSUFFICIENT_BUFFER)
496                         continue;
497
498                 if (!(device_detail_data = malloc(size)))
499                         continue;
500                 device_detail_data->cbSize = sizeof(*device_detail_data);
501                 if (!SetupDiGetDeviceInterfaceDetail(device_info,&device_interface_data,
502                                                      device_detail_data, size, &size,
503                                                      NULL)) {
504                         free(device_detail_data);
505                         continue;
506                 }
507
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);
512                         continue;
513                 }
514
515                 port->usb_bus = i + 1;
516
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);
523                 }
524                 free(device_detail_data);
525         }
526
527         SetupDiDestroyDeviceInfoList(device_info);
528         return;
529 }
530
531 #endif /* _WIN32 */
532
533 static enum sp_return sp_get_port_details(struct sp_port *port)
534 {
535         /* Description limited to 127 char,
536            anything longer would not be user friendly anyway */
537         char description[128];
538 #ifndef _WIN32
539         int bus, address, vid, pid = -1;
540         char manufacturer[128], product[128], serial[128];
541         char baddr[32];
542 #endif
543
544         port->description = NULL;
545         port->transport = SP_TRANSPORT_NATIVE;
546         port->usb_bus = -1;
547         port->usb_address = -1;
548         port->usb_vid = -1;
549         port->usb_pid = -1;
550         port->usb_manufacturer = NULL;
551         port->usb_product = NULL;
552         port->usb_serial = NULL;
553         port->bluetooth_address = NULL;
554
555 #ifdef _WIN32
556         SP_DEVINFO_DATA device_info_data = { .cbSize = sizeof(device_info_data) };
557         HDEVINFO device_info;
558         int i;
559
560         device_info = SetupDiGetClassDevs(NULL, 0, 0,
561                                           DIGCF_PRESENT | DIGCF_ALLCLASSES);
562         if (device_info == INVALID_HANDLE_VALUE)
563                 RETURN_FAIL("SetupDiGetClassDevs() failed");
564
565         for (i=0; SetupDiEnumDeviceInfo(device_info, i, &device_info_data); i++) {
566                 HKEY device_key;
567                 DEVINST dev_inst;
568                 char value[8], class[16];
569                 DWORD size, type;
570                 CONFIGRET cr;
571
572                 /* check if this is the device we are looking for */
573                 if (!(device_key = SetupDiOpenDevRegKey(device_info, &device_info_data,
574                                                         DICS_FLAG_GLOBAL, 0,
575                                                         DIREG_DEV, KEY_QUERY_VALUE)))
576                         continue;
577                 size = sizeof(value);
578                 if (RegQueryValueExA(device_key, "PortName", NULL, &type, (LPBYTE)value,
579                                      &size) != ERROR_SUCCESS || type != REG_SZ)
580                         continue;
581                 RegCloseKey(device_key);
582                 value[sizeof(value)-1] = 0;
583                 if (strcmp(value, port->name))
584                         continue;
585
586                 /* check port transport type */
587                 dev_inst = device_info_data.DevInst;
588                 size = sizeof(class);
589                 cr = CR_FAILURE;
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;
596                 }
597
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);
606
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];
611
612                         /* recurse over parents to build the USB device path */
613                         dev_inst = device_info_data.DevInst;
614                         do {
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))
619                                         continue;
620
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,
626                                                                       &compat_ids,
627                                                                       &size, 0) == CR_SUCCESS) {
628                                         while (*p) {
629                                                 if (!strncmp(p, "USB\\COMPOSITE", 13))
630                                                         break;
631                                                 p += strlen(p) + 1;
632                                         }
633                                         if (*p)
634                                                 continue;
635                                 }
636
637                                 /* stop the recursion when reaching the USB root */
638                                 if (!strncmp(device_id, "USB\\ROOT", 8))
639                                         break;
640
641                                 /* prepend the address of current USB layer to the USB path */
642                                 DWORD address;
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);
649                                 }
650                         } while (CM_Get_Parent(&dev_inst, dev_inst, 0) == CR_SUCCESS);
651
652                         port->usb_path = strdup(usb_path);
653
654                         /* wake up the USB device to be able to read string descriptor */
655                         char *escaped_port_name;
656                         HANDLE handle;
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,
661                                             OPEN_EXISTING,
662                                             FILE_ATTRIBUTE_NORMAL|FILE_FLAG_OVERLAPPED, 0);
663                         free(escaped_port_name);
664                         CloseHandle(handle);
665
666                         /* retrive USB device details from the device descriptor */
667                         get_usb_details(port, device_info_data.DevInst);
668                 }
669                 break;
670         }
671 #elif defined(__APPLE__)
672         CFMutableDictionaryRef classes;
673         io_iterator_t iter;
674         io_object_t ioport;
675         CFTypeRef cf_property, cf_bus, cf_address, cf_vendor, cf_product;
676         Boolean result;
677         char path[PATH_MAX];
678
679         DEBUG("Getting serial port list");
680         if (!(classes = IOServiceMatching(kIOSerialBSDServiceValue)))
681                 RETURN_FAIL("IOServiceMatching() failed");
682
683         if (IOServiceGetMatchingServices(kIOMasterPortDefault, classes,
684                                          &iter) != KERN_SUCCESS)
685                 RETURN_FAIL("IOServiceGetMatchingServices() failed");
686
687         DEBUG("Iterating over results");
688         while ((ioport = IOIteratorNext(iter))) {
689                 if (!(cf_property = IORegistryEntryCreateCFProperty(ioport,
690                             CFSTR(kIOCalloutDeviceKey), kCFAllocatorDefault, 0))) {
691                         IOObjectRelease(ioport);
692                         continue;
693                 }
694                 result = CFStringGetCString(cf_property, path, sizeof(path),
695                                             kCFStringEncodingASCII);
696                 CFRelease(cf_property);
697                 if (!result || strcmp(path, port->name)) {
698                         IOObjectRelease(ioport);
699                         continue;
700                 }
701                 DEBUG("Found port %s", path);
702
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;
712                         }
713                         CFRelease(cf_property);
714                 }
715                 IOObjectRelease(ioparent);
716
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);
732                         }
733                         CFRelease(cf_property);
734                 } else {
735                         DEBUG("No description for this device");
736                 }
737
738                 cf_bus = IORegistryEntrySearchCFProperty(ioport, kIOServicePlane,
739                                                          CFSTR("USBBusNumber"),
740                                                          kCFAllocatorDefault,
741                                                          kIORegistryIterateRecursively
742                                                          | kIORegistryIterateParents);
743                 cf_address = IORegistryEntrySearchCFProperty(ioport, kIOServicePlane,
744                                                          CFSTR("USB Address"),
745                                                          kCFAllocatorDefault,
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);
752                         port->usb_bus = bus;
753                         port->usb_address = address;
754                 }
755                 if (cf_bus    )  CFRelease(cf_bus);
756                 if (cf_address)  CFRelease(cf_address);
757
758                 cf_vendor = IORegistryEntrySearchCFProperty(ioport, kIOServicePlane,
759                                                          CFSTR("idVendor"),
760                                                          kCFAllocatorDefault,
761                                                          kIORegistryIterateRecursively
762                                                          | kIORegistryIterateParents);
763                 cf_product = IORegistryEntrySearchCFProperty(ioport, kIOServicePlane,
764                                                          CFSTR("idProduct"),
765                                                          kCFAllocatorDefault,
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);
772                         port->usb_vid = vid;
773                         port->usb_pid = pid;
774                 }
775                 if (cf_vendor )  CFRelease(cf_vendor);
776                 if (cf_product)  CFRelease(cf_product);
777
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);
785                         }
786                         CFRelease(cf_property);
787                 }
788
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);
796                         }
797                         CFRelease(cf_property);
798                 }
799
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);
807                         }
808                         CFRelease(cf_property);
809                 }
810
811                 IOObjectRelease(ioport);
812                 break;
813         }
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;
819         FILE *file;
820         int i, count;
821
822         if (strncmp(port->name, "/dev/", 5))
823                 RETURN_ERROR(SP_ERR_ARG, "Device name not recognized (%s)", port->name);
824
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;
834
835         if (port->transport == SP_TRANSPORT_USB) {
836                 for (i=0; i<5; i++) {
837                         strcat(sub_dir, "../");
838
839                         snprintf(file_name,sizeof(file_name),dir_name,dev,sub_dir,"busnum");
840                         if (!(file = fopen(file_name, "r")))
841                                 continue;
842                         count = fscanf(file, "%d", &bus);
843                         fclose(file);
844                         if (count != 1)
845                                 continue;
846
847                         snprintf(file_name,sizeof(file_name),dir_name,dev,sub_dir,"devnum");
848                         if (!(file = fopen(file_name, "r")))
849                                 continue;
850                         count = fscanf(file, "%d", &address);
851                         fclose(file);
852                         if (count != 1)
853                                 continue;
854
855                         snprintf(file_name,sizeof(file_name),dir_name,dev,sub_dir,"idVendor");
856                         if (!(file = fopen(file_name, "r")))
857                                 continue;
858                         count = fscanf(file, "%4x", &vid);
859                         fclose(file);
860                         if (count != 1)
861                                 continue;
862
863                         snprintf(file_name,sizeof(file_name),dir_name,dev,sub_dir,"idProduct");
864                         if (!(file = fopen(file_name, "r")))
865                                 continue;
866                         count = fscanf(file, "%4x", &pid);
867                         fclose(file);
868                         if (count != 1)
869                                 continue;
870
871                         port->usb_bus = bus;
872                         port->usb_address = address;
873                         port->usb_vid = vid;
874                         port->usb_pid = pid;
875
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')
881                                                 *ptr = 0;
882                                         port->description = strdup(description);
883                                 }
884                                 fclose(file);
885                         }
886                         if (!file || !ptr)
887                                 port->description = strdup(dev);
888
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')
894                                                 *ptr = 0;
895                                         port->usb_manufacturer = strdup(manufacturer);
896                                 }
897                                 fclose(file);
898                         }
899
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')
905                                                 *ptr = 0;
906                                         port->usb_product = strdup(product);
907                                 }
908                                 fclose(file);
909                         }
910
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')
916                                                 *ptr = 0;
917                                         port->usb_serial = strdup(serial);
918                                 }
919                                 fclose(file);
920                         }
921
922                         break;
923                 }
924         } else {
925                 port->description = strdup(dev);
926
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')
933                                                 *ptr = 0;
934                                         port->bluetooth_address = strdup(baddr);
935                                 }
936                                 fclose(file);
937                         }
938                 }
939         }
940 #else
941         DEBUG("Port details not supported on this platform");
942 #endif
943
944         RETURN_OK();
945 }
946
947 enum sp_return sp_get_port_by_name(const char *portname, struct sp_port **port_ptr)
948 {
949         struct sp_port *port;
950         enum sp_return ret;
951         int len;
952
953         TRACE("%s, %p", portname, port_ptr);
954
955         if (!port_ptr)
956                 RETURN_ERROR(SP_ERR_ARG, "Null result pointer");
957
958         *port_ptr = NULL;
959
960         if (!portname)
961                 RETURN_ERROR(SP_ERR_ARG, "Null port name");
962
963         DEBUG("Building structure for port %s", portname);
964
965         if (!(port = malloc(sizeof(struct sp_port))))
966                 RETURN_ERROR(SP_ERR_MEM, "Port structure malloc failed");
967
968         len = strlen(portname) + 1;
969
970         if (!(port->name = malloc(len))) {
971                 free(port);
972                 RETURN_ERROR(SP_ERR_MEM, "Port name malloc failed");
973         }
974
975         memcpy(port->name, portname, len);
976
977 #ifdef _WIN32
978         port->hdl = INVALID_HANDLE_VALUE;
979 #else
980         port->fd = -1;
981 #endif
982
983         if ((ret = sp_get_port_details(port)) != SP_OK) {
984                 sp_free_port(port);
985                 return ret;
986         }
987
988         *port_ptr = port;
989
990         RETURN_OK();
991 }
992
993 char *sp_get_port_name(const struct sp_port *port)
994 {
995         TRACE("%p", port);
996
997         if (!port)
998                 return NULL;
999
1000         RETURN_VALUE("%s", port->name);
1001 }
1002
1003 char *sp_get_port_description(struct sp_port *port)
1004 {
1005         TRACE("%p", port);
1006
1007         if (!port || !port->description)
1008                 return NULL;
1009
1010         RETURN_VALUE("%s", port->description);
1011 }
1012
1013 enum sp_transport sp_get_port_transport(struct sp_port *port)
1014 {
1015         TRACE("%p", port);
1016
1017         if (!port)
1018                 RETURN_ERROR(SP_ERR_ARG, "Null port");
1019
1020         RETURN_VALUE("%d", port->transport);
1021 }
1022
1023 enum sp_return sp_get_port_usb_bus_address(const struct sp_port *port,
1024                                            int *usb_bus, int *usb_address)
1025 {
1026         TRACE("%p", port);
1027
1028         if (!port)
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");
1032
1033         if (usb_bus)      *usb_bus     = port->usb_bus;
1034         if (usb_address)  *usb_address = port->usb_address;
1035
1036         RETURN_OK();
1037 }
1038
1039 enum sp_return sp_get_port_usb_vid_pid(const struct sp_port *port,
1040                                        int *usb_vid, int *usb_pid)
1041 {
1042         TRACE("%p", port);
1043
1044         if (!port)
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");
1048
1049         if (usb_vid)  *usb_vid = port->usb_vid;
1050         if (usb_pid)  *usb_pid = port->usb_pid;
1051
1052         RETURN_OK();
1053 }
1054
1055 char *sp_get_port_usb_manufacturer(const struct sp_port *port)
1056 {
1057         TRACE("%p", port);
1058
1059         if (!port || port->transport != SP_TRANSPORT_USB || !port->usb_manufacturer)
1060                 return NULL;
1061
1062         RETURN_VALUE("%s", port->usb_manufacturer);
1063 }
1064
1065 char *sp_get_port_usb_product(const struct sp_port *port)
1066 {
1067         TRACE("%p", port);
1068
1069         if (!port || port->transport != SP_TRANSPORT_USB || !port->usb_product)
1070                 return NULL;
1071
1072         RETURN_VALUE("%s", port->usb_product);
1073 }
1074
1075 char *sp_get_port_usb_serial(const struct sp_port *port)
1076 {
1077         TRACE("%p", port);
1078
1079         if (!port || port->transport != SP_TRANSPORT_USB || !port->usb_serial)
1080                 return NULL;
1081
1082         RETURN_VALUE("%s", port->usb_serial);
1083 }
1084
1085 char *sp_get_port_bluetooth_address(const struct sp_port *port)
1086 {
1087         TRACE("%p", port);
1088
1089         if (!port || port->transport != SP_TRANSPORT_BLUETOOTH
1090             || !port->bluetooth_address)
1091                 return NULL;
1092
1093         RETURN_VALUE("%s", port->bluetooth_address);
1094 }
1095
1096 enum sp_return sp_get_port_handle(const struct sp_port *port, void *result_ptr)
1097 {
1098         TRACE("%p, %p", port, result_ptr);
1099
1100         if (!port)
1101                 RETURN_ERROR(SP_ERR_ARG, "Null port");
1102
1103 #ifdef _WIN32
1104         HANDLE *handle_ptr = result_ptr;
1105         *handle_ptr = port->hdl;
1106 #else
1107         int *fd_ptr = result_ptr;
1108         *fd_ptr = port->fd;
1109 #endif
1110
1111         RETURN_OK();
1112 }
1113
1114 enum sp_return sp_copy_port(const struct sp_port *port, struct sp_port **copy_ptr)
1115 {
1116         TRACE("%p, %p", port, copy_ptr);
1117
1118         if (!copy_ptr)
1119                 RETURN_ERROR(SP_ERR_ARG, "Null result pointer");
1120
1121         *copy_ptr = NULL;
1122
1123         if (!port)
1124                 RETURN_ERROR(SP_ERR_ARG, "Null port");
1125
1126         if (!port->name)
1127                 RETURN_ERROR(SP_ERR_ARG, "Null port name");
1128
1129         DEBUG("Copying port structure");
1130
1131         RETURN_VALUE("%p", sp_get_port_by_name(port->name, copy_ptr));
1132 }
1133
1134 void sp_free_port(struct sp_port *port)
1135 {
1136         TRACE("%p", port);
1137
1138         if (!port) {
1139                 DEBUG("Null port");
1140                 RETURN();
1141         }
1142
1143         DEBUG("Freeing port structure");
1144
1145         if (port->name)
1146                 free(port->name);
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);
1157 #ifdef _WIN32
1158         if (port->usb_path)
1159                 free(port->usb_path);
1160 #endif
1161
1162         free(port);
1163
1164         RETURN();
1165 }
1166
1167 static struct sp_port **list_append(struct sp_port **list, const char *portname)
1168 {
1169         void *tmp;
1170         unsigned int count;
1171
1172         for (count = 0; list[count]; count++);
1173         if (!(tmp = realloc(list, sizeof(struct sp_port *) * (count + 2))))
1174                 goto fail;
1175         list = tmp;
1176         if (sp_get_port_by_name(portname, &list[count]) != SP_OK)
1177                 goto fail;
1178         list[count + 1] = NULL;
1179         return list;
1180
1181 fail:
1182         sp_free_port_list(list);
1183         return NULL;
1184 }
1185
1186 enum sp_return sp_list_ports(struct sp_port ***list_ptr)
1187 {
1188         struct sp_port **list;
1189         int ret = SP_ERR_SUPP;
1190
1191         TRACE("%p", list_ptr);
1192
1193         if (!list_ptr)
1194                 RETURN_ERROR(SP_ERR_ARG, "Null result pointer");
1195
1196         DEBUG("Enumerating ports");
1197
1198         if (!(list = malloc(sizeof(struct sp_port **))))
1199                 RETURN_ERROR(SP_ERR_MEM, "Port list malloc failed");
1200
1201         list[0] = NULL;
1202
1203 #ifdef _WIN32
1204         HKEY key;
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;
1209         char *name;
1210         int name_len;
1211
1212         ret = SP_OK;
1213
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");
1218                 goto out_done;
1219         }
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");
1224                 goto out_close;
1225         }
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");
1229                 goto out_close;
1230         }
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;
1234         }
1235         DEBUG("Iterating over values");
1236         while (
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)
1241         {
1242                 data_len = data_size / sizeof(TCHAR);
1243                 data[data_len] = '\0';
1244 #ifdef UNICODE
1245                 name_len = WideCharToMultiByte(CP_ACP, 0, data, -1, NULL, 0, NULL, NULL);
1246 #else
1247                 name_len = data_len + 1;
1248 #endif
1249                 if (!(name = malloc(name_len))) {
1250                         SET_ERROR(ret, SP_ERR_MEM, "registry port name malloc failed");
1251                         goto out;
1252                 }
1253 #ifdef UNICODE
1254                 WideCharToMultiByte(CP_ACP, 0, data, -1, name, name_len, NULL, NULL);
1255 #else
1256                 strcpy(name, data);
1257 #endif
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");
1262                                 goto out;
1263                         }
1264                 }
1265                 index++;
1266         }
1267 out:
1268         free(data);
1269 out_free_value:
1270         free(value);
1271 out_close:
1272         RegCloseKey(key);
1273 out_done:
1274 #endif
1275 #ifdef __APPLE__
1276         CFMutableDictionaryRef classes;
1277         io_iterator_t iter;
1278         char path[PATH_MAX];
1279         io_object_t port;
1280         CFTypeRef cf_path;
1281         Boolean result;
1282
1283         ret = SP_OK;
1284
1285         DEBUG("Creating matching dictionary");
1286         if (!(classes = IOServiceMatching(kIOSerialBSDServiceValue))) {
1287                 SET_FAIL(ret, "IOServiceMatching() failed");
1288                 goto out_done;
1289         }
1290
1291         DEBUG("Getting matching services");
1292         if (IOServiceGetMatchingServices(kIOMasterPortDefault, classes,
1293                                          &iter) != KERN_SUCCESS) {
1294                 SET_FAIL(ret, "IOServiceGetMatchingServices() failed");
1295                 goto out_done;
1296         }
1297
1298         DEBUG("Iterating over results");
1299         while ((port = IOIteratorNext(iter))) {
1300                 cf_path = IORegistryEntryCreateCFProperty(port,
1301                                 CFSTR(kIOCalloutDeviceKey), kCFAllocatorDefault, 0);
1302                 if (cf_path) {
1303                         result = CFStringGetCString(cf_path, path, sizeof(path),
1304                                                     kCFStringEncodingASCII);
1305                         CFRelease(cf_path);
1306                         if (result) {
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);
1311                                         goto out;
1312                                 }
1313                         }
1314                 }
1315                 IOObjectRelease(port);
1316         }
1317 out:
1318         IOObjectRelease(iter);
1319 out_done:
1320 #endif
1321 #ifdef __linux__
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;
1326         DIR *dir;
1327
1328         ret = SP_OK;
1329
1330         DEBUG("Enumerating tty devices");
1331         if (!(dir = opendir("/sys/class/tty")))
1332                 RETURN_FAIL("could not open /sys/class/tty");
1333
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)
1338                         continue;
1339                 target[len] = 0;
1340                 if (strstr(target, "virtual"))
1341                         continue;
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");
1351                                 continue;
1352                         }
1353                         ioctl_result = ioctl(fd, TIOCGSERIAL, &serial_info);
1354                         close(fd);
1355                         if (ioctl_result != 0) {
1356                                 DEBUG("ioctl failed, skipping");
1357                                 continue;
1358                         }
1359                         if (serial_info.type == PORT_UNKNOWN) {
1360                                 DEBUG("port type is unknown, skipping");
1361                                 continue;
1362                         }
1363                 }
1364                 DEBUG("Found port %s", name);
1365                 list = list_append(list, name);
1366                 if (!list) {
1367                         SET_ERROR(ret, SP_ERR_MEM, "list append failed");
1368                         break;
1369                 }
1370         }
1371         closedir(dir);
1372 #endif
1373
1374         switch (ret) {
1375         case SP_OK:
1376                 *list_ptr = list;
1377                 RETURN_OK();
1378         case SP_ERR_SUPP:
1379                 DEBUG_ERROR(SP_ERR_SUPP, "Enumeration not supported on this platform");
1380         default:
1381                 if (list)
1382                         sp_free_port_list(list);
1383                 *list_ptr = NULL;
1384                 return ret;
1385         }
1386 }
1387
1388 void sp_free_port_list(struct sp_port **list)
1389 {
1390         unsigned int i;
1391
1392         TRACE("%p", list);
1393
1394         if (!list) {
1395                 DEBUG("Null list");
1396                 RETURN();
1397         }
1398
1399         DEBUG("Freeing port list");
1400
1401         for (i = 0; list[i]; i++)
1402                 sp_free_port(list[i]);
1403         free(list);
1404
1405         RETURN();
1406 }
1407
1408 #define CHECK_PORT() do { \
1409         if (port == NULL) \
1410                 RETURN_ERROR(SP_ERR_ARG, "Null port"); \
1411         if (port->name == NULL) \
1412                 RETURN_ERROR(SP_ERR_ARG, "Null port name"); \
1413 } while (0)
1414 #ifdef _WIN32
1415 #define CHECK_PORT_HANDLE() do { \
1416         if (port->hdl == INVALID_HANDLE_VALUE) \
1417                 RETURN_ERROR(SP_ERR_ARG, "Invalid port handle"); \
1418 } while (0)
1419 #else
1420 #define CHECK_PORT_HANDLE() do { \
1421         if (port->fd < 0) \
1422                 RETURN_ERROR(SP_ERR_ARG, "Invalid port fd"); \
1423 } while (0)
1424 #endif
1425 #define CHECK_OPEN_PORT() do { \
1426         CHECK_PORT(); \
1427         CHECK_PORT_HANDLE(); \
1428 } while (0)
1429
1430 enum sp_return sp_open(struct sp_port *port, enum sp_mode flags)
1431 {
1432         struct port_data data;
1433         struct sp_port_config config;
1434         enum sp_return ret;
1435
1436         TRACE("%p, 0x%x", port, flags);
1437
1438         CHECK_PORT();
1439
1440         if (flags > (SP_MODE_READ | SP_MODE_WRITE))
1441                 RETURN_ERROR(SP_ERR_ARG, "Invalid flags");
1442
1443         DEBUG("Opening port %s", port->name);
1444
1445 #ifdef _WIN32
1446         DWORD desired_access = 0, flags_and_attributes = 0, errors;
1447         char *escaped_port_name;
1448         COMSTAT status;
1449
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);
1454
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;
1461
1462         port->hdl = CreateFile(escaped_port_name, desired_access, 0, 0,
1463                          OPEN_EXISTING, flags_and_attributes, 0);
1464
1465         free(escaped_port_name);
1466
1467         if (port->hdl == INVALID_HANDLE_VALUE)
1468                 RETURN_FAIL("port CreateFile() failed");
1469
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;
1476
1477         if (SetCommTimeouts(port->hdl, &port->timeouts) == 0) {
1478                 sp_close(port);
1479                 RETURN_FAIL("SetCommTimeouts() failed");
1480         }
1481
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) { \
1488                 sp_close(port); \
1489                 RETURN_FAIL(#ovl "CreateEvent() failed"); \
1490         } \
1491 } while (0)
1492
1493         INIT_OVERLAPPED(read_ovl);
1494         INIT_OVERLAPPED(write_ovl);
1495         INIT_OVERLAPPED(wait_ovl);
1496
1497         /* Set event mask for RX and error events. */
1498         if (SetCommMask(port->hdl, EV_RXCHAR | EV_ERR) == 0) {
1499                 sp_close(port);
1500                 RETURN_FAIL("SetCommMask() failed");
1501         }
1502
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) {
1506                         sp_close(port);
1507                         RETURN_FAIL("WaitCommEvent() failed");
1508                 }
1509         }
1510
1511         port->writing = FALSE;
1512
1513 #else
1514         int flags_local = O_NONBLOCK | O_NOCTTY;
1515
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;
1523
1524         if ((port->fd = open(port->name, flags_local)) < 0)
1525                 RETURN_FAIL("open() failed");
1526 #endif
1527
1528         ret = get_config(port, &data, &config);
1529
1530         if (ret < 0) {
1531                 sp_close(port);
1532                 RETURN_CODEVAL(ret);
1533         }
1534
1535         /* Set sane port settings. */
1536 #ifdef _WIN32
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;
1542 #else
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);
1545 #ifdef IUCLC
1546         data.term.c_iflag &= ~IUCLC;
1547 #endif
1548         data.term.c_oflag &= ~(OPOST | ONLCR | OCRNL | ONOCR | ONLRET);
1549 #ifdef OLCUC
1550         data.term.c_oflag &= ~OLCUC;
1551 #endif
1552 #ifdef NLDLY
1553         data.term.c_oflag &= ~NLDLY;
1554 #endif
1555 #ifdef CRDLY
1556         data.term.c_oflag &= ~CRDLY;
1557 #endif
1558 #ifdef TABDLY
1559         data.term.c_oflag &= ~TABDLY;
1560 #endif
1561 #ifdef BSDLY
1562         data.term.c_oflag &= ~BSDLY;
1563 #endif
1564 #ifdef VTDLY
1565         data.term.c_oflag &= ~VTDLY;
1566 #endif
1567 #ifdef FFDLY
1568         data.term.c_oflag &= ~FFDLY;
1569 #endif
1570 #ifdef OFILL
1571         data.term.c_oflag &= ~OFILL;
1572 #endif
1573         data.term.c_lflag &= ~(ISIG | ICANON | ECHO | IEXTEN);
1574         data.term.c_cc[VMIN] = 0;
1575         data.term.c_cc[VTIME] = 0;
1576
1577         /* Ignore modem status lines; enable receiver; leave control lines alone on close. */
1578         data.term.c_cflag |= (CLOCAL | CREAD | HUPCL);
1579 #endif
1580
1581 #ifdef _WIN32
1582         if (ClearCommError(port->hdl, &errors, &status) == 0)
1583                 RETURN_FAIL("ClearCommError() failed");
1584 #endif
1585
1586         ret = set_config(port, &data, &config);
1587
1588         if (ret < 0) {
1589                 sp_close(port);
1590                 RETURN_CODEVAL(ret);
1591         }
1592
1593         RETURN_OK();
1594 }
1595
1596 enum sp_return sp_close(struct sp_port *port)
1597 {
1598         TRACE("%p", port);
1599
1600         CHECK_OPEN_PORT();
1601
1602         DEBUG("Closing port %s", port->name);
1603
1604 #ifdef _WIN32
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;
1609
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"); \
1615 } while (0)
1616         CLOSE_OVERLAPPED(read_ovl);
1617         CLOSE_OVERLAPPED(write_ovl);
1618         CLOSE_OVERLAPPED(wait_ovl);
1619
1620 #else
1621         /* Returns 0 upon success, -1 upon failure. */
1622         if (close(port->fd) == -1)
1623                 RETURN_FAIL("close() failed");
1624         port->fd = -1;
1625 #endif
1626
1627         RETURN_OK();
1628 }
1629
1630 enum sp_return sp_flush(struct sp_port *port, enum sp_buffer buffers)
1631 {
1632         TRACE("%p, 0x%x", port, buffers);
1633
1634         CHECK_OPEN_PORT();
1635
1636         if (buffers > SP_BUF_BOTH)
1637                 RETURN_ERROR(SP_ERR_ARG, "Invalid buffer selection");
1638
1639         const char *buffer_names[] = {"no", "input", "output", "both"};
1640
1641         DEBUG("Flushing %s buffers on port %s", buffer_names[buffers], port->name);
1642
1643 #ifdef _WIN32
1644         DWORD flags = 0;
1645         if (buffers & SP_BUF_INPUT)
1646                 flags |= PURGE_RXCLEAR;
1647         if (buffers & SP_BUF_OUTPUT)
1648                 flags |= PURGE_TXCLEAR;
1649
1650         /* Returns non-zero upon success, 0 upon failure. */
1651         if (PurgeComm(port->hdl, flags) == 0)
1652                 RETURN_FAIL("PurgeComm() failed");
1653 #else
1654         int flags = 0;
1655         if (buffers & SP_BUF_BOTH)
1656                 flags = TCIOFLUSH;
1657         else if (buffers & SP_BUF_INPUT)
1658                 flags = TCIFLUSH;
1659         else if (buffers & SP_BUF_OUTPUT)
1660                 flags = TCOFLUSH;
1661
1662         /* Returns 0 upon success, -1 upon failure. */
1663         if (tcflush(port->fd, flags) < 0)
1664                 RETURN_FAIL("tcflush() failed");
1665 #endif
1666         RETURN_OK();
1667 }
1668
1669 enum sp_return sp_drain(struct sp_port *port)
1670 {
1671         TRACE("%p", port);
1672
1673         CHECK_OPEN_PORT();
1674
1675         DEBUG("Draining port %s", port->name);
1676
1677 #ifdef _WIN32
1678         /* Returns non-zero upon success, 0 upon failure. */
1679         if (FlushFileBuffers(port->hdl) == 0)
1680                 RETURN_FAIL("FlushFileBuffers() failed");
1681         RETURN_OK();
1682 #else
1683         int result;
1684         while (1) {
1685 #ifdef __ANDROID__
1686                 int arg = 1;
1687                 result = ioctl(port->fd, TCSBRK, &arg);
1688 #else
1689                 result = tcdrain(port->fd);
1690 #endif
1691                 if (result < 0) {
1692                         if (errno == EINTR) {
1693                                 DEBUG("tcdrain() was interrupted");
1694                                 continue;
1695                         } else {
1696                                 RETURN_FAIL("tcdrain() failed");
1697                         }
1698                 } else {
1699                         RETURN_OK();
1700                 }
1701         }
1702 #endif
1703 }
1704
1705 enum sp_return sp_blocking_write(struct sp_port *port, const void *buf, size_t count, unsigned int timeout)
1706 {
1707         TRACE("%p, %p, %d, %d", port, buf, count, timeout);
1708
1709         CHECK_OPEN_PORT();
1710
1711         if (!buf)
1712                 RETURN_ERROR(SP_ERR_ARG, "Null buffer");
1713
1714         if (timeout)
1715                 DEBUG("Writing %d bytes to port %s, timeout %d ms", count, port->name, timeout);
1716         else
1717                 DEBUG("Writing %d bytes to port %s, no timeout", count, port->name);
1718
1719         if (count == 0)
1720                 RETURN_VALUE("0", 0);
1721
1722 #ifdef _WIN32
1723         DWORD bytes_written = 0;
1724         BOOL result;
1725
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);
1730                 port->writing = 0;
1731                 if (!result)
1732                         RETURN_FAIL("Previous write failed to complete");
1733                 DEBUG("Previous write completed");
1734         }
1735
1736         /* Set timeout. */
1737         port->timeouts.WriteTotalTimeoutConstant = timeout;
1738         if (SetCommTimeouts(port->hdl, &port->timeouts) == 0)
1739                 RETURN_FAIL("SetCommTimeouts() failed");
1740
1741         /* Start write. */
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);
1748                 } else {
1749                         RETURN_FAIL("WriteFile() failed");
1750                 }
1751         } else {
1752                 DEBUG("Write completed immediately");
1753                 RETURN_VALUE("%d", count);
1754         }
1755 #else
1756         size_t bytes_written = 0;
1757         unsigned char *ptr = (unsigned char *) buf;
1758         struct timeval start, delta, now, end = {0, 0};
1759         fd_set fds;
1760         int result;
1761
1762         if (timeout) {
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);
1770         }
1771
1772         /* Loop until we have written the requested number of bytes. */
1773         while (bytes_written < count)
1774         {
1775                 /* Wait until space is available. */
1776                 FD_ZERO(&fds);
1777                 FD_SET(port->fd, &fds);
1778                 if (timeout) {
1779                         gettimeofday(&now, NULL);
1780                         if (timercmp(&now, &end, >)) {
1781                                 DEBUG("write timed out");
1782                                 RETURN_VALUE("%d", bytes_written);
1783                         }
1784                         timersub(&end, &now, &delta);
1785                 }
1786                 result = select(port->fd + 1, NULL, &fds, NULL, timeout ? &delta : NULL);
1787                 if (result < 0) {
1788                         if (errno == EINTR) {
1789                                 DEBUG("select() call was interrupted, repeating");
1790                                 continue;
1791                         } else {
1792                                 RETURN_FAIL("select() failed");
1793                         }
1794                 } else if (result == 0) {
1795                         DEBUG("write timed out");
1796                         RETURN_VALUE("%d", bytes_written);
1797                 }
1798
1799                 /* Do write. */
1800                 result = write(port->fd, ptr, count - bytes_written);
1801
1802                 if (result < 0) {
1803                         if (errno == EAGAIN)
1804                                 /* This shouldn't happen because we did a select() first, but handle anyway. */
1805                                 continue;
1806                         else
1807                                 /* This is an actual failure. */
1808                                 RETURN_FAIL("write() failed");
1809                 }
1810
1811                 bytes_written += result;
1812                 ptr += result;
1813         }
1814
1815         RETURN_VALUE("%d", bytes_written);
1816 #endif
1817 }
1818
1819 enum sp_return sp_nonblocking_write(struct sp_port *port, const void *buf, size_t count)
1820 {
1821         TRACE("%p, %p, %d", port, buf, count);
1822
1823         CHECK_OPEN_PORT();
1824
1825         if (!buf)
1826                 RETURN_ERROR(SP_ERR_ARG, "Null buffer");
1827
1828         DEBUG("Writing up to %d bytes to port %s", count, port->name);
1829
1830         if (count == 0)
1831                 RETURN_VALUE("0", 0);
1832
1833 #ifdef _WIN32
1834         DWORD written = 0;
1835         BYTE *ptr = (BYTE *) buf;
1836
1837         /* Check whether previous write is complete. */
1838         if (port->writing) {
1839                 if (HasOverlappedIoCompleted(&port->write_ovl)) {
1840                         DEBUG("Previous write completed");
1841                         port->writing = 0;
1842                 } else {
1843                         DEBUG("Previous write not complete");
1844                         /* Can't take a new write until the previous one finishes. */
1845                         RETURN_VALUE("0", 0);
1846                 }
1847         }
1848
1849         /* Set timeout. */
1850         port->timeouts.WriteTotalTimeoutConstant = 0;
1851         if (SetCommTimeouts(port->hdl, &port->timeouts) == 0)
1852                 RETURN_FAIL("SetCommTimeouts() failed");
1853
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)
1857         {
1858                 /* Copy first byte of user buffer. */
1859                 port->pending_byte = *ptr++;
1860
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");
1866                                         port->writing = 0;
1867                                         written++;
1868                                         continue;
1869                                 } else {
1870                                         DEBUG("Asynchronous write running");
1871                                         port->writing = 1;
1872                                         RETURN_VALUE("%d", ++written);
1873                                 }
1874                         } else {
1875                                 /* Actual failure of some kind. */
1876                                 RETURN_FAIL("WriteFile() failed");
1877                         }
1878                 } else {
1879                         DEBUG("Single byte written immediately");
1880                         written++;
1881                 }
1882         }
1883
1884         DEBUG("All bytes written immediately");
1885
1886         RETURN_VALUE("%d", written);
1887 #else
1888         /* Returns the number of bytes written, or -1 upon failure. */
1889         ssize_t written = write(port->fd, buf, count);
1890
1891         if (written < 0)
1892                 RETURN_FAIL("write() failed");
1893         else
1894                 RETURN_VALUE("%d", written);
1895 #endif
1896 }
1897
1898 enum sp_return sp_blocking_read(struct sp_port *port, void *buf, size_t count, unsigned int timeout)
1899 {
1900         TRACE("%p, %p, %d, %d", port, buf, count, timeout);
1901
1902         CHECK_OPEN_PORT();
1903
1904         if (!buf)
1905                 RETURN_ERROR(SP_ERR_ARG, "Null buffer");
1906
1907         if (timeout)
1908                 DEBUG("Reading %d bytes from port %s, timeout %d ms", count, port->name, timeout);
1909         else
1910                 DEBUG("Reading %d bytes from port %s, no timeout", count, port->name);
1911
1912         if (count == 0)
1913                 RETURN_VALUE("0", 0);
1914
1915 #ifdef _WIN32
1916         DWORD bytes_read = 0;
1917
1918         /* Set timeout. */
1919         port->timeouts.ReadIntervalTimeout = 0;
1920         port->timeouts.ReadTotalTimeoutConstant = timeout;
1921         if (SetCommTimeouts(port->hdl, &port->timeouts) == 0)
1922                 RETURN_FAIL("SetCommTimeouts() failed");
1923
1924         /* Start read. */
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);
1930                 } else {
1931                         RETURN_FAIL("ReadFile() failed");
1932                 }
1933         } else {
1934                 DEBUG("Read completed immediately");
1935                 bytes_read = count;
1936         }
1937
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");
1942         }
1943
1944         RETURN_VALUE("%d", bytes_read);
1945
1946 #else
1947         size_t bytes_read = 0;
1948         unsigned char *ptr = (unsigned char *) buf;
1949         struct timeval start, delta, now, end = {0, 0};
1950         fd_set fds;
1951         int result;
1952
1953         if (timeout) {
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);
1961         }
1962
1963         /* Loop until we have the requested number of bytes. */
1964         while (bytes_read < count)
1965         {
1966                 /* Wait until data is available. */
1967                 FD_ZERO(&fds);
1968                 FD_SET(port->fd, &fds);
1969                 if (timeout) {
1970                         gettimeofday(&now, NULL);
1971                         if (timercmp(&now, &end, >))
1972                                 /* Timeout has expired. */
1973                                 RETURN_VALUE("%d", bytes_read);
1974                         timersub(&end, &now, &delta);
1975                 }
1976                 result = select(port->fd + 1, &fds, NULL, NULL, timeout ? &delta : NULL);
1977                 if (result < 0) {
1978                         if (errno == EINTR) {
1979                                 DEBUG("select() call was interrupted, repeating");
1980                                 continue;
1981                         } else {
1982                                 RETURN_FAIL("select() failed");
1983                         }
1984                 } else if (result == 0) {
1985                         DEBUG("read timed out");
1986                         RETURN_VALUE("%d", bytes_read);
1987                 }
1988
1989                 /* Do read. */
1990                 result = read(port->fd, ptr, count - bytes_read);
1991
1992                 if (result < 0) {
1993                         if (errno == EAGAIN)
1994                                 /* This shouldn't happen because we did a select() first, but handle anyway. */
1995                                 continue;
1996                         else
1997                                 /* This is an actual failure. */
1998                                 RETURN_FAIL("read() failed");
1999                 }
2000
2001                 bytes_read += result;
2002                 ptr += result;
2003         }
2004
2005         RETURN_VALUE("%d", bytes_read);
2006 #endif
2007 }
2008
2009 enum sp_return sp_nonblocking_read(struct sp_port *port, void *buf, size_t count)
2010 {
2011         TRACE("%p, %p, %d", port, buf, count);
2012
2013         CHECK_OPEN_PORT();
2014
2015         if (!buf)
2016                 RETURN_ERROR(SP_ERR_ARG, "Null buffer");
2017
2018         DEBUG("Reading up to %d bytes from port %s", count, port->name);
2019
2020 #ifdef _WIN32
2021         DWORD bytes_read;
2022
2023         /* Set timeout. */
2024         port->timeouts.ReadIntervalTimeout = MAXDWORD;
2025         port->timeouts.ReadTotalTimeoutConstant = 0;
2026         if (SetCommTimeouts(port->hdl, &port->timeouts) == 0)
2027                 RETURN_FAIL("SetCommTimeouts() failed");
2028
2029         /* Do read. */
2030         if (ReadFile(port->hdl, buf, count, NULL, &port->read_ovl) == 0)
2031                 RETURN_FAIL("ReadFile() failed");
2032
2033         /* Get number of bytes read. */
2034         if (GetOverlappedResult(port->hdl, &port->read_ovl, &bytes_read, TRUE) == 0)
2035                 RETURN_FAIL("GetOverlappedResult() failed");
2036
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");
2042                 }
2043         }
2044
2045         RETURN_VALUE("%d", bytes_read);
2046 #else
2047         ssize_t bytes_read;
2048
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. */
2053                         bytes_read = 0;
2054                 else
2055                         /* This is an actual failure. */
2056                         RETURN_FAIL("read() failed");
2057         }
2058         RETURN_VALUE("%d", bytes_read);
2059 #endif
2060 }
2061
2062 enum sp_return sp_input_waiting(struct sp_port *port)
2063 {
2064         TRACE("%p", port);
2065
2066         CHECK_OPEN_PORT();
2067
2068         DEBUG("Checking input bytes waiting on port %s", port->name);
2069
2070 #ifdef _WIN32
2071         DWORD errors;
2072         COMSTAT comstat;
2073
2074         if (ClearCommError(port->hdl, &errors, &comstat) == 0)
2075                 RETURN_FAIL("ClearCommError() failed");
2076         RETURN_VALUE("%d", comstat.cbInQue);
2077 #else
2078         int bytes_waiting;
2079         if (ioctl(port->fd, TIOCINQ, &bytes_waiting) < 0)
2080                 RETURN_FAIL("TIOCINQ ioctl failed");
2081         RETURN_VALUE("%d", bytes_waiting);
2082 #endif
2083 }
2084
2085 enum sp_return sp_output_waiting(struct sp_port *port)
2086 {
2087         TRACE("%p", port);
2088
2089         CHECK_OPEN_PORT();
2090
2091         DEBUG("Checking output bytes waiting on port %s", port->name);
2092
2093 #ifdef _WIN32
2094         DWORD errors;
2095         COMSTAT comstat;
2096
2097         if (ClearCommError(port->hdl, &errors, &comstat) == 0)
2098                 RETURN_FAIL("ClearCommError() failed");
2099         RETURN_VALUE("%d", comstat.cbOutQue);
2100 #else
2101         int bytes_waiting;
2102         if (ioctl(port->fd, TIOCOUTQ, &bytes_waiting) < 0)
2103                 RETURN_FAIL("TIOCOUTQ ioctl failed");
2104         RETURN_VALUE("%d", bytes_waiting);
2105 #endif
2106 }
2107
2108 enum sp_return sp_new_event_set(struct sp_event_set **result_ptr)
2109 {
2110         struct sp_event_set *result;
2111
2112         TRACE("%p", result_ptr);
2113
2114         if (!result_ptr)
2115                 RETURN_ERROR(SP_ERR_ARG, "Null result");
2116
2117         *result_ptr = NULL;
2118
2119         if (!(result = malloc(sizeof(struct sp_event_set))))
2120                 RETURN_ERROR(SP_ERR_MEM, "sp_event_set malloc() failed");
2121
2122         memset(result, 0, sizeof(struct sp_event_set));
2123
2124         *result_ptr = result;
2125
2126         RETURN_OK();
2127 }
2128
2129 static enum sp_return add_handle(struct sp_event_set *event_set,
2130                 event_handle handle, enum sp_event mask)
2131 {
2132         void *new_handles;
2133         enum sp_event *new_masks;
2134
2135         TRACE("%p, %d, %d", event_set, handle, mask);
2136
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");
2140
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");
2144
2145         event_set->handles = new_handles;
2146         event_set->masks = new_masks;
2147
2148         ((event_handle *) event_set->handles)[event_set->count] = handle;
2149         event_set->masks[event_set->count] = mask;
2150
2151         event_set->count++;
2152
2153         RETURN_OK();
2154 }
2155
2156 enum sp_return sp_add_port_events(struct sp_event_set *event_set,
2157         const struct sp_port *port, enum sp_event mask)
2158 {
2159         TRACE("%p, %p, %d", event_set, port, mask);
2160
2161         if (!event_set)
2162                 RETURN_ERROR(SP_ERR_ARG, "Null event set");
2163
2164         if (!port)
2165                 RETURN_ERROR(SP_ERR_ARG, "Null port");
2166
2167         if (mask > (SP_EVENT_RX_READY | SP_EVENT_TX_READY | SP_EVENT_ERROR))
2168                 RETURN_ERROR(SP_ERR_ARG, "Invalid event mask");
2169
2170         if (!mask)
2171                 RETURN_OK();
2172
2173 #ifdef _WIN32
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));
2179 #else
2180         TRY(add_handle(event_set, port->fd, mask));
2181 #endif
2182
2183         RETURN_OK();
2184 }
2185
2186 void sp_free_event_set(struct sp_event_set *event_set)
2187 {
2188         TRACE("%p", event_set);
2189
2190         if (!event_set) {
2191                 DEBUG("Null event set");
2192                 RETURN();
2193         }
2194
2195         DEBUG("Freeing event set");
2196
2197         if (event_set->handles)
2198                 free(event_set->handles);
2199         if (event_set->masks)
2200                 free(event_set->masks);
2201
2202         free(event_set);
2203
2204         RETURN();
2205 }
2206
2207 enum sp_return sp_wait(struct sp_event_set *event_set, unsigned int timeout)
2208 {
2209         TRACE("%p, %d", event_set, timeout);
2210
2211         if (!event_set)
2212                 RETURN_ERROR(SP_ERR_ARG, "Null event set");
2213
2214 #ifdef _WIN32
2215         if (WaitForMultipleObjects(event_set->count, event_set->handles, FALSE,
2216                         timeout ? timeout : INFINITE) == WAIT_FAILED)
2217                 RETURN_FAIL("WaitForMultipleObjects() failed");
2218
2219         RETURN_OK();
2220 #else
2221         struct timeval start, delta, now, end = {0, 0};
2222         int result, timeout_remaining;
2223         struct pollfd *pollfds;
2224         unsigned int i;
2225
2226         if (!(pollfds = malloc(sizeof(struct pollfd) * event_set->count)))
2227                 RETURN_ERROR(SP_ERR_MEM, "pollfds malloc() failed");
2228
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;
2239         }
2240
2241         if (timeout) {
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);
2249         }
2250
2251         /* Loop until an event occurs. */
2252         while (1)
2253         {
2254                 if (timeout) {
2255                         gettimeofday(&now, NULL);
2256                         if (timercmp(&now, &end, >)) {
2257                                 DEBUG("wait timed out");
2258                                 break;
2259                         }
2260                         timersub(&end, &now, &delta);
2261                         timeout_remaining = delta.tv_sec * 1000 + delta.tv_usec / 1000;
2262                 }
2263
2264                 result = poll(pollfds, event_set->count, timeout ? timeout_remaining : -1);
2265
2266                 if (result < 0) {
2267                         if (errno == EINTR) {
2268                                 DEBUG("poll() call was interrupted, repeating");
2269                                 continue;
2270                         } else {
2271                                 free(pollfds);
2272                                 RETURN_FAIL("poll() failed");
2273                         }
2274                 } else if (result == 0) {
2275                         DEBUG("poll() timed out");
2276                         break;
2277                 } else {
2278                         DEBUG("poll() completed");
2279                         break;
2280                 }
2281         }
2282
2283         free(pollfds);
2284         RETURN_OK();
2285 #endif
2286 }
2287
2288 #ifdef USE_TERMIOS_SPEED
2289 static enum sp_return get_baudrate(int fd, int *baudrate)
2290 {
2291         void *data;
2292
2293         TRACE("%d, %p", fd, baudrate);
2294
2295         DEBUG("Getting baud rate");
2296
2297         if (!(data = malloc(get_termios_size())))
2298                 RETURN_ERROR(SP_ERR_MEM, "termios malloc failed");
2299
2300         if (ioctl(fd, get_termios_get_ioctl(), data) < 0) {
2301                 free(data);
2302                 RETURN_FAIL("getting termios failed");
2303         }
2304
2305         *baudrate = get_termios_speed(data);
2306
2307         free(data);
2308
2309         RETURN_OK();
2310 }
2311
2312 static enum sp_return set_baudrate(int fd, int baudrate)
2313 {
2314         void *data;
2315
2316         TRACE("%d, %d", fd, baudrate);
2317
2318         DEBUG("Getting baud rate");
2319
2320         if (!(data = malloc(get_termios_size())))
2321                 RETURN_ERROR(SP_ERR_MEM, "termios malloc failed");
2322
2323         if (ioctl(fd, get_termios_get_ioctl(), data) < 0) {
2324                 free(data);
2325                 RETURN_FAIL("getting termios failed");
2326         }
2327
2328         DEBUG("Setting baud rate");
2329
2330         set_termios_speed(data, baudrate);
2331
2332         if (ioctl(fd, get_termios_set_ioctl(), data) < 0) {
2333                 free(data);
2334                 RETURN_FAIL("setting termios failed");
2335         }
2336
2337         free(data);
2338
2339         RETURN_OK();
2340 }
2341 #endif /* USE_TERMIOS_SPEED */
2342
2343 #ifdef USE_TERMIOX
2344 static enum sp_return get_flow(int fd, struct port_data *data)
2345 {
2346         void *termx;
2347
2348         TRACE("%d, %p", fd, data);
2349
2350         DEBUG("Getting advanced flow control");
2351
2352         if (!(termx = malloc(get_termiox_size())))
2353                 RETURN_ERROR(SP_ERR_MEM, "termiox malloc failed");
2354
2355         if (ioctl(fd, TCGETX, termx) < 0) {
2356                 free(termx);
2357                 RETURN_FAIL("getting termiox failed");
2358         }
2359
2360         get_termiox_flow(termx, &data->rts_flow, &data->cts_flow,
2361                         &data->dtr_flow, &data->dsr_flow);
2362
2363         free(termx);
2364
2365         RETURN_OK();
2366 }
2367
2368 static enum sp_return set_flow(int fd, struct port_data *data)
2369 {
2370         void *termx;
2371
2372         TRACE("%d, %p", fd, data);
2373
2374         DEBUG("Getting advanced flow control");
2375
2376         if (!(termx = malloc(get_termiox_size())))
2377                 RETURN_ERROR(SP_ERR_MEM, "termiox malloc failed");
2378
2379         if (ioctl(fd, TCGETX, termx) < 0) {
2380                 free(termx);
2381                 RETURN_FAIL("getting termiox failed");
2382         }
2383
2384         DEBUG("Setting advanced flow control");
2385
2386         set_termiox_flow(termx, data->rts_flow, data->cts_flow,
2387                         data->dtr_flow, data->dsr_flow);
2388
2389         if (ioctl(fd, TCSETX, termx) < 0) {
2390                 free(termx);
2391                 RETURN_FAIL("setting termiox failed");
2392         }
2393
2394         free(termx);
2395
2396         RETURN_OK();
2397 }
2398 #endif /* USE_TERMIOX */
2399
2400 static enum sp_return get_config(struct sp_port *port, struct port_data *data,
2401         struct sp_port_config *config)
2402 {
2403         unsigned int i;
2404
2405         TRACE("%p, %p, %p", port, data, config);
2406
2407         DEBUG("Getting configuration for port %s", port->name);
2408
2409 #ifdef _WIN32
2410         if (!GetCommState(port->hdl, &data->dcb))
2411                 RETURN_FAIL("GetCommState() failed");
2412
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;
2416                         break;
2417                 }
2418         }
2419
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;
2423
2424         config->bits = data->dcb.ByteSize;
2425
2426         if (data->dcb.fParity)
2427                 switch (data->dcb.Parity) {
2428                 case NOPARITY:
2429                         config->parity = SP_PARITY_NONE;
2430                         break;
2431                 case ODDPARITY:
2432                         config->parity = SP_PARITY_ODD;
2433                         break;
2434                 case EVENPARITY:
2435                         config->parity = SP_PARITY_EVEN;
2436                         break;
2437                 case MARKPARITY:
2438                         config->parity = SP_PARITY_MARK;
2439                         break;
2440                 case SPACEPARITY:
2441                         config->parity = SP_PARITY_SPACE;
2442                         break;
2443                 default:
2444                         config->parity = -1;
2445                 }
2446         else
2447                 config->parity = SP_PARITY_NONE;
2448
2449         switch (data->dcb.StopBits) {
2450         case ONESTOPBIT:
2451                 config->stopbits = 1;
2452                 break;
2453         case TWOSTOPBITS:
2454                 config->stopbits = 2;
2455                 break;
2456         default:
2457                 config->stopbits = -1;
2458         }
2459
2460         switch (data->dcb.fRtsControl) {
2461         case RTS_CONTROL_DISABLE:
2462                 config->rts = SP_RTS_OFF;
2463                 break;
2464         case RTS_CONTROL_ENABLE:
2465                 config->rts = SP_RTS_ON;
2466                 break;
2467         case RTS_CONTROL_HANDSHAKE:
2468                 config->rts = SP_RTS_FLOW_CONTROL;
2469                 break;
2470         default:
2471                 config->rts = -1;
2472         }
2473
2474         config->cts = data->dcb.fOutxCtsFlow ? SP_CTS_FLOW_CONTROL : SP_CTS_IGNORE;
2475
2476         switch (data->dcb.fDtrControl) {
2477         case DTR_CONTROL_DISABLE:
2478                 config->dtr = SP_DTR_OFF;
2479                 break;
2480         case DTR_CONTROL_ENABLE:
2481                 config->dtr = SP_DTR_ON;
2482                 break;
2483         case DTR_CONTROL_HANDSHAKE:
2484                 config->dtr = SP_DTR_FLOW_CONTROL;
2485                 break;
2486         default:
2487                 config->dtr = -1;
2488         }
2489
2490         config->dsr = data->dcb.fOutxDsrFlow ? SP_DSR_FLOW_CONTROL : SP_DSR_IGNORE;
2491
2492         if (data->dcb.fInX) {
2493                 if (data->dcb.fOutX)
2494                         config->xon_xoff = SP_XONXOFF_INOUT;
2495                 else
2496                         config->xon_xoff = SP_XONXOFF_IN;
2497         } else {
2498                 if (data->dcb.fOutX)
2499                         config->xon_xoff = SP_XONXOFF_OUT;
2500                 else
2501                         config->xon_xoff = SP_XONXOFF_DISABLED;
2502         }
2503
2504 #else // !_WIN32
2505
2506         if (tcgetattr(port->fd, &data->term) < 0)
2507                 RETURN_FAIL("tcgetattr() failed");
2508
2509         if (ioctl(port->fd, TIOCMGET, &data->controlbits) < 0)
2510                 RETURN_FAIL("TIOCMGET ioctl failed");
2511
2512 #ifdef USE_TERMIOX
2513         int ret = get_flow(port->fd, data);
2514
2515         if (ret == SP_ERR_FAIL && errno == EINVAL)
2516                 data->termiox_supported = 0;
2517         else if (ret < 0)
2518                 RETURN_CODEVAL(ret);
2519         else
2520                 data->termiox_supported = 1;
2521 #else
2522         data->termiox_supported = 0;
2523 #endif
2524
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;
2528                         break;
2529                 }
2530         }
2531
2532         if (i == NUM_STD_BAUDRATES) {
2533 #ifdef __APPLE__
2534                 config->baudrate = (int)data->term.c_ispeed;
2535 #elif defined(USE_TERMIOS_SPEED)
2536                 TRY(get_baudrate(port->fd, &config->baudrate));
2537 #else
2538                 config->baudrate = -1;
2539 #endif
2540         }
2541
2542         switch (data->term.c_cflag & CSIZE) {
2543         case CS8:
2544                 config->bits = 8;
2545                 break;
2546         case CS7:
2547                 config->bits = 7;
2548                 break;
2549         case CS6:
2550                 config->bits = 6;
2551                 break;
2552         case CS5:
2553                 config->bits = 5;
2554                 break;
2555         default:
2556                 config->bits = -1;
2557         }
2558
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;
2563 #ifdef CMSPAR
2564         else if (data->term.c_cflag & CMSPAR)
2565                 config->parity = (data->term.c_cflag & PARODD) ? SP_PARITY_MARK : SP_PARITY_SPACE;
2566 #endif
2567         else
2568                 config->parity = (data->term.c_cflag & PARODD) ? SP_PARITY_ODD : SP_PARITY_EVEN;
2569
2570         config->stopbits = (data->term.c_cflag & CSTOPB) ? 2 : 1;
2571
2572         if (data->term.c_cflag & CRTSCTS) {
2573                 config->rts = SP_RTS_FLOW_CONTROL;
2574                 config->cts = SP_CTS_FLOW_CONTROL;
2575         } else {
2576                 if (data->termiox_supported && data->rts_flow)
2577                         config->rts = SP_RTS_FLOW_CONTROL;
2578                 else
2579                         config->rts = (data->controlbits & TIOCM_RTS) ? SP_RTS_ON : SP_RTS_OFF;
2580
2581                 config->cts = (data->termiox_supported && data->cts_flow) ?
2582                         SP_CTS_FLOW_CONTROL : SP_CTS_IGNORE;
2583         }
2584
2585         if (data->termiox_supported && data->dtr_flow)
2586                 config->dtr = SP_DTR_FLOW_CONTROL;
2587         else
2588                 config->dtr = (data->controlbits & TIOCM_DTR) ? SP_DTR_ON : SP_DTR_OFF;
2589
2590         config->dsr = (data->termiox_supported && data->dsr_flow) ?
2591                 SP_DSR_FLOW_CONTROL : SP_DSR_IGNORE;
2592
2593         if (data->term.c_iflag & IXOFF) {
2594                 if (data->term.c_iflag & IXON)
2595                         config->xon_xoff = SP_XONXOFF_INOUT;
2596                 else
2597                         config->xon_xoff = SP_XONXOFF_IN;
2598         } else {
2599                 if (data->term.c_iflag & IXON)
2600                         config->xon_xoff = SP_XONXOFF_OUT;
2601                 else
2602                         config->xon_xoff = SP_XONXOFF_DISABLED;
2603         }
2604 #endif
2605
2606         RETURN_OK();
2607 }
2608
2609 static enum sp_return set_config(struct sp_port *port, struct port_data *data,
2610         const struct sp_port_config *config)
2611 {
2612         unsigned int i;
2613 #ifdef __APPLE__
2614         BAUD_TYPE baud_nonstd;
2615
2616         baud_nonstd = B0;
2617 #endif
2618 #ifdef USE_TERMIOS_SPEED
2619         int baud_nonstd = 0;
2620 #endif
2621
2622         TRACE("%p, %p, %p", port, data, config);
2623
2624         DEBUG("Setting configuration for port %s", port->name);
2625
2626 #ifdef _WIN32
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;
2631                                 break;
2632                         }
2633                 }
2634
2635                 if (i == NUM_STD_BAUDRATES)
2636                         data->dcb.BaudRate = config->baudrate;
2637         }
2638
2639         if (config->bits >= 0)
2640                 data->dcb.ByteSize = config->bits;
2641
2642         if (config->parity >= 0) {
2643                 switch (config->parity) {
2644                 case SP_PARITY_NONE:
2645                         data->dcb.Parity = NOPARITY;
2646                         break;
2647                 case SP_PARITY_ODD:
2648                         data->dcb.Parity = ODDPARITY;
2649                         break;
2650                 case SP_PARITY_EVEN:
2651                         data->dcb.Parity = EVENPARITY;
2652                         break;
2653                 case SP_PARITY_MARK:
2654                         data->dcb.Parity = MARKPARITY;
2655                         break;
2656                 case SP_PARITY_SPACE:
2657                         data->dcb.Parity = SPACEPARITY;
2658                         break;
2659                 default:
2660                         RETURN_ERROR(SP_ERR_ARG, "Invalid parity setting");
2661                 }
2662         }
2663
2664         if (config->stopbits >= 0) {
2665                 switch (config->stopbits) {
2666                 /* Note: There's also ONE5STOPBITS == 1.5 (unneeded so far). */
2667                 case 1:
2668                         data->dcb.StopBits = ONESTOPBIT;
2669                         break;
2670                 case 2:
2671                         data->dcb.StopBits = TWOSTOPBITS;
2672                         break;
2673                 default:
2674                         RETURN_ERROR(SP_ERR_ARG, "Invalid stop bit setting");
2675                 }
2676         }
2677
2678         if (config->rts >= 0) {
2679                 switch (config->rts) {
2680                 case SP_RTS_OFF:
2681                         data->dcb.fRtsControl = RTS_CONTROL_DISABLE;
2682                         break;
2683                 case SP_RTS_ON:
2684                         data->dcb.fRtsControl = RTS_CONTROL_ENABLE;
2685                         break;
2686                 case SP_RTS_FLOW_CONTROL:
2687                         data->dcb.fRtsControl = RTS_CONTROL_HANDSHAKE;
2688                         break;
2689                 default:
2690                         RETURN_ERROR(SP_ERR_ARG, "Invalid RTS setting");
2691                 }
2692         }
2693
2694         if (config->cts >= 0) {
2695                 switch (config->cts) {
2696                 case SP_CTS_IGNORE:
2697                         data->dcb.fOutxCtsFlow = FALSE;
2698                         break;
2699                 case SP_CTS_FLOW_CONTROL:
2700                         data->dcb.fOutxCtsFlow = TRUE;
2701                         break;
2702                 default:
2703                         RETURN_ERROR(SP_ERR_ARG, "Invalid CTS setting");
2704                 }
2705         }
2706
2707         if (config->dtr >= 0) {
2708                 switch (config->dtr) {
2709                 case SP_DTR_OFF:
2710                         data->dcb.fDtrControl = DTR_CONTROL_DISABLE;
2711                         break;
2712                 case SP_DTR_ON:
2713                         data->dcb.fDtrControl = DTR_CONTROL_ENABLE;
2714                         break;
2715                 case SP_DTR_FLOW_CONTROL:
2716                         data->dcb.fDtrControl = DTR_CONTROL_HANDSHAKE;
2717                         break;
2718                 default:
2719                         RETURN_ERROR(SP_ERR_ARG, "Invalid DTR setting");
2720                 }
2721         }
2722
2723         if (config->dsr >= 0) {
2724                 switch (config->dsr) {
2725                 case SP_DSR_IGNORE:
2726                         data->dcb.fOutxDsrFlow = FALSE;
2727                         break;
2728                 case SP_DSR_FLOW_CONTROL:
2729                         data->dcb.fOutxDsrFlow = TRUE;
2730                         break;
2731                 default:
2732                         RETURN_ERROR(SP_ERR_ARG, "Invalid DSR setting");
2733                 }
2734         }
2735
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;
2741                         break;
2742                 case SP_XONXOFF_IN:
2743                         data->dcb.fInX = TRUE;
2744                         data->dcb.fOutX = FALSE;
2745                         break;
2746                 case SP_XONXOFF_OUT:
2747                         data->dcb.fInX = FALSE;
2748                         data->dcb.fOutX = TRUE;
2749                         break;
2750                 case SP_XONXOFF_INOUT:
2751                         data->dcb.fInX = TRUE;
2752                         data->dcb.fOutX = TRUE;
2753                         break;
2754                 default:
2755                         RETURN_ERROR(SP_ERR_ARG, "Invalid XON/XOFF setting");
2756                 }
2757         }
2758
2759         if (!SetCommState(port->hdl, &data->dcb))
2760                 RETURN_FAIL("SetCommState() failed");
2761
2762 #else /* !_WIN32 */
2763
2764         int controlbits;
2765
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");
2771
2772                                 if (cfsetispeed(&data->term, std_baudrates[i].index) < 0)
2773                                         RETURN_FAIL("cfsetispeed() failed");
2774                                 break;
2775                         }
2776                 }
2777
2778                 /* Non-standard baud rate */
2779                 if (i == NUM_STD_BAUDRATES) {
2780 #ifdef __APPLE__
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)
2786                         baud_nonstd = 1;
2787 #else
2788                         RETURN_ERROR(SP_ERR_SUPP, "Non-standard baudrate not supported");
2789 #endif
2790                 }
2791         }
2792
2793         if (config->bits >= 0) {
2794                 data->term.c_cflag &= ~CSIZE;
2795                 switch (config->bits) {
2796                 case 8:
2797                         data->term.c_cflag |= CS8;
2798                         break;
2799                 case 7:
2800                         data->term.c_cflag |= CS7;
2801                         break;
2802                 case 6:
2803                         data->term.c_cflag |= CS6;
2804                         break;
2805                 case 5:
2806                         data->term.c_cflag |= CS5;
2807                         break;
2808                 default:
2809                         RETURN_ERROR(SP_ERR_ARG, "Invalid data bits setting");
2810                 }
2811         }
2812
2813         if (config->parity >= 0) {
2814                 data->term.c_iflag &= ~IGNPAR;
2815                 data->term.c_cflag &= ~(PARENB | PARODD);
2816 #ifdef CMSPAR
2817                 data->term.c_cflag &= ~CMSPAR;
2818 #endif
2819                 switch (config->parity) {
2820                 case SP_PARITY_NONE:
2821                         data->term.c_iflag |= IGNPAR;
2822                         break;
2823                 case SP_PARITY_EVEN:
2824                         data->term.c_cflag |= PARENB;
2825                         break;
2826                 case SP_PARITY_ODD:
2827                         data->term.c_cflag |= PARENB | PARODD;
2828                         break;
2829 #ifdef CMSPAR
2830                 case SP_PARITY_MARK:
2831                         data->term.c_cflag |= PARENB | PARODD;
2832                         data->term.c_cflag |= CMSPAR;
2833                         break;
2834                 case SP_PARITY_SPACE:
2835                         data->term.c_cflag |= PARENB;
2836                         data->term.c_cflag |= CMSPAR;
2837                         break;
2838 #else
2839                 case SP_PARITY_MARK:
2840                 case SP_PARITY_SPACE:
2841                         RETURN_ERROR(SP_ERR_SUPP, "Mark/space parity not supported");
2842 #endif
2843                 default:
2844                         RETURN_ERROR(SP_ERR_ARG, "Invalid parity setting");
2845                 }
2846         }
2847
2848         if (config->stopbits >= 0) {
2849                 data->term.c_cflag &= ~CSTOPB;
2850                 switch (config->stopbits) {
2851                 case 1:
2852                         data->term.c_cflag &= ~CSTOPB;
2853                         break;
2854                 case 2:
2855                         data->term.c_cflag |= CSTOPB;
2856                         break;
2857                 default:
2858                         RETURN_ERROR(SP_ERR_ARG, "Invalid stop bits setting");
2859                 }
2860         }
2861
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) {
2866                         case SP_RTS_OFF:
2867                         case SP_RTS_ON:
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");
2871                                 break;
2872                         case SP_RTS_FLOW_CONTROL:
2873                                 data->rts_flow = 1;
2874                                 break;
2875                         default:
2876                                 break;
2877                         }
2878                         if (config->cts == SP_CTS_FLOW_CONTROL)
2879                                 data->cts_flow = 1;
2880
2881                         if (data->rts_flow && data->cts_flow)
2882                                 data->term.c_iflag |= CRTSCTS;
2883                         else
2884                                 data->term.c_iflag &= ~CRTSCTS;
2885                 } else {
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");
2892                                 }
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");
2896                                 }
2897                         } else {
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");
2902                         }
2903
2904                         if (config->rts >= 0) {
2905                                 if (config->rts == SP_RTS_FLOW_CONTROL) {
2906                                         data->term.c_iflag |= CRTSCTS;
2907                                 } else {
2908                                         controlbits = TIOCM_RTS;
2909                                         if (ioctl(port->fd, config->rts == SP_RTS_ON ? TIOCMBIS : TIOCMBIC,
2910                                                         &controlbits) < 0)
2911                                                 RETURN_FAIL("Setting RTS signal level failed");
2912                                 }
2913                         }
2914                 }
2915         }
2916
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) {
2921                         case SP_DTR_OFF:
2922                         case SP_DTR_ON:
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");
2926                                 break;
2927                         case SP_DTR_FLOW_CONTROL:
2928                                 data->dtr_flow = 1;
2929                                 break;
2930                         default:
2931                                 break;
2932                         }
2933                         if (config->dsr == SP_DSR_FLOW_CONTROL)
2934                                 data->dsr_flow = 1;
2935                 } else {
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");
2939
2940                         if (config->dtr >= 0) {
2941                                 controlbits = TIOCM_DTR;
2942                                 if (ioctl(port->fd, config->dtr == SP_DTR_ON ? TIOCMBIS : TIOCMBIC,
2943                                                 &controlbits) < 0)
2944                                         RETURN_FAIL("Setting DTR signal level failed");
2945                         }
2946                 }
2947         }
2948
2949         if (config->xon_xoff >= 0) {
2950                 data->term.c_iflag &= ~(IXON | IXOFF | IXANY);
2951                 switch (config->xon_xoff) {
2952                 case SP_XONXOFF_DISABLED:
2953                         break;
2954                 case SP_XONXOFF_IN:
2955                         data->term.c_iflag |= IXOFF;
2956                         break;
2957                 case SP_XONXOFF_OUT:
2958                         data->term.c_iflag |= IXON | IXANY;
2959                         break;
2960                 case SP_XONXOFF_INOUT:
2961                         data->term.c_iflag |= IXON | IXOFF | IXANY;
2962                         break;
2963                 default:
2964                         RETURN_ERROR(SP_ERR_ARG, "Invalid XON/XOFF setting");
2965                 }
2966         }
2967
2968         if (tcsetattr(port->fd, TCSANOW, &data->term) < 0)
2969                 RETURN_FAIL("tcsetattr() failed");
2970
2971 #ifdef __APPLE__
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");
2979         }
2980 #elif defined(__linux__)
2981 #ifdef USE_TERMIOS_SPEED
2982         if (baud_nonstd)
2983                 TRY(set_baudrate(port->fd, config->baudrate));
2984 #endif
2985 #ifdef USE_TERMIOX
2986         if (data->termiox_supported)
2987                 TRY(set_flow(port->fd, data));
2988 #endif
2989 #endif
2990
2991 #endif /* !_WIN32 */
2992
2993         RETURN_OK();
2994 }
2995
2996 enum sp_return sp_new_config(struct sp_port_config **config_ptr)
2997 {
2998         struct sp_port_config *config;
2999
3000         TRACE("%p", config_ptr);
3001
3002         if (!config_ptr)
3003                 RETURN_ERROR(SP_ERR_ARG, "Null result pointer");
3004
3005         *config_ptr = NULL;
3006
3007         if (!(config = malloc(sizeof(struct sp_port_config))))
3008                 RETURN_ERROR(SP_ERR_MEM, "config malloc failed");
3009
3010         config->baudrate = -1;
3011         config->bits = -1;
3012         config->parity = -1;
3013         config->stopbits = -1;
3014         config->rts = -1;
3015         config->cts = -1;
3016         config->dtr = -1;
3017         config->dsr = -1;
3018
3019         *config_ptr = config;
3020
3021         RETURN_OK();
3022 }
3023
3024 void sp_free_config(struct sp_port_config *config)
3025 {
3026         TRACE("%p", config);
3027
3028         if (!config)
3029                 DEBUG("Null config");
3030         else
3031                 free(config);
3032
3033         RETURN();
3034 }
3035
3036 enum sp_return sp_get_config(struct sp_port *port, struct sp_port_config *config)
3037 {
3038         struct port_data data;
3039
3040         TRACE("%p, %p", port, config);
3041
3042         CHECK_OPEN_PORT();
3043
3044         if (!config)
3045                 RETURN_ERROR(SP_ERR_ARG, "Null config");
3046
3047         TRY(get_config(port, &data, config));
3048
3049         RETURN_OK();
3050 }
3051
3052 enum sp_return sp_set_config(struct sp_port *port, const struct sp_port_config *config)
3053 {
3054         struct port_data data;
3055         struct sp_port_config prev_config;
3056
3057         TRACE("%p, %p", port, config);
3058
3059         CHECK_OPEN_PORT();
3060
3061         if (!config)
3062                 RETURN_ERROR(SP_ERR_ARG, "Null config");
3063
3064         TRY(get_config(port, &data, &prev_config));
3065         TRY(set_config(port, &data, config));
3066
3067         RETURN_OK();
3068 }
3069
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)); \
3077         config.x = x; \
3078         TRY(set_config(port, &data, &config)); \
3079         RETURN_OK(); \
3080 } \
3081 enum sp_return sp_get_config_##x(const struct sp_port_config *config, type *x) { \
3082         TRACE("%p, %p", config, x); \
3083         if (!config) \
3084                 RETURN_ERROR(SP_ERR_ARG, "Null config"); \
3085         *x = config->x; \
3086         RETURN_OK(); \
3087 } \
3088 enum sp_return sp_set_config_##x(struct sp_port_config *config, type x) { \
3089         TRACE("%p, %d", config, x); \
3090         if (!config) \
3091                 RETURN_ERROR(SP_ERR_ARG, "Null config"); \
3092         config->x = x; \
3093         RETURN_OK(); \
3094 }
3095
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)
3105
3106 enum sp_return sp_set_config_flowcontrol(struct sp_port_config *config, enum sp_flowcontrol flowcontrol)
3107 {
3108         if (!config)
3109                 RETURN_ERROR(SP_ERR_ARG, "Null configuration");
3110
3111         if (flowcontrol > SP_FLOWCONTROL_DTRDSR)
3112                 RETURN_ERROR(SP_ERR_ARG, "Invalid flow control setting");
3113
3114         if (flowcontrol == SP_FLOWCONTROL_XONXOFF)
3115                 config->xon_xoff = SP_XONXOFF_INOUT;
3116         else
3117                 config->xon_xoff = SP_XONXOFF_DISABLED;
3118
3119         if (flowcontrol == SP_FLOWCONTROL_RTSCTS) {
3120                 config->rts = SP_RTS_FLOW_CONTROL;
3121                 config->cts = SP_CTS_FLOW_CONTROL;
3122         } else {
3123                 if (config->rts == SP_RTS_FLOW_CONTROL)
3124                         config->rts = SP_RTS_ON;
3125                 config->cts = SP_CTS_IGNORE;
3126         }
3127
3128         if (flowcontrol == SP_FLOWCONTROL_DTRDSR) {
3129                 config->dtr = SP_DTR_FLOW_CONTROL;
3130                 config->dsr = SP_DSR_FLOW_CONTROL;
3131         } else {
3132                 if (config->dtr == SP_DTR_FLOW_CONTROL)
3133                         config->dtr = SP_DTR_ON;
3134                 config->dsr = SP_DSR_IGNORE;
3135         }
3136
3137         RETURN_OK();
3138 }
3139
3140 enum sp_return sp_set_flowcontrol(struct sp_port *port, enum sp_flowcontrol flowcontrol)
3141 {
3142         struct port_data data;
3143         struct sp_port_config config;
3144
3145         TRACE("%p, %d", port, flowcontrol);
3146
3147         CHECK_OPEN_PORT();
3148
3149         TRY(get_config(port, &data, &config));
3150
3151         TRY(sp_set_config_flowcontrol(&config, flowcontrol));
3152
3153         TRY(set_config(port, &data, &config));
3154
3155         RETURN_OK();
3156 }
3157
3158 enum sp_return sp_get_signals(struct sp_port *port, enum sp_signal *signals)
3159 {
3160         TRACE("%p, %p", port, signals);
3161
3162         CHECK_OPEN_PORT();
3163
3164         if (!signals)
3165                 RETURN_ERROR(SP_ERR_ARG, "Null result pointer");
3166
3167         DEBUG("Getting control signals for port %s", port->name);
3168
3169         *signals = 0;
3170 #ifdef _WIN32
3171         DWORD bits;
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;
3182 #else
3183         int bits;
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;
3194 #endif
3195         RETURN_OK();
3196 }
3197
3198 enum sp_return sp_start_break(struct sp_port *port)
3199 {
3200         TRACE("%p", port);
3201
3202         CHECK_OPEN_PORT();
3203 #ifdef _WIN32
3204         if (SetCommBreak(port->hdl) == 0)
3205                 RETURN_FAIL("SetCommBreak() failed");
3206 #else
3207         if (ioctl(port->fd, TIOCSBRK, 1) < 0)
3208                 RETURN_FAIL("TIOCSBRK ioctl failed");
3209 #endif
3210
3211         RETURN_OK();
3212 }
3213
3214 enum sp_return sp_end_break(struct sp_port *port)
3215 {
3216         TRACE("%p", port);
3217
3218         CHECK_OPEN_PORT();
3219 #ifdef _WIN32
3220         if (ClearCommBreak(port->hdl) == 0)
3221                 RETURN_FAIL("ClearCommBreak() failed");
3222 #else
3223         if (ioctl(port->fd, TIOCCBRK, 1) < 0)
3224                 RETURN_FAIL("TIOCCBRK ioctl failed");
3225 #endif
3226
3227         RETURN_OK();
3228 }
3229
3230 int sp_last_error_code(void)
3231 {
3232         TRACE("");
3233 #ifdef _WIN32
3234         RETURN_VALUE("%d", GetLastError());
3235 #else
3236         RETURN_VALUE("%d", errno);
3237 #endif
3238 }
3239
3240 char *sp_last_error_message(void)
3241 {
3242         TRACE("");
3243
3244 #ifdef _WIN32
3245         LPVOID message;
3246         DWORD error = GetLastError();
3247
3248         FormatMessage(
3249                 FORMAT_MESSAGE_ALLOCATE_BUFFER |
3250                 FORMAT_MESSAGE_FROM_SYSTEM |
3251                 FORMAT_MESSAGE_IGNORE_INSERTS,
3252                 NULL,
3253                 error,
3254                 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
3255                 (LPTSTR) &message,
3256                 0, NULL );
3257
3258         RETURN_VALUE("%s", message);
3259 #else
3260         RETURN_VALUE("%s", strerror(errno));
3261 #endif
3262 }
3263
3264 void sp_free_error_message(char *message)
3265 {
3266         TRACE("%s", message);
3267
3268 #ifdef _WIN32
3269         LocalFree(message);
3270 #else
3271         (void)message;
3272 #endif
3273
3274         RETURN();
3275 }
3276
3277 void sp_set_debug_handler(void (*handler)(const char *format, ...))
3278 {
3279         TRACE("%p", handler);
3280
3281         sp_debug_handler = handler;
3282
3283         RETURN();
3284 }
3285
3286 void sp_default_debug_handler(const char *format, ...)
3287 {
3288         va_list args;
3289         va_start(args, format);
3290         if (getenv("LIBSERIALPORT_DEBUG")) {
3291                 fputs("sp: ", stderr);
3292                 vfprintf(stderr, format, args);
3293         }
3294         va_end(args);
3295 }
3296
3297 int sp_get_major_package_version(void)
3298 {
3299         return SP_PACKAGE_VERSION_MAJOR;
3300 }
3301
3302 int sp_get_minor_package_version(void)
3303 {
3304         return SP_PACKAGE_VERSION_MINOR;
3305 }
3306
3307 int sp_get_micro_package_version(void)
3308 {
3309         return SP_PACKAGE_VERSION_MICRO;
3310 }
3311
3312 const char *sp_get_package_version_string(void)
3313 {
3314         return SP_PACKAGE_VERSION_STRING;
3315 }
3316
3317 int sp_get_current_lib_version(void)
3318 {
3319         return SP_LIB_VERSION_CURRENT;
3320 }
3321
3322 int sp_get_revision_lib_version(void)
3323 {
3324         return SP_LIB_VERSION_REVISION;
3325 }
3326
3327 int sp_get_age_lib_version(void)
3328 {
3329         return SP_LIB_VERSION_AGE;
3330 }
3331
3332 const char *sp_get_lib_version_string(void)
3333 {
3334         return SP_LIB_VERSION_STRING;
3335 }
3336
3337 /** @} */