diff options
Diffstat (limited to 'usr.bin/doscmd/int14.c')
-rw-r--r-- | usr.bin/doscmd/int14.c | 510 |
1 files changed, 510 insertions, 0 deletions
diff --git a/usr.bin/doscmd/int14.c b/usr.bin/doscmd/int14.c new file mode 100644 index 0000000..602bb80 --- /dev/null +++ b/usr.bin/doscmd/int14.c @@ -0,0 +1,510 @@ +/* + * Copyright (c) 1992, 1993, 1996 + * Berkeley Software Design, Inc. All rights reserved. + * + * This code is derived from software contributed to Berkeley Software + * Design, Inc. by Mark Linoman. + * + * 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. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Berkeley Software + * Design, Inc. + * + * THIS SOFTWARE IS PROVIDED BY Berkeley Software Design, Inc. ``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 Berkeley Software Design, Inc. 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. + * + * BSDI int14.c,v 2.2 1996/04/08 19:32:45 bostic Exp + * + * $Id: int14.c,v 1.3 1996/09/22 15:42:53 miff Exp $ + */ + +#include "doscmd.h" +#include <sys/ioctl.h> +#include <termios.h> +#include "com.h" + +struct com_data_struct com_data[N_COMS_MAX]; + +struct queue *create_queue() { return(0); } +int get_char_q() {} +int queue_not_empty() {} +int reset_irq_request() {} +int set_irq_request() {} +int test_irq_request() {} +int write_div_latches() {} + +void +int14(regcontext_t *REGS) +{ + int reg_num; + struct com_data_struct *cdsp; + int i; + int nbytes; + char c; + + debug (D_PORT, "int14: dl = 0x%02X, al = 0x%02X.\n", R_DL, R_AL); + if (R_DL >= N_COMS_MAX) { + if (vflag) + dump_regs(REGS); + fatal ("int14: illegal com port COM%d", R_DL + 1); + } + cdsp = &(com_data[R_DL]); + + switch (R_AH) { + case 0x00: /* Initialize Serial Port */ +#if 0 /* hold off: try to defeat stupid DOS defaults */ + com_set_line(cdsp, R_DL + 1, R_AL); + R_AH = LS_X_SHFT_E | LS_X_HOLD_E; + R_AL = 0; +#endif 0 + break; + + case 0x01: /* Write Character */ + errno = 0; + c = R_AL; + nbytes = write(cdsp->fd, &c, 1); + debug (D_PORT, "write of 0x%02x to fd %d on '%s' returned %d %s\n", + R_AL, cdsp->fd, cdsp->path, nbytes, strerror(errno)); + if (nbytes == 1) { + R_AH = LS_X_SHFT_E | LS_X_HOLD_E; + R_AL = 0; + } else { + debug(D_PORT, "int14: lost output character 0x%02x\n", + R_AL); + R_AH = LS_SW_TIME_OUT; + R_AL = 0; + } + break; + + case 0x02: /* Read Character */ + errno = 0; + nbytes = read(cdsp->fd, &c, 1); + debug (D_PORT, "read of fd %d on '%s' returned %d byte 0x%02x %s\n", + cdsp->fd, cdsp->path, nbytes, c, + errno ? strerror(errno) : ""); + if (nbytes == 1) { + R_AH = LS_X_SHFT_E | LS_X_HOLD_E; + R_AL = c; + } else { + R_AH = LS_SW_TIME_OUT; + R_AL = 0x60; + } + break; + + case 0x03: /* Status Request */ + R_AX = (LS_X_SHFT_E | LS_X_HOLD_E) << 8; + break; + + case 0x04: /* Extended Initialization */ + R_AX = (LS_SW_TIME_OUT) << 8; + break; + + case 0x05: /* Modem Control Register operations */ + switch (R_AH) { + case 0x00: /* Read Modem Control Register */ + R_AX = (LS_SW_TIME_OUT) << 8; + break; + + case 0x01: /* Write Modem Control Register */ + R_AX = (LS_SW_TIME_OUT) << 8; + break; + + default: + unknown_int3(0x14, 0x05, R_AL, REGS); + break; + } + break; + default: + unknown_int2(0x14, R_AH, REGS); + break; + } +} + + +/* called when doscmd initializes a single line */ +void +com_set_line(struct com_data_struct *cdsp, unsigned char port, unsigned char param) +{ + struct termios tty; + struct stat stat_buf; + int mode = 0; /* read|write */ + int speed; + int reg_num; + int ret_val; + + debug (D_PORT, "com_set_line: cdsp = 0x%08X, port = 0x%04x," + "param = 0x%04X.\n", cdsp, port, param); + if (cdsp->fd > 0) { + debug (D_PORT, "Re-initialize serial port com%d\n", port); + (void)close(cdsp->fd); + } else { + debug (D_PORT, "Initialize serial port com%d\n", port); + } + + stat(cdsp->path, &stat_buf); + if (!S_ISCHR(stat_buf.st_mode) || + ((cdsp->fd = open(cdsp->path, O_RDWR | O_NONBLOCK, 0666)) == -1)) { + + debug (D_PORT, + "Could not initialize serial port com%d on path '%s'\n", + port, cdsp->path); + return; + } + + cdsp->flags = 0x00; + cdsp->last_char_read = 0x00; +#if 0 + if ((param & PARITY_EVEN) == PARITY_NONE) + tty.c_iflag = IGNBRK | IGNPAR | IXON | IXOFF /* | IXANY */; + else + tty.c_iflag = IGNBRK | IXON | IXOFF /* | IXANY */; + tty.c_oflag = 0; + tty.c_lflag = 0; + tty.c_cc[VTIME] = 0; + tty.c_cc[VMIN] = 1; + tty.c_cflag = CREAD | CLOCAL | HUPCL; + /* MCL WHY CLOCAL ??????; but, gets errno EIO on writes, else */ + if ((param & TXLEN_8BITS) == TXLEN_8BITS) + tty.c_cflag |= CS8; + else + tty.c_cflag |= CS7; + if ((param & STOPBIT_2) == STOPBIT_2) + tty.c_cflag |= CSTOPB; + switch (param & PARITY_EVEN) { + case (PARITY_ODD): + tty.c_cflag |= (PARENB | PARODD); + break; + case (PARITY_EVEN): + tty.c_cflag |= PARENB; + break; + case (PARITY_NONE): + default: + break; + } + switch (param & BITRATE_9600) { + case (BITRATE_110): + speed = B110; + break; + case (BITRATE_150): + speed = B150; + break; + case (BITRATE_300): + speed = B300; + break; + case (BITRATE_600): + speed = B600; + break; + case (BITRATE_1200): + speed = B1200; + break; + case (BITRATE_2400): + speed = B2400; + break; + case (BITRATE_4800): + speed = B4800; + break; + case (BITRATE_9600): + speed = B9600; + break; + } + debug (D_PORT, "com_set_line: going with cflag 0x%X iflag 0x%X speed %d.\n", + tty.c_cflag, tty.c_iflag, speed); + errno = 0; + ret_val = cfsetispeed(&tty, speed); + debug (D_PORT, "com_set_line: cfsetispeed returned 0x%X.\n", ret_val); + errno = 0; + ret_val = cfsetospeed(&tty, speed); + debug (D_PORT, "com_set_line: cfsetospeed returned 0x%X.\n", ret_val); + errno = 0; + ret_val = tcsetattr(cdsp->fd, 0, &tty); + debug (D_PORT, "com_set_line: tcsetattr returned 0x%X.\n", ret_val); + + errno = 0; + ret_val = fcntl(cdsp->fd, F_SETFL, O_NDELAY); + debug (D_PORT, "fcntl of 0x%X, 0x%X to fd %d returned %d errno %d\n", + F_SETFL, O_NDELAY, cdsp->fd, ret_val, errno); + errno = 0; + ret_val = ioctl(cdsp->fd, TIOCFLUSH, &mode); + debug (D_PORT, "ioctl of 0x%02x to fd %d on 0x%X returned %d errno %d\n", + TIOCFLUSH, cdsp->fd, mode, ret_val, errno); +#endif + for (reg_num = 0; reg_num < N_OF_COM_REGS; reg_num++) { + define_input_port_handler(cdsp->addr + reg_num, + com_port_in); + define_output_port_handler(cdsp->addr + reg_num, + com_port_out); + } + cdsp->com_queue = create_queue(cdsp->irq); + debug(D_PORT, "com%d: attached '%s' at addr 0x%04x irq %d\n", + port, cdsp->path, cdsp->addr, cdsp->irq); +} + + +/* called when config.c initializes a single line */ +void +init_com(int port, char *path, int addr, unsigned char irq) +{ + struct com_data_struct *cdsp; + + debug (D_PORT, "init_com: port = 0x%04x, addr = 0x%04X, irq = %d.\n", + port, addr, irq); + cdsp = &(com_data[port]); + cdsp->path = path; /* XXX DEBUG strcpy? */ + cdsp->addr = addr; + cdsp->irq = irq; + cdsp->fd = -1; + com_set_line(cdsp, port + 1, TXLEN_8BITS | BITRATE_9600); +} + + +/* called when DOS wants to read directly from a physical port */ +unsigned char +com_port_in(int port) +{ + struct com_data_struct *cdsp; + unsigned char rs; + unsigned char i; + int nbytes; + + /* search for a valid COM ???or MOUSE??? port */ + for (i = 0; i < N_COMS_MAX; i++) { + if (com_data[i].addr == ((unsigned short)port & 0xfff8)) { + cdsp = &(com_data[i]); + break; + } + } + if (i == N_COMS_MAX) { + debug (D_PORT, "com port 0x%04x not found\n", port); + return 0xff; + } + + switch (port - cdsp->addr) { + /* 0x03F8 - (receive buffer) or (divisor latch LO) */ + case 0: + if (cdsp->line_ctrl & LC_DIV_ACC) + rs = cdsp->div_latch[DIV_LATCH_LOW]; + else { +#if 0 + if (queue_not_empty(cdsp->com_queue)) { + rs = get_char_q(cdsp->com_queue); + cdsp->last_char_read = rs; + if (queue_not_empty(cdsp->com_queue) && + (cdsp->int_enable & IE_RCV_DATA) != 0) { + debug(D_PORT, + "com_port_in: setting irq %d because bytes yet to be read.\n", + cdsp->irq); + set_irq_request(cdsp->irq); + } + } else +#else + errno = 0; + nbytes = read(cdsp->fd, &rs, 1); + debug (D_PORT, "read of fd %d on '%s' returned %d byte 0x%02x errno %d\n", + cdsp->fd, cdsp->path, nbytes, rs, errno); + if (nbytes != 1) +#endif + rs = cdsp->last_char_read; + } + break; + + /* 0x03F9 - (interrupt enable) or (divisor latch HI) */ + case 1: + if (cdsp->line_ctrl & LC_DIV_ACC) + rs = cdsp->div_latch[DIV_LATCH_HIGH]; + else + rs = cdsp->int_enable; + + /* 0x03FA - interrupt identification register */ + case 2: + /* rs = cdsp->int_id; * XXX DEBUG not initialized */ + rs = 0; + if ((queue_not_empty(cdsp->com_queue)) + && (test_irq_request(cdsp->irq) != 0)) + rs |= II_PEND_INT | II_RCV_DATA; + if ((cdsp->fifo_ctrl & FC_FIFO_EN) == FC_FIFO_EN) + rs |= II_FIFOS_EN; + break; + + /* 0x03FB - line control register */ + case 3: + rs = cdsp->line_ctrl; + break; + + /* 0x03FC - modem control register */ + case 4: + rs = cdsp->modem_ctrl; + break; + + /* 0x03FD - line status register */ + case 5: + rs = LS_X_SHFT_E | LS_X_HOLD_E; + /* if (queue_not_empty(cdsp->com_queue)) */ + ioctl(cdsp->fd, FIONREAD, &nbytes); + if (nbytes > 0); + rs |= LS_RCV_DATA_RD; + break; + + /* 0x03FE - modem status register */ + case 6: + rs = cdsp->modem_stat | MS_DCD | MS_DSR | MS_CTS; + break; + + /* 0x03FF - spare register */ + case 7: + rs = cdsp->uart_spare; + break; + + default: + debug(D_PORT, "com_port_in: illegal port index 0x%04x - 0x%04x\n", + port, cdsp->addr); + break; + } + return rs; +} + + +/* called when DOS wants to write directly to a physical port */ +void +com_port_out(int port, unsigned char val) +{ + struct com_data_struct *cdsp; + int nbytes; + int i; + + /* search for a valid COM ???or MOUSE??? port */ + for (i = 0; i < N_COMS_MAX; i++) { + if (com_data[i].addr == ((unsigned short)port & 0xfff8)) { + cdsp = &(com_data[i]); + break; + } + } + if (i == N_COMS_MAX) { + debug (D_PORT, "com port 0x%04x not found\n", port); + return; + } + + switch (port - cdsp->addr) { + /* 0x03F8 - (transmit buffer) or (divisor latch LO) */ + case 0: + if (cdsp->line_ctrl & LC_DIV_ACC) { + cdsp->div_latch[DIV_LATCH_LOW] = val; + cdsp->flags |= DIV_LATCH_LOW_WRITTEN; + write_div_latches(cdsp); + } else { + errno = 0; + nbytes = write(cdsp->fd, val, 1); + debug (D_PORT, "write of 0x%02x to fd %d on '%s' returned %d errno %d\n", + val, cdsp->fd, cdsp->path, nbytes, errno); + if (nbytes != 1) + debug(D_PORT, + "int14: lost output character 0x%02x\n", + val); + } + break; + + /* 0x03F9 - (interrupt enable) or (divisor latch HI) */ + case 1: + if (cdsp->line_ctrl & LC_DIV_ACC) { + cdsp->div_latch[DIV_LATCH_HIGH] = val; + cdsp->flags |= DIV_LATCH_HIGH_WRITTEN; + write_div_latches(cdsp); + } else { + cdsp->int_enable = val; + if ((val & IE_RCV_DATA) == 0) { + reset_irq_request(cdsp->irq); + } else { + if (queue_not_empty(cdsp->com_queue)) { + set_irq_request(cdsp->irq); + } + } + } + break; + + /* 0x03FA - FIFO control register */ + case 2: + cdsp->fifo_ctrl = val; + break; + + /* 0x03FB - line control register */ + case 3: + cdsp->line_ctrl = val; + break; + + /* 0x03FC - modem control register */ + case 4: + cdsp->modem_ctrl = val; + break; + + /* 0x03FD - line status register */ + case 5: + cdsp->line_stat = val; + break; + + /* 0x03FE - modem status register */ + case 6: + cdsp->modem_stat = val; + break; + + /* 0x03FF - spare register */ + case 7: + cdsp->uart_spare = val; + break; + + default: + debug(D_PORT, "com_port_out: illegal port index 0x%04x - 0x%04x\n", + port, cdsp->addr); + break; + } +} + +#if 0 +/* + * called when BSD has bytes ready (as discovered via select) for DOS + */ +static void do_com_input(int fd) +{ + struct com_data_struct *cdsp; + unsigned char buffer[BUFSIZE]; + int i, nbytes; + + dp = search_com_device_by_fd(fd); + if (dp == NULL) + return; + do { + nbytes = read(cdsp->fd, buffer, BUFSIZE); + if (nbytes > 0) { + debug(D_PORT, "do_com_input: read %d bytes from fd %d (aka %d): ", + nbytes, fd, cdsp->fd); + for (i = 0; i < nbytes; i++) { + put_char_q(cdsp->com_queue, buffer[i]); + if (cdsp->int_enable & IE_RCV_DATA) { + debug(D_PORT, "\n"); + debug(D_PORT, "do_com_input: setting irq %d because %d bytes read.\n", + dp->irq, nbytes); + debug(D_PORT, "do_com_input: "); + set_irq_request(dp->irq); + } + debug(D_PORT, "%02x ", buffer[i]); + } + debug(D_PORT, "\n"); + } + } while (nbytes == BUFSIZE); +} +#endif 0 |