~paulliu/ubuntu/quantal/freerdp/fixext

« back to all changes in this revision

Viewing changes to channels/rdpdr/serial/serial_tty.c

  • Committer: Package Import Robot
  • Author(s): Martin Pitt
  • Date: 2012-01-31 10:02:14 UTC
  • mto: This revision was merged to the branch mainline in revision 11.
  • Revision ID: package-import@ubuntu.com-20120131100214-zvig71djj2sqgq22
Tags: upstream-1.0.0
ImportĀ upstreamĀ versionĀ 1.0.0

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/**
 
2
 * FreeRDP: A Remote Desktop Protocol client.
 
3
 * Serial Port Device Service Virtual Channel
 
4
 *
 
5
 * Copyright 2011 O.S. Systems Software Ltda.
 
6
 * Copyright 2011 Eduardo Fiss Beloni <beloni@ossystems.com.br>
 
7
 *
 
8
 * Licensed under the Apache License, Version 2.0 (the "License");
 
9
 * you may not use this file except in compliance with the License.
 
10
 * You may obtain a copy of the License at
 
11
 *
 
12
 *     http://www.apache.org/licenses/LICENSE-2.0
 
13
 *
 
14
 * Unless required by applicable law or agreed to in writing, software
 
15
 * distributed under the License is distributed on an "AS IS" BASIS,
 
16
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 
17
 * See the License for the specific language governing permissions and
 
18
 * limitations under the License.
 
19
 */
 
20
 
 
21
#include "config.h"
 
22
#include <stdio.h>
 
23
#include <stdlib.h>
 
24
#include <string.h>
 
25
#include <freerdp/utils/memory.h>
 
26
#include <freerdp/utils/stream.h>
 
27
#include <freerdp/utils/unicode.h>
 
28
#include <freerdp/utils/list.h>
 
29
#include <freerdp/utils/thread.h>
 
30
#include <freerdp/utils/svc_plugin.h>
 
31
#include <freerdp/utils/hexdump.h>
 
32
 
 
33
#include <unistd.h>
 
34
#include <termios.h>
 
35
#include <fcntl.h>
 
36
#include <sys/types.h>
 
37
#include <sys/stat.h>
 
38
#include <dirent.h>
 
39
#include <sys/ioctl.h>
 
40
#include <errno.h>
 
41
 
 
42
#include "rdpdr_constants.h"
 
43
#include "rdpdr_types.h"
 
44
#include "serial_tty.h"
 
45
#include "serial_constants.h"
 
46
 
 
47
#ifdef HAVE_SYS_MODEM_H
 
48
#include <sys/modem.h>
 
49
#endif
 
50
#ifdef HAVE_SYS_FILIO_H
 
51
#include <sys/filio.h>
 
52
#endif
 
53
#ifdef HAVE_SYS_STRTIO_H
 
54
#include <sys/strtio.h>
 
55
#endif
 
56
 
 
57
#ifndef CRTSCTS
 
58
#define CRTSCTS 0
 
59
#endif
 
60
 
 
61
/* FIONREAD should really do the same thing as TIOCINQ, where it is
 
62
 * not available */
 
63
#if !defined(TIOCINQ) && defined(FIONREAD)
 
64
#define TIOCINQ FIONREAD
 
65
#endif
 
66
#if !defined(TIOCOUTQ) && defined(FIONWRITE)
 
67
#define TIOCOUTQ FIONWRITE
 
68
#endif
 
69
 
 
70
 
 
71
static uint32 tty_write_data(SERIAL_TTY* tty, uint8* data, int len);
 
72
static void tty_set_termios(SERIAL_TTY* tty);
 
73
static boolean tty_get_termios(SERIAL_TTY* tty);
 
74
static int tty_get_error_status();
 
75
 
 
76
uint32 serial_tty_control(SERIAL_TTY* tty, uint32 IoControlCode, STREAM* input, STREAM* output, uint32* abort_io)
 
