/* * Copyright 1993-2003 by The XFree86 Project, Inc. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * THE XFREE86 PROJECT BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * Except as contained in this notice, the name of the XFree86 Project shall * not be used in advertising or otherwise to promote the sale, use or other * dealings in this Software without prior written authorization from the * XFree86 Project. */ /* * * Copyright (c) 1997 Metro Link Incorporated * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * THE X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * Except as contained in this notice, the name of the Metro Link shall not be * used in advertising or otherwise to promote the sale, use or other dealings * in this Software without prior written authorization from Metro Link. * */ #ifdef HAVE_XORG_CONFIG_H #include #endif #include #include "xf86.h" #include "xf86Priv.h" #include "xf86_OSlib.h" static int GetBaud(int baudrate) { #ifdef B300 if (baudrate == 300) return B300; #endif #ifdef B1200 if (baudrate == 1200) return B1200; #endif #ifdef B2400 if (baudrate == 2400) return B2400; #endif #ifdef B4800 if (baudrate == 4800) return B4800; #endif #ifdef B9600 if (baudrate == 9600) return B9600; #endif #ifdef B19200 if (baudrate == 19200) return B19200; #endif #ifdef B38400 if (baudrate == 38400) return B38400; #endif #ifdef B57600 if (baudrate == 57600) return B57600; #endif #ifdef B115200 if (baudrate == 115200) return B115200; #endif #ifdef B230400 if (baudrate == 230400) return B230400; #endif #ifdef B460800 if (baudrate == 460800) return B460800; #endif return 0; } int xf86OpenSerial(XF86OptionPtr options) { struct termios t; int fd, i; char *dev; dev = xf86SetStrOption(options, "Device", NULL); if (!dev) { xf86Msg(X_ERROR, "xf86OpenSerial: No Device specified.\n"); return -1; } #ifndef X_PRIVSEP SYSCALL(fd = open(dev, O_RDWR | O_NONBLOCK)); #else fd = priv_open_device (dev); #endif if (fd == -1) { xf86Msg(X_ERROR, "xf86OpenSerial: Cannot open device %s\n\t%s.\n", dev, strerror(errno)); free(dev); return -1; } if (!isatty(fd)) { /* Allow non-tty devices to be opened. */ free(dev); return fd; } /* set up default port parameters */ SYSCALL(tcgetattr(fd, &t)); t.c_iflag &= ~(IGNBRK | BRKINT | PARMRK | ISTRIP | INLCR | IGNCR | ICRNL | IXON); t.c_oflag &= ~OPOST; t.c_lflag &= ~(ECHO | ECHONL | ICANON | ISIG | IEXTEN); t.c_cflag &= ~(CSIZE | PARENB); t.c_cflag |= CS8 | CLOCAL; cfsetispeed(&t, B9600); cfsetospeed(&t, B9600); t.c_cc[VMIN] = 1; t.c_cc[VTIME] = 0; SYSCALL(tcsetattr(fd, TCSANOW, &t)); if (xf86SetSerial(fd, options) == -1) { SYSCALL(close(fd)); free(dev); return -1; } #ifndef X_PRIVSEP SYSCALL(i = fcntl(fd, F_GETFL, 0)); #else fd = priv_open_device (dev); #endif if (i == -1) { SYSCALL(close(fd)); free(dev); return -1; } i &= ~O_NONBLOCK; SYSCALL(i = fcntl(fd, F_SETFL, i)); if (i == -1) { SYSCALL(close(fd)); free(dev); return -1; } free(dev); return fd; } int xf86SetSerial(int fd, XF86OptionPtr options) { struct termios t; int val; const char *s; int baud, r; if (fd < 0) return -1; /* Don't try to set parameters for non-tty devices. */ if (!isatty(fd)) return 0; SYSCALL(tcgetattr(fd, &t)); if ((val = xf86SetIntOption(options, "BaudRate", 0))) { if ((baud = GetBaud(val))) { cfsetispeed(&t, baud); cfsetospeed(&t, baud); } else { xf86Msg(X_ERROR, "Invalid Option BaudRate value: %d\n", val); return -1; } } if ((val = xf86SetIntOption(options, "StopBits", 0))) { switch (val) { case 1: t.c_cflag &= ~(CSTOPB); break; case 2: t.c_cflag |= CSTOPB; break; default: xf86Msg(X_ERROR, "Invalid Option StopBits value: %d\n", val); return -1; break; } } if ((val = xf86SetIntOption(options, "DataBits", 0))) { switch (val) { case 5: t.c_cflag &= ~(CSIZE); t.c_cflag |= CS5; break; case 6: t.c_cflag &= ~(CSIZE); t.c_cflag |= CS6; break; case 7: t.c_cflag &= ~(CSIZE); t.c_cflag |= CS7; break; case 8: t.c_cflag &= ~(CSIZE); t.c_cflag |= CS8; break; default: xf86Msg(X_ERROR, "Invalid Option DataBits value: %d\n", val); return -1; break; } } if ((s = xf86SetStrOption(options, "Parity", NULL))) { if (xf86NameCmp(s, "Odd") == 0) { t.c_cflag |= PARENB | PARODD; } else if (xf86NameCmp(s, "Even") == 0) { t.c_cflag |= PARENB; t.c_cflag &= ~(PARODD); } else if (xf86NameCmp(s, "None") == 0) { t.c_cflag &= ~(PARENB); } else { xf86Msg(X_ERROR, "Invalid Option Parity value: %s\n", s); return -1; } } if ((val = xf86SetIntOption(options, "Vmin", -1)) != -1) { t.c_cc[VMIN] = val; } if ((val = xf86SetIntOption(options, "Vtime", -1)) != -1) { t.c_cc[VTIME] = val; } if ((s = xf86SetStrOption(options, "FlowControl", NULL))) { xf86MarkOptionUsedByName(options, "FlowControl"); if (xf86NameCmp(s, "Xoff") == 0) { t.c_iflag |= IXOFF; } else if (xf86NameCmp(s, "Xon") == 0) { t.c_iflag |= IXON; } else if (xf86NameCmp(s, "XonXoff") == 0) { t.c_iflag |= IXON | IXOFF; } else if (xf86NameCmp(s, "None") == 0) { t.c_iflag &= ~(IXON | IXOFF); } else { xf86Msg(X_ERROR, "Invalid Option FlowControl value: %s\n", s); return -1; } } if ((xf86SetBoolOption(options, "ClearDTR", FALSE))) { #ifdef CLEARDTR_SUPPORT #if defined(TIOCMBIC) val = TIOCM_DTR; SYSCALL(ioctl(fd, TIOCMBIC, &val)); #else SYSCALL(ioctl(fd, TIOCCDTR, NULL)); #endif #else xf86Msg(X_WARNING, "Option ClearDTR not supported on this OS\n"); return -1; #endif xf86MarkOptionUsedByName(options, "ClearDTR"); } if ((xf86SetBoolOption(options, "ClearRTS", FALSE))) { xf86Msg(X_WARNING, "Option ClearRTS not supported on this OS\n"); return -1; xf86MarkOptionUsedByName(options, "ClearRTS"); } SYSCALL(r = tcsetattr(fd, TCSANOW, &t)); return r; } int xf86SetSerialSpeed(int fd, int speed) { struct termios t; int baud, r; if (fd < 0) return -1; /* Don't try to set parameters for non-tty devices. */ if (!isatty(fd)) return 0; SYSCALL(tcgetattr(fd, &t)); if ((baud = GetBaud(speed))) { cfsetispeed(&t, baud); cfsetospeed(&t, baud); } else { xf86Msg(X_ERROR, "Invalid Option BaudRate value: %d\n", speed); return -1; } SYSCALL(r = tcsetattr(fd, TCSANOW, &t)); return r; } int xf86ReadSerial(int fd, void *buf, int count) { int r; int i; SYSCALL(r = read(fd, buf, count)); DebugF("ReadingSerial: 0x%x", (unsigned char) *(((unsigned char *) buf))); for (i = 1; i < r; i++) DebugF(", 0x%x", (unsigned char) *(((unsigned char *) buf) + i)); DebugF("\n"); return r; } int xf86WriteSerial(int fd, const void *buf, int count) { int r; int i; DebugF("WritingSerial: 0x%x", (unsigned char) *(((unsigned char *) buf))); for (i = 1; i < count; i++) DebugF(", 0x%x", (unsigned char) *(((unsigned char *) buf) + i)); DebugF("\n"); SYSCALL(r = write(fd, buf, count)); return r; } int xf86CloseSerial(int fd) { int r; SYSCALL(r = close(fd)); return r; } int xf86WaitForInput(int fd, int timeout) { fd_set readfds; struct timeval to; int r; FD_ZERO(&readfds); if (fd >= 0) { FD_SET(fd, &readfds); } to.tv_sec = timeout / 1000000; to.tv_usec = timeout % 1000000; if (fd >= 0) { SYSCALL(r = select(FD_SETSIZE, &readfds, NULL, NULL, &to)); } else { SYSCALL(r = select(FD_SETSIZE, NULL, NULL, NULL, &to)); } xf86ErrorFVerb(9, "select returned %d\n", r); return r; } int xf86SerialSendBreak(int fd, int duration) { int r; SYSCALL(r = tcsendbreak(fd, duration)); return r; } int xf86FlushInput(int fd) { fd_set fds; struct timeval timeout; char c[4]; DebugF("FlushingSerial\n"); if (tcflush(fd, TCIFLUSH) == 0) return 0; timeout.tv_sec = 0; timeout.tv_usec = 0; FD_ZERO(&fds); FD_SET(fd, &fds); while (select(FD_SETSIZE, &fds, NULL, NULL, &timeout) > 0) { if (read(fd, &c, sizeof(c)) < 1) return 0; FD_ZERO(&fds); FD_SET(fd, &fds); } return 0; } static struct states { int xf; int os; } modemStates[] = { #ifdef TIOCM_LE { XF86_M_LE, TIOCM_LE}, #endif #ifdef TIOCM_DTR { XF86_M_DTR, TIOCM_DTR}, #endif #ifdef TIOCM_RTS { XF86_M_RTS, TIOCM_RTS}, #endif #ifdef TIOCM_ST { XF86_M_ST, TIOCM_ST}, #endif #ifdef TIOCM_SR { XF86_M_SR, TIOCM_SR}, #endif #ifdef TIOCM_CTS { XF86_M_CTS, TIOCM_CTS}, #endif #ifdef TIOCM_CAR { XF86_M_CAR, TIOCM_CAR}, #elif defined(TIOCM_CD) { XF86_M_CAR, TIOCM_CD}, #endif #ifdef TIOCM_RNG { XF86_M_RNG, TIOCM_RNG}, #elif defined(TIOCM_RI) { XF86_M_CAR, TIOCM_RI}, #endif #ifdef TIOCM_DSR { XF86_M_DSR, TIOCM_DSR}, #endif }; static int numStates = sizeof(modemStates) / sizeof(modemStates[0]); static int xf2osState(int state) { int i; int ret = 0; for (i = 0; i < numStates; i++) if (state & modemStates[i].xf) ret |= modemStates[i].os; return ret; } static int os2xfState(int state) { int i; int ret = 0; for (i = 0; i < numStates; i++) if (state & modemStates[i].os) ret |= modemStates[i].xf; return ret; } static int getOsStateMask(void) { int i; int ret = 0; for (i = 0; i < numStates; i++) ret |= modemStates[i].os; return ret; } static int osStateMask = 0; int xf86SetSerialModemState(int fd, int state) { int ret; int s; if (fd < 0) return -1; /* Don't try to set parameters for non-tty devices. */ if (!isatty(fd)) return 0; #ifndef TIOCMGET return -1; #else if (!osStateMask) osStateMask = getOsStateMask(); state = xf2osState(state); SYSCALL((ret = ioctl(fd, TIOCMGET, &s))); if (ret < 0) return -1; s &= ~osStateMask; s |= state; SYSCALL((ret = ioctl(fd, TIOCMSET, &s))); if (ret < 0) return -1; else return 0; #endif } int xf86GetSerialModemState(int fd) { int ret; int s; if (fd < 0) return -1; /* Don't try to set parameters for non-tty devices. */ if (!isatty(fd)) return 0; #ifndef TIOCMGET return -1; #else SYSCALL((ret = ioctl(fd, TIOCMGET, &s))); if (ret < 0) return -1; return os2xfState(s); #endif } int xf86SerialModemSetBits(int fd, int bits) { int ret; int s; if (fd < 0) return -1; /* Don't try to set parameters for non-tty devices. */ if (!isatty(fd)) return 0; #ifndef TIOCMGET return -1; #else s = xf2osState(bits); SYSCALL((ret = ioctl(fd, TIOCMBIS, &s))); return ret; #endif } int xf86SerialModemClearBits(int fd, int bits) { int ret; int s; if (fd < 0) return -1; /* Don't try to set parameters for non-tty devices. */ if (!isatty(fd)) return 0; #ifndef TIOCMGET return -1; #else s = xf2osState(bits); SYSCALL((ret = ioctl(fd, TIOCMBIC, &s))); return ret; #endif }