1 /*
2 * Copyright 1993-2003 by The XFree86 Project, Inc.
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice shall be included in
12 * all copies or substantial portions of the Software.
13 *
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
17 * THE XFREE86 PROJECT BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
18 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
19 * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20 * SOFTWARE.
21 *
22 * Except as contained in this notice, the name of the XFree86 Project shall
23 * not be used in advertising or otherwise to promote the sale, use or other
24 * dealings in this Software without prior written authorization from the
25 * XFree86 Project.
26 */
27 /*
28 *
29 * Copyright (c) 1997 Metro Link Incorporated
30 *
31 * Permission is hereby granted, free of charge, to any person obtaining a
32 * copy of this software and associated documentation files (the "Software"),
33 * to deal in the Software without restriction, including without limitation
34 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
35 * and/or sell copies of the Software, and to permit persons to whom the
36 * Software is furnished to do so, subject to the following conditions:
37 *
38 * The above copyright notice and this permission notice shall be included in
39 * all copies or substantial portions of the Software.
40 *
41 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
42 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
43 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
44 * THE X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
45 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
46 * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
47 * SOFTWARE.
48 *
49 * Except as contained in this notice, the name of the Metro Link shall not be
50 * used in advertising or otherwise to promote the sale, use or other dealings
51 * in this Software without prior written authorization from Metro Link.
52 *
53 */
54
55 #ifdef HAVE_XORG_CONFIG_H
56 #include <xorg-config.h>
57 #endif
58
59 #include <X11/X.h>
60 #include <xserver_poll.h>
61 #include "xf86.h"
62 #include "xf86Priv.h"
63 #include "xf86_OSlib.h"
64
65 static int
GetBaud(int baudrate)66 GetBaud(int baudrate)
67 {
68 #ifdef B300
69 if (baudrate == 300)
70 return B300;
71 #endif
72 #ifdef B1200
73 if (baudrate == 1200)
74 return B1200;
75 #endif
76 #ifdef B2400
77 if (baudrate == 2400)
78 return B2400;
79 #endif
80 #ifdef B4800
81 if (baudrate == 4800)
82 return B4800;
83 #endif
84 #ifdef B9600
85 if (baudrate == 9600)
86 return B9600;
87 #endif
88 #ifdef B19200
89 if (baudrate == 19200)
90 return B19200;
91 #endif
92 #ifdef B38400
93 if (baudrate == 38400)
94 return B38400;
95 #endif
96 #ifdef B57600
97 if (baudrate == 57600)
98 return B57600;
99 #endif
100 #ifdef B115200
101 if (baudrate == 115200)
102 return B115200;
103 #endif
104 #ifdef B230400
105 if (baudrate == 230400)
106 return B230400;
107 #endif
108 #ifdef B460800
109 if (baudrate == 460800)
110 return B460800;
111 #endif
112 return 0;
113 }
114
115 int
xf86OpenSerial(XF86OptionPtr options)116 xf86OpenSerial(XF86OptionPtr options)
117 {
118 struct termios t;
119 int fd, i;
120 char *dev;
121
122 dev = xf86SetStrOption(options, "Device", NULL);
123 if (!dev) {
124 xf86Msg(X_ERROR, "xf86OpenSerial: No Device specified.\n");
125 return -1;
126 }
127
128 fd = xf86CheckIntOption(options, "fd", -1);
129
130 if (fd == -1)
131 SYSCALL(fd = open(dev, O_RDWR | O_NONBLOCK));
132
133 if (fd == -1) {
134 xf86Msg(X_ERROR,
135 "xf86OpenSerial: Cannot open device %s\n\t%s.\n",
136 dev, strerror(errno));
137 free(dev);
138 return -1;
139 }
140
141 if (!isatty(fd)) {
142 /* Allow non-tty devices to be opened. */
143 free(dev);
144 return fd;
145 }
146
147 /* set up default port parameters */
148 SYSCALL(tcgetattr(fd, &t));
149 t.c_iflag &= ~(IGNBRK | BRKINT | PARMRK | ISTRIP | INLCR
150 | IGNCR | ICRNL | IXON);
151 t.c_oflag &= ~OPOST;
152 t.c_lflag &= ~(ECHO | ECHONL | ICANON | ISIG | IEXTEN);
153 t.c_cflag &= ~(CSIZE | PARENB);
154 t.c_cflag |= CS8 | CLOCAL;
155
156 cfsetispeed(&t, B9600);
157 cfsetospeed(&t, B9600);
158 t.c_cc[VMIN] = 1;
159 t.c_cc[VTIME] = 0;
160
161 SYSCALL(tcsetattr(fd, TCSANOW, &t));
162
163 if (xf86SetSerial(fd, options) == -1) {
164 SYSCALL(close(fd));
165 free(dev);
166 return -1;
167 }
168
169 SYSCALL(i = fcntl(fd, F_GETFL, 0));
170 if (i == -1) {
171 SYSCALL(close(fd));
172 free(dev);
173 return -1;
174 }
175 i &= ~O_NONBLOCK;
176 SYSCALL(i = fcntl(fd, F_SETFL, i));
177 if (i == -1) {
178 SYSCALL(close(fd));
179 free(dev);
180 return -1;
181 }
182 free(dev);
183 return fd;
184 }
185
186 int
xf86SetSerial(int fd,XF86OptionPtr options)187 xf86SetSerial(int fd, XF86OptionPtr options)
188 {
189 struct termios t;
190 int val;
191 char *s;
192 int baud, r;
193
194 if (fd < 0)
195 return -1;
196
197 /* Don't try to set parameters for non-tty devices. */
198 if (!isatty(fd))
199 return 0;
200
201 SYSCALL(tcgetattr(fd, &t));
202
203 if ((val = xf86SetIntOption(options, "BaudRate", 0))) {
204 if ((baud = GetBaud(val))) {
205 cfsetispeed(&t, baud);
206 cfsetospeed(&t, baud);
207 }
208 else {
209 xf86Msg(X_ERROR, "Invalid Option BaudRate value: %d\n", val);
210 return -1;
211 }
212 }
213
214 if ((val = xf86SetIntOption(options, "StopBits", 0))) {
215 switch (val) {
216 case 1:
217 t.c_cflag &= ~(CSTOPB);
218 break;
219 case 2:
220 t.c_cflag |= CSTOPB;
221 break;
222 default:
223 xf86Msg(X_ERROR, "Invalid Option StopBits value: %d\n", val);
224 return -1;
225 break;
226 }
227 }
228
229 if ((val = xf86SetIntOption(options, "DataBits", 0))) {
230 switch (val) {
231 case 5:
232 t.c_cflag &= ~(CSIZE);
233 t.c_cflag |= CS5;
234 break;
235 case 6:
236 t.c_cflag &= ~(CSIZE);
237 t.c_cflag |= CS6;
238 break;
239 case 7:
240 t.c_cflag &= ~(CSIZE);
241 t.c_cflag |= CS7;
242 break;
243 case 8:
244 t.c_cflag &= ~(CSIZE);
245 t.c_cflag |= CS8;
246 break;
247 default:
248 xf86Msg(X_ERROR, "Invalid Option DataBits value: %d\n", val);
249 return -1;
250 break;
251 }
252 }
253
254 if ((s = xf86SetStrOption(options, "Parity", NULL))) {
255 if (xf86NameCmp(s, "Odd") == 0) {
256 t.c_cflag |= PARENB | PARODD;
257 }
258 else if (xf86NameCmp(s, "Even") == 0) {
259 t.c_cflag |= PARENB;
260 t.c_cflag &= ~(PARODD);
261 }
262 else if (xf86NameCmp(s, "None") == 0) {
263 t.c_cflag &= ~(PARENB);
264 }
265 else {
266 xf86Msg(X_ERROR, "Invalid Option Parity value: %s\n", s);
267 free(s);
268 return -1;
269 }
270 free(s);
271 }
272
273 if ((val = xf86SetIntOption(options, "Vmin", -1)) != -1) {
274 t.c_cc[VMIN] = val;
275 }
276 if ((val = xf86SetIntOption(options, "Vtime", -1)) != -1) {
277 t.c_cc[VTIME] = val;
278 }
279
280 if ((s = xf86SetStrOption(options, "FlowControl", NULL))) {
281 xf86MarkOptionUsedByName(options, "FlowControl");
282 if (xf86NameCmp(s, "Xoff") == 0) {
283 t.c_iflag |= IXOFF;
284 }
285 else if (xf86NameCmp(s, "Xon") == 0) {
286 t.c_iflag |= IXON;
287 }
288 else if (xf86NameCmp(s, "XonXoff") == 0) {
289 t.c_iflag |= IXON | IXOFF;
290 }
291 else if (xf86NameCmp(s, "None") == 0) {
292 t.c_iflag &= ~(IXON | IXOFF);
293 }
294 else {
295 xf86Msg(X_ERROR, "Invalid Option FlowControl value: %s\n", s);
296 free(s);
297 return -1;
298 }
299 free(s);
300 }
301
302 if ((xf86SetBoolOption(options, "ClearDTR", FALSE))) {
303 #ifdef CLEARDTR_SUPPORT
304 #if defined(TIOCMBIC)
305 val = TIOCM_DTR;
306 SYSCALL(ioctl(fd, TIOCMBIC, &val));
307 #else
308 SYSCALL(ioctl(fd, TIOCCDTR, NULL));
309 #endif
310 #else
311 xf86Msg(X_WARNING, "Option ClearDTR not supported on this OS\n");
312 return -1;
313 #endif
314 xf86MarkOptionUsedByName(options, "ClearDTR");
315 }
316
317 if ((xf86SetBoolOption(options, "ClearRTS", FALSE))) {
318 xf86Msg(X_WARNING, "Option ClearRTS not supported on this OS\n");
319 return -1;
320 xf86MarkOptionUsedByName(options, "ClearRTS");
321 }
322
323 SYSCALL(r = tcsetattr(fd, TCSANOW, &t));
324 return r;
325 }
326
327 int
xf86SetSerialSpeed(int fd,int speed)328 xf86SetSerialSpeed(int fd, int speed)
329 {
330 struct termios t;
331 int baud, r;
332
333 if (fd < 0)
334 return -1;
335
336 /* Don't try to set parameters for non-tty devices. */
337 if (!isatty(fd))
338 return 0;
339
340 SYSCALL(tcgetattr(fd, &t));
341
342 if ((baud = GetBaud(speed))) {
343 cfsetispeed(&t, baud);
344 cfsetospeed(&t, baud);
345 }
346 else {
347 xf86Msg(X_ERROR, "Invalid Option BaudRate value: %d\n", speed);
348 return -1;
349 }
350
351 SYSCALL(r = tcsetattr(fd, TCSANOW, &t));
352 return r;
353 }
354
355 int
xf86ReadSerial(int fd,void * buf,int count)356 xf86ReadSerial(int fd, void *buf, int count)
357 {
358 int r;
359 int i;
360
361 SYSCALL(r = read(fd, buf, count));
362 DebugF("ReadingSerial: 0x%x", (unsigned char) *(((unsigned char *) buf)));
363 for (i = 1; i < r; i++)
364 DebugF(", 0x%x", (unsigned char) *(((unsigned char *) buf) + i));
365 DebugF("\n");
366 return r;
367 }
368
369 int
xf86WriteSerial(int fd,const void * buf,int count)370 xf86WriteSerial(int fd, const void *buf, int count)
371 {
372 int r;
373 int i;
374
375 DebugF("WritingSerial: 0x%x", (unsigned char) *(((unsigned char *) buf)));
376 for (i = 1; i < count; i++)
377 DebugF(", 0x%x", (unsigned char) *(((unsigned char *) buf) + i));
378 DebugF("\n");
379 SYSCALL(r = write(fd, buf, count));
380 return r;
381 }
382
383 int
xf86CloseSerial(int fd)384 xf86CloseSerial(int fd)
385 {
386 int r;
387
388 SYSCALL(r = close(fd));
389 return r;
390 }
391
392 int
xf86WaitForInput(int fd,int timeout)393 xf86WaitForInput(int fd, int timeout)
394 {
395 int r;
396 struct pollfd poll_fd;
397
398 poll_fd.fd = fd;
399 poll_fd.events = POLLIN;
400
401 /* convert microseconds to milliseconds */
402 timeout = (timeout + 999) / 1000;
403
404 if (fd >= 0) {
405 SYSCALL(r = xserver_poll(&poll_fd, 1, timeout));
406 }
407 else {
408 SYSCALL(r = xserver_poll(&poll_fd, 0, timeout));
409 }
410 xf86ErrorFVerb(9, "poll returned %d\n", r);
411 return r;
412 }
413
414 int
xf86SerialSendBreak(int fd,int duration)415 xf86SerialSendBreak(int fd, int duration)
416 {
417 int r;
418
419 SYSCALL(r = tcsendbreak(fd, duration));
420 return r;
421
422 }
423
424 int
xf86FlushInput(int fd)425 xf86FlushInput(int fd)
426 {
427 struct pollfd poll_fd;
428 /* this needs to be big enough to flush an evdev event. */
429 char c[256];
430
431 DebugF("FlushingSerial\n");
432 if (tcflush(fd, TCIFLUSH) == 0)
433 return 0;
434
435 poll_fd.fd = fd;
436 poll_fd.events = POLLIN;
437 while (xserver_poll(&poll_fd, 1, 0) > 0) {
438 if (read(fd, &c, sizeof(c)) < 1)
439 return 0;
440 }
441 return 0;
442 }
443
444 static struct states {
445 int xf;
446 int os;
447 } modemStates[] = {
448 #ifdef TIOCM_LE
449 {
450 XF86_M_LE, TIOCM_LE},
451 #endif
452 #ifdef TIOCM_DTR
453 {
454 XF86_M_DTR, TIOCM_DTR},
455 #endif
456 #ifdef TIOCM_RTS
457 {
458 XF86_M_RTS, TIOCM_RTS},
459 #endif
460 #ifdef TIOCM_ST
461 {
462 XF86_M_ST, TIOCM_ST},
463 #endif
464 #ifdef TIOCM_SR
465 {
466 XF86_M_SR, TIOCM_SR},
467 #endif
468 #ifdef TIOCM_CTS
469 {
470 XF86_M_CTS, TIOCM_CTS},
471 #endif
472 #ifdef TIOCM_CAR
473 {
474 XF86_M_CAR, TIOCM_CAR},
475 #elif defined(TIOCM_CD)
476 {
477 XF86_M_CAR, TIOCM_CD},
478 #endif
479 #ifdef TIOCM_RNG
480 {
481 XF86_M_RNG, TIOCM_RNG},
482 #elif defined(TIOCM_RI)
483 {
484 XF86_M_CAR, TIOCM_RI},
485 #endif
486 #ifdef TIOCM_DSR
487 {
488 XF86_M_DSR, TIOCM_DSR},
489 #endif
490 };
491
492 static int numStates = ARRAY_SIZE(modemStates);
493
494 static int
xf2osState(int state)495 xf2osState(int state)
496 {
497 int i;
498 int ret = 0;
499
500 for (i = 0; i < numStates; i++)
501 if (state & modemStates[i].xf)
502 ret |= modemStates[i].os;
503 return ret;
504 }
505
506 static int
os2xfState(int state)507 os2xfState(int state)
508 {
509 int i;
510 int ret = 0;
511
512 for (i = 0; i < numStates; i++)
513 if (state & modemStates[i].os)
514 ret |= modemStates[i].xf;
515 return ret;
516 }
517
518 static int
getOsStateMask(void)519 getOsStateMask(void)
520 {
521 int i;
522 int ret = 0;
523
524 for (i = 0; i < numStates; i++)
525 ret |= modemStates[i].os;
526 return ret;
527 }
528
529 static int osStateMask = 0;
530
531 int
xf86SetSerialModemState(int fd,int state)532 xf86SetSerialModemState(int fd, int state)
533 {
534 int ret;
535 int s;
536
537 if (fd < 0)
538 return -1;
539
540 /* Don't try to set parameters for non-tty devices. */
541 if (!isatty(fd))
542 return 0;
543
544 #ifndef TIOCMGET
545 return -1;
546 #else
547 if (!osStateMask)
548 osStateMask = getOsStateMask();
549
550 state = xf2osState(state);
551 SYSCALL((ret = ioctl(fd, TIOCMGET, &s)));
552 if (ret < 0)
553 return -1;
554 s &= ~osStateMask;
555 s |= state;
556 SYSCALL((ret = ioctl(fd, TIOCMSET, &s)));
557 if (ret < 0)
558 return -1;
559 else
560 return 0;
561 #endif
562 }
563
564 int
xf86GetSerialModemState(int fd)565 xf86GetSerialModemState(int fd)
566 {
567 int ret;
568 int s;
569
570 if (fd < 0)
571 return -1;
572
573 /* Don't try to set parameters for non-tty devices. */
574 if (!isatty(fd))
575 return 0;
576
577 #ifndef TIOCMGET
578 return -1;
579 #else
580 SYSCALL((ret = ioctl(fd, TIOCMGET, &s)));
581 if (ret < 0)
582 return -1;
583 return os2xfState(s);
584 #endif
585 }
586
587 int
xf86SerialModemSetBits(int fd,int bits)588 xf86SerialModemSetBits(int fd, int bits)
589 {
590 int ret;
591 int s;
592
593 if (fd < 0)
594 return -1;
595
596 /* Don't try to set parameters for non-tty devices. */
597 if (!isatty(fd))
598 return 0;
599
600 #ifndef TIOCMGET
601 return -1;
602 #else
603 s = xf2osState(bits);
604 SYSCALL((ret = ioctl(fd, TIOCMBIS, &s)));
605 return ret;
606 #endif
607 }
608
609 int
xf86SerialModemClearBits(int fd,int bits)610 xf86SerialModemClearBits(int fd, int bits)
611 {
612 int ret;
613 int s;
614
615 if (fd < 0)
616 return -1;
617
618 /* Don't try to set parameters for non-tty devices. */
619 if (!isatty(fd))
620 return 0;
621
622 #ifndef TIOCMGET
623 return -1;
624 #else
625 s = xf2osState(bits);
626 SYSCALL((ret = ioctl(fd, TIOCMBIC, &s)));
627 return ret;
628 #endif
629 }
630