77
{
 
78
        int purge_mask;
 
79
        uint32 result;
 
80
        uint32 modemstate;
 
81
        uint8 immediate;
 
82
        uint32 ret = STATUS_SUCCESS;
 
83
        uint32 length = 0;
 
84
        uint32 pos;
 
85
 
 
86
        DEBUG_SVC("in");
 
87
 
 
88
        stream_seek(output, sizeof(uint32));
 
89
 
 
90
        switch (IoControlCode)
 
91
        {
 
92
                case IOCTL_SERIAL_SET_BAUD_RATE:
 
93
                        stream_read_uint32(input, tty->baud_rate);
 
94
                        tty_set_termios(tty);
 
95
                        DEBUG_SVC("SERIAL_SET_BAUD_RATE %d", tty->baud_rate);
 
96
                        break;
 
97
 
 
98
                case IOCTL_SERIAL_GET_BAUD_RATE:
 
99
                        length = 4;
 
100
                        stream_write_uint32(output, tty->baud_rate);
 
101
                        DEBUG_SVC("SERIAL_GET_BAUD_RATE %d", tty->baud_rate);
 
102
                        break;
 
103
 
 
104
                case IOCTL_SERIAL_SET_QUEUE_SIZE:
 
105
                        stream_read_uint32(input, tty->queue_in_size);
 
106
                        stream_read_uint32(input, tty->queue_out_size);
 
107
                        DEBUG_SVC("SERIAL_SET_QUEUE_SIZE in %d out %d", tty->queue_in_size, tty->queue_out_size);
 
108
                        break;
 
109
 
 
110
                case IOCTL_SERIAL_SET_LINE_CONTROL:
 
111
                        stream_read_uint8(input, tty->stop_bits);
 
112
                        stream_read_uint8(input, tty->parity);
 
113
                        stream_read_uint8(input, tty->word_length);
 
114
                        tty_set_termios(tty);
 
115
                        DEBUG_SVC("SERIAL_SET_LINE_CONTROL stop %d parity %d word %d",
 
116
                                tty->stop_bits, tty->parity, tty->word_length);
 
117
                        break;
 
118
 
 
119
                case IOCTL_SERIAL_GET_LINE_CONTROL:
 
120
                        DEBUG_SVC("SERIAL_GET_LINE_CONTROL");
 
121
                        length = 3;
 
122
                        stream_write_uint8(output, tty->stop_bits);
 
123
                        stream_write_uint8(output, tty->parity);
 
124
                        stream_write_uint8(output, tty->word_length);
 
125
                        break;
 
126
 
 
127
                case IOCTL_SERIAL_IMMEDIATE_CHAR:
 
128
                        DEBUG_SVC("SERIAL_IMMEDIATE_CHAR");
 
129
                        stream_read_uint8(input, immediate);
 
130
                        tty_write_data(tty, &immediate, 1);
 
131
                        break;
 
132
 
 
133
                case IOCTL_SERIAL_CONFIG_SIZE:
 
134
                        DEBUG_SVC("SERIAL_CONFIG_SIZE");
 
135
                        length = 4;
 
136
                        stream_write_uint32(output, 0);
 
137
                        break;
 
138
 
 
139
                case IOCTL_SERIAL_GET_CHARS:
 
140
                        DEBUG_SVC("SERIAL_GET_CHARS");
 
141
                        length = 6;
 
142
                        stream_write(output, tty->chars, 6);
 
143
                        break;
 
144
 
 
145
                case IOCTL_SERIAL_SET_CHARS:
 
146
                        DEBUG_SVC("SERIAL_SET_CHARS");
 
147
                        stream_read(input, tty->chars, 6);
 
148
                        tty_set_termios(tty);
 
149
                        break;
 
150
 
 
151
                case IOCTL_SERIAL_GET_HANDFLOW:
 
152
                        length = 16;
 
153
                        tty_get_termios(tty);
 
154
                        stream_write_uint32(output, tty->control);
 
155
                        stream_write_uint32(output, tty->xonoff);
 
156
                        stream_write_uint32(output, tty->onlimit);
 
157
                        stream_write_uint32(output, tty->offlimit);
 
158
                        DEBUG_SVC("IOCTL_SERIAL_GET_HANDFLOW %X %X %X %X",
 
159
                                tty->control, tty->xonoff, tty->onlimit, tty->offlimit);
 
160
                        break;
 
161
 
 
162
                case IOCTL_SERIAL_SET_HANDFLOW:
 
163
                        stream_read_uint32(input, tty->control);
 
164
                        stream_read_uint32(input, tty->xonoff);
 
165
                        stream_read_uint32(input, tty->onlimit);
 
166
                        stream_read_uint32(input, tty->offlimit);
 
167
                        DEBUG_SVC("IOCTL_SERIAL_SET_HANDFLOW %X %X %X %X",
 
168
                                tty->control, tty->xonoff, tty->onlimit, tty->offlimit);
 
169
                        tty_set_termios(tty);
 
170
                        break;
 
171
 
 
172
                case IOCTL_SERIAL_SET_TIMEOUTS:
 
173
                        stream_read_uint32(input, tty->read_interval_timeout);
 
174
                        stream_read_uint32(input, tty->read_total_timeout_multiplier);
 
175
                        stream_read_uint32(input, tty->read_total_timeout_constant);
 
176
                        stream_read_uint32(input, tty->write_total_timeout_multiplier);
 
177
                        stream_read_uint32(input, tty->write_total_timeout_constant);
 
178
 
 
179
                        /* http://www.codeproject.com/KB/system/chaiyasit_t.aspx, see 'ReadIntervalTimeout' section
 
180
                                http://msdn.microsoft.com/en-us/library/ms885171.aspx */
 
181
                        if (tty->read_interval_timeout == SERIAL_TIMEOUT_MAX)
 
182
                        {
 
183
                                tty->read_interval_timeout = 0;
 
184
                                tty->read_total_timeout_multiplier = 0;
 
185
                        }
 
186
 
 
187
                        DEBUG_SVC("SERIAL_SET_TIMEOUTS read timeout %d %d %d",
 
188
                                tty->read_interval_timeout,
 
189
                                tty->read_total_timeout_multiplier,
 
190
                                tty->read_total_timeout_constant);
 
191
                        break;
 
192
 
 
193
                case IOCTL_SERIAL_GET_TIMEOUTS:
 
194
                        DEBUG_SVC("SERIAL_GET_TIMEOUTS read timeout %d %d %d",
 
195
                                tty->read_interval_timeout,
 
196
                                tty->read_total_timeout_multiplier,
 
197
                                tty->read_total_timeout_constant);
 
198
                        length = 20;
 
199
                        stream_write_uint32(output, tty->read_interval_timeout);
 
200
                        stream_write_uint32(output, tty->read_total_timeout_multiplier);
 
201
                        stream_write_uint32(output, tty->read_total_timeout_constant);
 
202
                        stream_write_uint32(output, tty->write_total_timeout_multiplier);
 
203
                        stream_write_uint32(output, tty->write_total_timeout_constant);
 
204
                        break;
 
205
 
 
206
                case IOCTL_SERIAL_GET_WAIT_MASK:
 
207
                        DEBUG_SVC("SERIAL_GET_WAIT_MASK %X", tty->wait_mask);
 
208
                        length = 4;
 
209
                        stream_write_uint32(output, tty->wait_mask);
 
210
                        break;
 
211
 
 
212
                case IOCTL_SERIAL_SET_WAIT_MASK:
 
213
                        stream_read_uint32(input, tty->wait_mask);
 
214
                        DEBUG_SVC("SERIAL_SET_WAIT_MASK %X", tty->wait_mask);
 
215
                        break;
 
216
 
 
217
                case IOCTL_SERIAL_SET_DTR:
 
218
                        DEBUG_SVC("SERIAL_SET_DTR");
 
219
                        ioctl(tty->fd, TIOCMGET, &result);
 
220
                        result |= TIOCM_DTR;
 
221
                        ioctl(tty->fd, TIOCMSET, &result);
 
222
                        tty->dtr = 1;
 
223
                        break;
 
224
 
 
225
                case IOCTL_SERIAL_CLR_DTR:
 
226
                        DEBUG_SVC("SERIAL_CLR_DTR");
 
227
                        ioctl(tty->fd, TIOCMGET, &result);
 
228
                        result &= ~TIOCM_DTR;
 
229
                        ioctl(tty->fd, TIOCMSET, &result);
 
230
                        tty->dtr = 0;
 
231
                        break;
 
232
 
 
233
                case IOCTL_SERIAL_SET_RTS:
 
234
                        DEBUG_SVC("SERIAL_SET_RTS");
 
235
                        ioctl(tty->fd, TIOCMGET, &result);
 
236
                        result |= TIOCM_RTS;
 
237
                        ioctl(tty->fd, TIOCMSET, &result);
 
238
                        tty->rts = 1;
 
239
                        break;
 
240
 
 
241
                case IOCTL_SERIAL_CLR_RTS:
 
242
                        DEBUG_SVC("SERIAL_CLR_RTS");
 
243
                        ioctl(tty->fd, TIOCMGET, &result);
 
244
                        result &= ~TIOCM_RTS;
 
245
                        ioctl(tty->fd, TIOCMSET, &result);
 
246
                        tty->rts = 0;
 
247
                        break;
 
248
 
 
249
                case IOCTL_SERIAL_GET_MODEMSTATUS:
 
250
                        modemstate = 0;
 
251
#ifdef TIOCMGET
 
252
                        ioctl(tty->fd, TIOCMGET, &result);
 
253
                        if (result & TIOCM_CTS)
 
254
                                modemstate |= SERIAL_MS_CTS;
 
255
                        if (result & TIOCM_DSR)
 
256
                                modemstate |= SERIAL_MS_DSR;
 
257
                        if (result & TIOCM_RNG)
 
258
                                modemstate |= SERIAL_MS_RNG;
 
259
                        if (result & TIOCM_CAR)
 
260
                                modemstate |= SERIAL_MS_CAR;
 
261
                        if (result & TIOCM_DTR)
 
262
                                modemstate |= SERIAL_MS_DTR;
 
263
                        if (result & TIOCM_RTS)
 
264
                                modemstate |= SERIAL_MS_RTS;
 
265
#endif
 
266
                        DEBUG_SVC("SERIAL_GET_MODEMSTATUS %X", modemstate);
 
267
                        length = 4;
 
268
                        stream_write_uint32(output, modemstate);
 
269
                        break;
 
270
 
 
271
                case IOCTL_SERIAL_GET_COMMSTATUS:
 
272
                        length = 18;
 
273
                        stream_write_uint32(output, 0); /* Errors */
 
274
                        stream_write_uint32(output, 0); /* Hold reasons */
 
275
 
 
276
                        result = 0;
 
277
#ifdef TIOCINQ
 
278
                        ioctl(tty->fd, TIOCINQ, &result);
 
279
#endif
 
280
                        stream_write_uint32(output, result); /* Amount in in queue */
 
281
                        if (result)
 
282
                                DEBUG_SVC("SERIAL_GET_COMMSTATUS in queue %d", result);
 
283
 
 
284
                        result = 0;
 
285
#ifdef TIOCOUTQ
 
286
                        ioctl(tty->fd, TIOCOUTQ, &result);
 
287
#endif
 
288
                        stream_write_uint32(output, result);    /* Amount in out queue */
 
289
                        DEBUG_SVC("SERIAL_GET_COMMSTATUS out queue %d", result);
 
290
 
 
291
                        stream_write_uint8(output, 0); /* EofReceived */
 
292
                        stream_write_uint8(output, 0); /* WaitForImmediate */
 
293
                        break;
 
294
 
 
295
                case IOCTL_SERIAL_PURGE:
 
296
                        stream_read_uint32(input, purge_mask);
 
297
                        DEBUG_SVC("SERIAL_PURGE purge_mask %X", purge_mask);
 
298
 
 
299
                /*      See http://msdn.microsoft.com/en-us/library/ms901431.aspx
 
300
                        PURGE_TXCLEAR   Clears the output buffer, if the driver has one.
 
301
                        PURGE_RXCLEAR   Clears the input buffer, if the driver has one.
 
302
 
 
303
                        It clearly states to clear the *driver* buffer, not the port buffer
 
304
                */
 
305
 
 
306
#ifdef DEBUG_SVC
 
307
                        if (purge_mask & SERIAL_PURGE_TXCLEAR)
 
308
                                DEBUG_SVC("Ignoring SERIAL_PURGE_TXCLEAR");
 
309
                        if (purge_mask & SERIAL_PURGE_RXCLEAR)
 
310
                                DEBUG_SVC("Ignoring SERIAL_PURGE_RXCLEAR");
 
311
#endif
 
312
 
 
313
                        if (purge_mask & SERIAL_PURGE_TXABORT)
 
314
                                *abort_io |= SERIAL_ABORT_IO_WRITE;
 
315
                        if (purge_mask & SERIAL_PURGE_RXABORT)
 
316
                                *abort_io |= SERIAL_ABORT_IO_READ;
 
317
                        break;
 
318
                case IOCTL_SERIAL_WAIT_ON_MASK:
 
319
                        DEBUG_SVC("SERIAL_WAIT_ON_MASK %X", tty->wait_mask);
 
320
                        tty->event_pending = 1;
 
321
                        length = 4;
 
322
                        if (serial_tty_get_event(tty, &result))
 
323
                        {
 
324
                                DEBUG_SVC("WAIT end  event = %X", result);
 
325
                                stream_write_uint32(output, result);
 
326
                                break;
 
327
                        }
 
328
                        ret = STATUS_PENDING;
 
329
                        break;
 
330
 
 
331
                case IOCTL_SERIAL_SET_BREAK_ON:
 
332
                        DEBUG_SVC("SERIAL_SET_BREAK_ON");
 
333
                        tcsendbreak(tty->fd, 0);
 
334
                        break;
 
335
 
 
336
                case IOCTL_SERIAL_RESET_DEVICE:
 
337
                        DEBUG_SVC("SERIAL_RESET_DEVICE");
 
338
                        break;
 
339
 
 
340
                case IOCTL_SERIAL_SET_BREAK_OFF:
 
341
                        DEBUG_SVC("SERIAL_SET_BREAK_OFF");
 
342
                        break;
 
343
 
 
344
                case IOCTL_SERIAL_SET_XOFF:
 
345
                        DEBUG_SVC("SERIAL_SET_XOFF");
 
346
                        break;
 
347
 
 
348
                case IOCTL_SERIAL_SET_XON:
 
349
                        DEBUG_SVC("SERIAL_SET_XON");
 
350
                        tcflow(tty->fd, TCION);
 
351
                        break;
 
352
 
 
353
                default:
 
354
                        DEBUG_SVC("NOT FOUND IoControlCode SERIAL IOCTL %d", IoControlCode);
 
355
                        return STATUS_INVALID_PARAMETER;
 
356
        }
 
357
 
 
358
        /* Write OutputBufferLength */
 
359
        pos = stream_get_pos(output);
 
360
        stream_set_pos(output, 16);
 
361
        stream_write_uint32(output, length);
 
362
        stream_set_pos(output, pos);
 
363
 
 
364
        return ret;
 
365
}
 
