/*- * Copyright (c) 2006 Robert N. M. Watson * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ /* * Implement the WWIV communications API using a device node rather than i386 * hardware I/O. Replaces only the functions that interact directly with the * hardware, not their consumers in com.c. */ #include #include #include #include #include #include #include "emul.h" #include "vars.h" static char com_devname[PATH_MAX]; static int com_io_fd = -1; static char com_peek_char; static int com_peek_char_valid; static struct termios com_termios; /* * Determine whether a communications port is present. Return 0 if none, * otherwise 1 for a cheap serial port and 2 for an expensive one. We * emulate only expensive serial ports. * * For now, we ignore the requested port number and just use whatever was * passed to com_init(). In the future, something more sophisticated might * be called for (such as a configuration file). */ int check_comport(int pn) { if (access(com_devname, F_OK) < 0) return (0); else return (2); } /* * Communications port interrupt handler. Not required. */ void async_isr(void) { buffer[head++] = inportb(base); if (head == MAX_BUF) head = 0; outportb(0x20, 0x20); } /* * Output a character on the serial port. */ void outcomch(char ch) { struct pollfd pollfd; ssize_t len; if (com_io_fd == -1) #if 0 panic("outcomch: com_io_fd -1"); #else return; #endif bzero(&pollfd, sizeof(pollfd)); pollfd.fd = com_io_fd; pollfd.events = POLLOUT; if (poll(&pollfd, 1, 0) < 0) panic("outcomch: poll(): %s", strerror(errno)); len = write(com_io_fd, &ch, sizeof(ch)); if (len < 0) panic("outcomch: write(0x%02x): %s", ch, strerror(errno)); if (len != sizeof(ch)) panic("outcomch: write(0x%02x): ret %d", ch, len); } char peek1c(void) { ssize_t len; char ch; if (com_io_fd == -1) #if 0 panic("peek1c: com_io_fd -1"); #else return (0); #endif if (com_peek_char_valid) return (com_peek_char); len = read(com_io_fd, &ch, sizeof(ch)); if (len < 0 && errno == EAGAIN) return (0); if (len < 0) panic("peek1c: read(): %s", strerror(errno)); if (len != sizeof(ch)) panic("peek1c: read(): ret %d", len); com_peek_char_valid = 1; com_peek_char = ch; return (ch); } char get1c(void) { ssize_t len; char ch; if (com_io_fd == -1) #if 0 panic("get1c: com_io_fd -1"); #else return (0); #endif /* * If we peeked ahead, return that char, otherwise, get a new one. */ if (com_peek_char_valid) { com_peek_char_valid = 0; return (com_peek_char); } len = read(com_io_fd, &ch, sizeof(ch)); if (len < 0 && errno == EAGAIN) return (0); if (len < 0) panic("get1c: read(): %s", strerror(errno)); if (len != sizeof(ch)) panic("get1c: read(): ret %d", len); return (ch); } int comhit(void) { if (peek1c() != 0) return (1); else return (0); } void dump(void) { } void set_baud(unsigned int rate) { /* * XXXRW: termios standard seems to specify using constants B*, but * we have a number, so use it. Works on FreeBSD? */ if (cfsetispeed(&com_termios, rate) < 0) panic("set_baud: cfsetispeed"); if (cfsetospeed(&com_termios, rate) < 0) panic("set_baud: cfsetospeed"); if (tcsetattr(com_io_fd, TCSANOW, &com_termios) < 0) panic("set_baud: tcsetattr"); } void initport(int port_num) { int fd; if (com_io_fd != -1) { close(com_io_fd); com_io_fd = -1; } fd = open(com_devname, O_RDWR |/* O_NONBLOCK |*/ O_NOCTTY); if (fd == -1) panic("initport: open('%s')", com_devname); com_io_fd = fd; if (fcntl(com_io_fd, F_SETFL, O_NONBLOCK) < 0) panic("initport: fcntl(F_SETFL, O_NONBLOCK)"); if (tcgetattr(com_io_fd, &com_termios) < 0) panic("initport: tcgetattr"); com_termios.c_iflag = 0; com_termios.c_oflag = 0; com_termios.c_cflag = (CS8 | CREAD | HUPCL | CLOCAL /* | CCTS_OFLOW | CRTS_IFLOW*/); com_termios.c_lflag = NOKERNINFO; if (tcsetattr(com_io_fd, TCSANOW, &com_termios) < 0) panic("initport: tcsetattr"); } void closeport(void) { if (com_io_fd == -1) panic("closeport: com_io_fd -1"); close(com_io_fd); com_io_fd = -1; } void dtr(int i) { int state; if (com_io_fd == -1) #if 0 panic("dtr: com_io_fd -1"); #else return; #endif state = TIOCM_DTR; if (i) { if (ioctl(com_io_fd, TIOCMBIS, &state) < 0) panic("dtr: ioctl(TIOCMBIS, %x ): %s", state, strerror(errno)); } else { if (ioctl(com_io_fd, TIOCMBIC, &state) < 0) panic("dtr: ioctl(TIOCMBIC, %x): %s", state, strerror(errno)); } } void rts(int i) { int state; if (com_io_fd == -1) #if 0 panic("rts: com_io_fd -1"); #else return; #endif state = TIOCM_RTS; if (i) { if (ioctl(com_io_fd, TIOCMBIS, &state) < 0) panic("rts: ioctl(TIOCMBIS, %x ): %s", state, strerror(errno)); } else { if (ioctl(com_io_fd, TIOCMBIC, &state) < 0) panic("rts: ioctl(TIOCMBIC, %x): %s", state, strerror(errno)); } } int cdet(void) { int state; if (com_io_fd == -1) #if 0 panic("rts: com_io_fd -1"); #else return (0); #endif if (ioctl(com_io_fd, TIOCMGET, &state) < 0) panic("cdet: ioctl(TIOCMGET): %s", strerror(errno)); if (state & TIOCM_CD) return (1); else return (0); } int empty(void) { if (x_only) return(1); if (kbhitb() || (incom && peek1c() != 0) || (charbufferpointer && charbuffer[charbufferpointer]) || (in_extern == 2)) return(0); return(1); } void com_init(const char *devname) { strlcpy(com_devname, devname, PATH_MAX); }