1*0d6140beSAndroid Build Coastguard Worker /*
2*0d6140beSAndroid Build Coastguard Worker * This file is part of the flashrom project.
3*0d6140beSAndroid Build Coastguard Worker *
4*0d6140beSAndroid Build Coastguard Worker * Copyright (C) 2009 Urja Rannikko <[email protected]>
5*0d6140beSAndroid Build Coastguard Worker * Copyright (C) 2009,2010 Carl-Daniel Hailfinger
6*0d6140beSAndroid Build Coastguard Worker *
7*0d6140beSAndroid Build Coastguard Worker * This program is free software; you can redistribute it and/or modify
8*0d6140beSAndroid Build Coastguard Worker * it under the terms of the GNU General Public License as published by
9*0d6140beSAndroid Build Coastguard Worker * the Free Software Foundation; either version 2 of the License, or
10*0d6140beSAndroid Build Coastguard Worker * (at your option) any later version.
11*0d6140beSAndroid Build Coastguard Worker *
12*0d6140beSAndroid Build Coastguard Worker * This program is distributed in the hope that it will be useful,
13*0d6140beSAndroid Build Coastguard Worker * but WITHOUT ANY WARRANTY; without even the implied warranty of
14*0d6140beSAndroid Build Coastguard Worker * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15*0d6140beSAndroid Build Coastguard Worker * GNU General Public License for more details.
16*0d6140beSAndroid Build Coastguard Worker */
17*0d6140beSAndroid Build Coastguard Worker
18*0d6140beSAndroid Build Coastguard Worker #include <stdio.h>
19*0d6140beSAndroid Build Coastguard Worker #include <stdlib.h>
20*0d6140beSAndroid Build Coastguard Worker #include <unistd.h>
21*0d6140beSAndroid Build Coastguard Worker #include <string.h>
22*0d6140beSAndroid Build Coastguard Worker #include <ctype.h>
23*0d6140beSAndroid Build Coastguard Worker #include <fcntl.h>
24*0d6140beSAndroid Build Coastguard Worker #include <sys/stat.h>
25*0d6140beSAndroid Build Coastguard Worker #include <errno.h>
26*0d6140beSAndroid Build Coastguard Worker #include <inttypes.h>
27*0d6140beSAndroid Build Coastguard Worker #if IS_WINDOWS
28*0d6140beSAndroid Build Coastguard Worker #include <conio.h>
29*0d6140beSAndroid Build Coastguard Worker #else
30*0d6140beSAndroid Build Coastguard Worker #include <termios.h>
31*0d6140beSAndroid Build Coastguard Worker #include <unistd.h>
32*0d6140beSAndroid Build Coastguard Worker #include <sys/types.h>
33*0d6140beSAndroid Build Coastguard Worker #include <sys/ioctl.h>
34*0d6140beSAndroid Build Coastguard Worker #endif
35*0d6140beSAndroid Build Coastguard Worker #include "flash.h"
36*0d6140beSAndroid Build Coastguard Worker #include "programmer.h"
37*0d6140beSAndroid Build Coastguard Worker #include "custom_baud.h"
38*0d6140beSAndroid Build Coastguard Worker
39*0d6140beSAndroid Build Coastguard Worker fdtype sp_fd = SER_INV_FD;
40*0d6140beSAndroid Build Coastguard Worker
41*0d6140beSAndroid Build Coastguard Worker /* There is no way defined by POSIX to use arbitrary baud rates. It only defines some macros that can be used to
42*0d6140beSAndroid Build Coastguard Worker * specify respective baud rates and many implementations extend this list with further macros, cf. TERMIOS(3)
43*0d6140beSAndroid Build Coastguard Worker * and http://git.kernel.org/?p=linux/kernel/git/torvalds/linux.git;a=blob;f=include/uapi/asm-generic/termbits.h
44*0d6140beSAndroid Build Coastguard Worker * The code below creates a mapping in sp_baudtable between these macros and the numerical baud rates to deal
45*0d6140beSAndroid Build Coastguard Worker * with numerical user input.
46*0d6140beSAndroid Build Coastguard Worker *
47*0d6140beSAndroid Build Coastguard Worker * On Linux there is a non-standard way to use arbitrary baud rates that we use if there is no
48*0d6140beSAndroid Build Coastguard Worker * matching standard rate, see custom_baud.c
49*0d6140beSAndroid Build Coastguard Worker *
50*0d6140beSAndroid Build Coastguard Worker * On Darwin there is also a non-standard ioctl() to set arbitrary baud rates
51*0d6140beSAndroid Build Coastguard Worker * and any above 230400, see custom_baud_darwin.c and
52*0d6140beSAndroid Build Coastguard Worker * https://opensource.apple.com/source/IOSerialFamily/IOSerialFamily-91/tests/IOSerialTestLib.c.auto.html
53*0d6140beSAndroid Build Coastguard Worker *
54*0d6140beSAndroid Build Coastguard Worker * On Windows there exist similar macros (starting with CBR_ instead of B) but they are only defined for
55*0d6140beSAndroid Build Coastguard Worker * backwards compatibility and the API supports arbitrary baud rates in the same manner as the macros, see
56*0d6140beSAndroid Build Coastguard Worker * http://msdn.microsoft.com/en-us/library/windows/desktop/aa363214(v=vs.85).aspx
57*0d6140beSAndroid Build Coastguard Worker */
58*0d6140beSAndroid Build Coastguard Worker #if !IS_WINDOWS
59*0d6140beSAndroid Build Coastguard Worker #define BAUDENTRY(baud) { B##baud, baud },
60*0d6140beSAndroid Build Coastguard Worker
61*0d6140beSAndroid Build Coastguard Worker static const struct baudentry sp_baudtable[] = {
62*0d6140beSAndroid Build Coastguard Worker BAUDENTRY(9600) /* unconditional default */
63*0d6140beSAndroid Build Coastguard Worker #ifdef B19200
64*0d6140beSAndroid Build Coastguard Worker BAUDENTRY(19200)
65*0d6140beSAndroid Build Coastguard Worker #endif
66*0d6140beSAndroid Build Coastguard Worker #ifdef B38400
67*0d6140beSAndroid Build Coastguard Worker BAUDENTRY(38400)
68*0d6140beSAndroid Build Coastguard Worker #endif
69*0d6140beSAndroid Build Coastguard Worker #ifdef B57600
70*0d6140beSAndroid Build Coastguard Worker BAUDENTRY(57600)
71*0d6140beSAndroid Build Coastguard Worker #endif
72*0d6140beSAndroid Build Coastguard Worker #ifdef B115200
73*0d6140beSAndroid Build Coastguard Worker BAUDENTRY(115200)
74*0d6140beSAndroid Build Coastguard Worker #endif
75*0d6140beSAndroid Build Coastguard Worker #ifdef B230400
76*0d6140beSAndroid Build Coastguard Worker BAUDENTRY(230400)
77*0d6140beSAndroid Build Coastguard Worker #endif
78*0d6140beSAndroid Build Coastguard Worker #ifdef B460800
79*0d6140beSAndroid Build Coastguard Worker BAUDENTRY(460800)
80*0d6140beSAndroid Build Coastguard Worker #endif
81*0d6140beSAndroid Build Coastguard Worker #ifdef B500000
82*0d6140beSAndroid Build Coastguard Worker BAUDENTRY(500000)
83*0d6140beSAndroid Build Coastguard Worker #endif
84*0d6140beSAndroid Build Coastguard Worker #ifdef B576000
85*0d6140beSAndroid Build Coastguard Worker BAUDENTRY(576000)
86*0d6140beSAndroid Build Coastguard Worker #endif
87*0d6140beSAndroid Build Coastguard Worker #ifdef B921600
88*0d6140beSAndroid Build Coastguard Worker BAUDENTRY(921600)
89*0d6140beSAndroid Build Coastguard Worker #endif
90*0d6140beSAndroid Build Coastguard Worker #ifdef B1000000
91*0d6140beSAndroid Build Coastguard Worker BAUDENTRY(1000000)
92*0d6140beSAndroid Build Coastguard Worker #endif
93*0d6140beSAndroid Build Coastguard Worker #ifdef B1152000
94*0d6140beSAndroid Build Coastguard Worker BAUDENTRY(1152000)
95*0d6140beSAndroid Build Coastguard Worker #endif
96*0d6140beSAndroid Build Coastguard Worker #ifdef B1500000
97*0d6140beSAndroid Build Coastguard Worker BAUDENTRY(1500000)
98*0d6140beSAndroid Build Coastguard Worker #endif
99*0d6140beSAndroid Build Coastguard Worker #ifdef B2000000
100*0d6140beSAndroid Build Coastguard Worker BAUDENTRY(2000000)
101*0d6140beSAndroid Build Coastguard Worker #endif
102*0d6140beSAndroid Build Coastguard Worker #ifdef B2500000
103*0d6140beSAndroid Build Coastguard Worker BAUDENTRY(2500000)
104*0d6140beSAndroid Build Coastguard Worker #endif
105*0d6140beSAndroid Build Coastguard Worker #ifdef B3000000
106*0d6140beSAndroid Build Coastguard Worker BAUDENTRY(3000000)
107*0d6140beSAndroid Build Coastguard Worker #endif
108*0d6140beSAndroid Build Coastguard Worker #ifdef B3500000
109*0d6140beSAndroid Build Coastguard Worker BAUDENTRY(3500000)
110*0d6140beSAndroid Build Coastguard Worker #endif
111*0d6140beSAndroid Build Coastguard Worker #ifdef B4000000
112*0d6140beSAndroid Build Coastguard Worker BAUDENTRY(4000000)
113*0d6140beSAndroid Build Coastguard Worker #endif
114*0d6140beSAndroid Build Coastguard Worker {0, 0} /* Terminator */
115*0d6140beSAndroid Build Coastguard Worker };
116*0d6140beSAndroid Build Coastguard Worker
round_baud(unsigned int baud)117*0d6140beSAndroid Build Coastguard Worker static const struct baudentry *round_baud(unsigned int baud)
118*0d6140beSAndroid Build Coastguard Worker {
119*0d6140beSAndroid Build Coastguard Worker int i;
120*0d6140beSAndroid Build Coastguard Worker /* Round baud rate to next lower entry in sp_baudtable if it exists, else use the lowest entry. */
121*0d6140beSAndroid Build Coastguard Worker for (i = ARRAY_SIZE(sp_baudtable) - 2; i >= 0 ; i--) {
122*0d6140beSAndroid Build Coastguard Worker if (sp_baudtable[i].baud == baud)
123*0d6140beSAndroid Build Coastguard Worker return &sp_baudtable[i];
124*0d6140beSAndroid Build Coastguard Worker
125*0d6140beSAndroid Build Coastguard Worker if (sp_baudtable[i].baud < baud) {
126*0d6140beSAndroid Build Coastguard Worker msg_pwarn("Warning: given baudrate %d rounded down to %d.\n",
127*0d6140beSAndroid Build Coastguard Worker baud, sp_baudtable[i].baud);
128*0d6140beSAndroid Build Coastguard Worker return &sp_baudtable[i];
129*0d6140beSAndroid Build Coastguard Worker }
130*0d6140beSAndroid Build Coastguard Worker }
131*0d6140beSAndroid Build Coastguard Worker msg_pinfo("Using slowest possible baudrate: %d.\n", sp_baudtable[0].baud);
132*0d6140beSAndroid Build Coastguard Worker return &sp_baudtable[0];
133*0d6140beSAndroid Build Coastguard Worker }
134*0d6140beSAndroid Build Coastguard Worker #endif
135*0d6140beSAndroid Build Coastguard Worker
136*0d6140beSAndroid Build Coastguard Worker /* Uses msg_perr to print the last system error.
137*0d6140beSAndroid Build Coastguard Worker * Prints "Error: " followed first by \c msg and then by the description of the last error retrieved via
138*0d6140beSAndroid Build Coastguard Worker * strerror() or FormatMessage() and ending with a linebreak. */
msg_perr_strerror(const char * msg)139*0d6140beSAndroid Build Coastguard Worker static void msg_perr_strerror(const char *msg)
140*0d6140beSAndroid Build Coastguard Worker {
141*0d6140beSAndroid Build Coastguard Worker msg_perr("Error: %s", msg);
142*0d6140beSAndroid Build Coastguard Worker #if IS_WINDOWS
143*0d6140beSAndroid Build Coastguard Worker char *lpMsgBuf;
144*0d6140beSAndroid Build Coastguard Worker DWORD nErr = GetLastError();
145*0d6140beSAndroid Build Coastguard Worker FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, NULL, nErr,
146*0d6140beSAndroid Build Coastguard Worker MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR) &lpMsgBuf, 0, NULL);
147*0d6140beSAndroid Build Coastguard Worker msg_perr(lpMsgBuf);
148*0d6140beSAndroid Build Coastguard Worker /* At least some formatted messages contain a line break at the end. Make sure to always print one */
149*0d6140beSAndroid Build Coastguard Worker if (lpMsgBuf[strlen(lpMsgBuf)-1] != '\n')
150*0d6140beSAndroid Build Coastguard Worker msg_perr("\n");
151*0d6140beSAndroid Build Coastguard Worker LocalFree(lpMsgBuf);
152*0d6140beSAndroid Build Coastguard Worker #else
153*0d6140beSAndroid Build Coastguard Worker msg_perr("%s\n", strerror(errno));
154*0d6140beSAndroid Build Coastguard Worker #endif
155*0d6140beSAndroid Build Coastguard Worker }
156*0d6140beSAndroid Build Coastguard Worker
serialport_config(fdtype fd,int baud)157*0d6140beSAndroid Build Coastguard Worker int serialport_config(fdtype fd, int baud)
158*0d6140beSAndroid Build Coastguard Worker {
159*0d6140beSAndroid Build Coastguard Worker if (fd == SER_INV_FD) {
160*0d6140beSAndroid Build Coastguard Worker msg_perr("%s: File descriptor is invalid.\n", __func__);
161*0d6140beSAndroid Build Coastguard Worker return 1;
162*0d6140beSAndroid Build Coastguard Worker }
163*0d6140beSAndroid Build Coastguard Worker
164*0d6140beSAndroid Build Coastguard Worker #if IS_WINDOWS
165*0d6140beSAndroid Build Coastguard Worker DCB dcb;
166*0d6140beSAndroid Build Coastguard Worker if (!GetCommState(fd, &dcb)) {
167*0d6140beSAndroid Build Coastguard Worker msg_perr_strerror("Could not fetch original serial port configuration: ");
168*0d6140beSAndroid Build Coastguard Worker return 1;
169*0d6140beSAndroid Build Coastguard Worker }
170*0d6140beSAndroid Build Coastguard Worker if (baud >= 0) {
171*0d6140beSAndroid Build Coastguard Worker dcb.BaudRate = baud;
172*0d6140beSAndroid Build Coastguard Worker }
173*0d6140beSAndroid Build Coastguard Worker dcb.ByteSize = 8;
174*0d6140beSAndroid Build Coastguard Worker dcb.Parity = NOPARITY;
175*0d6140beSAndroid Build Coastguard Worker dcb.StopBits = ONESTOPBIT;
176*0d6140beSAndroid Build Coastguard Worker if (!SetCommState(fd, &dcb)) {
177*0d6140beSAndroid Build Coastguard Worker msg_perr_strerror("Could not change serial port configuration: ");
178*0d6140beSAndroid Build Coastguard Worker return 1;
179*0d6140beSAndroid Build Coastguard Worker }
180*0d6140beSAndroid Build Coastguard Worker if (!GetCommState(fd, &dcb)) {
181*0d6140beSAndroid Build Coastguard Worker msg_perr_strerror("Could not fetch new serial port configuration: ");
182*0d6140beSAndroid Build Coastguard Worker return 1;
183*0d6140beSAndroid Build Coastguard Worker }
184*0d6140beSAndroid Build Coastguard Worker msg_pdbg("Baud rate is %ld.\n", dcb.BaudRate);
185*0d6140beSAndroid Build Coastguard Worker #else
186*0d6140beSAndroid Build Coastguard Worker int custom_baud = (baud >= 0 && use_custom_baud(baud, sp_baudtable));
187*0d6140beSAndroid Build Coastguard Worker struct termios wanted, observed;
188*0d6140beSAndroid Build Coastguard Worker if (tcgetattr(fd, &observed) != 0) {
189*0d6140beSAndroid Build Coastguard Worker msg_perr_strerror("Could not fetch original serial port configuration: ");
190*0d6140beSAndroid Build Coastguard Worker return 1;
191*0d6140beSAndroid Build Coastguard Worker }
192*0d6140beSAndroid Build Coastguard Worker wanted = observed;
193*0d6140beSAndroid Build Coastguard Worker if (baud >= 0) {
194*0d6140beSAndroid Build Coastguard Worker if (custom_baud) {
195*0d6140beSAndroid Build Coastguard Worker if (set_custom_baudrate(fd, baud, BEFORE_FLAGS, NULL)) {
196*0d6140beSAndroid Build Coastguard Worker msg_perr_strerror("Could not set custom baudrate: ");
197*0d6140beSAndroid Build Coastguard Worker return 1;
198*0d6140beSAndroid Build Coastguard Worker }
199*0d6140beSAndroid Build Coastguard Worker /* We want whatever the termios looks like now, so the rest of the
200*0d6140beSAndroid Build Coastguard Worker setup doesn't mess up the custom rate. */
201*0d6140beSAndroid Build Coastguard Worker if (tcgetattr(fd, &wanted) != 0) {
202*0d6140beSAndroid Build Coastguard Worker /* This should pretty much never happen (see above), but.. */
203*0d6140beSAndroid Build Coastguard Worker msg_perr_strerror("Could not fetch serial port configuration: ");
204*0d6140beSAndroid Build Coastguard Worker return 1;
205*0d6140beSAndroid Build Coastguard Worker }
206*0d6140beSAndroid Build Coastguard Worker } else {
207*0d6140beSAndroid Build Coastguard Worker const struct baudentry *entry = round_baud(baud);
208*0d6140beSAndroid Build Coastguard Worker if (cfsetispeed(&wanted, entry->flag) != 0 || cfsetospeed(&wanted, entry->flag) != 0) {
209*0d6140beSAndroid Build Coastguard Worker msg_perr_strerror("Could not set serial baud rate: ");
210*0d6140beSAndroid Build Coastguard Worker return 1;
211*0d6140beSAndroid Build Coastguard Worker }
212*0d6140beSAndroid Build Coastguard Worker }
213*0d6140beSAndroid Build Coastguard Worker }
214*0d6140beSAndroid Build Coastguard Worker wanted.c_cflag &= ~(PARENB | CSTOPB | CSIZE | CRTSCTS);
215*0d6140beSAndroid Build Coastguard Worker wanted.c_cflag |= (CS8 | CLOCAL | CREAD);
216*0d6140beSAndroid Build Coastguard Worker wanted.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG | IEXTEN);
217*0d6140beSAndroid Build Coastguard Worker wanted.c_iflag &= ~(IXON | IXOFF | IXANY | ICRNL | IGNCR | INLCR);
218*0d6140beSAndroid Build Coastguard Worker wanted.c_oflag &= ~OPOST;
219*0d6140beSAndroid Build Coastguard Worker if (custom_baud && set_custom_baudrate(fd, baud, WITH_FLAGS, &wanted)) {
220*0d6140beSAndroid Build Coastguard Worker msg_perr_strerror("Could not set custom baudrate: ");
221*0d6140beSAndroid Build Coastguard Worker return 1;
222*0d6140beSAndroid Build Coastguard Worker }
223*0d6140beSAndroid Build Coastguard Worker if (tcsetattr(fd, TCSANOW, &wanted) != 0) {
224*0d6140beSAndroid Build Coastguard Worker msg_perr_strerror("Could not change serial port configuration: ");
225*0d6140beSAndroid Build Coastguard Worker return 1;
226*0d6140beSAndroid Build Coastguard Worker }
227*0d6140beSAndroid Build Coastguard Worker if (tcgetattr(fd, &observed) != 0) {
228*0d6140beSAndroid Build Coastguard Worker msg_perr_strerror("Could not fetch new serial port configuration: ");
229*0d6140beSAndroid Build Coastguard Worker return 1;
230*0d6140beSAndroid Build Coastguard Worker }
231*0d6140beSAndroid Build Coastguard Worker if (observed.c_cflag != wanted.c_cflag ||
232*0d6140beSAndroid Build Coastguard Worker observed.c_lflag != wanted.c_lflag ||
233*0d6140beSAndroid Build Coastguard Worker observed.c_iflag != wanted.c_iflag ||
234*0d6140beSAndroid Build Coastguard Worker observed.c_oflag != wanted.c_oflag) {
235*0d6140beSAndroid Build Coastguard Worker msg_pwarn("Some requested serial options did not stick, continuing anyway.\n");
236*0d6140beSAndroid Build Coastguard Worker msg_pdbg(" observed wanted\n"
237*0d6140beSAndroid Build Coastguard Worker "c_cflag: 0x%08lX 0x%08lX\n"
238*0d6140beSAndroid Build Coastguard Worker "c_lflag: 0x%08lX 0x%08lX\n"
239*0d6140beSAndroid Build Coastguard Worker "c_iflag: 0x%08lX 0x%08lX\n"
240*0d6140beSAndroid Build Coastguard Worker "c_oflag: 0x%08lX 0x%08lX\n",
241*0d6140beSAndroid Build Coastguard Worker (long)observed.c_cflag, (long)wanted.c_cflag,
242*0d6140beSAndroid Build Coastguard Worker (long)observed.c_lflag, (long)wanted.c_lflag,
243*0d6140beSAndroid Build Coastguard Worker (long)observed.c_iflag, (long)wanted.c_iflag,
244*0d6140beSAndroid Build Coastguard Worker (long)observed.c_oflag, (long)wanted.c_oflag
245*0d6140beSAndroid Build Coastguard Worker );
246*0d6140beSAndroid Build Coastguard Worker }
247*0d6140beSAndroid Build Coastguard Worker if (custom_baud) {
248*0d6140beSAndroid Build Coastguard Worker if (set_custom_baudrate(fd, baud, AFTER_FLAGS, &wanted)) {
249*0d6140beSAndroid Build Coastguard Worker msg_perr_strerror("Could not set custom baudrate: ");
250*0d6140beSAndroid Build Coastguard Worker return 1;
251*0d6140beSAndroid Build Coastguard Worker }
252*0d6140beSAndroid Build Coastguard Worker msg_pdbg("Using custom baud rate.\n");
253*0d6140beSAndroid Build Coastguard Worker }
254*0d6140beSAndroid Build Coastguard Worker if (cfgetispeed(&observed) != cfgetispeed(&wanted) ||
255*0d6140beSAndroid Build Coastguard Worker cfgetospeed(&observed) != cfgetospeed(&wanted)) {
256*0d6140beSAndroid Build Coastguard Worker msg_pwarn("Could not set baud rates exactly.\n");
257*0d6140beSAndroid Build Coastguard Worker msg_pdbg("Actual baud flags are: ispeed: 0x%08lX, ospeed: 0x%08lX\n",
258*0d6140beSAndroid Build Coastguard Worker (long)cfgetispeed(&observed), (long)cfgetospeed(&observed));
259*0d6140beSAndroid Build Coastguard Worker }
260*0d6140beSAndroid Build Coastguard Worker // FIXME: display actual baud rate - at least if none was specified by the user.
261*0d6140beSAndroid Build Coastguard Worker #endif
262*0d6140beSAndroid Build Coastguard Worker return 0;
263*0d6140beSAndroid Build Coastguard Worker }
264*0d6140beSAndroid Build Coastguard Worker
sp_openserport(char * dev,int baud)265*0d6140beSAndroid Build Coastguard Worker fdtype sp_openserport(char *dev, int baud)
266*0d6140beSAndroid Build Coastguard Worker {
267*0d6140beSAndroid Build Coastguard Worker fdtype fd;
268*0d6140beSAndroid Build Coastguard Worker #if IS_WINDOWS
269*0d6140beSAndroid Build Coastguard Worker char *dev2 = dev;
270*0d6140beSAndroid Build Coastguard Worker if ((strlen(dev) > 3) &&
271*0d6140beSAndroid Build Coastguard Worker (tolower((unsigned char)dev[0]) == 'c') &&
272*0d6140beSAndroid Build Coastguard Worker (tolower((unsigned char)dev[1]) == 'o') &&
273*0d6140beSAndroid Build Coastguard Worker (tolower((unsigned char)dev[2]) == 'm')) {
274*0d6140beSAndroid Build Coastguard Worker dev2 = malloc(strlen(dev) + 5);
275*0d6140beSAndroid Build Coastguard Worker if (!dev2) {
276*0d6140beSAndroid Build Coastguard Worker msg_perr_strerror("Out of memory: ");
277*0d6140beSAndroid Build Coastguard Worker return SER_INV_FD;
278*0d6140beSAndroid Build Coastguard Worker }
279*0d6140beSAndroid Build Coastguard Worker strcpy(dev2, "\\\\.\\");
280*0d6140beSAndroid Build Coastguard Worker strcpy(dev2 + 4, dev);
281*0d6140beSAndroid Build Coastguard Worker }
282*0d6140beSAndroid Build Coastguard Worker fd = CreateFile(dev2, GENERIC_READ | GENERIC_WRITE, 0, NULL,
283*0d6140beSAndroid Build Coastguard Worker OPEN_EXISTING, 0, NULL);
284*0d6140beSAndroid Build Coastguard Worker if (dev2 != dev)
285*0d6140beSAndroid Build Coastguard Worker free(dev2);
286*0d6140beSAndroid Build Coastguard Worker if (fd == INVALID_HANDLE_VALUE) {
287*0d6140beSAndroid Build Coastguard Worker msg_perr_strerror("Cannot open serial port: ");
288*0d6140beSAndroid Build Coastguard Worker return SER_INV_FD;
289*0d6140beSAndroid Build Coastguard Worker }
290*0d6140beSAndroid Build Coastguard Worker if (serialport_config(fd, baud) != 0) {
291*0d6140beSAndroid Build Coastguard Worker CloseHandle(fd);
292*0d6140beSAndroid Build Coastguard Worker return SER_INV_FD;
293*0d6140beSAndroid Build Coastguard Worker }
294*0d6140beSAndroid Build Coastguard Worker return fd;
295*0d6140beSAndroid Build Coastguard Worker #else
296*0d6140beSAndroid Build Coastguard Worker fd = open(dev, O_RDWR | O_NOCTTY | O_NDELAY); // Use O_NDELAY to ignore DCD state
297*0d6140beSAndroid Build Coastguard Worker if (fd < 0) {
298*0d6140beSAndroid Build Coastguard Worker msg_perr_strerror("Cannot open serial port: ");
299*0d6140beSAndroid Build Coastguard Worker return SER_INV_FD;
300*0d6140beSAndroid Build Coastguard Worker }
301*0d6140beSAndroid Build Coastguard Worker
302*0d6140beSAndroid Build Coastguard Worker /* Ensure that we use blocking I/O */
303*0d6140beSAndroid Build Coastguard Worker const int flags = fcntl(fd, F_GETFL);
304*0d6140beSAndroid Build Coastguard Worker if (flags == -1) {
305*0d6140beSAndroid Build Coastguard Worker msg_perr_strerror("Could not get serial port mode: ");
306*0d6140beSAndroid Build Coastguard Worker goto err;
307*0d6140beSAndroid Build Coastguard Worker }
308*0d6140beSAndroid Build Coastguard Worker if (fcntl(fd, F_SETFL, flags & ~O_NONBLOCK) != 0) {
309*0d6140beSAndroid Build Coastguard Worker msg_perr_strerror("Could not set serial port mode to blocking: ");
310*0d6140beSAndroid Build Coastguard Worker goto err;
311*0d6140beSAndroid Build Coastguard Worker }
312*0d6140beSAndroid Build Coastguard Worker
313*0d6140beSAndroid Build Coastguard Worker if (serialport_config(fd, baud) != 0) {
314*0d6140beSAndroid Build Coastguard Worker goto err;
315*0d6140beSAndroid Build Coastguard Worker }
316*0d6140beSAndroid Build Coastguard Worker return fd;
317*0d6140beSAndroid Build Coastguard Worker err:
318*0d6140beSAndroid Build Coastguard Worker close(fd);
319*0d6140beSAndroid Build Coastguard Worker return SER_INV_FD;
320*0d6140beSAndroid Build Coastguard Worker #endif
321*0d6140beSAndroid Build Coastguard Worker }
322*0d6140beSAndroid Build Coastguard Worker
sp_set_pin(enum SP_PIN pin,int val)323*0d6140beSAndroid Build Coastguard Worker void sp_set_pin(enum SP_PIN pin, int val) {
324*0d6140beSAndroid Build Coastguard Worker #if IS_WINDOWS
325*0d6140beSAndroid Build Coastguard Worker DWORD ctl;
326*0d6140beSAndroid Build Coastguard Worker
327*0d6140beSAndroid Build Coastguard Worker if(pin == PIN_TXD) {
328*0d6140beSAndroid Build Coastguard Worker ctl = val ? SETBREAK: CLRBREAK;
329*0d6140beSAndroid Build Coastguard Worker }
330*0d6140beSAndroid Build Coastguard Worker else if(pin == PIN_DTR) {
331*0d6140beSAndroid Build Coastguard Worker ctl = val ? SETDTR: CLRDTR;
332*0d6140beSAndroid Build Coastguard Worker }
333*0d6140beSAndroid Build Coastguard Worker else {
334*0d6140beSAndroid Build Coastguard Worker ctl = val ? SETRTS: CLRRTS;
335*0d6140beSAndroid Build Coastguard Worker }
336*0d6140beSAndroid Build Coastguard Worker EscapeCommFunction(sp_fd, ctl);
337*0d6140beSAndroid Build Coastguard Worker #else
338*0d6140beSAndroid Build Coastguard Worker int ctl, s;
339*0d6140beSAndroid Build Coastguard Worker
340*0d6140beSAndroid Build Coastguard Worker if(pin == PIN_TXD) {
341*0d6140beSAndroid Build Coastguard Worker ioctl(sp_fd, val ? TIOCSBRK : TIOCCBRK, 0);
342*0d6140beSAndroid Build Coastguard Worker }
343*0d6140beSAndroid Build Coastguard Worker else {
344*0d6140beSAndroid Build Coastguard Worker s = (pin == PIN_DTR) ? TIOCM_DTR : TIOCM_RTS;
345*0d6140beSAndroid Build Coastguard Worker ioctl(sp_fd, TIOCMGET, &ctl);
346*0d6140beSAndroid Build Coastguard Worker
347*0d6140beSAndroid Build Coastguard Worker if (val) {
348*0d6140beSAndroid Build Coastguard Worker ctl |= s;
349*0d6140beSAndroid Build Coastguard Worker }
350*0d6140beSAndroid Build Coastguard Worker else {
351*0d6140beSAndroid Build Coastguard Worker ctl &= ~s;
352*0d6140beSAndroid Build Coastguard Worker }
353*0d6140beSAndroid Build Coastguard Worker ioctl(sp_fd, TIOCMSET, &ctl);
354*0d6140beSAndroid Build Coastguard Worker }
355*0d6140beSAndroid Build Coastguard Worker #endif
356*0d6140beSAndroid Build Coastguard Worker }
357*0d6140beSAndroid Build Coastguard Worker
sp_get_pin(enum SP_PIN pin)358*0d6140beSAndroid Build Coastguard Worker int sp_get_pin(enum SP_PIN pin) {
359*0d6140beSAndroid Build Coastguard Worker int s;
360*0d6140beSAndroid Build Coastguard Worker #if IS_WINDOWS
361*0d6140beSAndroid Build Coastguard Worker DWORD ctl;
362*0d6140beSAndroid Build Coastguard Worker
363*0d6140beSAndroid Build Coastguard Worker s = (pin == PIN_CTS) ? MS_CTS_ON : MS_DSR_ON;
364*0d6140beSAndroid Build Coastguard Worker GetCommModemStatus(sp_fd, &ctl);
365*0d6140beSAndroid Build Coastguard Worker #else
366*0d6140beSAndroid Build Coastguard Worker int ctl;
367*0d6140beSAndroid Build Coastguard Worker s = (pin == PIN_CTS) ? TIOCM_CTS : TIOCM_DSR;
368*0d6140beSAndroid Build Coastguard Worker ioctl(sp_fd, TIOCMGET, &ctl);
369*0d6140beSAndroid Build Coastguard Worker #endif
370*0d6140beSAndroid Build Coastguard Worker
371*0d6140beSAndroid Build Coastguard Worker return ((ctl & s) ? 1 : 0);
372*0d6140beSAndroid Build Coastguard Worker
373*0d6140beSAndroid Build Coastguard Worker }
374*0d6140beSAndroid Build Coastguard Worker
sp_flush_incoming(void)375*0d6140beSAndroid Build Coastguard Worker void sp_flush_incoming(void)
376*0d6140beSAndroid Build Coastguard Worker {
377*0d6140beSAndroid Build Coastguard Worker #if IS_WINDOWS
378*0d6140beSAndroid Build Coastguard Worker PurgeComm(sp_fd, PURGE_RXCLEAR);
379*0d6140beSAndroid Build Coastguard Worker #else
380*0d6140beSAndroid Build Coastguard Worker if (!tcflush(sp_fd, TCIFLUSH))
381*0d6140beSAndroid Build Coastguard Worker return;
382*0d6140beSAndroid Build Coastguard Worker
383*0d6140beSAndroid Build Coastguard Worker if (errno == ENOTTY) { // TCP socket case: sp_fd is not a terminal descriptor - tcflush is not supported
384*0d6140beSAndroid Build Coastguard Worker unsigned char c;
385*0d6140beSAndroid Build Coastguard Worker int ret;
386*0d6140beSAndroid Build Coastguard Worker
387*0d6140beSAndroid Build Coastguard Worker do {
388*0d6140beSAndroid Build Coastguard Worker ret = serialport_read_nonblock(&c, 1, 1, NULL);
389*0d6140beSAndroid Build Coastguard Worker } while (ret == 0);
390*0d6140beSAndroid Build Coastguard Worker
391*0d6140beSAndroid Build Coastguard Worker // positive error code indicates no data available immediately - similar to EAGAIN/EWOULDBLOCK
392*0d6140beSAndroid Build Coastguard Worker // i.e. all buffered data was read
393*0d6140beSAndroid Build Coastguard Worker // negative error code indicates a permanent error
394*0d6140beSAndroid Build Coastguard Worker if (ret < 0)
395*0d6140beSAndroid Build Coastguard Worker msg_perr("Could not flush serial port incoming buffer: read has failed");
396*0d6140beSAndroid Build Coastguard Worker } else { // any other errno indicates an unrecoverable sp_fd state
397*0d6140beSAndroid Build Coastguard Worker msg_perr_strerror("Could not flush serial port incoming buffer: ");
398*0d6140beSAndroid Build Coastguard Worker }
399*0d6140beSAndroid Build Coastguard Worker #endif
400*0d6140beSAndroid Build Coastguard Worker }
401*0d6140beSAndroid Build Coastguard Worker
serialport_shutdown(void * data)402*0d6140beSAndroid Build Coastguard Worker int serialport_shutdown(void *data)
403*0d6140beSAndroid Build Coastguard Worker {
404*0d6140beSAndroid Build Coastguard Worker #if IS_WINDOWS
405*0d6140beSAndroid Build Coastguard Worker CloseHandle(sp_fd);
406*0d6140beSAndroid Build Coastguard Worker #else
407*0d6140beSAndroid Build Coastguard Worker close(sp_fd);
408*0d6140beSAndroid Build Coastguard Worker #endif
409*0d6140beSAndroid Build Coastguard Worker return 0;
410*0d6140beSAndroid Build Coastguard Worker }
411*0d6140beSAndroid Build Coastguard Worker
serialport_write(const unsigned char * buf,unsigned int writecnt)412*0d6140beSAndroid Build Coastguard Worker int serialport_write(const unsigned char *buf, unsigned int writecnt)
413*0d6140beSAndroid Build Coastguard Worker {
414*0d6140beSAndroid Build Coastguard Worker #if IS_WINDOWS
415*0d6140beSAndroid Build Coastguard Worker DWORD tmp = 0;
416*0d6140beSAndroid Build Coastguard Worker #else
417*0d6140beSAndroid Build Coastguard Worker ssize_t tmp = 0;
418*0d6140beSAndroid Build Coastguard Worker #endif
419*0d6140beSAndroid Build Coastguard Worker unsigned int empty_writes = 250; /* results in a ca. 125ms timeout */
420*0d6140beSAndroid Build Coastguard Worker
421*0d6140beSAndroid Build Coastguard Worker while (writecnt > 0) {
422*0d6140beSAndroid Build Coastguard Worker #if IS_WINDOWS
423*0d6140beSAndroid Build Coastguard Worker if (!WriteFile(sp_fd, buf, writecnt, &tmp, NULL)) {
424*0d6140beSAndroid Build Coastguard Worker msg_perr("Serial port write error!\n");
425*0d6140beSAndroid Build Coastguard Worker return 1;
426*0d6140beSAndroid Build Coastguard Worker }
427*0d6140beSAndroid Build Coastguard Worker #else
428*0d6140beSAndroid Build Coastguard Worker tmp = write(sp_fd, buf, writecnt);
429*0d6140beSAndroid Build Coastguard Worker if (tmp == -1) {
430*0d6140beSAndroid Build Coastguard Worker msg_perr("Serial port write error!\n");
431*0d6140beSAndroid Build Coastguard Worker return 1;
432*0d6140beSAndroid Build Coastguard Worker }
433*0d6140beSAndroid Build Coastguard Worker #endif
434*0d6140beSAndroid Build Coastguard Worker if (!tmp) {
435*0d6140beSAndroid Build Coastguard Worker msg_pdbg2("Empty write\n");
436*0d6140beSAndroid Build Coastguard Worker empty_writes--;
437*0d6140beSAndroid Build Coastguard Worker default_delay(500);
438*0d6140beSAndroid Build Coastguard Worker if (empty_writes == 0) {
439*0d6140beSAndroid Build Coastguard Worker msg_perr("Serial port is unresponsive!\n");
440*0d6140beSAndroid Build Coastguard Worker return 1;
441*0d6140beSAndroid Build Coastguard Worker }
442*0d6140beSAndroid Build Coastguard Worker }
443*0d6140beSAndroid Build Coastguard Worker writecnt -= tmp;
444*0d6140beSAndroid Build Coastguard Worker buf += tmp;
445*0d6140beSAndroid Build Coastguard Worker }
446*0d6140beSAndroid Build Coastguard Worker
447*0d6140beSAndroid Build Coastguard Worker return 0;
448*0d6140beSAndroid Build Coastguard Worker }
449*0d6140beSAndroid Build Coastguard Worker
serialport_read(unsigned char * buf,unsigned int readcnt)450*0d6140beSAndroid Build Coastguard Worker int serialport_read(unsigned char *buf, unsigned int readcnt)
451*0d6140beSAndroid Build Coastguard Worker {
452*0d6140beSAndroid Build Coastguard Worker #if IS_WINDOWS
453*0d6140beSAndroid Build Coastguard Worker DWORD tmp = 0;
454*0d6140beSAndroid Build Coastguard Worker #else
455*0d6140beSAndroid Build Coastguard Worker ssize_t tmp = 0;
456*0d6140beSAndroid Build Coastguard Worker #endif
457*0d6140beSAndroid Build Coastguard Worker
458*0d6140beSAndroid Build Coastguard Worker while (readcnt > 0) {
459*0d6140beSAndroid Build Coastguard Worker #if IS_WINDOWS
460*0d6140beSAndroid Build Coastguard Worker if (!ReadFile(sp_fd, buf, readcnt, &tmp, NULL)) {
461*0d6140beSAndroid Build Coastguard Worker msg_perr("Serial port read error!\n");
462*0d6140beSAndroid Build Coastguard Worker return 1;
463*0d6140beSAndroid Build Coastguard Worker }
464*0d6140beSAndroid Build Coastguard Worker #else
465*0d6140beSAndroid Build Coastguard Worker tmp = read(sp_fd, buf, readcnt);
466*0d6140beSAndroid Build Coastguard Worker if (tmp == -1) {
467*0d6140beSAndroid Build Coastguard Worker msg_perr("Serial port read error!\n");
468*0d6140beSAndroid Build Coastguard Worker return 1;
469*0d6140beSAndroid Build Coastguard Worker }
470*0d6140beSAndroid Build Coastguard Worker #endif
471*0d6140beSAndroid Build Coastguard Worker if (!tmp)
472*0d6140beSAndroid Build Coastguard Worker msg_pdbg2("Empty read\n");
473*0d6140beSAndroid Build Coastguard Worker readcnt -= tmp;
474*0d6140beSAndroid Build Coastguard Worker buf += tmp;
475*0d6140beSAndroid Build Coastguard Worker }
476*0d6140beSAndroid Build Coastguard Worker
477*0d6140beSAndroid Build Coastguard Worker return 0;
478*0d6140beSAndroid Build Coastguard Worker }
479*0d6140beSAndroid Build Coastguard Worker
480*0d6140beSAndroid Build Coastguard Worker /* Tries up to timeout ms to read readcnt characters and places them into the array starting at c. Returns
481*0d6140beSAndroid Build Coastguard Worker * 0 on success, positive values on temporary errors (e.g. timeouts) and negative ones on permanent errors.
482*0d6140beSAndroid Build Coastguard Worker * If really_read is not NULL, this function sets its contents to the number of bytes read successfully. */
serialport_read_nonblock(unsigned char * c,unsigned int readcnt,unsigned int timeout,unsigned int * really_read)483*0d6140beSAndroid Build Coastguard Worker int serialport_read_nonblock(unsigned char *c, unsigned int readcnt, unsigned int timeout, unsigned int *really_read)
484*0d6140beSAndroid Build Coastguard Worker {
485*0d6140beSAndroid Build Coastguard Worker int ret = 1;
486*0d6140beSAndroid Build Coastguard Worker /* disable blocked i/o and declare platform-specific variables */
487*0d6140beSAndroid Build Coastguard Worker #if IS_WINDOWS
488*0d6140beSAndroid Build Coastguard Worker DWORD rv;
489*0d6140beSAndroid Build Coastguard Worker COMMTIMEOUTS oldTimeout;
490*0d6140beSAndroid Build Coastguard Worker COMMTIMEOUTS newTimeout = {
491*0d6140beSAndroid Build Coastguard Worker .ReadIntervalTimeout = MAXDWORD,
492*0d6140beSAndroid Build Coastguard Worker .ReadTotalTimeoutMultiplier = 0,
493*0d6140beSAndroid Build Coastguard Worker .ReadTotalTimeoutConstant = 0,
494*0d6140beSAndroid Build Coastguard Worker .WriteTotalTimeoutMultiplier = 0,
495*0d6140beSAndroid Build Coastguard Worker .WriteTotalTimeoutConstant = 0
496*0d6140beSAndroid Build Coastguard Worker };
497*0d6140beSAndroid Build Coastguard Worker if(!GetCommTimeouts(sp_fd, &oldTimeout)) {
498*0d6140beSAndroid Build Coastguard Worker msg_perr_strerror("Could not get serial port timeout settings: ");
499*0d6140beSAndroid Build Coastguard Worker return -1;
500*0d6140beSAndroid Build Coastguard Worker }
501*0d6140beSAndroid Build Coastguard Worker if(!SetCommTimeouts(sp_fd, &newTimeout)) {
502*0d6140beSAndroid Build Coastguard Worker msg_perr_strerror("Could not set serial port timeout settings: ");
503*0d6140beSAndroid Build Coastguard Worker return -1;
504*0d6140beSAndroid Build Coastguard Worker }
505*0d6140beSAndroid Build Coastguard Worker #else
506*0d6140beSAndroid Build Coastguard Worker ssize_t rv;
507*0d6140beSAndroid Build Coastguard Worker const int flags = fcntl(sp_fd, F_GETFL);
508*0d6140beSAndroid Build Coastguard Worker if (flags == -1) {
509*0d6140beSAndroid Build Coastguard Worker msg_perr_strerror("Could not get serial port mode: ");
510*0d6140beSAndroid Build Coastguard Worker return -1;
511*0d6140beSAndroid Build Coastguard Worker }
512*0d6140beSAndroid Build Coastguard Worker if (fcntl(sp_fd, F_SETFL, flags | O_NONBLOCK) != 0) {
513*0d6140beSAndroid Build Coastguard Worker msg_perr_strerror("Could not set serial port mode to non-blocking: ");
514*0d6140beSAndroid Build Coastguard Worker return -1;
515*0d6140beSAndroid Build Coastguard Worker }
516*0d6140beSAndroid Build Coastguard Worker #endif
517*0d6140beSAndroid Build Coastguard Worker
518*0d6140beSAndroid Build Coastguard Worker unsigned int i;
519*0d6140beSAndroid Build Coastguard Worker unsigned int rd_bytes = 0;
520*0d6140beSAndroid Build Coastguard Worker for (i = 0; i < timeout; i++) {
521*0d6140beSAndroid Build Coastguard Worker msg_pspew("readcnt %u rd_bytes %u\n", readcnt, rd_bytes);
522*0d6140beSAndroid Build Coastguard Worker #if IS_WINDOWS
523*0d6140beSAndroid Build Coastguard Worker if (!ReadFile(sp_fd, c + rd_bytes, readcnt - rd_bytes, &rv, NULL)) {
524*0d6140beSAndroid Build Coastguard Worker msg_perr_strerror("Serial port read error: ");
525*0d6140beSAndroid Build Coastguard Worker ret = -1;
526*0d6140beSAndroid Build Coastguard Worker break;
527*0d6140beSAndroid Build Coastguard Worker }
528*0d6140beSAndroid Build Coastguard Worker msg_pspew("read %lu bytes\n", rv);
529*0d6140beSAndroid Build Coastguard Worker #else
530*0d6140beSAndroid Build Coastguard Worker rv = read(sp_fd, c + rd_bytes, readcnt - rd_bytes);
531*0d6140beSAndroid Build Coastguard Worker msg_pspew("read %zd bytes\n", rv);
532*0d6140beSAndroid Build Coastguard Worker if ((rv == -1) && (errno != EAGAIN)) {
533*0d6140beSAndroid Build Coastguard Worker msg_perr_strerror("Serial port read error: ");
534*0d6140beSAndroid Build Coastguard Worker ret = -1;
535*0d6140beSAndroid Build Coastguard Worker break;
536*0d6140beSAndroid Build Coastguard Worker }
537*0d6140beSAndroid Build Coastguard Worker #endif
538*0d6140beSAndroid Build Coastguard Worker if (rv > 0)
539*0d6140beSAndroid Build Coastguard Worker rd_bytes += rv;
540*0d6140beSAndroid Build Coastguard Worker if (rd_bytes == readcnt) {
541*0d6140beSAndroid Build Coastguard Worker ret = 0;
542*0d6140beSAndroid Build Coastguard Worker break;
543*0d6140beSAndroid Build Coastguard Worker }
544*0d6140beSAndroid Build Coastguard Worker default_delay(1000); /* 1ms units */
545*0d6140beSAndroid Build Coastguard Worker }
546*0d6140beSAndroid Build Coastguard Worker if (really_read != NULL)
547*0d6140beSAndroid Build Coastguard Worker *really_read = rd_bytes;
548*0d6140beSAndroid Build Coastguard Worker
549*0d6140beSAndroid Build Coastguard Worker /* restore original blocking behavior */
550*0d6140beSAndroid Build Coastguard Worker #if IS_WINDOWS
551*0d6140beSAndroid Build Coastguard Worker if (!SetCommTimeouts(sp_fd, &oldTimeout)) {
552*0d6140beSAndroid Build Coastguard Worker msg_perr_strerror("Could not restore serial port timeout settings: ");
553*0d6140beSAndroid Build Coastguard Worker ret = -1;
554*0d6140beSAndroid Build Coastguard Worker }
555*0d6140beSAndroid Build Coastguard Worker #else
556*0d6140beSAndroid Build Coastguard Worker if (fcntl(sp_fd, F_SETFL, flags) != 0) {
557*0d6140beSAndroid Build Coastguard Worker msg_perr_strerror("Could not restore serial port mode to blocking: ");
558*0d6140beSAndroid Build Coastguard Worker ret = -1;
559*0d6140beSAndroid Build Coastguard Worker }
560*0d6140beSAndroid Build Coastguard Worker #endif
561*0d6140beSAndroid Build Coastguard Worker return ret;
562*0d6140beSAndroid Build Coastguard Worker }
563*0d6140beSAndroid Build Coastguard Worker
564*0d6140beSAndroid Build Coastguard Worker /* Tries up to timeout ms to write writecnt characters from the array starting at buf. Returns
565*0d6140beSAndroid Build Coastguard Worker * 0 on success, positive values on temporary errors (e.g. timeouts) and negative ones on permanent errors.
566*0d6140beSAndroid Build Coastguard Worker * If really_wrote is not NULL, this function sets its contents to the number of bytes written successfully. */
serialport_write_nonblock(const unsigned char * buf,unsigned int writecnt,unsigned int timeout,unsigned int * really_wrote)567*0d6140beSAndroid Build Coastguard Worker int serialport_write_nonblock(const unsigned char *buf, unsigned int writecnt, unsigned int timeout, unsigned int *really_wrote)
568*0d6140beSAndroid Build Coastguard Worker {
569*0d6140beSAndroid Build Coastguard Worker int ret = 1;
570*0d6140beSAndroid Build Coastguard Worker /* disable blocked i/o and declare platform-specific variables */
571*0d6140beSAndroid Build Coastguard Worker #if IS_WINDOWS
572*0d6140beSAndroid Build Coastguard Worker DWORD rv;
573*0d6140beSAndroid Build Coastguard Worker COMMTIMEOUTS oldTimeout;
574*0d6140beSAndroid Build Coastguard Worker COMMTIMEOUTS newTimeout = {
575*0d6140beSAndroid Build Coastguard Worker .ReadIntervalTimeout = MAXDWORD,
576*0d6140beSAndroid Build Coastguard Worker .ReadTotalTimeoutMultiplier = 0,
577*0d6140beSAndroid Build Coastguard Worker .ReadTotalTimeoutConstant = 0,
578*0d6140beSAndroid Build Coastguard Worker .WriteTotalTimeoutMultiplier = 0,
579*0d6140beSAndroid Build Coastguard Worker .WriteTotalTimeoutConstant = 0
580*0d6140beSAndroid Build Coastguard Worker };
581*0d6140beSAndroid Build Coastguard Worker if(!GetCommTimeouts(sp_fd, &oldTimeout)) {
582*0d6140beSAndroid Build Coastguard Worker msg_perr_strerror("Could not get serial port timeout settings: ");
583*0d6140beSAndroid Build Coastguard Worker return -1;
584*0d6140beSAndroid Build Coastguard Worker }
585*0d6140beSAndroid Build Coastguard Worker if(!SetCommTimeouts(sp_fd, &newTimeout)) {
586*0d6140beSAndroid Build Coastguard Worker msg_perr_strerror("Could not set serial port timeout settings: ");
587*0d6140beSAndroid Build Coastguard Worker return -1;
588*0d6140beSAndroid Build Coastguard Worker }
589*0d6140beSAndroid Build Coastguard Worker #else
590*0d6140beSAndroid Build Coastguard Worker ssize_t rv;
591*0d6140beSAndroid Build Coastguard Worker const int flags = fcntl(sp_fd, F_GETFL);
592*0d6140beSAndroid Build Coastguard Worker if (flags == -1) {
593*0d6140beSAndroid Build Coastguard Worker msg_perr_strerror("Could not get serial port mode: ");
594*0d6140beSAndroid Build Coastguard Worker return -1;
595*0d6140beSAndroid Build Coastguard Worker }
596*0d6140beSAndroid Build Coastguard Worker if (fcntl(sp_fd, F_SETFL, flags | O_NONBLOCK) != 0) {
597*0d6140beSAndroid Build Coastguard Worker msg_perr_strerror("Could not set serial port mode to non-blocking: ");
598*0d6140beSAndroid Build Coastguard Worker return -1;
599*0d6140beSAndroid Build Coastguard Worker }
600*0d6140beSAndroid Build Coastguard Worker #endif
601*0d6140beSAndroid Build Coastguard Worker
602*0d6140beSAndroid Build Coastguard Worker unsigned int i;
603*0d6140beSAndroid Build Coastguard Worker unsigned int wr_bytes = 0;
604*0d6140beSAndroid Build Coastguard Worker for (i = 0; i < timeout; i++) {
605*0d6140beSAndroid Build Coastguard Worker msg_pspew("writecnt %u wr_bytes %u\n", writecnt, wr_bytes);
606*0d6140beSAndroid Build Coastguard Worker #if IS_WINDOWS
607*0d6140beSAndroid Build Coastguard Worker if (!WriteFile(sp_fd, buf + wr_bytes, writecnt - wr_bytes, &rv, NULL)) {
608*0d6140beSAndroid Build Coastguard Worker msg_perr_strerror("Serial port write error: ");
609*0d6140beSAndroid Build Coastguard Worker ret = -1;
610*0d6140beSAndroid Build Coastguard Worker break;
611*0d6140beSAndroid Build Coastguard Worker }
612*0d6140beSAndroid Build Coastguard Worker msg_pspew("wrote %lu bytes\n", rv);
613*0d6140beSAndroid Build Coastguard Worker #else
614*0d6140beSAndroid Build Coastguard Worker rv = write(sp_fd, buf + wr_bytes, writecnt - wr_bytes);
615*0d6140beSAndroid Build Coastguard Worker msg_pspew("wrote %zd bytes\n", rv);
616*0d6140beSAndroid Build Coastguard Worker if ((rv == -1) && (errno != EAGAIN)) {
617*0d6140beSAndroid Build Coastguard Worker msg_perr_strerror("Serial port write error: ");
618*0d6140beSAndroid Build Coastguard Worker ret = -1;
619*0d6140beSAndroid Build Coastguard Worker break;
620*0d6140beSAndroid Build Coastguard Worker }
621*0d6140beSAndroid Build Coastguard Worker #endif
622*0d6140beSAndroid Build Coastguard Worker if (rv > 0) {
623*0d6140beSAndroid Build Coastguard Worker wr_bytes += rv;
624*0d6140beSAndroid Build Coastguard Worker if (wr_bytes == writecnt) {
625*0d6140beSAndroid Build Coastguard Worker msg_pspew("write successful\n");
626*0d6140beSAndroid Build Coastguard Worker ret = 0;
627*0d6140beSAndroid Build Coastguard Worker break;
628*0d6140beSAndroid Build Coastguard Worker }
629*0d6140beSAndroid Build Coastguard Worker }
630*0d6140beSAndroid Build Coastguard Worker default_delay(1000); /* 1ms units */
631*0d6140beSAndroid Build Coastguard Worker }
632*0d6140beSAndroid Build Coastguard Worker if (really_wrote != NULL)
633*0d6140beSAndroid Build Coastguard Worker *really_wrote = wr_bytes;
634*0d6140beSAndroid Build Coastguard Worker
635*0d6140beSAndroid Build Coastguard Worker /* restore original blocking behavior */
636*0d6140beSAndroid Build Coastguard Worker #if IS_WINDOWS
637*0d6140beSAndroid Build Coastguard Worker if (!SetCommTimeouts(sp_fd, &oldTimeout)) {
638*0d6140beSAndroid Build Coastguard Worker msg_perr_strerror("Could not restore serial port timeout settings: ");
639*0d6140beSAndroid Build Coastguard Worker return -1;
640*0d6140beSAndroid Build Coastguard Worker }
641*0d6140beSAndroid Build Coastguard Worker #else
642*0d6140beSAndroid Build Coastguard Worker if (fcntl(sp_fd, F_SETFL, flags) != 0) {
643*0d6140beSAndroid Build Coastguard Worker msg_perr_strerror("Could not restore serial port blocking behavior: ");
644*0d6140beSAndroid Build Coastguard Worker return -1;
645*0d6140beSAndroid Build Coastguard Worker }
646*0d6140beSAndroid Build Coastguard Worker #endif
647*0d6140beSAndroid Build Coastguard Worker return ret;
648*0d6140beSAndroid Build Coastguard Worker }
649