366
 
 
367
boolean serial_tty_read(SERIAL_TTY* tty, uint8* buffer, uint32* Length)
 
368
{
 
369
        long timeout = 90;
 
370
        struct termios *ptermios;
 
371
        ssize_t r;
 
372
 
 
373
        DEBUG_SVC("in");
 
374
        ptermios = tty->ptermios;
 
375
 
 
376
        /* Set timeouts kind of like the windows serial timeout parameters. Multiply timeout
 
377
           with requested read size */
 
378
        if (tty->read_total_timeout_multiplier | tty->read_total_timeout_constant)
 
379
        {
 
380
                timeout =
 
381
                        (tty->read_total_timeout_multiplier * (*Length) +
 
382
                         tty->read_total_timeout_constant + 99) / 100;
 
383
        }
 
384
        else if (tty->read_interval_timeout)
 
385
        {
 
386
                timeout = (tty->read_interval_timeout * (*Length) + 99) / 100;
 
387
        }
 
388
 
 
389
        /* If a timeout is set, do a blocking read, which times out after some time.
 
390
           It will make FreeRDP less responsive, but it will improve serial performance,
 
391
           by not reading one character at a time. */
 
392
        if (timeout == 0)
 
393
        {
 
394
                ptermios->c_cc[VTIME] = 0;
 
395
                ptermios->c_cc[VMIN] = 0;
 
396
        }
 
397
        else
 
398
        {
 
399
                ptermios->c_cc[VTIME] = timeout;
 
400
                ptermios->c_cc[VMIN] = 1;
 
401
        }
 
402
 
 
403
        tcsetattr(tty->fd, TCSANOW, ptermios);
 
404
 
 
405
        memset(buffer, 0, *Length);
 
406
        r = read(tty->fd, buffer, *Length);
 
407
        if (r < 0)
 
408
                return false;
 
409
 
 
410
        tty->event_txempty = r;
 
411
        *Length = r;
 
412
 
 
413
        return true;
 
414
}
 
