From 8b03a29638e82cb11f004eab7ec85f0241d3358e Mon Sep 17 00:00:00 2001 From: waltje Date: Sat, 17 Jun 2017 03:31:11 -0400 Subject: [PATCH] Fix up the serial mess. New mouse_serial.ch, new serial.h, updated (but old) serial.c. --- src/mouse_serial.c | 177 ++++++------ src/serial.c | 660 --------------------------------------------- src/serial.h | 29 +- 3 files changed, 108 insertions(+), 758 deletions(-) delete mode 100644 src/serial.c diff --git a/src/mouse_serial.c b/src/mouse_serial.c index bb855ecc0..5095ca949 100644 --- a/src/mouse_serial.c +++ b/src/mouse_serial.c @@ -10,7 +10,7 @@ * * Based on the 86Box Serial Mouse driver as a framework. * - * Version: @(#)mouse_serial.c 1.0.3 2017/05/07 + * Version: @(#)mouse_serial.c 1.0.5 2017/06/18 * * Author: Fred N. van Kempen, */ @@ -22,13 +22,18 @@ #include "mouse_serial.h" +#define SERMOUSE_TYPE_MSYSTEMS 1 /* Mouse Systems */ +#define SERMOUSE_TYPE_MICROSOFT 2 /* Microsoft */ +#define SERMOUSE_TYPE_LOGITECH 3 /* Logitech */ + + typedef struct mouse_serial_t { - int port; + int8_t port, + type; int pos, delay; int oldb; SERIAL *serial; - int is_ms_format; } mouse_serial_t; @@ -51,12 +56,16 @@ sermouse_timer(void *priv) mouse_serial_t *ms = (mouse_serial_t *)priv; ms->delay = 0; - if (ms->pos == -1) - { - ms->pos = 0; + switch(ms->type) { + case SERMOUSE_TYPE_MICROSOFT: /* This identifies a two-button Microsoft Serial mouse. */ - serial_write_fifo(ms->serial, 'M'); + serial_write_fifo(ms->serial, 'M', 1); + break; + + default: + /* No action needed. */ + break; } } @@ -65,53 +74,63 @@ static uint8_t sermouse_poll(int x, int y, int z, int b, void *priv) { mouse_serial_t *ms = (mouse_serial_t *)priv; - uint8_t data[3]; + uint8_t buff[16]; + int len; if (!x && !y && b == ms->oldb) return(1); ms->oldb = b; + + if (ms->type == SERMOUSE_TYPE_MSYSTEMS) y = -y; + if (x>127) x = 127; if (y>127) y = 127; if (x<-128) x = -128; if (y<-128) y = -128; - /* Use Microsoft format. */ - data[0] = 0x40; - data[0] |= (((y>>6)&3)<<2); - data[0] |= ((x>>6)&3); - if (b&1) data[0] |= 0x20; - if (b&2) data[0] |= 0x10; - data[1] = x & 0x3F; - data[2] = y & 0x3F; + len = 0; + switch(ms->type) { + case SERMOUSE_TYPE_MSYSTEMS: + buff[0] = 0x80; + buff[0] |= (b&0x01) ? 0x00 : 0x04; /* left button */ + buff[0] |= (b&0x02) ? 0x00 : 0x01; /* middle button */ + buff[0] |= (b&0x04) ? 0x00 : 0x02; /* right button */ + buff[1] = x; + buff[2] = y; + buff[3] = x; /* same as byte 1 */ + buff[4] = y; /* same as byte 2 */ + len = 5; + break; + + case SERMOUSE_TYPE_MICROSOFT: + buff[0] = 0x40; + buff[0] |= (((y>>6)&03)<<2); + buff[0] |= ((x>>6)&03); + if (b&0x01) buff[0] |= 0x20; + if (b&0x02) buff[0] |= 0x10; + buff[1] = x & 0x3F; + buff[2] = y & 0x3F; + len = 3; + break; + + case SERMOUSE_TYPE_LOGITECH: + break; + } + +#if 0 + pclog("Mouse_Serial(%d): [", ms->type); + for (b=0; bserial, data[0]); - serial_write_fifo(ms->serial, data[1]); - serial_write_fifo(ms->serial, data[2]); + for (b=0; bserial, buff[b], 1); return(0); } -static void * -sermouse_init(void) -{ - mouse_serial_t *ms = (mouse_serial_t *)malloc(sizeof(mouse_serial_t)); - memset(ms, 0x00, sizeof(mouse_serial_t)); - ms->port = SERMOUSE_PORT; - - /* Attach a serial port to the mouse. */ - ms->serial = serial_attach(ms->port, sermouse_callback, ms); - - timer_add(sermouse_timer, &ms->delay, &ms->delay, ms); - - return(ms); -} - - static void sermouse_close(void *priv) { @@ -124,59 +143,14 @@ sermouse_close(void *priv) } -mouse_t mouse_serial_microsoft = { - "Microsoft 2-button mouse (serial)", - "msserial", - MOUSE_TYPE_SERIAL, - sermouse_init, - sermouse_close, - sermouse_poll -}; - -static uint8_t -mssystems_mouse_poll(int x, int y, int z, int b, void *priv) -{ - mouse_serial_t *ms = (mouse_serial_t *)priv; - uint8_t data[5]; - - if (!x && !y && b == ms->oldb) return(1); - - ms->oldb = b; - - y=-y; - - if (x>127) x = 127; - if (y>127) y = 127; - if (x<-128) x = -128; - if (y<-128) y = -128; - - data[0] = 0x80; - data[0] |= (b & 0x01 ? 0x00 : 0x04); /*Left button*/ - data[0] |= (b & 0x02 ? 0x00 : 0x01); /*Middle button*/ - data[0] |= (b & 0x04 ? 0x00 : 0x02); /*Right button*/ - data[1] = x; - data[2] = y; - data[3] = x;/*Same as byte 1*/ - data[4] = y;/*Same as byte 2*/ - - pclog("Mouse_Systems_Serial: data %02X %02X %02X\n", data[0], data[1], data[2]); - - serial_write_fifo(ms->serial, data[0]); - serial_write_fifo(ms->serial, data[1]); - serial_write_fifo(ms->serial, data[2]); - serial_write_fifo(ms->serial, data[3]); - serial_write_fifo(ms->serial, data[4]); - - return(0); -} - static void * -mssystems_mouse_init(void) +sermouse_init(int type) { mouse_serial_t *ms = (mouse_serial_t *)malloc(sizeof(mouse_serial_t)); memset(ms, 0x00, sizeof(mouse_serial_t)); ms->port = SERMOUSE_PORT; - + ms->type = type; + /* Attach a serial port to the mouse. */ ms->serial = serial_attach(ms->port, sermouse_callback, ms); @@ -185,11 +159,36 @@ mssystems_mouse_init(void) return(ms); } + +static void * +sermouse_init_microsoft(void) +{ + return(sermouse_init(SERMOUSE_TYPE_MICROSOFT)); +} + + +static void * +sermouse_init_msystems(void) +{ + return(sermouse_init(SERMOUSE_TYPE_MSYSTEMS)); +} + + mouse_t mouse_msystems = { "Mouse Systems Mouse (serial)", "mssystems", MOUSE_TYPE_MSYSTEMS, - mssystems_mouse_init, + sermouse_init_msystems, sermouse_close, - mssystems_mouse_poll -}; \ No newline at end of file + sermouse_poll +}; + + +mouse_t mouse_serial_microsoft = { + "Microsoft 2-button mouse (serial)", + "msserial", + MOUSE_TYPE_SERIAL, + sermouse_init_microsoft, + sermouse_close, + sermouse_poll +}; diff --git a/src/serial.c b/src/serial.c deleted file mode 100644 index ae33dc16d..000000000 --- a/src/serial.c +++ /dev/null @@ -1,660 +0,0 @@ -/* - * 86Box A hypervisor and IBM PC system emulator that specializes in - * running old operating systems and software designed for IBM - * PC systems and compatibles from 1981 through fairly recent - * system designs based on the PCI bus. - * - * This file is part of the 86Box distribution. - * - * Implementation of NS8250-series UART devices. - * - * The original IBM-PC design did not have any serial ports of - * any kind. Rather, these were offered as add-on devices, most - * likely because a) most people did not need one at the time, - * and, b) this way, IBM could make more money off them. - * - * So, for the PC, the offerings were for an IBM Asynchronous - * Communications Adapter, and, later, a model for synchronous - * communications. - * - * The "Async Adapter" was based on the NS8250 UART chip, and - * is what we now call the "serial" or "com" port of the PC. - * - * Of course, many system builders came up with similar boards, - * and even more boards were designed where several I/O functions - * were combined into a single board: the Multi-I/O adapters. - * Initially, these had all the chips as-is, but later many of - * these functions were integrated into a single MIO chip. - * - * This file implements the standard NS8250 series of chips, with - * support for the later (16450 and 16550) FIFO additions. On the - * lower half of the driver, we interface to the host system's - * serial ports for real-world access. - * - * Based on the 86Box serial port driver as a framework. - * - * Version: @(#)serial.c 1.0.7 2017/06/04 - * - * Author: Fred N. van Kempen, - * Copyright 2017 Fred N. van Kempen. - */ -#include -#include "ibm.h" -#include "io.h" -#include "pic.h" -#include "timer.h" -#include "serial.h" -#include "plat_serial.h" - - -#define NUM_SERIAL 2 /* we support 2 ports */ - - -enum { - SERINT_LSR = 1, - SERINT_RECEIVE = 2, - SERINT_TRANSMIT = 4, - SERINT_MSR = 8 -}; - - -/* IER register bits. */ -#define IER_RDAIE (0x01) -#define IER_THREIE (0x02) -#define IER_RXLSIE (0x04) -#define IER_MSIE (0x08) -#define IER_SLEEP (0x10) /* NS16750 */ -#define IER_LOWPOWER (0x20) /* NS16750 */ -#define IER_MASK (0x0f) /* not including SLEEP|LOWP */ - -/* IIR register bits. */ -#define IIR_IP (0x01) -#define IIR_IID (0x0e) -# define IID_IDMDM (0x00) -# define IID_IDTX (0x02) -# define IID_IDRX (0x04) -# define IID_IDERR (0x06) -# define IID_IDTMO (0x0c) -#define IIR_IIRFE (0xc0) -# define IIR_FIFO64 (0x20) -# define IIR_FIFOBAD (0x80) /* 16550 */ -# define IIR_FIFOENB (0xc0) - -/* FCR register bits. */ -#define FCR_FCRFE (0x01) -#define FCR_RFR (0x02) -#define FCR_TFR (0x04) -#define FCR_SELDMA1 (0x08) -#define FCR_FENB64 (0x20) /* 16750 */ -#define FCR_RTLS (0xc0) -# define FCR_RTLS1 (0x00) -# define FCR_RTLS4 (0x40) -# define FCR_RTLS8 (0x80) -# define FCR_RTLS14 (0xc0) - -/* LCR register bits. */ -#define LCR_WLS (0x03) -# define WLS_BITS5 (0x00) -# define WLS_BITS6 (0x01) -# define WLS_BITS7 (0x02) -# define WLS_BITS8 (0x03) -#define LCR_SBS (0x04) -#define LCR_PE (0x08) -#define LCR_EP (0x10) -#define LCR_PS (0x20) -# define PAR_NONE (0x00) -# define PAR_EVEN (LCR_PE | LCR_EP) -# define PAR_ODD (LCR_PE) -# define PAR_MARK (LCR_PE | LCR_PS) -# define PAR_SPACE (LCR_PE | LCR_PS | LCR_EP) -#define LCR_BC (0x40) -#define LCR_DLAB (0x80) - -/* MCR register bits. */ -#define MCR_DTR (0x01) -#define MCR_RTS (0x02) -#define MCR_OUT1 (0x04) /* 8250 */ -#define MCR_OUT2 (0x08) /* 8250, INTEN on IBM-PC */ -#define MCR_LMS (0x10) -#define MCR_AUTOFLOW (0x20) /* 16750 */ - -/* LSR register bits. */ -#define LSR_DR (0x01) -#define LSR_OE (0x02) -#define LSR_PE (0x04) -#define LSR_FE (0x08) -#define LSR_BI (0x10) -#define LSR_THRE (0x20) -#define LSR_TEMT (0x40) -#define LSR_RXFE (0x80) - -/* MSR register bits. */ -#define MSR_DCTS (0x01) -#define MSR_DDSR (0x02) -#define MSR_TERI (0x04) -#define MSR_DDCD (0x08) -#define MSR_CTS (0x10) -#define MSR_DSR (0x20) -#define MSR_RI (0x40) -#define MSR_DCD (0x80) -#define MSR_MASK (0x0f) - - -static SERIAL ports[NUM_SERIAL]; /* serial port data */ - int serial_do_log; - - -#if 0 -static void -serial_log(int lvl, const char *fmt, ...) -{ -#ifdef ENABLE_SERIAL_LOG - va_list ap; - - if (serial_do_log >= lvl) { - va_start(ap, fmt); - vprintf(fmt, ap); - va_end(ap); - fflush(stdout); - } -#endif -} -#endif - - -static void -update_ints(SERIAL *sp) -{ - int stat = 0; - - sp->iir = IIR_IP; - if ((sp->ier & IER_RXLSIE) && (sp->int_status & SERINT_LSR)) { - /* Line Status interrupt. */ - stat = 1; - sp->iir = IID_IDERR; - } else if ((sp->ier & IER_RDAIE) && (sp->int_status & SERINT_RECEIVE)) { - /* Received Data available. */ - stat = 1; - sp->iir = IID_IDRX; - } else if ((sp->ier & IER_THREIE) && (sp->int_status & SERINT_TRANSMIT)) { - /* Transmit Data empty. */ - stat = 1; - sp->iir = IID_IDTX; - } else if ((sp->ier & IER_MSIE) && (sp->int_status & SERINT_MSR)) { - /* Modem Status interrupt. */ - stat = 1; - sp->iir = IID_IDMDM; - } - - /* Raise or clear the level-based IRQ. */ - if (stat && ((sp->mctrl & MCR_OUT2) || PCJR)) - picintlevel(1 << sp->irq); - else - picintc(1 << sp->irq); -} - - -/* Fake interrupt generator, needed for Serial Mouse. */ -static void -serial_timer(void *priv) -{ - SERIAL *sp = (SERIAL *)priv; - - sp->receive_delay = 0; - - if (sp->fifo_read != sp->fifo_write) { - sp->lsr |= LSR_DR; - sp->int_status |= SERINT_RECEIVE; - update_ints(sp); - } -} - - -/* Write data to the (input) FIFO. Used by MOUSE driver. */ -void -serial_write_fifo(SERIAL *sp, uint8_t dat) -{ - /* Stuff data into FIFO. */ - sp->fifo[sp->fifo_write] = dat; - sp->fifo_write = (sp->fifo_write + 1) & 0xFF; - - if (! (sp->lsr & LSR_DR)) { - sp->lsr |= LSR_DR; - sp->int_status |= SERINT_RECEIVE; - update_ints(sp); - } -} - - -static uint8_t -read_fifo(SERIAL *sp) -{ - if (sp->fifo_read != sp->fifo_write) { - sp->dat = sp->fifo[sp->fifo_read]; - sp->fifo_read = (sp->fifo_read + 1) & 0xFF; - } - - return(sp->dat); -} - - -/* Handle a WRITE operation to one of our registers. */ -static void -serial_write(uint16_t addr, uint8_t val, void *priv) -{ - SERIAL *sp = (SERIAL *)priv; - uint8_t wl, sb, pa; - uint16_t baud; - long speed; - -#if ENABLE_SERIAL_LOG - serial_log(2, "Serial%d: write(%04x, %02x)\n", sp->port, addr, val); -#endif - switch (addr & 0x07) { - case 0: /* DATA / DLAB1 */ - if (sp->lcr & LCR_DLAB) { - sp->dlab1 = val; - return; - } - sp->thr = val; - if (sp->bh != NULL) { - /* We are linked, so send to BH layer. */ - bhtty_write((BHTTY *)sp->bh, sp->thr); - - /* The WRITE completed, we are ready for more. */ - sp->lsr |= LSR_THRE; - sp->int_status |= SERINT_TRANSMIT; - update_ints(sp); - } else { - /* Not linked. Just fake LOOPBACK mode. */ - if (! (sp->mctrl & MCR_LMS)) - serial_write_fifo(sp, val); - } - - if (sp->mctrl & MCR_LMS) { - /* Echo data back to RX. */ - serial_write_fifo(sp, val); - } - break; - - case 1: /* IER / DLAB2 */ - if (sp->lcr & LCR_DLAB) { - sp->dlab2 = val; - return; - } - sp->ier = (val & IER_MASK); - update_ints(sp); - break; - - case 2: /* FCR */ - sp->fcr = val; - break; - - case 3: /* LCR */ - if ((sp->lcr & LCR_DLAB) && !(val & LCR_DLAB)) { - /* We dropped DLAB, so handle baudrate. */ - baud = ((sp->dlab2<<8) | sp->dlab1); - if (baud > 0) { - speed = 115200UL/baud; -#ifdef ENABLE_SERIAL_LOG - serial_log(2, "Serial%d: divisor %u, baudrate %ld\n", - sp->port, baud, speed); -#endif - if ((sp->bh != NULL) && (speed > 0)) - bhtty_speed((BHTTY *)sp->bh, speed); - } else { -#ifdef ENABLE_SERIAL_LOG - serial_log(1, "Serial%d: divisor %u invalid!\n", - sp->port, baud); -#endif - } - } - wl = (val & LCR_WLS) + 5; /* databits */ - sb = (val & LCR_SBS) ? 2 : 1; /* stopbits */ - pa = (val & (LCR_PE|LCR_EP|LCR_PS)) >> 3; -#ifdef ENABLE_SERIAL_LOG - serial_log(2, "Serial%d: WL=%d SB=%d PA=%d\n", sp->port, wl, sb, pa); -#endif - if (sp->bh != NULL) - bhtty_params((BHTTY *)sp->bh, wl, pa, sb); - sp->lcr = val; - break; - - case 4: - if ((val & MCR_RTS) && !(sp->mctrl & MCR_RTS)) { - /* - * This is old code for use by the Serial Mouse - * driver. If the user toggles RTS, serial mice - * are expected to send an ID, to inform any - * enumerator there 'is' something. - */ - if (sp->rts_callback) { - sp->rts_callback(sp->rts_callback_p); -#ifdef ENABLE_SERIAL_LOG - serial_log(1, "RTS raised; sending ID\n"); -#endif - } - } - - if ((val & MCR_OUT2) && !(sp->mctrl & MCR_OUT2)) { - if (sp->bh != NULL) { - /* Linked, start host port. */ - (void)bhtty_active(sp->bh, 1); - } else { - /* Not linked, start RX timer. */ - timer_add(serial_timer, - &sp->receive_delay, - &sp->receive_delay, sp); - - /* Fake CTS, DSR and DCD (for now.) */ - sp->msr = (MSR_CTS | MSR_DCTS | - MSR_DSR | MSR_DDSR | - MSR_DCD | MSR_DDCD); - sp->int_status |= SERINT_MSR; - update_ints(sp); - } - } - sp->mctrl = val; - if (val & MCR_LMS) { /* loopback mode */ - uint8_t new_msr; - - /*FIXME: WTF does this do?? --FvK */ - new_msr = (val & 0x0c) << 4; - new_msr |= (val & MCR_RTS) ? MCR_LMS : 0; - new_msr |= (val & MCR_DTR) ? MCR_AUTOFLOW : 0; - - if ((sp->msr ^ new_msr) & 0x10) - new_msr |= MCR_DTR; - if ((sp->msr ^ new_msr) & 0x20) - new_msr |= MCR_RTS; - if ((sp->msr ^ new_msr) & 0x80) - new_msr |= 0x08; - if ((sp->msr & 0x40) && !(new_msr & 0x40)) - new_msr |= 0x04; - - sp->msr = new_msr; - } - break; - - case 5: - sp->lsr = val; - if (sp->lsr & LSR_DR) - sp->int_status |= SERINT_RECEIVE; - if (sp->lsr & 0x1e) - sp->int_status |= SERINT_LSR; - if (sp->lsr & LSR_THRE) - sp->int_status |= SERINT_TRANSMIT; - update_ints(sp); - break; - - case 6: - sp->msr = val; - if (sp->msr & MSR_MASK) - sp->int_status |= SERINT_MSR; - update_ints(sp); - break; - - case 7: - sp->scratch = val; - break; - } -} - - -/* BHTTY READ COMPLETE handler. */ -static void -serial_rd_done(void *arg, int num) -{ - SERIAL *sp = (SERIAL *)arg; - - /* We can do at least 'num' bytes.. */ - while (num-- > 0) { - /* Get a byte from them. */ - if (bhtty_read(sp->bh, &sp->hold, 1) < 0) break; - - /* Stuff it into the FIFO and set intr. */ - serial_write_fifo(sp, sp->hold); - } -} - - -/* Handle a READ operation from one of our registers. */ -static uint8_t -serial_read(uint16_t addr, void *priv) -{ - SERIAL *sp = (SERIAL *)priv; - uint8_t ret = 0x00; - - switch (addr&0x07) { - case 0: /* DATA / DLAB1 */ - if (sp->lcr & LCR_DLAB) { - ret = sp->dlab1; - } else { - sp->lsr &= ~LSR_DR; - sp->int_status &= ~SERINT_RECEIVE; - update_ints(sp); - ret = read_fifo(sp); - if ((sp->bh == NULL) && - (sp->fifo_read != sp->fifo_write)) - sp->receive_delay = 1000 * TIMER_USEC; - } - break; - - case 1: /* LCR / DLAB2 */ - ret = (sp->lcr & LCR_DLAB) ? sp->dlab2 : sp->ier; - break; - - case 2: /* IIR */ - ret = sp->iir; - if ((ret & IIR_IID) == IID_IDTX) { - sp->int_status &= ~SERINT_TRANSMIT; - update_ints(sp); - } - if (sp->fcr & 0x01) - ret |= 0xc0; - break; - - case 3: /* LCR */ - ret = sp->lcr; - break; - - case 4: /* MCR */ - ret = sp->mctrl; - break; - - case 5: /* LSR */ - if (sp->lsr & LSR_THRE) - sp->lsr |= LSR_TEMT; - sp->lsr |= LSR_THRE; - ret = sp->lsr; - if (sp->lsr & 0x1f) - sp->lsr &= ~0x1e; -#if 0 - sp->lsr |= (LSR_THRE | LSR_TEMT); -#endif - sp->int_status &= ~SERINT_LSR; - update_ints(sp); - break; - - case 6: - ret = sp->msr; - sp->msr &= ~0x0f; - sp->int_status &= ~SERINT_MSR; - update_ints(sp); - break; - - case 7: - ret = sp->scratch; - break; - } - - return(ret); -} - - -/* Set up a serial port for use. */ -void -serial_setup(int port, uint16_t addr, int irq) -{ - SERIAL *sp; - -#ifdef ENABLE_SERIAL_LOG - serial_log(0, "Serial%d: I/O=%04x, IRQ=%d\n", port, addr, irq); -#endif - - /* Grab the desired port block. */ - sp = &ports[port-1]; - - /* Set up the basic info. */ - if (sp->addr != 0x0000) { - /* Unlink the previous handler. Just in case. */ - io_removehandler(sp->addr, 8, - serial_read, NULL, NULL, serial_write, NULL, NULL, sp); - } - sp->addr = addr; - sp->irq = irq; - - /* Request an I/O range. */ - io_sethandler(sp->addr, 8, - serial_read, NULL, NULL, serial_write, NULL, NULL, sp); -} - - -/* Release all resources held by a serial port. */ -void -serial_remove(int port) -{ - SERIAL *sp; - - /* Grab the desired port block. */ - sp = &ports[port-1]; - - // FIXME: stop timer, if enabled! - - /* Close the host device. */ - if (sp->bh != NULL) - (void)serial_link(port, NULL); - - /* Release our I/O range. */ - if (sp->addr != 0x0000) { - io_removehandler(sp->addr, 8, - serial_read, NULL, NULL, serial_write, NULL, NULL, sp); - } - sp->addr = 0x0000; - sp->irq = 0; -} - - -/* Initialize the serial ports. */ -void -serial_init(void) -{ - SERIAL *sp; - int i; - -#if ENABLE_SERIAL_LOG - serial_do_log = ENABLE_SERIAL_LOG; -#endif - - /* FIXME: we should probably initialize the platform module here. */ - - /* Initialize each port. */ - for (i=0; iport = (i+1); - - if (i == 0) - serial_setup(sp->port, SERIAL1_ADDR, SERIAL1_IRQ); - else - serial_setup(sp->port, SERIAL2_ADDR, SERIAL2_IRQ); - } - -#ifdef WALTJE - /* Link to host port. */ - serial_link(1, "COM1"); - serial_link(2, "COM2"); -#endif -} - - -/* - * Reset the serial ports. - * - * This should be a per-port function. - */ -void -serial_reset(void) -{ - SERIAL *sp; - int i; - - for (i=0; iiir = sp->ier = sp->lcr = sp->mctrl = 0x00; - sp->fifo_read = sp->fifo_write = 0x00; - } -} - - -/* Link a serial port to a host (serial) port. */ -int -serial_link(int port, char *arg) -{ - SERIAL *sp; - BHTTY *bh; - - /* Grab the desired port block. */ - sp = &ports[port-1]; - - if (arg != NULL) { - /* Make sure we're not already linked. */ - if (sp->bh != NULL) { -#if ENABLE_SERIAL_LOG - serial_log(0, "Serial%d already linked!\n", port); -#endif - return(-1); - } - - /* Request a port from the host system. */ - bh = bhtty_open(arg, 0); - if (bh == NULL) { -#if ENABLE_SERIAL_LOG - serial_log(0, "Serial%d unable to link to '%s' !\n", port, arg); -#endif - return(-1); - } - sp->bh = bh; - - /* Set up bottom-half I/O callback info. */ - bh->rd_done = serial_rd_done; - bh->rd_arg = sp; - } else { - /* If we are linked, unlink it. */ - if (sp->bh != NULL) { - bhtty_close((BHTTY *)sp->bh); - sp->bh = NULL; - } - - } - - return(0); -} - - -/* Attach another device (MOUSE) to a serial port. */ -SERIAL * -serial_attach(int port, void *func, void *arg) -{ - SERIAL *sp; - - /* Grab the desired port block. */ - sp = &ports[port-1]; - - /* Set up callback info. */ - sp->rts_callback = func; - sp->rts_callback_p = arg; - - return(sp); -} diff --git a/src/serial.h b/src/serial.h index 4602429f0..fec2d2b5c 100644 --- a/src/serial.h +++ b/src/serial.h @@ -8,7 +8,7 @@ * * Definitions for the SERIAL card. * - * Version: @(#)serial.h 1.0.4 2017/06/03 + * Version: @(#)serial.h 1.0.6 2017/06/17 * * Author: Fred N. van Kempen, * Copyright 2017 Fred N. van Kempen. @@ -18,22 +18,33 @@ /* Default settings for the standard ports. */ -#define SERIAL1_ADDR 0x03f8 -#define SERIAL1_IRQ 4 -#define SERIAL2_ADDR 0x02f8 -#define SERIAL2_IRQ 3 +#define SERIAL1_ADDR 0x03f8 +#define SERIAL1_IRQ 4 +#define SERIAL2_ADDR 0x02f8 +#define SERIAL2_IRQ 3 + + +/* Supported UART types. */ +#define UART_TYPE_8250 0 /* standard NS8250 */ +#define UART_TYPE_8250A 1 /* updated NS8250(A) */ +#define UART_TYPE_16450 2 /* 16450 */ +#define UART_TYPE_16550 3 /* 16550 (broken fifo) */ +#define UART_TYPE_16550A 4 /* 16550a (working fifo) */ +#define UART_TYPE_16670 5 /* 16670 (64b fifo) */ typedef struct _serial_ { int8_t port; /* port number (1,2,..) */ int8_t irq; /* IRQ channel used */ uint16_t addr; /* I/O address used */ + int8_t type; /* UART type */ + uint8_t int_status; uint8_t lsr, thr, mctrl, rcr, /* UART registers */ iir, ier, lcr, msr; uint8_t dlab1, dlab2; - uint8_t dat; - uint8_t int_status; + uint8_t dat, + hold; uint8_t scratch; uint8_t fcr; @@ -41,7 +52,6 @@ typedef struct _serial_ { void (*rts_callback)(void *); void *rts_callback_p; - uint8_t hold; uint8_t fifo[256]; int fifo_read, fifo_write; @@ -58,7 +68,8 @@ extern void serial_setup(int port, uint16_t addr, int irq); extern void serial_remove(int port); extern SERIAL *serial_attach(int, void *, void *); extern int serial_link(int, char *); -extern void serial_write_fifo(SERIAL *, uint8_t); + +extern void serial_write_fifo(SERIAL *, uint8_t, int); #endif /*EMU_SERIAL_H*/