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 "xf86.h" 61#include "xf86Priv.h" 62#include "xf86_OSlib.h" 63 64static int 65GetBaud (int baudrate) 66{ 67#ifdef B300 68 if (baudrate == 300) 69 return B300; 70#endif 71#ifdef B1200 72 if (baudrate == 1200) 73 return B1200; 74#endif 75#ifdef B2400 76 if (baudrate == 2400) 77 return B2400; 78#endif 79#ifdef B4800 80 if (baudrate == 4800) 81 return B4800; 82#endif 83#ifdef B9600 84 if (baudrate == 9600) 85 return B9600; 86#endif 87#ifdef B19200 88 if (baudrate == 19200) 89 return B19200; 90#endif 91#ifdef B38400 92 if (baudrate == 38400) 93 return B38400; 94#endif 95#ifdef B57600 96 if (baudrate == 57600) 97 return B57600; 98#endif 99#ifdef B115200 100 if (baudrate == 115200) 101 return B115200; 102#endif 103#ifdef B230400 104 if (baudrate == 230400) 105 return B230400; 106#endif 107#ifdef B460800 108 if (baudrate == 460800) 109 return B460800; 110#endif 111 return 0; 112} 113 114int 115xf86OpenSerial (pointer options) 116{ 117 struct termios t; 118 int fd, i; 119 char *dev; 120 121 dev = xf86SetStrOption (options, "Device", NULL); 122 if (!dev) 123 { 124 xf86Msg (X_ERROR, "xf86OpenSerial: No Device specified.\n"); 125 return -1; 126 } 127 128 SYSCALL (fd = open (dev, O_RDWR | O_NONBLOCK)); 129 if (fd == -1) 130 { 131 xf86Msg (X_ERROR, 132 "xf86OpenSerial: Cannot open device %s\n\t%s.\n", 133 dev, strerror (errno)); 134 free(dev); 135 return -1; 136 } 137 138 if (!isatty (fd)) 139 { 140 /* Allow non-tty devices to be opened. */ 141 free(dev); 142 return fd; 143 } 144 145 /* set up default port parameters */ 146 SYSCALL (tcgetattr (fd, &t)); 147 t.c_iflag &= ~(IGNBRK|BRKINT|PARMRK|ISTRIP|INLCR\ 148 |IGNCR|ICRNL|IXON); 149 t.c_oflag &= ~OPOST; 150 t.c_lflag &= ~(ECHO|ECHONL|ICANON|ISIG|IEXTEN); 151 t.c_cflag &= ~(CSIZE|PARENB); 152 t.c_cflag |= CS8|CLOCAL; 153 154 cfsetispeed (&t, B9600); 155 cfsetospeed (&t, B9600); 156 t.c_cc[VMIN] = 1; 157 t.c_cc[VTIME] = 0; 158 159 SYSCALL (tcsetattr (fd, TCSANOW, &t)); 160 161 if (xf86SetSerial (fd, options) == -1) 162 { 163 SYSCALL (close (fd)); 164 free(dev); 165 return -1; 166 } 167 168 SYSCALL (i = fcntl (fd, F_GETFL, 0)); 169 if (i == -1) 170 { 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 { 179 SYSCALL (close (fd)); 180 free(dev); 181 return -1; 182 } 183 free(dev); 184 return fd; 185} 186 187int 188xf86SetSerial (int fd, pointer options) 189{ 190 struct termios t; 191 int val; 192 const char *s; 193 int baud, r; 194 195 if (fd < 0) 196 return -1; 197 198 /* Don't try to set parameters for non-tty devices. */ 199 if (!isatty(fd)) 200 return 0; 201 202 SYSCALL (tcgetattr (fd, &t)); 203 204 if ((val = xf86SetIntOption (options, "BaudRate", 0))) 205 { 206 if ((baud = GetBaud (val))) 207 { 208 cfsetispeed (&t, baud); 209 cfsetospeed (&t, baud); 210 } 211 else 212 { 213 xf86Msg (X_ERROR, 214 "Invalid Option BaudRate value: %d\n", val); 215 return -1; 216 } 217 } 218 219 if ((val = xf86SetIntOption (options, "StopBits", 0))) 220 { 221 switch (val) 222 { 223 case 1: 224 t.c_cflag &= ~(CSTOPB); 225 break; 226 case 2: 227 t.c_cflag |= CSTOPB; 228 break; 229 default: 230 xf86Msg (X_ERROR, 231 "Invalid Option StopBits value: %d\n", val); 232 return -1; 233 break; 234 } 235 } 236 237 if ((val = xf86SetIntOption (options, "DataBits", 0))) 238 { 239 switch (val) 240 { 241 case 5: 242 t.c_cflag &= ~(CSIZE); 243 t.c_cflag |= CS5; 244 break; 245 case 6: 246 t.c_cflag &= ~(CSIZE); 247 t.c_cflag |= CS6; 248 break; 249 case 7: 250 t.c_cflag &= ~(CSIZE); 251 t.c_cflag |= CS7; 252 break; 253 case 8: 254 t.c_cflag &= ~(CSIZE); 255 t.c_cflag |= CS8; 256 break; 257 default: 258 xf86Msg (X_ERROR, 259 "Invalid Option DataBits value: %d\n", val); 260 return -1; 261 break; 262 } 263 } 264 265 if ((s = xf86SetStrOption (options, "Parity", NULL))) 266 { 267 if (xf86NameCmp (s, "Odd") == 0) 268 { 269 t.c_cflag |= PARENB | PARODD; 270 } 271 else if (xf86NameCmp (s, "Even") == 0) 272 { 273 t.c_cflag |= PARENB; 274 t.c_cflag &= ~(PARODD); 275 } 276 else if (xf86NameCmp (s, "None") == 0) 277 { 278 t.c_cflag &= ~(PARENB); 279 } 280 else 281 { 282 xf86Msg (X_ERROR, "Invalid Option Parity value: %s\n", 283 s); 284 return -1; 285 } 286 } 287 288 if ((val = xf86SetIntOption (options, "Vmin", -1)) != -1) 289 { 290 t.c_cc[VMIN] = val; 291 } 292 if ((val = xf86SetIntOption (options, "Vtime", -1)) != -1) 293 { 294 t.c_cc[VTIME] = val; 295 } 296 297 if ((s = xf86SetStrOption (options, "FlowControl", NULL))) 298 { 299 xf86MarkOptionUsedByName (options, "FlowControl"); 300 if (xf86NameCmp (s, "Xoff") == 0) 301 { 302 t.c_iflag |= IXOFF; 303 } 304 else if (xf86NameCmp (s, "Xon") == 0) 305 { 306 t.c_iflag |= IXON; 307 } 308 else if (xf86NameCmp (s, "XonXoff") == 0) 309 { 310 t.c_iflag |= IXON|IXOFF; 311 } 312 else if (xf86NameCmp (s, "None") == 0) 313 { 314 t.c_iflag &= ~(IXON | IXOFF); 315 } 316 else 317 { 318 xf86Msg (X_ERROR, 319 "Invalid Option FlowControl value: %s\n", s); 320 return -1; 321 } 322 } 323 324 if ((xf86SetBoolOption (options, "ClearDTR", FALSE))) 325 { 326#ifdef CLEARDTR_SUPPORT 327# if defined(TIOCMBIC) 328 val = TIOCM_DTR; 329 SYSCALL (ioctl(fd, TIOCMBIC, &val)); 330# else 331 SYSCALL (ioctl(fd, TIOCCDTR, NULL)); 332# endif 333#else 334 xf86Msg (X_WARNING, 335 "Option ClearDTR not supported on this OS\n"); 336 return -1; 337#endif 338 xf86MarkOptionUsedByName (options, "ClearDTR"); 339 } 340 341 if ((xf86SetBoolOption (options, "ClearRTS", FALSE))) 342 { 343 xf86Msg (X_WARNING, 344 "Option ClearRTS not supported on this OS\n"); 345 return -1; 346 xf86MarkOptionUsedByName (options, "ClearRTS"); 347 } 348 349 SYSCALL (r = tcsetattr (fd, TCSANOW, &t)); 350 return r; 351} 352 353int 354xf86SetSerialSpeed (int fd, int speed) 355{ 356 struct termios t; 357 int baud, r; 358 359 if (fd < 0) 360 return -1; 361 362 /* Don't try to set parameters for non-tty devices. */ 363 if (!isatty(fd)) 364 return 0; 365 366 SYSCALL (tcgetattr (fd, &t)); 367 368 if ((baud = GetBaud (speed))) 369 { 370 cfsetispeed (&t, baud); 371 cfsetospeed (&t, baud); 372 } 373 else 374 { 375 xf86Msg (X_ERROR, 376 "Invalid Option BaudRate value: %d\n", speed); 377 return -1; 378 } 379 380 SYSCALL (r = tcsetattr (fd, TCSANOW, &t)); 381 return r; 382} 383 384int 385xf86ReadSerial (int fd, void *buf, int count) 386{ 387 int r; 388 int i; 389 390 SYSCALL (r = read (fd, buf, count)); 391 DebugF("ReadingSerial: 0x%x", 392 (unsigned char)*(((unsigned char *)buf))); 393 for (i = 1; i < r; i++) 394 DebugF(", 0x%x",(unsigned char)*(((unsigned char *)buf) + i)); 395 DebugF("\n"); 396 return r; 397} 398 399int 400xf86WriteSerial (int fd, const void *buf, int count) 401{ 402 int r; 403 int i; 404 405 DebugF("WritingSerial: 0x%x",(unsigned char)*(((unsigned char *)buf))); 406 for (i = 1; i < count; i++) 407 ErrorF(", 0x%x",(unsigned char)*(((unsigned char *)buf) + i)); 408 DebugF("\n"); 409 SYSCALL (r = write (fd, buf, count)); 410 return r; 411} 412 413int 414xf86CloseSerial (int fd) 415{ 416 int r; 417 418 SYSCALL (r = close (fd)); 419 return r; 420} 421 422int 423xf86WaitForInput (int fd, int timeout) 424{ 425 fd_set readfds; 426 struct timeval to; 427 int r; 428 429 FD_ZERO(&readfds); 430 431 if (fd >= 0) { 432 FD_SET(fd, &readfds); 433 } 434 435 to.tv_sec = timeout / 1000000; 436 to.tv_usec = timeout % 1000000; 437 438 if (fd >= 0) { 439 SYSCALL (r = select (FD_SETSIZE, &readfds, NULL, NULL, &to)); 440 } 441 else { 442 SYSCALL (r = select (FD_SETSIZE, NULL, NULL, NULL, &to)); 443 } 444 xf86ErrorFVerb (9,"select returned %d\n", r); 445 return r; 446} 447 448int 449xf86SerialSendBreak (int fd, int duration) 450{ 451 int r; 452 453 SYSCALL (r = tcsendbreak (fd, duration)); 454 return r; 455 456} 457 458int 459xf86FlushInput(int fd) 460{ 461 fd_set fds; 462 struct timeval timeout; 463 char c[4]; 464 465 DebugF("FlushingSerial\n"); 466 if (tcflush(fd, TCIFLUSH) == 0) 467 return 0; 468 469 timeout.tv_sec = 0; 470 timeout.tv_usec = 0; 471 FD_ZERO(&fds); 472 FD_SET(fd, &fds); 473 while (select(FD_SETSIZE, &fds, NULL, NULL, &timeout) > 0) { 474 if (read(fd, &c, sizeof(c)) < 1) 475 return 0; 476 FD_ZERO(&fds); 477 FD_SET(fd, &fds); 478 } 479 return 0; 480} 481 482static struct states { 483 int xf; 484 int os; 485} modemStates[] = { 486#ifdef TIOCM_LE 487 { XF86_M_LE, TIOCM_LE }, 488#endif 489#ifdef TIOCM_DTR 490 { XF86_M_DTR, TIOCM_DTR }, 491#endif 492#ifdef TIOCM_RTS 493 { XF86_M_RTS, TIOCM_RTS }, 494#endif 495#ifdef TIOCM_ST 496 { XF86_M_ST, TIOCM_ST }, 497#endif 498#ifdef TIOCM_SR 499 { XF86_M_SR, TIOCM_SR }, 500#endif 501#ifdef TIOCM_CTS 502 { XF86_M_CTS, TIOCM_CTS }, 503#endif 504#ifdef TIOCM_CAR 505 { XF86_M_CAR, TIOCM_CAR }, 506#elif defined(TIOCM_CD) 507 { XF86_M_CAR, TIOCM_CD }, 508#endif 509#ifdef TIOCM_RNG 510 { XF86_M_RNG, TIOCM_RNG }, 511#elif defined(TIOCM_RI) 512 { XF86_M_CAR, TIOCM_RI }, 513#endif 514#ifdef TIOCM_DSR 515 { XF86_M_DSR, TIOCM_DSR }, 516#endif 517}; 518 519static int numStates = sizeof(modemStates) / sizeof(modemStates[0]); 520 521static int 522xf2osState(int state) 523{ 524 int i; 525 int ret = 0; 526 527 for (i = 0; i < numStates; i++) 528 if (state & modemStates[i].xf) 529 ret |= modemStates[i].os; 530 return ret; 531} 532 533static int 534os2xfState(int state) 535{ 536 int i; 537 int ret = 0; 538 539 for (i = 0; i < numStates; i++) 540 if (state & modemStates[i].os) 541 ret |= modemStates[i].xf; 542 return ret; 543} 544 545static int 546getOsStateMask(void) 547{ 548 int i; 549 int ret = 0; 550 for (i = 0; i < numStates; i++) 551 ret |= modemStates[i].os; 552 return ret; 553} 554 555static int osStateMask = 0; 556 557int 558xf86SetSerialModemState(int fd, int state) 559{ 560 int ret; 561 int s; 562 563 if (fd < 0) 564 return -1; 565 566 /* Don't try to set parameters for non-tty devices. */ 567 if (!isatty(fd)) 568 return 0; 569 570#ifndef TIOCMGET 571 return -1; 572#else 573 if (!osStateMask) 574 osStateMask = getOsStateMask(); 575 576 state = xf2osState(state); 577 SYSCALL((ret = ioctl(fd, TIOCMGET, &s))); 578 if (ret < 0) 579 return -1; 580 s &= ~osStateMask; 581 s |= state; 582 SYSCALL((ret = ioctl(fd, TIOCMSET, &s))); 583 if (ret < 0) 584 return -1; 585 else 586 return 0; 587#endif 588} 589 590int 591xf86GetSerialModemState(int fd) 592{ 593 int ret; 594 int s; 595 596 if (fd < 0) 597 return -1; 598 599 /* Don't try to set parameters for non-tty devices. */ 600 if (!isatty(fd)) 601 return 0; 602 603#ifndef TIOCMGET 604 return -1; 605#else 606 SYSCALL((ret = ioctl(fd, TIOCMGET, &s))); 607 if (ret < 0) 608 return -1; 609 return os2xfState(s); 610#endif 611} 612 613int 614xf86SerialModemSetBits(int fd, int bits) 615{ 616 int ret; 617 int s; 618 619 if (fd < 0) 620 return -1; 621 622 /* Don't try to set parameters for non-tty devices. */ 623 if (!isatty(fd)) 624 return 0; 625 626#ifndef TIOCMGET 627 return -1; 628#else 629 s = xf2osState(bits); 630 SYSCALL((ret = ioctl(fd, TIOCMBIS, &s))); 631 return ret; 632#endif 633} 634 635int 636xf86SerialModemClearBits(int fd, int bits) 637{ 638 int ret; 639 int s; 640 641 if (fd < 0) 642 return -1; 643 644 /* Don't try to set parameters for non-tty devices. */ 645 if (!isatty(fd)) 646 return 0; 647 648#ifndef TIOCMGET 649 return -1; 650#else 651 s = xf2osState(bits); 652 SYSCALL((ret = ioctl(fd, TIOCMBIC, &s))); 653 return ret; 654#endif 655} 656