415
 
 
416
boolean serial_tty_write(SERIAL_TTY* tty, uint8* buffer, uint32 Length)
 
417
{
 
418
        ssize_t r;
 
419
        uint32 event_txempty = Length;
 
420
 
 
421
        DEBUG_SVC("in");
 
422
 
 
423
        while (Length > 0)
 
424
        {
 
425
                r = write(tty->fd, buffer, Length);
 
426
                if (r < 0)
 
427
                        return false;
 
428
 
 
429
                Length -= r;
 
430
                buffer += r;
 
431
        }
 
432
        tty->event_txempty = event_txempty;
 
433
 
 
434
        return true;
 
435
}
 
436
 
 
437
void serial_tty_free(SERIAL_TTY* tty)
 
438
{
 
439
        DEBUG_SVC("in");
 
440
 
 
441
        if (tty->fd >= 0)
 
442
        {
 
443
                tcsetattr(tty->fd, TCSANOW, tty->pold_termios);
 
444
                close(tty->fd);
 
445
        }
 
446
 
 
447
        xfree(tty->ptermios);
 
448
        xfree(tty->pold_termios);
 
449
        xfree(tty);
 
450
}
 
451
 
 
452
SERIAL_TTY* serial_tty_new(const char* path, uint32 id)
 
453
{
 
454
        SERIAL_TTY* tty;
 
455
 
 
456
        tty = xnew(SERIAL_TTY);
 
457
        tty->id = id;
 
458
        tty->fd = open(path, O_RDWR | O_NOCTTY | O_NONBLOCK);
 
459
        if (tty->fd < 0)
 
460
        {
 
461
                perror("open");
 
462
                DEBUG_WARN("failed to open device %s", path);
 
463
                return NULL;
 
464
        }
 
465
        else
 
466
                DEBUG_SVC("tty fd %d successfully opened", tty->fd);
 
467
 
 
468
        tty->ptermios = (struct termios*) malloc(sizeof(struct termios));
 
469
        memset(tty->ptermios, 0, sizeof(struct termios));
 
470
        tty->pold_termios = (struct termios*) malloc(sizeof(struct termios));
 
471
        memset(tty->pold_termios, 0, sizeof(struct termios));
 
472
        tcgetattr(tty->fd, tty->pold_termios);
 
473
 
 
474
        if (!tty_get_termios(tty))
 
475
        {
 
476
                DEBUG_WARN("%s access denied", path);
 
477
                fflush(stdout);
 
478
                return NULL;
 
479
        }
 
480
 
 
481
        tty->ptermios->c_iflag &= ~(IGNBRK | BRKINT | PARMRK | ISTRIP | INLCR | IGNCR | ICRNL | IXON);
 
482
        tty->ptermios->c_iflag = IGNPAR | ICRNL;
 
483
        tty->ptermios->c_oflag &= ~OPOST;
 
484
        tty->ptermios->c_lflag &= ~(ECHO | ECHONL | ICANON | ISIG | IEXTEN);
 
485
        tty->ptermios->c_cflag &= ~(CSIZE | PARENB);
 
486
        tty->ptermios->c_cflag |= CLOCAL | CREAD | CS8;
 
487
        tcsetattr(tty->fd, TCSANOW, tty->ptermios);
 
488
 
 
489
        tty->event_txempty = 0;
 
490
        tty->event_cts = 0;
 
491
        tty->event_dsr = 0;
 
492
        tty->event_rlsd = 0;
 
493
        tty->event_pending = 0;
 
494
 
 
495
        /* all read and writes should be non-blocking */
 
496
        if (fcntl(tty->fd, F_SETFL, O_NONBLOCK) == -1)
 
497
        {
 
498
                DEBUG_WARN("%s fcntl", path);
 
499
                perror("fcntl");
 
500
                return NULL;
 
501
        }
 
502
 
 
503
        tty->read_total_timeout_constant = 5;
 
504
 
 
505
        return tty;
 
506
}
 
