diff --git a/src/config.c b/src/config.c index 72d9ea2..23c5aa8 100644 --- a/src/config.c +++ b/src/config.c @@ -12,7 +12,7 @@ * it on Windows XP, and possibly also Vista. Use the * -DANSI_CFG for use on these systems. * - * Version: @(#)config.c 1.0.39 2018/11/06 + * Version: @(#)config.c 1.0.40 2018/11/20 * * Authors: Fred N. van Kempen, * Miran Grca, @@ -305,7 +305,7 @@ save_general(const char *cat) if (vid_resize == 0) config_delete_var(cat, "vid_resize"); - str = vidapi_internal_name(vid_api); + str = vidapi_get_internal_name(vid_api); if (! strcmp(str, "default")) { config_delete_var(cat, "vid_renderer"); } else { diff --git a/src/cpu/codegen.h b/src/cpu/codegen.h index 9562d5b..6a53c7a 100644 --- a/src/cpu/codegen.h +++ b/src/cpu/codegen.h @@ -176,7 +176,6 @@ extern void (*codegen_timing_opcode)(uint8_t opcode, uint32_t fetchdat, int op_3 extern void (*codegen_timing_block_start)(void); extern void (*codegen_timing_block_end)(void); - extern x86seg *op_ea_seg; extern int op_ssegs; extern uint32_t op_old_pc; diff --git a/src/devices/disk/hdc_ide_ata.c b/src/devices/disk/hdc_ide_ata.c index 9eb3d8d..0e376cc 100644 --- a/src/devices/disk/hdc_ide_ata.c +++ b/src/devices/disk/hdc_ide_ata.c @@ -14,7 +14,7 @@ * Devices currently implemented are hard disk, CD-ROM and * ZIP IDE/ATAPI devices. * - * Version: @(#)hdc_ide_ata.c 1.0.28 2018/11/11 + * Version: @(#)hdc_ide_ata.c 1.0.29 2018/11/13 * * Authors: Miran Grca, * Sarah Walker, @@ -2229,6 +2229,8 @@ ide_set_handlers(uint8_t board) static void ide_remove_handlers(uint8_t board) { + if (ide_boards[board] == NULL) return; + if (ide_boards[board]->bit32) { io_removehandler(ide_base_main[board], 1, ide_readb, ide_readw, ide_readl, diff --git a/src/devices/input/mouse.c b/src/devices/input/mouse.c index 939c030..5aba015 100644 --- a/src/devices/input/mouse.c +++ b/src/devices/input/mouse.c @@ -10,7 +10,7 @@ * * TODO: Add the Genius bus- and serial mouse. * - * Version: @(#)mouse.c 1.0.15 2018/11/10 + * Version: @(#)mouse.c 1.0.16 2018/11/20 * * Authors: Fred N. van Kempen, * Miran Grca, @@ -90,6 +90,7 @@ static const struct { const device_t *device; } mouse_devices[] = { { "none", &mouse_none_device }, + { "internal", &mouse_internal_device }, { "logibus", &mouse_logibus_device }, { "msbus", &mouse_msinport_device }, @@ -101,6 +102,7 @@ static const struct { { "ltserial", &mouse_ltserial_device }, { "mswhserial", &mouse_mswhserial_device }, { "ps2", &mouse_ps2_device }, + { NULL, NULL } }; diff --git a/src/devices/input/mouse_bus.c b/src/devices/input/mouse_bus.c index 76cd434..282d781 100644 --- a/src/devices/input/mouse_bus.c +++ b/src/devices/input/mouse_bus.c @@ -53,7 +53,7 @@ * Microsoft Windows NT 3.1 * Microsoft Windows 98 SE * - * Version: @(#)mouse_bus.c 1.1.2 2018/10/21 + * Version: @(#)mouse_bus.c 1.1.3 2018/11/20 * * Authors: Fred N. van Kempen, * Miran Grca, @@ -390,6 +390,7 @@ ms_read(uint16_t port, void *priv) } DBGLOG(2, "MOUSE: read(%04x) = %02x\n", port, ret); +pclog(0,"MOUSE: read(%04x) = %02x\n", port, ret); return(ret); } @@ -402,6 +403,7 @@ ms_write(uint16_t port, uint8_t val, void *priv) mouse_t *dev = (mouse_t *)priv; DBGLOG(2, "MOUSE: write(%04x, %02x)\n", port, val); +pclog(0,"MOUSE: write(%04x, %02x)\n", port, val); switch (port & 0x0003) { case INP_PORT_CONTROL: @@ -724,7 +726,7 @@ bm_init(const device_t *info) timer_add(bm_timer, &dev->timer, &dev->timer_enabled, dev); - INFO("MOUSE: %s (I/O=%04x, IRQ=%d, buttons=%d\n", + INFO("MOUSE: %s (I/O=%04x, IRQ=%i, buttons=%i\n", dev->name, dev->base, dev->irq, dev->bn); return(dev); @@ -878,16 +880,17 @@ const device_t mouse_logibus_device = { const device_t mouse_logibus_internal_device = { "Logitech Bus Mouse (Internal)", 0, - 2, + 1, bm_init, bm_close, NULL, - bm_poll, NULL, NULL, NULL, + bm_poll, + NULL, NULL, NULL, NULL }; const device_t mouse_msinport_device = { "Microsoft Bus Mouse (InPort)", DEVICE_ISA, - 1, + 10, bm_init, bm_close, NULL, bm_poll, NULL, NULL, NULL, diff --git a/src/devices/input/mouse_serial.c b/src/devices/input/mouse_serial.c index 10ebbad..6831870 100644 --- a/src/devices/input/mouse_serial.c +++ b/src/devices/input/mouse_serial.c @@ -10,7 +10,7 @@ * * TODO: Add the Genius Serial Mouse. * - * Version: @(#)mouse_serial.c 1.0.11 2018/11/11 + * Version: @(#)mouse_serial.c 1.0.12 2018/11/13 * * Authors: Fred N. van Kempen, * Miran Grca, @@ -93,7 +93,7 @@ typedef struct { int64_t period, delay; - SERIAL *serial; + void *serial; uint8_t id[255], data[5]; @@ -106,22 +106,6 @@ typedef struct { #define FLAG_ENABLED 0x01 /* dev is enabled for use */ -/* Callback from serial driver: RTS was toggled. */ -static void -ser_callback(struct SERIAL *serial, void *priv) -{ - mouse_t *dev = (mouse_t *)priv; - - dev->serial->clear_fifo(serial); - - dev->pos = 0; - dev->phase = PHASE_ID; - - /* Start a timer to wake us up in a little while. */ - dev->delay = dev->period; -} - - static uint8_t data_msystems(mouse_t *dev, int x, int y, int b) { @@ -261,7 +245,7 @@ ser_report(mouse_t *dev, int x, int y, int z, int b) { int len = 0; - memset(dev->data, 0x00, 5); + memset(dev->data, 0x00, sizeof(dev->data)); switch(dev->type) { case MOUSE_MSYSTEMS: @@ -319,21 +303,22 @@ ser_report(mouse_t *dev, int x, int y, int z, int b) if (! dev->delay) dev->delay = dev->period; +//pclog(0,"SerMouse%d: report(%d), len=%d\n", dev->port,dev->type,dev->data_len); } -/* Callback timer expired, now send our "mouse ID" to the serial port. */ +/* Timer expired, now send data (back) to the serial port. */ static void ser_timer(void *priv) { mouse_t *dev = (mouse_t *)priv; - uint8_t b; + uint8_t b = 0x00; +//pclog(0,"SerMouse%d: timer, phase=%d pos=%d\n",dev->port,dev->phase,dev->pos); switch (dev->phase) { case PHASE_ID: + /* Grab next ID byte. */ b = dev->id[dev->pos]; - if (dev->serial != NULL) - dev->serial->write_fifo(dev->serial, &b, 1); if (++dev->pos == dev->id_len) { dev->delay = 0LL; dev->pos = 0; @@ -343,9 +328,8 @@ ser_timer(void *priv) break; case PHASE_DATA: + /* Grab next data byte. */ b = dev->data[dev->pos]; - if (dev->serial != NULL) - dev->serial->write_fifo(dev->serial, &b, 1); if (++dev->pos == dev->data_len) { dev->delay = 0LL; dev->pos = 0; @@ -356,8 +340,6 @@ ser_timer(void *priv) case PHASE_STATUS: b = dev->status; - if (dev->serial != NULL) - dev->serial->write_fifo(dev->serial, &b, 1); dev->delay = 0LL; dev->pos = 0; dev->phase = PHASE_IDLE; @@ -373,8 +355,6 @@ ser_timer(void *priv) */ b = 0x00; } - if (dev->serial != NULL) - dev->serial->write_fifo(dev->serial, &b, 1); if (++dev->pos == 3) { dev->delay = 0LL; dev->pos = 0; @@ -385,8 +365,6 @@ ser_timer(void *priv) case PHASE_FMT_REV: b = 0x10 | (dev->format << 1); - if (dev->serial != NULL) - dev->serial->write_fifo(dev->serial, &b, 1); dev->delay = 0LL; dev->pos = 0; dev->phase = PHASE_IDLE; @@ -396,8 +374,33 @@ ser_timer(void *priv) dev->delay = 0LL; dev->pos = 0; dev->phase = PHASE_IDLE; - break; + return; } + + /* Send byte if we can. */ + if (dev->serial != NULL) { + serial_write(dev->serial, &b, 1); +//pclog(0,"SerMouse%d: writing %02x\n",dev->port, b); +} +} + + +/* Callback from serial driver: RTS was toggled. */ +static void +ser_callback(void *serial, void *priv) +{ + mouse_t *dev = (mouse_t *)priv; + +pclog(0,"Serial%d: callback @%08lx\n", dev->port, dev->serial); + if (serial == NULL) return; + + serial_clear(serial); + + dev->pos = 0; + dev->phase = PHASE_ID; + + /* Wait a little while and then actually send the ID. */ + dev->delay = dev->period; } @@ -407,9 +410,9 @@ ser_poll(int x, int y, int z, int b, void *priv) mouse_t *dev = (mouse_t *)priv; if (!x && !y && (b == dev->oldb) && dev->continuous) - return(1); + return(0); - DBGLOG(1, "MOUSE: poll(%d,%d,%d,%02x)\n", x, y, z, b); + DBGLOG(1, "MOUSE: poll(%i,%i,%i,%02x)\n", x, y, z, b); dev->oldb = b; @@ -444,15 +447,17 @@ ser_poll(int x, int y, int z, int b, void *priv) if (!dev->prompt && !dev->want_data) ser_report(dev, x, y, z, b); - return(0); + return(1); } static void -ltser_write(SERIAL *serial, void *priv, uint8_t data) +ltser_write(void *serial, void *priv, uint8_t data) { mouse_t *dev = (mouse_t *)priv; + pclog(0,"MOUSE: ltwrite(%02x) @%08lx\n", data, dev->serial); + #if 0 /* Make sure to stop any transmission when we receive a byte. */ if (dev->phase != PHASE_IDLE) { @@ -593,6 +598,11 @@ ser_close(void *priv) static void * ser_init(const device_t *info) { + static serial_ops_t ops = { + ser_callback, /* mcr */ + NULL, /* read */ + ltser_write, /* write */ + }; mouse_t *dev; int i; @@ -625,7 +635,7 @@ ser_init(const device_t *info) case 3: dev->id_len = 2; dev->id[1] = '3'; - /*FALLTHROUGH*/ + break; case 4: dev->type = MOUSE_MSWHEEL; @@ -640,20 +650,15 @@ ser_init(const device_t *info) } /* Attach a serial port to the mouse. */ - dev->serial = serial_attach(dev->port-1, ser_callback, dev); + dev->serial = serial_attach(dev->port, &ops, dev); if (dev->serial == NULL) { - ERRLOG("MOUSE: %s (port=COM%i, butons=%i) port disabled!\n", - dev->name, dev->port+1, i); + ERRLOG("MOUSE: %s (port COM%i not available) device disabled!\n", + dev->name, dev->port+1); free(dev); return(NULL); } -#if 0 - /* Add our WRITE routine. */ - serial_attach2(dev->port-1, ser_write, dev); -#endif - - INFO("MOUSE: %s (port=COM%d, butons=%d)\n", dev->name, dev->port+1, i); + INFO("MOUSE: %s (port=COM%i, buttons=%i)\n", dev->name, dev->port+1, i); timer_add(ser_timer, &dev->delay, &dev->delay, dev); @@ -667,15 +672,12 @@ ser_init(const device_t *info) static const device_config_t ser_config[] = { { - "port", "Serial Port", CONFIG_SELECTION, "", 1, { + "port", "Serial Port", CONFIG_SELECTION, "", 0, { { - "Disabled", 0 + "COM1", 0 }, { - "COM1", 1 - }, - { - "COM2", 2 + "COM2", 1 }, { "" diff --git a/src/devices/ports/serial.c b/src/devices/ports/serial.c index c39a98e..af9d2fe 100644 --- a/src/devices/ports/serial.c +++ b/src/devices/ports/serial.c @@ -6,35 +6,67 @@ * * This file is part of the VARCem Project. * - * Implementation of 8250-style serial port. + * Implementation of NS8250-series UART devices. * - * Version: @(#)serial.c 1.0.11 2018/11/11 + * 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. * - * Authors: Fred N. van Kempen, - * Miran Grca, - * Sarah Walker, + * 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 "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 "multi-I/O" board, as that saved + * space and bus slots. Early boards had discrete chips for most + * functions, but later on, many of these were integrated into a + * single "super-I/O" chip. + * + * This file implements the standard NS8250, as well as the later + * 16450 and 16550 series, which fixed bugs and added features + * like FIFO buffers, higher line speeds and DMA transfers. + * + * The lower half of the driver can interface to the host system + * serial ports, or other channels, for real-world access. + * + * Version: @(#)serial.c 1.0.12 2018/11/16 + * + * Author: Fred N. van Kempen, * * Copyright 2017,2018 Fred N. van Kempen. - * Copyright 2016-2018 Miran Grca. - * Copyright 2008-2018 Sarah Walker. * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. + * Redistribution and use in source and binary forms, with + * or without modification, are permitted provided that the + * following conditions are met: * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. + * 1. Redistributions of source code must retain the entire + * above notice, this list of conditions and the following + * disclaimer. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the: + * 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. * - * Free Software Foundation, Inc. - * 59 Temple Place - Suite 330 - * Boston, MA 02111-1307 - * USA. + * 3. Neither the name of the copyright holder nor the names + * of its contributors may be used to endorse or promote + * products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT + * HOLDER 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. */ #include #include @@ -54,12 +86,124 @@ #include "serial.h" -enum { - SERIAL_INT_LSR = 1, - SERIAL_INT_RECEIVE = 2, - SERIAL_INT_TRANSMIT = 4, - SERIAL_INT_MSR = 8 -}; +/* Interrupt reasons. */ +#define SER_INT_LSR 0x01 +#define SER_INT_RX 0x02 +#define SER_INT_TX 0x04 +#define SER_INT_MSR 0x08 + +/* 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 /* 16550+ */ +#define IIR_IIRFE 0xc0 /* 16550+ */ +# define IIR_FIFO64 0x20 +# define IIR_FIFOBAD 0x80 +# 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 +#define LSR_MASK (LSR_BI|LSR_FE|LSR_PE|LSR_OE) + +/* 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 (MSR_DDCD|MSR_TERI|MSR_DDSR|MSR_DCTS) + + +typedef struct serial { + int8_t port; /* port number (0,1,..) */ + int8_t irq; /* IRQ channel used */ + uint16_t base; /* I/O address used */ + + int8_t is_pcjr; /* PCjr UART (fixed OUT2) */ + int8_t type; /* UART type */ + uint8_t int_status; + + uint8_t lsr, thr, mcr, rcr, /* UART registers */ + iir, ier, lcr, msr; + uint8_t dlab1, dlab2; + uint8_t dat, + hold; + uint8_t scratch; + uint8_t fcr; + + /* Callback data. */ + serial_ops_t *ops; + void *ops_arg; + + int64_t delay; + + void *bh; /* BottomHalf handler */ + + int fifo_read, + fifo_write; + uint8_t fifo[64]; +} serial_t; #ifdef ENABLE_SERIAL_LOG @@ -67,19 +211,11 @@ int serial_do_log = ENABLE_SERIAL_LOG; #endif -static const struct { - uint16_t addr; - int8_t irq; - int8_t pad; -} addr_list[] = { /* valid port addresses */ - { SERIAL1_ADDR, 4 }, - { SERIAL2_ADDR, 3 } -}; -static SERIAL ports[SERIAL_MAX]; /* the ports */ +static serial_t ports[SERIAL_MAX]; /* the ports */ #ifdef _LOGGING -void +static void serial_log(int level, const char *fmt, ...) { # ifdef ENABLE_SERIAL_LOG @@ -96,70 +232,107 @@ serial_log(int level, const char *fmt, ...) static void -update_ints(SERIAL *dev) +update_ints(serial_t *dev) { int stat = 0; - dev->iir = 1; + /* None yet. */ + dev->iir = IIR_IP; - if ((dev->ier & 4) && (dev->int_status & SERIAL_INT_LSR)) { - /*Line status interrupt*/ + if ((dev->ier & IER_RXLSIE) && (dev->int_status & SER_INT_LSR)) { + /* Line Status interrupt. */ stat = 1; - dev->iir = 6; - } else if ((dev->ier & 1) && (dev->int_status & SERIAL_INT_RECEIVE)) { - /*Received data available*/ + dev->iir = IID_IDERR; + } else if ((dev->ier & IER_RDAIE) && (dev->int_status & SER_INT_RX)) { + /* Received Data available. */ stat = 1; - dev->iir = 4; - } else if ((dev->ier & 2) && (dev->int_status & SERIAL_INT_TRANSMIT)) { - /*Transmit data empty*/ + dev->iir = IID_IDRX; + } else if ((dev->ier & IER_THREIE) && (dev->int_status & SER_INT_TX)) { + /* Transmit Data empty. */ stat = 1; - dev->iir = 2; - } else if ((dev->ier & 8) && (dev->int_status & SERIAL_INT_MSR)) { - /*Modem status interrupt*/ + dev->iir = IID_IDTX; + } else if ((dev->ier & IER_MSIE) && (dev->int_status & SER_INT_MSR)) { + /* Modem Status interrupt. */ stat = 1; - dev->iir = 0; + dev->iir = IID_IDMDM; } - if (stat && ((dev->mcr & 8) || dev->is_pcjr)) - picintlevel(1 << dev->irq); - else + DEBUG("Serial%d: intr, IIR=%02X, type=%d, mcr=%02X\n", + dev->port, dev->iir, dev->type, dev->mcr); + + if (stat && ((dev->mcr & MCR_OUT2) || dev->is_pcjr)) { + /* Raise an interrupt. */ + if (dev->type < UART_TYPE_16450) { + /* Edge-triggered. */ + picint(1 << dev->irq); + } else { + /* Level-triggered. */ + picintlevel(1 << dev->irq); + } + } else { + /* Clear an interrupt. */ picintc(1 << dev->irq); + } } static void -clear_fifo(SERIAL *dev) +clear_fifo(serial_t *dev) { - memset(dev->fifo, 0x00, 256); + memset(dev->fifo, 0x00, sizeof(dev->fifo)); + dev->fifo_read = dev->fifo_write = 0; } static void -write_fifo(SERIAL *dev, uint8_t *ptr, uint8_t len) +write_fifo(serial_t *dev, uint8_t *ptr, uint8_t len) { while (len-- > 0) { - dev->fifo[dev->fifo_write] = *ptr++; - dev->fifo_write = (dev->fifo_write + 1) & 0xff; + dev->fifo[dev->fifo_write++] = *ptr++; + if (dev->fifo_write == sizeof(dev->fifo)) + dev->fifo_write = 0; /*OVERFLOW NOT DETECTED*/ } - if (! (dev->lsr & 1)) { - dev->lsr |= 1; - dev->int_status |= SERIAL_INT_RECEIVE; + if (! (dev->lsr & LSR_DR)) { + dev->lsr |= LSR_DR; + dev->int_status |= SER_INT_RX; + update_ints(dev); } } static uint8_t -read_fifo(SERIAL *dev) +read_fifo(serial_t *dev) { if (dev->fifo_read != dev->fifo_write) { - dev->dat = dev->fifo[dev->fifo_read]; - dev->fifo_read = (dev->fifo_read + 1) & 0xff; + dev->dat = dev->fifo[dev->fifo_read++]; + if (dev->fifo_read == sizeof(dev->fifo)) + dev->fifo_read = 0; } +#if 0 + /* If we have more, generate (new) int. */ + if (sp->fifo_read != sp->fifo_write) { +#if 1 + sp->delay = 1000*TIMER_USEC; +#else + if (sp->bh != NULL) { + sp->int_status |= SERINT_RECEIVE; + sp->lsr |= LSR_DR; + + /* Update interrupt state. */ + update_ints(sp); + } else { + sp->delay = 1000*TIMER_USEC; + } +#endif + } + } +#endif + return(dev->dat); } @@ -167,20 +340,21 @@ read_fifo(SERIAL *dev) static void receive_callback(void *priv) { - SERIAL *dev = (SERIAL *)priv; + serial_t *dev = (serial_t *)priv; dev->delay = 0; if (dev->fifo_read != dev->fifo_write) { - dev->lsr |= 1; - dev->int_status |= SERIAL_INT_RECEIVE; + dev->lsr |= LSR_DR; + dev->int_status |= SER_INT_RX; + update_ints(dev); } } static void -reset_port(SERIAL *dev) +reset_port(serial_t *dev) { dev->iir = dev->ier = dev->lcr = 0; dev->fifo_read = dev->fifo_write = 0; @@ -189,160 +363,321 @@ reset_port(SERIAL *dev) } +/* Fake interrupt generator, needed for Serial Mouse. */ static void -serial_write(uint16_t addr, uint8_t val, void *priv) +read_timer(void *priv) { - SERIAL *dev = (SERIAL *)priv; + serial_t *dev = (serial_t *)priv; - switch (addr & 7) { - case 0: - if (dev->lcr & 0x80) { + dev->delay = 0; + + if (dev->fifo_read != dev->fifo_write) { + dev->lsr |= LSR_DR; + dev->int_status |= SER_INT_RX; + update_ints(dev); + } +} + + +#ifdef USE_HOST_SERIAL +/* BHTTY READ COMPLETE handler. */ +static void +read_done(void *arg, int num) +{ + serial_t *dev = (serial_t *)arg; + + /* We can do at least 'num' bytes.. */ + while (num-- > 0) { + /* Get a byte from them. */ + if (bhtty_read(dev->bh, &dev->hold, 1) < 0) break; + + /* Stuff it into the FIFO and set intr. */ + write_fifo(dev, &dev->hold, 1); + } + + /* We have data waiting for us.. delay a little, and then read it. */ + timer_add(ser_timer, &dev->delay, &dev->delay, dev); +} +#endif + + +static void +ser_write(uint16_t addr, uint8_t val, void *priv) +{ + serial_t *dev = (serial_t *)priv; + uint8_t wl, sb, pa, msr; + uint32_t baud, speed; + + DEBUG("Serial%i: write(%i, %02x)\n", dev->port, (addr & 0x0007), val); + + switch (addr & 0x0007) { + case 0: /* DLAB, DATA */ + if (dev->lcr & LCR_DLAB) { + /* DLAB set, set DLAB low byte. */ dev->dlab1 = val; return; } + + /* DLAB clear, regular data write. */ dev->thr = val; - dev->lsr |= 0x20; - dev->int_status |= SERIAL_INT_TRANSMIT; + +#ifdef USE_HOST_SERIAL + if (dev->bh != NULL) { + /* We are linked, so send to BH layer. */ + bhtty_write((BHTTY *)dev->bh, dev->thr); + } +#endif + + if (dev->ops && dev->ops->write) + dev->ops->write(dev, dev->ops_arg, val); + + /* WRITE completed, we are ready for more. */ + dev->lsr |= LSR_THRE; + dev->int_status |= SER_INT_TX; update_ints(dev); - if (dev->mcr & 0x10) + + /* Loopback echo data to RX needed? */ + if (dev->mcr & MCR_LMS) { write_fifo(dev, &val, 1); + + dev->int_status |= SER_INT_TX; + update_ints(dev); + } break; - case 1: - if (dev->lcr & 0x80) { + case 1: /* DLAB, IER */ + if (dev->lcr & LCR_DLAB) { + /* DLAB set, set DLAB high byte. */ dev->dlab2 = val; return; } - dev->ier = val & 0xf; + + /* DLAB clear, set IER register bits. */ + dev->ier = (val & IER_MASK); update_ints(dev); break; - case 2: + case 2: /* FCR */ +#if 0 + if (dev->type >= UART_TYPE_16550) { +DEBUG("Serial%i: tried to enable FIFO (%02x), type %d!\n", dev->port, val, dev->type); + dev->fcr = val; + } +#else dev->fcr = val; +#endif break; - case 3: - dev->lcr = val; - break; + case 3: /* LCR */ + if ((dev->lcr & LCR_DLAB) && !(val & LCR_DLAB)) { + /* We dropped DLAB, so handle baudrate. */ + baud = ((dev->dlab2 << 8) | dev->dlab1); + if (baud > 0) { + speed = 115200UL / baud; + DEBUG("Serial%i: divisor %u, baudrate %i\n", + dev->port, baud, speed); +#ifdef USE_HOST_SERIAL + if (dev->bh != NULL) + bhtty_speed((BHTTY *)dev->bh, speed); +#endif + } else { + DEBUG("Serial%i: divisor %u invalid!\n", + dev->port, baud); + } + } + + wl = (val & LCR_WLS) + 5; /* databits */ + sb = (val & LCR_SBS) ? 2 : 1; /* stopbits */ + pa = (val & (LCR_PE|LCR_EP|LCR_PS)) >> 3; + DEBUG("Serial%i: WL=%i SB=%i PA=%i\n", dev->port, wl, sb, pa); +#ifdef USE_HOST_SERIAL + if (dev->bh != NULL) + bhtty_params((BHTTY *)dev->bh, wl, pa, sb); +#endif + + dev->lcr = val; + break; + + case 4: /*MCR*/ +#ifdef USE_HOST_SERIAL + if (dev->bh == NULL) { + /* Not linked, force LOOPBACK mode. */ + val |= MCR_LMS; + } +#endif + + if ((val & MCR_RTS) && !(dev->mcr & 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 (dev->ops && dev->ops->mcr) { + dev->ops->mcr(dev, dev->ops_arg); + DEBUG("Serial%i: RTS raised\n", dev->port); + } + } + + if ((val & MCR_OUT2) && !(dev->mcr & MCR_OUT2)) { +#ifdef USE_HOST_SERIAL + if (dev->bh != NULL) { + /* Linked, start host port. */ + (void)bhtty_active(dev->bh, 1); + } else { +#endif + /* Not linked, start RX timer. */ + timer_add(read_timer, + &dev->delay, &dev->delay, dev); + + /* Fake CTS, DSR and DCD (for now.) */ + dev->msr = (MSR_CTS | MSR_DCTS | + MSR_DSR | MSR_DDSR | + MSR_DCD | MSR_DDCD); + dev->int_status |= SER_INT_MSR; + update_ints(dev); +#ifdef USE_HOST_SERIAL + } +#endif + } - case 4: - if ((val & 2) && !(dev->mcr & 2)) { - if (dev->rts_callback) - dev->rts_callback(dev, dev->rts_callback_p); - } dev->mcr = val; - if (val & 0x10) { - uint8_t new_msr; - new_msr = (val & 0x0c) << 4; - new_msr |= (val & 0x02) ? 0x10: 0; - new_msr |= (val & 0x01) ? 0x20: 0; + if (val & MCR_LMS) { /* loopback mode */ + msr = (val & 0x0c) << 4; + msr |= (val & MCR_RTS) ? MCR_LMS : 0; + msr |= (val & MCR_DTR) ? MCR_AUTOFLOW : 0; - if ((dev->msr ^ new_msr) & 0x10) - new_msr |= 0x01; - if ((dev->msr ^ new_msr) & 0x20) - new_msr |= 0x02; - if ((dev->msr ^ new_msr) & 0x80) - new_msr |= 0x08; - if ((dev->msr & 0x40) && !(new_msr & 0x40)) - new_msr |= 0x04; - - dev->msr = new_msr; - } - break; + if ((dev->msr ^ msr) & MSR_CTS) + msr |= MSR_DCTS; + if ((dev->msr ^ msr) & MSR_DSR) + msr |= MSR_DDSR; + if ((dev->msr ^ msr) & MSR_DCD) + msr |= MSR_DDCD; + if ((dev->msr & MSR_TERI) && !(msr & MSR_RI)) + msr |= MSR_TERI; - case 5: + dev->msr = msr; + } + break; + + case 5: /*LSR*/ + if (val & LSR_MASK) + dev->int_status |= SER_INT_LSR; + if (val & LSR_DR) + dev->int_status |= SER_INT_RX; + if (val & LSR_THRE) + dev->int_status |= SER_INT_TX; dev->lsr = val; - if (dev->lsr & 0x01) - dev->int_status |= SERIAL_INT_RECEIVE; - if (dev->lsr & 0x1e) - dev->int_status |= SERIAL_INT_LSR; - if (dev->lsr & 0x20) - dev->int_status |= SERIAL_INT_TRANSMIT; update_ints(dev); break; - case 6: + case 6: /*MSR*/ dev->msr = val; - if (dev->msr & 0x0f) - dev->int_status |= SERIAL_INT_MSR; + if (dev->msr & MSR_MASK) + dev->int_status |= SER_INT_MSR; update_ints(dev); break; - case 7: - dev->scratch = val; + case 7: /*SCRATCH*/ + if (dev->type > UART_TYPE_8250) { + dev->scratch = val; + } break; } } static uint8_t -serial_read(uint16_t addr, void *priv) +ser_read(uint16_t addr, void *priv) { - SERIAL *dev = (SERIAL *)priv; + serial_t *dev = (serial_t *)priv; uint8_t ret = 0x00; - switch (addr & 7) { - case 0: - if (dev->lcr & 0x80) { + switch (addr & 0x0007) { + case 0: /* DATA / DLAB1 */ + if (dev->lcr & LCR_DLAB) { + /* DLAB set, read DLAB low byte. */ ret = dev->dlab1; break; } - dev->lsr &= ~1; - dev->int_status &= ~SERIAL_INT_RECEIVE; + /* + * DLAB clear, regular data read. + * First, clear the RXDATA interrupt. + */ + dev->lsr &= ~LSR_DR; + dev->int_status &= ~SER_INT_RX; update_ints(dev); + + /* If there is data in the RX FIFO, grab it. */ ret = read_fifo(dev); + if (dev->fifo_read != dev->fifo_write) { dev->delay = 1000LL * TIMER_USEC; } break; - case 1: - if (dev->lcr & 0x80) - ret = dev->dlab2; - else - ret = dev->ier; - break; + case 1: /* LCR / DLAB2 */ + if (dev->lcr & LCR_DLAB) { + /* DLAB set, read DLAB high byte. */ + ret = dev->dlab2; + } else { + /* DLAB clear, read IER register bits. */ + ret = dev->ier; + } + break; - case 2: + case 2: /* IIR */ ret = dev->iir; - if ((ret & 0xe) == 2) { - dev->int_status &= ~SERIAL_INT_TRANSMIT; + if ((ret & IIR_IID) == IID_IDTX) { + /* Transmit is done. */ + dev->int_status &= ~SER_INT_TX; update_ints(dev); } - if (dev->fcr & 1) - ret |= 0xc0; + + if (dev->type >= UART_TYPE_16550) { + /* If FIFO enabled.. */ + if (dev->fcr & FCR_FCRFE) + /* Report FIFO active. */ + ret |= FCR_RTLS14; + } break; - case 3: + case 3: /* LCR */ ret = dev->lcr; break; - case 4: + case 4: /* MCR */ ret = dev->mcr; break; - case 5: - if (dev->lsr & 0x20) - dev->lsr |= 0x40; - dev->lsr |= 0x20; + case 5: /* LSR */ + if (dev->lsr & LSR_THRE) + dev->lsr |= LSR_TEMT; + dev->lsr |= LSR_THRE; ret = dev->lsr; if (dev->lsr & 0x1f) dev->lsr &= ~0x1e; - dev->int_status &= ~SERIAL_INT_LSR; + + dev->int_status &= ~SER_INT_LSR; update_ints(dev); break; - case 6: + case 6: /* MSR */ + /* Grab current modem status and reset delta bits. */ ret = dev->msr; dev->msr &= ~0x0f; - dev->int_status &= ~SERIAL_INT_MSR; + + /* Clear MSR interrupt status. */ + dev->int_status &= ~SER_INT_MSR; update_ints(dev); break; - case 7: - ret = dev->scratch; + case 7: /* SCRATCH */ + if (dev->type > UART_TYPE_8250) { + ret = dev->scratch; + } break; } @@ -351,27 +686,22 @@ serial_read(uint16_t addr, void *priv) static void * -serial_init(const device_t *info) +ser_init(const device_t *info) { - SERIAL *dev; + serial_t *dev; /* Get the correct device. */ - dev = &ports[info->local - 1]; + dev = &ports[(info->local & 127) - 1]; /* Set up local/weird stuff. */ if (info->local & 128) dev->is_pcjr = 1; - /* Set up callback functions. */ - dev->clear_fifo = clear_fifo; - dev->write_fifo = write_fifo; - /* Clear port. */ reset_port(dev); /* Enable the I/O handler for this port. */ - io_sethandler(dev->base, 8, - serial_read,NULL,NULL, serial_write,NULL,NULL, dev); + io_sethandler(dev->base, 8, ser_read,NULL,NULL, ser_write,NULL,NULL, dev); timer_add(receive_callback, &dev->delay, &dev->delay, dev); @@ -383,13 +713,19 @@ serial_init(const device_t *info) static void -serial_close(void *priv) +ser_close(void *priv) { - SERIAL *dev = (SERIAL *)priv; + serial_t *dev = (serial_t *)priv; + +#ifdef USE_HOST_SERIAL + /* Close the host device. */ + if (dev->bh != NULL) + (void)serial_link(dev->port, NULL); +#endif /* Remove the I/O handler. */ io_removehandler(dev->base, 8, - serial_read,NULL,NULL, serial_write,NULL,NULL, dev); + ser_read,NULL,NULL, ser_write,NULL,NULL, dev); /* Clear port. */ reset_port(dev); @@ -400,7 +736,7 @@ const device_t serial_1_device = { "COM1:", 0, 1, - serial_init, serial_close, NULL, + ser_init, ser_close, NULL, NULL, NULL, NULL, NULL, NULL }; @@ -409,7 +745,7 @@ const device_t serial_2_device = { "COM2:", 0, 2, - serial_init, serial_close, NULL, + ser_init, ser_close, NULL, NULL, NULL, NULL, NULL, NULL, }; @@ -418,29 +754,54 @@ const device_t serial_1_pcjr_device = { "COM1:", 0, 1+128, - serial_init, serial_close, NULL, + ser_init, ser_close, NULL, NULL, NULL, NULL, NULL, NULL }; -/* (Re-)initialize all serial ports. */ +/* API: (re-)initialize all serial ports. */ void serial_reset(void) { - SERIAL *dev; + serial_t *dev; int i; DEBUG("SERIAL: reset ([%i] [%i])\n", serial_enabled[0], serial_enabled[1]); for (i = 0; i < SERIAL_MAX; i++) { + /* Get the correct device and clear it. */ dev = &ports[i]; + memset(dev, 0x00, sizeof(serial_t)); + dev->port = i; + dev->type = UART_TYPE_8250; - memset(dev, 0x00, sizeof(SERIAL)); + /* Set up default port and IRQ for the device. */ + switch(i) { + case 0: /* standard first port, "COM1" */ + dev->base = SERIAL1_ADDR; + dev->irq = 4; + break; - dev->base = addr_list[i].addr; - dev->irq = addr_list[i].irq; + case 1: /* standard second port, "COM2" */ + dev->base = SERIAL2_ADDR; + dev->irq = 3; + break; + + case 2: /* "COM3" */ + dev->base = 0x03e8; + dev->irq = 4; + break; + + case 3: /* "COM4" */ + dev->base = 0x02e8; + dev->irq = 3; + break; + + default: + break; + } /* Clear port. */ reset_port(dev); @@ -448,11 +809,11 @@ serial_reset(void) } -/* Set up (the address/IRQ of) one of the serial ports. */ +/* API: set up (the address/IRQ of) one of the serial ports. */ void serial_setup(int id, uint16_t port, int8_t irq) { - SERIAL *dev = &ports[id]; + serial_t *dev = &ports[id]; INFO("SERIAL: setting up COM%i as %04X [enabled=%i]\n", id+1, port, serial_enabled[id]); @@ -464,11 +825,11 @@ serial_setup(int id, uint16_t port, int8_t irq) } -/* Attach another device (MOUSE) to a serial port. */ -SERIAL * -serial_attach(int port, void *func, void *arg) +/* API: attach another device to a serial port. */ +void * +serial_attach(int port, serial_ops_t *ops, void *arg) { - SERIAL *dev; + serial_t *dev; /* No can do if port not enabled. */ if (! serial_enabled[port]) return(NULL); @@ -477,8 +838,28 @@ serial_attach(int port, void *func, void *arg) dev = &ports[port]; /* Set up callback info. */ - dev->rts_callback = (void (*)(struct SERIAL *, void *))func; - dev->rts_callback_p = arg; + dev->ops = ops; + dev->ops_arg = arg; return(dev); } + + +/* API: clear the FIFO buffers of a serial port. */ +void +serial_clear(void *arg) +{ + serial_t *dev = (serial_t *)arg; + + clear_fifo(dev); +} + + +/* API: write data to a serial port. */ +void +serial_write(void *arg, uint8_t *ptr, uint8_t len) +{ + serial_t *dev = (serial_t *)arg; + + write_fifo(dev, ptr, len); +} diff --git a/src/devices/ports/serial.h b/src/devices/ports/serial.h index d32b294..e6fc280 100644 --- a/src/devices/ports/serial.h +++ b/src/devices/ports/serial.h @@ -8,7 +8,7 @@ * * Definitions for the SERIAL card. * - * Version: @(#)serial.h 1.0.6 2018/11/11 + * Version: @(#)serial.h 1.0.8 2018/11/15 * * Author: Fred N. van Kempen, * @@ -49,6 +49,7 @@ #define SERIAL_MAX 2 /* two ports supported */ +#define SERIAL_FIFO_MAX 64 /* maximum FIFO size */ /* Default settings for the standard ports. */ #define SERIAL1_ADDR 0x03f8 @@ -61,64 +62,35 @@ #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_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 base; /* I/O address used */ - - int8_t is_pcjr; /* PCjr UART (fixed OUT2) */ - int8_t type; /* UART type */ - uint8_t int_status; - - uint8_t lsr, thr, mcr, rcr, /* UART registers */ - iir, ier, lcr, msr; - uint8_t dlab1, dlab2; - uint8_t dat, - hold; - uint8_t scratch; - uint8_t fcr; - - /* Access to internal functions. */ - void (*clear_fifo)(struct SERIAL *); - void (*write_fifo)(struct SERIAL *, uint8_t *, uint8_t); - - /* Data for the RTS-toggle callback. */ - void (*rts_callback)(struct SERIAL *, void *); - void *rts_callback_p; - - int64_t delay; - -#ifdef WALTJE_SERIAL - void *bh; /* BottomHalf handler */ -#endif - - int fifo_read, - fifo_write; - uint8_t fifo[256]; -} SERIAL; +typedef struct { + void (*mcr)(void *dev, void *arg); + uint8_t (*read)(void *dev, void *arg); + void (*write)(void *dev, void *arg, uint8_t val); +} serial_ops_t; /* Global variables. */ #ifdef EMU_DEVICE_H -extern const device_t serial_1_device; -extern const device_t serial_1_pcjr_device; -extern const device_t serial_2_device; +extern const device_t serial_1_device; +extern const device_t serial_2_device; + +extern const device_t serial_1_pcjr_device; #endif /* Functions. */ -extern void serial_log(int level, const char *fmt, ...); extern void serial_reset(void); -extern void serial_setup(int port, uint16_t addr, int8_t irq); -extern SERIAL *serial_attach(int port, void *func, void *priv); -#ifdef WALTJE_SERIAL -extern int serial_link(int port, char *name); -#endif +extern void serial_setup(int port, uint16_t addr, int8_t irq); +extern void *serial_attach(int port, serial_ops_t *ops, void *priv); +extern int serial_link(int port, const char *name); + +extern void serial_clear(void *arg); +extern void serial_write(void *arg, uint8_t *ptr, uint8_t len); #endif /*EMU_SERIAL_H*/ diff --git a/src/devices/video/vid_tvga.c b/src/devices/video/vid_tvga.c index c94f4cc..8326414 100644 --- a/src/devices/video/vid_tvga.c +++ b/src/devices/video/vid_tvga.c @@ -6,9 +6,9 @@ * * This file is part of the VARCem Project. * - * Trident TVGA (8900D) emulation. + * Trident TVGA (8900C/8900D) emulation. * - * Version: @(#)vid_tvga.c 1.0.9 2018/10/08 + * Version: @(#)vid_tvga.c 1.0.10 2018/11/20 * * Authors: Fred N. van Kempen, * Miran Grca, @@ -52,7 +52,8 @@ #include "vid_tkd8001_ramdac.h" -#define ROM_TVGA_BIOS L"video/trident/tvga/trident.bin" +#define ROM_T8900CX_BIOS L"video/trident/8916cx2/bios.bin" +#define ROM_T8900D_BIOS L"video/trident/tvga/trident.bin" typedef struct { @@ -342,17 +343,29 @@ tvga_init(const device_t *info) { tvga_t *tvga = (tvga_t *)mem_alloc(sizeof(tvga_t)); memset(tvga, 0x00, sizeof(tvga_t)); + const wchar_t *fn = NULL; tvga->vram_size = device_get_config_int("memory") << 10; tvga->vram_mask = tvga->vram_size - 1; - rom_init(&tvga->bios_rom, ROM_TVGA_BIOS, - 0xc0000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL); - svga_init(&tvga->svga, tvga, tvga->vram_size, tvga_recalctimings, tvga_in, tvga_out, NULL, NULL); - tvga->svga.ramdac = device_add(&tkd8001_ramdac_device); + switch(info->local) { + case 0: /* TVGA 8900CX LC2 */ + fn = ROM_T8900CX_BIOS; + tvga->svga.ramdac = device_add(&tkd8001_ramdac_device); + break; + + case 1: /* TVGA 8900D */ + fn = ROM_T8900D_BIOS; + tvga->svga.ramdac = device_add(&tkd8001_ramdac_device); + break; + } + + if (fn != NULL) + rom_init(&tvga->bios_rom, fn, + 0xc0000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL); io_sethandler(0x03c0, 32, tvga_in,NULL,NULL, tvga_out,NULL,NULL, tvga); @@ -393,10 +406,17 @@ tvga_force_redraw(void *p) } +static int +tvga8900c_available(void) +{ + return rom_present(ROM_T8900CX_BIOS); +} + + static int tvga8900d_available(void) { - return rom_present(ROM_TVGA_BIOS); + return rom_present(ROM_T8900D_BIOS); } @@ -425,17 +445,29 @@ static const device_config_t tvga_config[] = } }; -static const video_timings_t tvga8900d_timing = {VID_ISA,3,3,6,8,8,12}; +static const video_timings_t tvga8900_timing = {VID_ISA,3,3,6,8,8,12}; +const device_t tvga8900cx_device = { + "Trident TVGA 8900CX 2/4/8 LC2 Rev.A", + DEVICE_ISA, + 0, + tvga_init, tvga_close, NULL, + tvga8900c_available, + tvga_speed_changed, + tvga_force_redraw, + &tvga8900_timing, + tvga_config +}; + const device_t tvga8900d_device = { "Trident TVGA 8900D", DEVICE_ISA, - 0, + 1, tvga_init, tvga_close, NULL, tvga8900d_available, tvga_speed_changed, tvga_force_redraw, - &tvga8900d_timing, + &tvga8900_timing, tvga_config }; diff --git a/src/devices/video/video.h b/src/devices/video/video.h index 49dcb89..d3a0bea 100644 --- a/src/devices/video/video.h +++ b/src/devices/video/video.h @@ -8,7 +8,7 @@ * * Definitions for the video controller module. * - * Version: @(#)video.h 1.0.22 2018/10/28 + * Version: @(#)video.h 1.0.23 2018/11/20 * * Authors: Fred N. van Kempen, * Miran Grca, @@ -276,6 +276,7 @@ extern const device_t s3_virge_375_4_pci_device; extern const device_t sigma_device; /* Trident 8900 series cards. */ +extern const device_t tvga8900cx_device; extern const device_t tvga8900d_device; /* Trident 9400 series cards. */ diff --git a/src/devices/video/video_dev.c b/src/devices/video/video_dev.c index ff9bf6d..5f8715c 100644 --- a/src/devices/video/video_dev.c +++ b/src/devices/video/video_dev.c @@ -12,7 +12,7 @@ * "extern" reference to its device into the video.h file, * and add an entry for it into the table here. * - * Version: @(#)video_dev.c 1.0.27 2018/10/24 + * Version: @(#)video_dev.c 1.0.28 2018/11/20 * * Authors: Fred N. van Kempen, * Miran Grca, @@ -108,6 +108,7 @@ static const struct { #if defined(DEV_BRANCH) && defined(USE_TI) { "ti_cf62011", &ti_cf62011_device }, #endif + { "tvga8900cx", &tvga8900cx_device }, { "tvga8900d", &tvga8900d_device }, { "et4000ax", &et4000_isa_device }, { "tgkorvga", &et4000k_isa_device }, diff --git a/src/plat.h b/src/plat.h index b5903f3..8157a42 100644 --- a/src/plat.h +++ b/src/plat.h @@ -8,7 +8,7 @@ * * Define the various platform support functions. * - * Version: @(#)plat.h 1.0.20 2018/10/24 + * Version: @(#)plat.h 1.0.21 2018/11/20 * * Author: Fred N. van Kempen, * @@ -115,8 +115,11 @@ extern "C" { /* Define a "vidapi", or, rather, a Renderer API. */ typedef struct { + const char *internal_name; const char *name; + int local; + int (*init)(int fs); void (*close)(void); void (*reset)(int fs); diff --git a/src/ui/ui.h b/src/ui/ui.h index 29a64aa..127f865 100644 --- a/src/ui/ui.h +++ b/src/ui/ui.h @@ -8,7 +8,7 @@ * * Define the various UI functions. * - * Version: @(#)ui.h 1.0.15 2018/09/29 + * Version: @(#)ui.h 1.0.16 2018/11/20 * * Author: Fred N. van Kempen, * @@ -195,7 +195,8 @@ extern int dlg_file(const wchar_t *filt, const wchar_t *ifn, extern int vidapi_count(void); extern int vidapi_available(int api); extern int vidapi_from_internal_name(const char *name); -extern const char *vidapi_internal_name(int api); +extern const char *vidapi_get_internal_name(int api); +extern const char *vidapi_getname(int api); extern int vidapi_set(int api); extern void vidapi_resize(int x, int y); extern int vidapi_pause(void); diff --git a/src/ui/ui_main.c b/src/ui/ui_main.c index bb96441..b769a6d 100644 --- a/src/ui/ui_main.c +++ b/src/ui/ui_main.c @@ -11,7 +11,7 @@ * This code is called by the UI frontend modules, and, also, * depends on those same modules for lower-level functions. * - * Version: @(#)ui_main.c 1.0.20 2018/10/26 + * Version: @(#)ui_main.c 1.0.21 2018/11/20 * * Author: Fred N. van Kempen, * @@ -295,14 +295,16 @@ main_reset_all(void) menu_set_item(IDM_REMEMBER, window_remember); /* Add all renderers to the Renderer menu. */ - for (i = 0; i < vidapi_count(); i++) { - if (vidapi_available(i)) { - /* Get name of the renderer and add a menu item. */ - mbstowcs(temp, vidapi_internal_name(i), sizeof_w(temp)); - menu_add_item(IDM_RENDER, ITEM_RADIO, IDM_RENDER_1 + i, temp); - } + for (i = 0; vidapi_getname(i) != NULL; i++) { + /* Get name of the renderer and add a menu item. */ + mbstowcs(temp, vidapi_getname(i), sizeof_w(temp)); + menu_add_item(IDM_RENDER, ITEM_RADIO, IDM_RENDER_1 + i, temp); + + /* Disable entries that are not available. */ + if (! vidapi_available(i)) + menu_enable_item(IDM_RENDER_1 + i, 0); } - menu_set_radio_item(IDM_RENDER_1, vidapi_count(), vid_api); + menu_set_radio_item(IDM_RENDER_1, i, vid_api); menu_set_radio_item(IDM_SCALE_1, 4, scale); diff --git a/src/ui/ui_vidapi.c b/src/ui/ui_vidapi.c index b747787..6f09eca 100644 --- a/src/ui/ui_vidapi.c +++ b/src/ui/ui_vidapi.c @@ -8,7 +8,7 @@ * * Handle the various video renderer modules. * - * Version: @(#)ui_vidapi.c 1.0.3 2018/09/26 + * Version: @(#)ui_vidapi.c 1.0.4 2018/11/20 * * Author: Fred N. van Kempen, * @@ -74,16 +74,13 @@ vidapi_available(int api) int vidapi_from_internal_name(const char *name) { - int i = 0; + int i; if (!strcasecmp(name, "default") || !strcasecmp(name, "system")) return(0); - while(plat_vidapis[i] != NULL) { - if (! strcasecmp(plat_vidapis[i]->name, name)) return(i); - - i++; - } + for (i = 0; plat_vidapis[i] != NULL; i++) + if (! strcasecmp(plat_vidapis[i]->internal_name, name)) return(i); /* Default value. */ return(0); @@ -92,10 +89,23 @@ vidapi_from_internal_name(const char *name) /* Return the VIDAPI name for the given number. */ const char * -vidapi_internal_name(int api) +vidapi_get_internal_name(int api) { const char *name = "default"; + if (plat_vidapis[api] != NULL) + return(plat_vidapis[api]->internal_name); + + return(name); +} + + +/* Return the VIDAPI dpslay name for the given number. */ +const char * +vidapi_getname(int api) +{ + const char *name = NULL; + if (plat_vidapis[api] != NULL) return(plat_vidapis[api]->name); diff --git a/src/vnc.c b/src/vnc.c index 0de3a44..8c689d3 100644 --- a/src/vnc.c +++ b/src/vnc.c @@ -10,7 +10,7 @@ * * TODO: Implement screenshots, and Audio Redirection. * - * Version: @(#)vnc.c 1.0.7 2018/10/05 + * Version: @(#)vnc.c 1.0.8 2018/11/20 * * Author: Fred N. van Kempen, * Based on raw code by RichardG, @@ -427,13 +427,17 @@ vnc_available(void) void *handle; handle = dynld_module(PATH_VNC_DLL, NULL); - if (handle != NULL) return(1); + if (handle != NULL) { + dynld_close(handle); + return(1); + } return(0); } const vidapi_t vnc_vidapi = { + "vnc", "VNC", 0, vnc_init, diff --git a/src/win/win.c b/src/win/win.c index e9d507c..5b8ca93 100644 --- a/src/win/win.c +++ b/src/win/win.c @@ -8,7 +8,7 @@ * * Platform main support module for Windows. * - * Version: @(#)win.c 1.0.24 2018/10/24 + * Version: @(#)win.c 1.0.25 2018/11/20 * * Authors: Fred N. van Kempen, * Miran Grca, @@ -100,9 +100,11 @@ const vidapi_t *plat_vidapis[] = { #ifdef USE_SDL &sdl_vidapi, #endif + #ifdef USE_VNC &vnc_vidapi, #endif + #ifdef USE_RDP &rdp_vidapi, #endif diff --git a/src/win/win_d2d.cpp b/src/win/win_d2d.cpp index b05acf0..2ce0728 100644 --- a/src/win/win_d2d.cpp +++ b/src/win/win_d2d.cpp @@ -8,7 +8,7 @@ * * Rendering module for Microsoft Direct2D. * - * Version: @(#)win_d2d.cpp 1.0.2 2018/10/05 + * Version: @(#)win_d2d.cpp 1.0.3 2018/11/20 * * Authors: Fred N. van Kempen, * David Hrdlicka, @@ -57,19 +57,16 @@ #include "win_d2d.h" -#ifdef USE_D2D - -# if USE_D2D == 2 -# define PATH_D2D_DLL "d2d1.dll" -# define DLLFUNC(x) D2D1_ ## x +#if USE_D2D == 2 +# define PATH_D2D_DLL "d2d1.dll" +# define DLLFUNC(x) D2D1_ ## x /* Pointers to the real functions. */ -static bool (*D2D1_CreateFactory)( - D2D1_FACTORY_TYPE factoryType, - REFIID riid, - CONST D2D1_FACTORY_OPTIONS *pFactoryOptions, - void **ppIFactory); +static bool (*D2D1_CreateFactory)(D2D1_FACTORY_TYPE facType, + REFIID riid, + CONST D2D1_FACTORY_OPTIONS *pFacOptions, + void **ppIFactory); static const dllimp_t d2d_imports[] = { { "D2D1CreateFactory", &D2D1_CreateFactory }, @@ -77,9 +74,8 @@ static const dllimp_t d2d_imports[] = { }; static void *d2d_handle = NULL; -# else -# define DLLFUNC(x) D2D1 ## x -# endif +#else +# define DLLFUNC(x) D2D1 ## x #endif @@ -209,16 +205,13 @@ d2d_blit(int x, int y, int y1, int y2, int w, int h) hr = d2d_hwndRT->CreateCompatibleRenderTarget( D2D1::SizeF((float)w, (float)h), &d2d_btmpRT); - if (SUCCEEDED(hr)) { - d2d_width = w; - d2d_height = h; - } } else { hr = d2d_hwndRT->Resize(D2D1::SizeU(w, h)); - if (SUCCEEDED(hr)) { - d2d_width = w; - d2d_height = h; - } + } + + if (SUCCEEDED(hr)) { + d2d_width = w; + d2d_height = h; } } @@ -231,31 +224,33 @@ d2d_blit(int x, int y, int y1, int y2, int w, int h) srcdata = mem_alloc(h * w * 4); for (yy = y1; yy < y2; yy++) { if ((y + yy) >= 0 && (y + yy) < buffer32->h) { -#if 0 if (vid_grayscale || invert_display) video_transform_copy( - (uint32_t *) &(((uint8_t *)srcdata)[yy * w * 4]), + (uint32_t *)&(((uint8_t *)srcdata)[yy * w * 4]), &(((uint32_t *)buffer32->line[y + yy])[x]), w); else -#endif memcpy( - (uint32_t *) &(((uint8_t *)srcdata)[yy * w * 4]), + (uint32_t *)&(((uint8_t *)srcdata)[yy * w * 4]), &(((uint32_t *)buffer32->line[y + yy])[x]), w * 4); } } - video_blit_complete(); rectU = D2D1::RectU(0, 0, w, h); hr = d2d_bitmap->CopyFromMemory(&rectU, srcdata, w * 4); - // In fullscreen mode we first draw offscreen to an intermediate - // BitmapRenderTarget, which then gets rendered to the actual - // HwndRenderTarget in order to implement different scaling modes - // In windowed mode we draw directly to the HwndRenderTarget + + /* + * In fullscreen mode we first draw offscreen to an intermediate + * BitmapRenderTarget, which then gets rendered to the actual + * HwndRenderTarget in order to implement different scaling modes. + * + * In windowed mode we draw directly to the HwndRenderTarget. + */ if (SUCCEEDED(hr)) { - RT = d2d_fs ? (ID2D1RenderTarget *) d2d_btmpRT : (ID2D1RenderTarget *) d2d_hwndRT; + RT = d2d_fs ? (ID2D1RenderTarget *)d2d_btmpRT + : (ID2D1RenderTarget *)d2d_hwndRT; RT->BeginDraw(); RT->DrawBitmap(d2d_bitmap, D2D1::RectF(0, (float)y1, (float)w, (float)y2), @@ -268,15 +263,20 @@ d2d_blit(int x, int y, int y1, int y2, int w, int h) if (d2d_fs) { if (SUCCEEDED(hr)) hr = d2d_btmpRT->GetBitmap(&fs_bitmap); + if (SUCCEEDED(hr)) { d2d_stretch(&fs_w, &fs_h, &fs_x, &fs_y); + d2d_hwndRT->BeginDraw(); + d2d_hwndRT->Clear(D2D1::ColorF(D2D1::ColorF::Black)); + d2d_hwndRT->DrawBitmap(fs_bitmap, D2D1::RectF(fs_x, fs_y, fs_x + fs_w, fs_y + fs_h), 1.0f, D2D1_BITMAP_INTERPOLATION_MODE_LINEAR, D2D1::RectF(0, 0, (float)w, (float)h)); + hr = d2d_hwndRT->EndDraw(); } } @@ -309,10 +309,12 @@ d2d_close(void) d2d_hwndRT->Release(); d2d_hwndRT = NULL; } + if (d2d_factory) { d2d_factory->Release(); d2d_factory = NULL; } + if (d2d_hwnd) { hwndMain = old_hwndMain; plat_set_input(hwndMain); @@ -321,7 +323,7 @@ d2d_close(void) old_hwndMain = NULL; } -#if defined(USE_D2D) && USE_D2D == 2 +#if USE_D2D == 2 /* Quit and unload the DLL if possible. */ if (d2d_handle != NULL) { dynld_close(d2d_handle); @@ -342,7 +344,7 @@ d2d_init(int fs) cgapal_rebuild(); -#if defined(USE_D2D) && USE_D2D == 2 +#if USE_D2D == 2 /* Try loading the DLL. */ d2d_handle = dynld_module(PATH_D2D_DLL, d2d_imports); if (d2d_handle == NULL) { @@ -436,8 +438,25 @@ d2d_screenshot(const wchar_t *fn) } +/* See if this module is available or not. */ +static int +d2d_available(void) +{ + void *handle; + + handle = dynld_module(PATH_D2D_DLL, NULL); + if (handle != NULL) { + dynld_close(handle); + return(1); + } + + return(0); +} + + const vidapi_t d2d_vidapi = { - "D2D", + "d2d", + "Direct 2D", 1, d2d_init, d2d_close, @@ -445,5 +464,5 @@ const vidapi_t d2d_vidapi = { NULL, NULL, d2d_screenshot, - NULL + d2d_available }; diff --git a/src/win/win_d3d.cpp b/src/win/win_d3d.cpp index 42c1664..ff74757 100644 --- a/src/win/win_d3d.cpp +++ b/src/win/win_d3d.cpp @@ -8,7 +8,7 @@ * * Rendering module for Microsoft Direct3D 9. * - * Version: @(#)win_d3d.cpp 1.0.12 2018/10/05 + * Version: @(#)win_d3d.cpp 1.0.13 2018/11/20 * * Authors: Fred N. van Kempen, * Miran Grca, @@ -623,7 +623,8 @@ d3d_screenshot(const wchar_t *fn) const vidapi_t d3d_vidapi = { - "D3D", + "d3d", + "DirectDraw 3D", 1, d3d_init, d3d_close, diff --git a/src/win/win_ddraw.cpp b/src/win/win_ddraw.cpp index d445d76..1a64aa9 100644 --- a/src/win/win_ddraw.cpp +++ b/src/win/win_ddraw.cpp @@ -760,7 +760,8 @@ ddraw_screenshot(const wchar_t *fn) const vidapi_t ddraw_vidapi = { - "DDraw", + "ddraw", + "DirectDraw 9+", 1, ddraw_init, ddraw_close, diff --git a/src/win/win_sdl.c b/src/win/win_sdl.c index 1f3fc49..3a4e79a 100644 --- a/src/win/win_sdl.c +++ b/src/win/win_sdl.c @@ -12,7 +12,7 @@ * we will not use that, but, instead, use a new window which * coverrs the entire desktop. * - * Version: @(#)win_sdl.c 1.0.6 2018/10/21 + * Version: @(#)win_sdl.c 1.0.7 2018/11/20 * * Authors: Fred N. van Kempen, * Michael Drüing, @@ -512,7 +512,8 @@ sdl_available(void) const vidapi_t sdl_vidapi = { - "SDL", + "sdl", + "SDL2", 1, sdl_init, sdl_close, diff --git a/src/win/win_ui.c b/src/win/win_ui.c index 201ee6d..0ec4626 100644 --- a/src/win/win_ui.c +++ b/src/win/win_ui.c @@ -8,7 +8,7 @@ * * Implement the user Interface module. * - * Version: @(#)win_ui.c 1.0.32 2018/10/25 + * Version: @(#)win_ui.c 1.0.33 2018/11/20 * * Authors: Fred N. van Kempen, * Miran Grca, @@ -816,7 +816,8 @@ again: * to the system default one instead. */ swprintf(title, sizeof_w(title), - get_string(IDS_ERR_NORENDR), vidapi_internal_name(vid_api)); + get_string(IDS_ERR_NORENDR), + vidapi_get_internal_name(vid_api)); if (ui_msgbox(MBX_CONFIG, title) != 0) { /* Nope, they don't, so just exit. */ return(5);