507
 
 
508
boolean serial_tty_get_event(SERIAL_TTY* tty, uint32* result)
 
509
{
 
510
        int bytes;
 
511
        boolean ret = false;
 
512
 
 
513
        DEBUG_SVC("in");
 
514
 
 
515
        *result = 0;
 
516
 
 
517
#ifdef TIOCINQ
 
518
        /* When wait_mask is set to zero we ought to cancel it all
 
519
           For reference: http://msdn.microsoft.com/en-us/library/aa910487.aspx */
 
520
        if (tty->wait_mask == 0)
 
521
        {
 
522
                tty->event_pending = 0;
 
523
                return true;
 
524
        }
 
525
 
 
526
        ioctl(tty->fd, TIOCINQ, &bytes);
 
527
 
 
528
        if (bytes > 0)
 
529
        {
 
530
                DEBUG_SVC("bytes %d", bytes);
 
531
 
 
532
                if (bytes > tty->event_rlsd)
 
533
                {
 
534
                        tty->event_rlsd = bytes;
 
535
                        if (tty->wait_mask & SERIAL_EV_RLSD)
 
536
                        {
 
537
                                DEBUG_SVC("SERIAL_EV_RLSD");
 
538
                                *result |= SERIAL_EV_RLSD;
 
539
                                ret = true;
 
540
                        }
 
541
 
 
542
                }
 
543
 
 
544
                if ((bytes > 1) && (tty->wait_mask & SERIAL_EV_RXFLAG))
 
545
                {
 
546
                        DEBUG_SVC("SERIAL_EV_RXFLAG bytes %d", bytes);
 
547
                        *result |= SERIAL_EV_RXFLAG;
 
548
                        ret = true;
 
549
                }
 
550
                if ((tty->wait_mask & SERIAL_EV_RXCHAR))
 
551
                {
 
552
                        DEBUG_SVC("SERIAL_EV_RXCHAR bytes %d", bytes);
 
553
                        *result |= SERIAL_EV_RXCHAR;
 
554
                        ret = true;
 
555
                }
 
556
 
 
557
        }
 
558
        else
 
559
        {
 
560
                tty->event_rlsd = 0;
 
561
        }
 
562
#endif
 
563
 
 
564
#ifdef TIOCOUTQ
 
565
        ioctl(tty->fd, TIOCOUTQ, &bytes);
 
566
        if ((bytes == 0)
 
567
            && (tty->event_txempty > 0) && (tty->wait_mask & SERIAL_EV_TXEMPTY))
 
568
        {
 
569
                DEBUG_SVC("SERIAL_EV_TXEMPTY");
 
570
                *result |= SERIAL_EV_TXEMPTY;
 
571
                ret = true;
 
572
        }
 
573
        tty->event_txempty = bytes;
 
574
#endif
 
575
 
 
576
        ioctl(tty->fd, TIOCMGET, &bytes);
 
577
        if ((bytes & TIOCM_DSR) != tty->event_dsr)
 
578
        {
 
579
                tty->event_dsr = bytes & TIOCM_DSR;
 
580
                if (tty->wait_mask & SERIAL_EV_DSR)
 
581
                {
 
582
                        DEBUG_SVC("SERIAL_EV_DSR %s", (bytes & TIOCM_DSR) ? "ON" : "OFF");
 
583
                        *result |= SERIAL_EV_DSR;
 
584
                        ret = true;
 
585
                }
 
586
        }
 
587
 
 
588
        if ((bytes & TIOCM_CTS) != tty->event_cts)
 
589
        {
 
590
                tty->event_cts = bytes & TIOCM_CTS;
 
591
                if (tty->wait_mask & SERIAL_EV_CTS)
 
592
                {
 
593
                        DEBUG_SVC("SERIAL_EV_CTS %s", (bytes & TIOCM_CTS) ? "ON" : "OFF");
 
594
                        *result |= SERIAL_EV_CTS;
 
595
                        ret = true;
 
596
                }
 
597
        }
 
598
 
 
599
        if (ret)
 
600
                tty->event_pending = 0;
 
601
 
 
602
        return ret;
 
603
}
 
604
 
 
605
static boolean tty_get_termios(SERIAL_TTY* tty)
 
606
{
 
607
        speed_t speed;
 
608
        struct termios *ptermios;
 
609
        ptermios = tty->ptermios;
 
610
 
 
611
        DEBUG_SVC("tcgetattr? %d", tcgetattr(tty->fd, ptermios) >= 0);
 
612
        if (tcgetattr(tty->fd, ptermios) < 0)
 
613
                return false;
 
614
 
 
615
        speed = cfgetispeed(ptermios);
 
616
        switch (speed)
 
617
        {
 
618
#ifdef B75
 
619
                case B75:
 
620
                        tty->baud_rate = 75;
 
621
                        break;
 
622
#endif
 
623
#ifdef B110
 
624
                case B110:
 
625
                        tty->baud_rate = 110;
 
626
                        break;
 
627
#endif
 
628
#ifdef B134
 
629
                case B134:
 
630
                        tty->baud_rate = 134;
 
631
                        break;
 
632
#endif
 
633
#ifdef B150
 
634
                case B150:
 
635
                        tty->baud_rate = 150;
 
636
                        break;
 
637
#endif
 
638
#ifdef B300
 
639
                case B300:
 
640
                        tty->baud_rate = 300;
 
641
                        break;
 
642
#endif
 
643
#ifdef B600
 
644
                case B600:
 
645
                        tty->baud_rate = 600;
 
646
                        break;
 
647
#endif
 
648
#ifdef B1200
 
649
                case B1200:
 
650
                        tty->baud_rate = 1200;
 
651
                        break;
 
652
#endif
 
653
#ifdef B1800
 
654
                case B1800:
 
655
                        tty->baud_rate = 1800;
 
656
                        break;
 
657
#endif
 
658
#ifdef B2400
 
659
                case B2400:
 
660
                        tty->baud_rate = 2400;
 
661
                        break;
 
662
#endif
 
663
#ifdef B4800
 
664
                case B4800:
 
665
                        tty->baud_rate = 4800;
 
666
                        break;
 
667
#endif
 
668
#ifdef B9600
 
669
                case B9600:
 
670
                        tty->baud_rate = 9600;
 
671
                        break;
 
672
#endif
 
673
#ifdef B19200
 
674
                case B19200:
 
675
                        tty->baud_rate = 19200;
 
676
                        break;
 
677
#endif
 
678
#ifdef B38400
 
679
                case B38400:
 
680
                        tty->baud_rate = 38400;
 
681
                        break;
 
682
#endif
 
683
#ifdef B57600
 
684
                case B57600:
 
685
                        tty->baud_rate = 57600;
 
686
                        break;
 
687
#endif
 
688
#ifdef B115200
 
689
                case B115200:
 
690
                        tty->baud_rate = 115200;
 
691
                        break;
 
692
#endif
 
693
#ifdef B230400
 
694
                case B230400:
 
695
                        tty->baud_rate = 230400;
 
696
                        break;
 
697
#endif
 
698
#ifdef B460800
 
699
                case B460800:
 
700
                        tty->baud_rate = 460800;
 
701
                        break;
 
702
#endif
 
703
                default:
 
704
                        tty->baud_rate = 9600;
 
705
                        break;
 
706
        }
 
707
 
 
708
        speed = cfgetospeed(ptermios);
 
709
        tty->dtr = (speed == B0) ? 0 : 1;
 
710
 
 
711
        tty->stop_bits = (ptermios->c_cflag & CSTOPB) ? SERIAL_STOP_BITS_2 : SERIAL_STOP_BITS_1;
 
712
        tty->parity =
 
713
                (ptermios->c_cflag & PARENB) ? ((ptermios->c_cflag & PARODD) ? SERIAL_ODD_PARITY :
 
714
                                                SERIAL_EVEN_PARITY) : SERIAL_NO_PARITY;
 
715
        switch (ptermios->c_cflag & CSIZE)
 
716
        {
 
717
                case CS5:
 
718
                        tty->word_length = 5;
 
719
                        break;
 
720
                case CS6:
 
721
                        tty->word_length = 6;
 
722
                        break;
 
723
                case CS7:
 
724
                        tty->word_length = 7;
 
725
                        break;
 
726
                default:
 
727
                        tty->word_length = 8;
 
728
                        break;
 
729
        }
 
730
 
 
731
        if (ptermios->c_cflag & CRTSCTS)
 
732
        {
 
733
                tty->control = SERIAL_DTR_CONTROL | SERIAL_CTS_HANDSHAKE | SERIAL_ERROR_ABORT;
 
734
        }
 
735
        else
 
736
        {
 
737
                tty->control = SERIAL_DTR_CONTROL | SERIAL_ERROR_ABORT;
 
738
        }
 
739
 
 
740
        tty->xonoff = SERIAL_DSR_SENSITIVITY;
 
741
        if (ptermios->c_iflag & IXON)
 
742
                tty->xonoff |= SERIAL_XON_HANDSHAKE;
 
743
 
 
744
        if (ptermios->c_iflag & IXOFF)
 
745
                tty->xonoff |= SERIAL_XOFF_HANDSHAKE;
 
746
 
 
747
        tty->chars[SERIAL_CHAR_XON] = ptermios->c_cc[VSTART];
 
748
        tty->chars[SERIAL_CHAR_XOFF] = ptermios->c_cc[VSTOP];
 
749
        tty->chars[SERIAL_CHAR_EOF] = ptermios->c_cc[VEOF];
 
750
        tty->chars[SERIAL_CHAR_BREAK] = ptermios->c_cc[VINTR];
 
751
        tty->chars[SERIAL_CHAR_ERROR] = ptermios->c_cc[VKILL];
 
752
 
 
753
        return true;
 
754
}
 
755
 
 
756
static void tty_set_termios(SERIAL_TTY* tty)
 
757
{
 
758
        speed_t speed;
 
759
        struct termios *ptermios;
 
760
 
 
761
        DEBUG_SVC("in");
 
762
        ptermios = tty->ptermios;
 
763
        switch (tty->baud_rate)
 
764
        {
 
765
#ifdef B75
 
766
                case 75:
 
767
                        speed = B75;
 
768
                        break;
 
769
#endif
 
770
#ifdef B110
 
771
                case 110:
 
772
                        speed = B110;
 
773
                        break;
 
774
#endif
 
775
#ifdef B134
 
776
                case 134:
 
777
                        speed = B134;
 
778
                        break;
 
779
#endif
 
780
#ifdef B150
 
781
                case 150:
 
782
                        speed = B150;
 
783
                        break;
 
784
#endif
 
785
#ifdef B300
 
786
                case 300:
 
787
                        speed = B300;
 
788
                        break;
 
789
#endif
 
790
#ifdef B600
 
791
                case 600:
 
792
                        speed = B600;
 
793
                        break;
 
794
#endif
 
795
#ifdef B1200
 
796
                case 1200:
 
797
                        speed = B1200;
 
798
                        break;
 
799
#endif
 
800
#ifdef B1800
 
801
                case 1800:
 
802
                        speed = B1800;
 
803
                        break;
 
804
#endif
 
805
#ifdef B2400
 
806
                case 2400:
 
807
                        speed = B2400;
 
808
                        break;
 
809
#endif
 
810
#ifdef B4800
 
811
                case 4800:
 
812
                        speed = B4800;
 
813
                        break;
 
814
#endif
 
815
#ifdef B9600
 
816
                case 9600:
 
817
                        speed = B9600;
 
818
                        break;
 
819
#endif
 
820
#ifdef B19200
 
821
                case 19200:
 
822
                        speed = B19200;
 
823
                        break;
 
824
#endif
 
825
#ifdef B38400
 
826
                case 38400:
 
827
                        speed = B38400;
 
828
                        break;
 
829
#endif
 
830
#ifdef B57600
 
831
                case 57600:
 
832
                        speed = B57600;
 
833
                        break;
 
834
#endif
 
835
#ifdef B115200
 
836
                case 115200:
 
837
                        speed = B115200;
 
838
                        break;
 
839
#endif
 
840
#ifdef B230400
 
841
                case 230400:
 
842
                        speed = B115200;
 
843
                        break;
 
844
#endif
 
845
#ifdef B460800
 
846
                case 460800:
 
847
                        speed = B115200;
 
848
                        break;
 
849
#endif
 
850
                default:
 
851
                        speed = B9600;
 
852
                        break;
 
853
        }
 
854
 
 
855
#ifdef CBAUD
 
856
        ptermios->c_cflag &= ~CBAUD;
 
857
        ptermios->c_cflag |= speed;
 
858
#else
 
859
        /* on systems with separate ispeed and ospeed, we can remember the speed
 
860
           in ispeed while changing DTR with ospeed */
 
861
        cfsetispeed(tty->ptermios, speed);
 
862
        cfsetospeed(tty->ptermios, tty->dtr ? speed : 0);
 
863
#endif
 
864
 
 
865
        ptermios->c_cflag &= ~(CSTOPB | PARENB | PARODD | CSIZE | CRTSCTS);
 
866
        switch (tty->stop_bits)
 
867
        {
 
868
                case SERIAL_STOP_BITS_2:
 
869
                        ptermios->c_cflag |= CSTOPB;
 
870
                        break;
 
871
                default:
 
872
                        ptermios->c_cflag &= ~CSTOPB;
 
873
                        break;
 
874
        }
 
875
 
 
876
        switch (tty->parity)
 
877
        {
 
878
                case SERIAL_EVEN_PARITY:
 
879
                        ptermios->c_cflag |= PARENB;
 
880
                        break;
 
881
                case SERIAL_ODD_PARITY:
 
882
                        ptermios->c_cflag |= PARENB | PARODD;
 
883
                        break;
 
884
                case SERIAL_NO_PARITY:
 
885
                        ptermios->c_cflag &= ~(PARENB | PARODD);
 
886
                        break;
 
887
        }
 
888
 
 
889
        switch (tty->word_length)
 
890
        {
 
891
                case 5:
 
892
                        ptermios->c_cflag |= CS5;
 
893
                        break;
 
894
                case 6:
 
895
                        ptermios->c_cflag |= CS6;
 
896
                        break;
 
897
                case 7:
 
898
                        ptermios->c_cflag |= CS7;
 
899
                        break;
 
900
                default:
 
901
                        ptermios->c_cflag |= CS8;
 
902
                        break;
 
903
        }
 
904
 
 
905
#if 0
 
906
        if (tty->rts)
 
907
                ptermios->c_cflag |= CRTSCTS;
 
908
        else
 
909
                ptermios->c_cflag &= ~CRTSCTS;
 
910
#endif
 
911
 
 
912
        if (tty->control & SERIAL_CTS_HANDSHAKE)
 
913
        {
 
914
                ptermios->c_cflag |= CRTSCTS;
 
915
        }
 
916
        else
 
917
        {
 
918
                ptermios->c_cflag &= ~CRTSCTS;
 
919
        }
 
920
 
 
921
 
 
922
        if (tty->xonoff & SERIAL_XON_HANDSHAKE)
 
923
        {
 
924
                ptermios->c_iflag |= IXON | IMAXBEL;
 
925
        }
 
926
        if (tty->xonoff & SERIAL_XOFF_HANDSHAKE)
 
927
        {
 
928
                ptermios->c_iflag |= IXOFF | IMAXBEL;
 
929
        }
 
930
 
 
931
        if ((tty->xonoff & (SERIAL_XOFF_HANDSHAKE | SERIAL_XON_HANDSHAKE)) == 0)
 
932
        {
 
933
                ptermios->c_iflag &= ~IXON;
 
934
                ptermios->c_iflag &= ~IXOFF;
 
935
        }
 
936
 
 
937
        ptermios->c_cc[VSTART] = tty->chars[SERIAL_CHAR_XON];
 
938
        ptermios->c_cc[VSTOP] = tty->chars[SERIAL_CHAR_XOFF];
 
939
        ptermios->c_cc[VEOF] = tty->chars[SERIAL_CHAR_EOF];
 
940
        ptermios->c_cc[VINTR] = tty->chars[SERIAL_CHAR_BREAK];
 
941
        ptermios->c_cc[VKILL] = tty->chars[SERIAL_CHAR_ERROR];
 
942
 
 
943
        tcsetattr(tty->fd, TCSANOW, ptermios);
 
944
}
 
945
 
 
946
static uint32 tty_write_data(SERIAL_TTY* tty, uint8* data, int len)
 
947
{
 
948
        ssize_t r;
 
949
 
 
950
        DEBUG_SVC("in");
 
951
 
 
952
        r = write(tty->fd, data, len);
 
953
        if (r < 0)
 
954
                return tty_get_error_status();
 
955
 
 
956
        tty->event_txempty = r;
 
957
 
 
958
        return STATUS_SUCCESS;
 
959
}
 
960
 
 
961
static int tty_get_error_status()
 
962
{
 
963
        DEBUG_SVC("in errno %d", errno);
 
964
 
 
965
        switch (errno)
 
966
        {
 
967
                case EACCES:
 
968
                case ENOTDIR:
 
969
                case ENFILE:
 
970
                        return STATUS_ACCESS_DENIED;
 
971
                case EISDIR:
 
972
                        return STATUS_FILE_IS_A_DIRECTORY;
 
973
                case EEXIST:
 
974
                        return STATUS_OBJECT_NAME_COLLISION;
 
975
                case EBADF:
 
976
                        return STATUS_INVALID_HANDLE;
 
977
                default:
 
978
                        return STATUS_NO_SUCH_FILE;
 
979
        }
 
980
}