Serial Passthrough

This commit is contained in:
Jasmine Iwanek
2023-02-14 20:37:58 -05:00
parent 16b9a5d3e0
commit f643391975
52 changed files with 1622 additions and 95 deletions

View File

@@ -19,11 +19,14 @@
* Copyright 2017-2020 Fred N. van Kempen. * Copyright 2017-2020 Fred N. van Kempen.
* Copyright 2021 Laci bá' * Copyright 2021 Laci bá'
* Copyright 2021 dob205 * Copyright 2021 dob205
* Copyright 2021 Andreas J. Reichel.
* Copyright 2021-2022 Jasmine Iwanek.
*/ */
#include <inttypes.h> #include <inttypes.h>
#include <stdarg.h> #include <stdarg.h>
#include <stdio.h> #include <stdio.h>
#include <stdint.h> #include <stdint.h>
#include <stdbool.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <time.h> #include <time.h>
@@ -68,6 +71,7 @@
#include <86box/isartc.h> #include <86box/isartc.h>
#include <86box/lpt.h> #include <86box/lpt.h>
#include <86box/serial.h> #include <86box/serial.h>
#include <86box/serial_passthrough.h>
#include <86box/keyboard.h> #include <86box/keyboard.h>
#include <86box/mouse.h> #include <86box/mouse.h>
#include <86box/gameport.h> #include <86box/gameport.h>
@@ -162,6 +166,7 @@ int video_filter_method = 1; /* (C) video */
int video_vsync = 0; /* (C) video */ int video_vsync = 0; /* (C) video */
int video_framerate = -1; /* (C) video */ int video_framerate = -1; /* (C) video */
char video_shader[512] = { '\0' }; /* (C) video */ char video_shader[512] = { '\0' }; /* (C) video */
bool serial_passthrough_enabled[SERIAL_MAX] = { 0, 0, 0, 0 }; /* (C) activation and kind of pass-through for serial ports */
int bugger_enabled = 0; /* (C) enable ISAbugger */ int bugger_enabled = 0; /* (C) enable ISAbugger */
int postcard_enabled = 0; /* (C) enable POST card */ int postcard_enabled = 0; /* (C) enable POST card */
int isamem_type[ISAMEM_MAX] = { 0, 0, 0, 0 }; /* (C) enable ISA mem cards */ int isamem_type[ISAMEM_MAX] = { 0, 0, 0, 0 }; /* (C) enable ISA mem cards */
@@ -1038,6 +1043,7 @@ pc_reset_hard_init(void)
/* Reset and reconfigure the serial ports. */ /* Reset and reconfigure the serial ports. */
serial_standalone_init(); serial_standalone_init();
serial_passthrough_init();
/* Reset and reconfigure the Sound Card layer. */ /* Reset and reconfigure the Sound Card layer. */
sound_card_reset(); sound_card_reset();

View File

@@ -20,6 +20,8 @@
* Copyright 2016-2019 Miran Grca. * Copyright 2016-2019 Miran Grca.
* Copyright 2017-2019 Fred N. van Kempen. * Copyright 2017-2019 Fred N. van Kempen.
* Copyright 2018-2019 David Hrdlička. * Copyright 2018-2019 David Hrdlička.
* Copyright 2021 Andreas J. Reichel.
* Copyright 2021-2022 Jasmine Iwanek.
* *
* NOTE: Forcing config files to be in Unicode encoding breaks * NOTE: Forcing config files to be in Unicode encoding breaks
* it on Windows XP, and possibly also Vista. Use the * it on Windows XP, and possibly also Vista. Use the
@@ -54,6 +56,8 @@
#include <86box/fdc.h> #include <86box/fdc.h>
#include <86box/fdc_ext.h> #include <86box/fdc_ext.h>
#include <86box/gameport.h> #include <86box/gameport.h>
#include <86box/serial.h>
#include <86box/serial_passthrough.h>
#include <86box/machine.h> #include <86box/machine.h>
#include <86box/mouse.h> #include <86box/mouse.h>
#include <86box/thread.h> #include <86box/thread.h>
@@ -81,6 +85,7 @@ static ini_t config;
static int backwards_compat = 0; static int backwards_compat = 0;
static int backwards_compat2 = 0; static int backwards_compat2 = 0;
#define ENABLE_CONFIG_LOG 1
#ifdef ENABLE_CONFIG_LOG #ifdef ENABLE_CONFIG_LOG
int config_do_log = ENABLE_CONFIG_LOG; int config_do_log = ENABLE_CONFIG_LOG;
@@ -834,6 +839,8 @@ load_ports(void)
char temp[512]; char temp[512];
int c, d; int c, d;
memset(temp, 0, sizeof(temp));
for (c = 0; c < SERIAL_MAX; c++) { for (c = 0; c < SERIAL_MAX; c++) {
sprintf(temp, "serial%d_enabled", c + 1); sprintf(temp, "serial%d_enabled", c + 1);
com_ports[c].enabled = !!ini_section_get_int(cat, temp, (c >= 2) ? 0 : 1); com_ports[c].enabled = !!ini_section_get_int(cat, temp, (c >= 2) ? 0 : 1);
@@ -843,6 +850,12 @@ load_ports(void)
p = (char *) ini_section_get_string(cat, temp, "none"); p = (char *) ini_section_get_string(cat, temp, "none");
com_ports[c].device = com_device_get_from_internal_name(p); com_ports[c].device = com_device_get_from_internal_name(p);
*/ */
sprintf(temp, "serial%d_passthrough_enabled", c + 1);
serial_passthrough_enabled[c] = !!ini_section_get_int(cat, temp, 0);
if (serial_passthrough_enabled[c])
config_log("Serial Port %d: passthrough enabled.\n\n", c+1);
} }
for (c = 0; c < PARALLEL_MAX; c++) { for (c = 0; c < PARALLEL_MAX; c++) {
@@ -2458,6 +2471,12 @@ save_ports(void)
ini_section_set_string(cat, temp, ini_section_set_string(cat, temp,
(char *) com_device_get_internal_name(com_ports[c].device)); (char *) com_device_get_internal_name(com_ports[c].device));
*/ */
if (com_ports[c].enabled)
if (serial_passthrough_enabled[c]) {
sprintf(temp, "serial%d_passthrough_enabled", c + 1);
ini_section_set_int(cat, temp, 1);
}
} }
for (c = 0; c < PARALLEL_MAX; c++) { for (c = 0; c < PARALLEL_MAX; c++) {

View File

@@ -18,6 +18,8 @@
* Copyright 2017-2019 Fred N. van Kempen. * Copyright 2017-2019 Fred N. van Kempen.
* Copyright 2016-2019 Miran Grca. * Copyright 2016-2019 Miran Grca.
* Copyright 2008-2019 Sarah Walker. * Copyright 2008-2019 Sarah Walker.
* Copyright 2021 Andreas J. Reichel.
* Copyright 2021-2022 Jasmine Iwanek.
* *
* This program is free software; you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by
@@ -91,6 +93,7 @@ device_set_context(device_context_t *c, const device_t *d, int inst)
memset(c, 0, sizeof(device_context_t)); memset(c, 0, sizeof(device_context_t));
c->dev = d; c->dev = d;
c->instance = inst;
if (inst) { if (inst) {
sprintf(c->name, "%s #%i", d->name, inst); sprintf(c->name, "%s #%i", d->name, inst);
@@ -556,6 +559,12 @@ device_force_redraw(void)
} }
} }
const int
device_get_instance(void)
{
return device_current.instance;
}
const char * const char *
device_get_config_string(const char *s) device_get_config_string(const char *s)
{ {

View File

@@ -11,13 +11,16 @@
# Authors: David Hrdlička, <hrdlickadavid@outlook.com> # Authors: David Hrdlička, <hrdlickadavid@outlook.com>
# #
# Copyright 2020-2021 David Hrdlička. # Copyright 2020-2021 David Hrdlička.
# Copyright 2021 Andreas J. Reichel.
# Copyright 2021-2022 Jasmine Iwanek.
# #
add_library(dev OBJECT bugger.c cassette.c cartridge.c hasp.c hwm.c hwm_lm75.c hwm_lm78.c hwm_gl518sm.c add_library(dev OBJECT bugger.c cassette.c cartridge.c hasp.c hwm.c hwm_lm75.c hwm_lm78.c hwm_gl518sm.c
hwm_vt82c686.c ibm_5161.c isamem.c isartc.c ../lpt.c pci_bridge.c hwm_vt82c686.c ibm_5161.c isamem.c isartc.c ../lpt.c pci_bridge.c
postcard.c serial.c clock_ics9xxx.c isapnp.c i2c.c i2c_gpio.c postcard.c serial.c clock_ics9xxx.c isapnp.c i2c.c i2c_gpio.c
smbus_piix4.c smbus_ali7101.c keyboard.c keyboard_xt.c keyboard_at.c smbus_piix4.c smbus_ali7101.c keyboard.c keyboard_xt.c keyboard_at.c
mouse.c mouse_bus.c mouse_serial.c mouse_ps2.c phoenix_486_jumper.c) mouse.c mouse_bus.c mouse_serial.c mouse_ps2.c phoenix_486_jumper.c
serial_passthrough.c)
if(ISAMEM_RAMPAGE) if(ISAMEM_RAMPAGE)
target_compile_definitions(dev PRIVATE USE_ISAMEM_RAMPAGE) target_compile_definitions(dev PRIVATE USE_ISAMEM_RAMPAGE)

View File

@@ -93,6 +93,8 @@ serial_transmit_period(serial_t *dev)
/* Bit period based on DLAB. */ /* Bit period based on DLAB. */
dev->transmit_period = (16000000.0 * ddlab) / dev->clock_src; dev->transmit_period = (16000000.0 * ddlab) / dev->clock_src;
if (dev->sd && dev->sd->transmit_period_callback)
dev->sd->transmit_period_callback(dev, dev->sd->priv, dev->transmit_period);
} }
void void
@@ -161,7 +163,7 @@ write_fifo(serial_t *dev, uint8_t dat)
dev->lsr |= 0x01; dev->lsr |= 0x01;
dev->int_status |= SERIAL_INT_RECEIVE; dev->int_status |= SERIAL_INT_RECEIVE;
} }
if (dev->rcvr_fifo_pos < 15) if (dev->rcvr_fifo_pos < (dev->rcvr_fifo_len - 1))
dev->rcvr_fifo_pos++; dev->rcvr_fifo_pos++;
else else
dev->rcvr_fifo_full = 1; dev->rcvr_fifo_full = 1;
@@ -175,6 +177,8 @@ write_fifo(serial_t *dev, uint8_t dat)
dev->dat = dat; dev->dat = dat;
dev->lsr |= 0x01; dev->lsr |= 0x01;
dev->int_status |= SERIAL_INT_RECEIVE; dev->int_status |= SERIAL_INT_RECEIVE;
if (dev->lsr & 0x02)
dev->int_status |= SERIAL_INT_LSR;
serial_update_ints(dev); serial_update_ints(dev);
} }
} }
@@ -311,6 +315,22 @@ serial_timeout_timer(void *priv)
serial_update_ints(dev); serial_update_ints(dev);
} }
void
serial_device_timeout(void *priv)
{
serial_t *dev = (serial_t *) priv;
#ifdef ENABLE_SERIAL_LOG
serial_log("serial_device_timeout()\n");
#endif
if (!dev->fifo_enabled) {
dev->lsr |= 0x10;
dev->int_status |= SERIAL_INT_LSR;
serial_update_ints(dev);
}
}
static void static void
serial_update_speed(serial_t *dev) serial_update_speed(serial_t *dev)
{ {
@@ -331,6 +351,63 @@ serial_reset_fifo(serial_t *dev)
dev->rcvr_fifo_full = 0; dev->rcvr_fifo_full = 0;
} }
void
serial_set_dsr(serial_t *dev, uint8_t enabled)
{
if (dev->mctrl & 0x10)
return;
dev->msr &= ~0x2;
dev->msr |= !!((dev->msr & 0x20) ^ (enabled << 5)) << 1;
dev->msr &= ~0x20;
dev->msr |= (!!enabled) << 5;
dev->msr_set &= ~0x20;
dev->msr_set |= (!!enabled) << 5;
if (dev->msr & 0x2) {
dev->int_status |= SERIAL_INT_MSR;
serial_update_ints(dev);
}
}
void
serial_set_cts(serial_t *dev, uint8_t enabled)
{
if (dev->mctrl & 0x10)
return;
dev->msr &= ~0x1;
dev->msr |= !!((dev->msr & 0x10) ^ (enabled << 4));
dev->msr &= ~0x10;
dev->msr |= (!!enabled) << 4;
dev->msr_set &= ~0x10;
dev->msr_set |= (!!enabled) << 4;
if (dev->msr & 0x1) {
dev->int_status |= SERIAL_INT_MSR;
serial_update_ints(dev);
}
}
void
serial_set_dcd(serial_t *dev, uint8_t enabled)
{
if (dev->mctrl & 0x10)
return;
dev->msr &= ~0x8;
dev->msr |= !!((dev->msr & 0x80) ^ (enabled << 7));
dev->msr &= ~0x80;
dev->msr |= (!!enabled) << 7;
dev->msr_set &= ~0x80;
dev->msr_set |= (!!enabled) << 7;
if (dev->msr & 0x8) {
dev->int_status |= SERIAL_INT_MSR;
serial_update_ints(dev);
}
}
void void
serial_set_clock_src(serial_t *dev, double clock_src) serial_set_clock_src(serial_t *dev, double clock_src)
{ {
@@ -431,7 +508,7 @@ serial_write(uint16_t addr, uint8_t val, void *p)
case 3: case 3:
old = dev->lcr; old = dev->lcr;
dev->lcr = val; dev->lcr = val;
if ((old ^ val) & 0x0f) { if ((old ^ val) & 0x3f) {
/* Data bits + start bit. */ /* Data bits + start bit. */
dev->bits = ((dev->lcr & 0x03) + 5) + 1; dev->bits = ((dev->lcr & 0x03) + 5) + 1;
/* Stop bits. */ /* Stop bits. */
@@ -444,11 +521,14 @@ serial_write(uint16_t addr, uint8_t val, void *p)
serial_transmit_period(dev); serial_transmit_period(dev);
serial_update_speed(dev); serial_update_speed(dev);
if (dev->sd && dev->sd->lcr_callback)
dev->sd->lcr_callback(dev, dev->sd->priv, dev->lcr);
} }
break; break;
case 4: case 4:
if ((val & 2) && !(dev->mctrl & 2)) { if ((val & 2) && !(dev->mctrl & 2)) {
if (dev->sd->rcr_callback) if (dev->sd && dev->sd->rcr_callback)
dev->sd->rcr_callback(dev, dev->sd->priv); dev->sd->rcr_callback(dev, dev->sd->priv);
} }
if (!(val & 8) && (dev->mctrl & 8)) if (!(val & 8) && (dev->mctrl & 8))
@@ -487,7 +567,7 @@ serial_write(uint16_t addr, uint8_t val, void *p)
serial_update_ints(dev); serial_update_ints(dev);
break; break;
case 6: case 6:
dev->msr = val; dev->msr = (val & 0xF0) | (dev->msr & 0x0F);
if (dev->msr & 0x0f) if (dev->msr & 0x0f)
dev->int_status |= SERIAL_INT_MSR; dev->int_status |= SERIAL_INT_MSR;
serial_update_ints(dev); serial_update_ints(dev);
@@ -521,11 +601,15 @@ serial_read(uint16_t addr, void *p)
ret = dev->rcvr_fifo[0]; ret = dev->rcvr_fifo[0];
dev->rcvr_fifo_full = 0; dev->rcvr_fifo_full = 0;
if (dev->rcvr_fifo_pos > 0) {
for (i = 1; i < 16; i++) for (i = 1; i < 16; i++)
dev->rcvr_fifo[i - 1] = dev->rcvr_fifo[i]; dev->rcvr_fifo[i - 1] = dev->rcvr_fifo[i];
serial_log("FIFO position %i: read %02X, next %02X\n", dev->rcvr_fifo_pos, ret, dev->rcvr_fifo[0]);
dev->rcvr_fifo_pos--; dev->rcvr_fifo_pos--;
if (dev->rcvr_fifo_pos > 0) {
serial_log("FIFO position %i: read %02X, next %02X\n", dev->rcvr_fifo_pos, ret, dev->rcvr_fifo[0]);
/* At least one byte remains to be read, start the timeout /* At least one byte remains to be read, start the timeout
timer so that a timeout is indicated in case of no read. */ timer so that a timeout is indicated in case of no read. */
timer_on_auto(&dev->timeout_timer, 4.0 * dev->bits * dev->transmit_period); timer_on_auto(&dev->timeout_timer, 4.0 * dev->bits * dev->transmit_period);
@@ -571,7 +655,7 @@ serial_read(uint16_t addr, void *p)
serial_update_ints(dev); serial_update_ints(dev);
break; break;
case 6: case 6:
ret = dev->msr; ret = dev->msr | dev->msr_set;
dev->msr &= ~0x0f; dev->msr &= ~0x0f;
dev->int_status &= ~SERIAL_INT_MSR; dev->int_status &= ~SERIAL_INT_MSR;
serial_update_ints(dev); serial_update_ints(dev);
@@ -632,6 +716,27 @@ serial_attach(int port,
sd->rcr_callback = rcr_callback; sd->rcr_callback = rcr_callback;
sd->dev_write = dev_write; sd->dev_write = dev_write;
sd->transmit_period_callback = NULL;
sd->lcr_callback = NULL;
sd->priv = priv;
return sd->serial;
}
serial_t *
serial_attach_ex(int port,
void (*rcr_callback)(struct serial_s *serial, void *p),
void (*dev_write)(struct serial_s *serial, void *p, uint8_t data),
void (*transmit_period_callback)(struct serial_s *serial, void *p, double transmit_period),
void (*lcr_callback)(struct serial_s *serial, void *p, uint8_t data_bits),
void *priv)
{
serial_device_t *sd = &serial_devices[port];
sd->rcr_callback = rcr_callback;
sd->dev_write = dev_write;
sd->transmit_period_callback = transmit_period_callback;
sd->lcr_callback = lcr_callback;
sd->priv = priv; sd->priv = priv;
return sd->serial; return sd->serial;

View File

@@ -0,0 +1,357 @@
/*
* 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 Serial passthrough device.
*
*
* Authors: Andreas J. Reichel <webmaster@6th-dimension.com>,
* Jasmine Iwanek <jasmine@iwanek.co.uk>
*
* Copyright 2021 Andreas J. Reichel.
* Copyright 2021-2022 Jasmine Iwanek.
*/
#include <stdarg.h>
#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include <stdlib.h>
#include <wchar.h>
#define HAVE_STDARG_H
#include <86box/86box.h>
#include <86box/device.h>
#include <86box/timer.h>
#include <86box/serial.h>
#include <86box/serial_passthrough.h>
#include <86box/plat_serial_passthrough.h>
#define ENABLE_SERIAL_PASSTHROUGH_LOG 1
#ifdef ENABLE_SERIAL_PASSTHROUGH_LOG
int serial_passthrough_do_log = ENABLE_SERIAL_PASSTHROUGH_LOG;
static void
serial_passthrough_log(const char *fmt, ...)
{
va_list ap;
if (serial_passthrough_do_log) {
va_start(ap, fmt);
pclog_ex(fmt, ap);
va_end(ap);
}
}
#else
# define serial_passthrough_log(fmt, ...)
#endif
void
serial_passthrough_init(void)
{
int c;
for (c = 0; c < SERIAL_MAX; c++) {
if (serial_passthrough_enabled[c]) {
/* Instance n for COM n */
device_add_inst(&serial_passthrough_device, c + 1);
}
}
}
static void
serial_passthrough_timers_off(serial_passthrough_t *dev)
{
timer_stop(&dev->host_to_serial_timer);
}
static void
serial_passthrough_write(serial_t *s, void *priv, uint8_t val)
{
plat_serpt_write(priv, val);
}
static void
host_to_serial_cb(void *priv)
{
serial_passthrough_t *dev = (serial_passthrough_t *) priv;
uint8_t byte;
/* write_fifo has no failure indication, but if we write to fast, the host
* can never fetch the bytes in time, so check if the fifo is full if in
* fifo mode or if lsr has bit 0 set if not in fifo mode */
if ((dev->serial->type >= SERIAL_16550) && dev->serial->fifo_enabled) {
if (dev->serial->rcvr_fifo_full) {
goto no_write_to_machine;
}
} else {
if (dev->serial->lsr & 1) {
goto no_write_to_machine;
}
}
if (plat_serpt_read(dev, &byte)) {
// printf("got byte %02X\n", byte);
serial_write_fifo(dev->serial, byte);
// serial_set_dsr(dev->serial, 1);
}
no_write_to_machine:
// serial_device_timeout(dev->serial);
timer_on_auto(&dev->host_to_serial_timer, (1000000.0 / dev->baudrate) * (double) dev->bits);
}
static void
serial_passthrough_rcr_cb(struct serial_s *serial, void *priv)
{
serial_passthrough_t *dev = (serial_passthrough_t *) priv;
timer_stop(&dev->host_to_serial_timer);
/* FIXME: do something to dev->baudrate */
timer_on_auto(&dev->host_to_serial_timer, (1000000.0 / dev->baudrate) * (double) dev->bits);
// serial_clear_fifo(dev->serial);
}
static void
serial_passthrough_speed_changed(void *priv)
{
serial_passthrough_t *dev = (serial_passthrough_t *) priv;
timer_stop(&dev->host_to_serial_timer);
/* FIXME: do something to dev->baudrate */
timer_on_auto(&dev->host_to_serial_timer, (1000000.0 / dev->baudrate) * (double) dev->bits);
// serial_clear_fifo(dev->serial);
}
static void
serial_passthrough_dev_close(void *priv)
{
serial_passthrough_t *dev = (serial_passthrough_t *) priv;
/* Detach passthrough device from COM port */
if (dev && dev->serial && dev->serial->sd)
memset(dev->serial->sd, 0, sizeof(serial_device_t));
plat_serpt_close(dev);
free(dev);
}
void
serial_passthrough_transmit_period(serial_t *serial, void *p, double transmit_period)
{
serial_passthrough_t *dev = (serial_passthrough_t *) p;
if (dev->mode != SERPT_MODE_HOSTSER)
return;
dev->baudrate = 1000000.0 / (transmit_period);
serial_passthrough_speed_changed(p);
plat_serpt_set_params(dev);
}
void
serial_passthrough_lcr_callback(serial_t *serial, void *p, uint8_t lcr)
{
serial_passthrough_t *dev = (serial_passthrough_t *) p;
if (dev->mode != SERPT_MODE_HOSTSER)
return;
dev->bits = serial->bits;
dev->data_bits = ((lcr & 0x03) + 5);
serial_passthrough_speed_changed(p);
plat_serpt_set_params(dev);
}
/* Initialize the device for use by the user. */
static void *
serial_passthrough_dev_init(const device_t *info)
{
serial_passthrough_t *dev;
dev = (serial_passthrough_t *) malloc(sizeof(serial_passthrough_t));
memset(dev, 0, sizeof(serial_passthrough_t));
dev->mode = device_get_config_int("mode");
dev->port = device_get_instance() - 1;
dev->baudrate = device_get_config_int("baudrate");
dev->data_bits = device_get_config_int("data_bits");
/* Attach passthrough device to a COM port */
dev->serial = serial_attach_ex(dev->port, serial_passthrough_rcr_cb,
serial_passthrough_write, serial_passthrough_transmit_period, serial_passthrough_lcr_callback, dev);
strncpy(dev->host_serial_path, device_get_config_string("host_serial_path"), 1024);
serial_passthrough_log("%s: port=COM%d\n", info->name, dev->port + 1);
serial_passthrough_log("%s: baud=%f\n", info->name, dev->baudrate);
serial_passthrough_log("%s: mode=%s\n", info->name, serpt_mode_names[dev->mode]);
if (plat_serpt_open_device(dev)) {
serial_passthrough_log("%s: not running\n", info->name);
return NULL;
}
serial_passthrough_log("%s: running\n", info->name);
memset(&dev->host_to_serial_timer, 0, sizeof(pc_timer_t));
timer_add(&dev->host_to_serial_timer, host_to_serial_cb, dev, 1);
serial_set_cts(dev->serial, 1);
serial_set_dsr(dev->serial, 1);
serial_set_dcd(dev->serial, 1);
/* 1 start bit + data bits + stop bits (no parity assumed) */
dev->bits = 1 + device_get_config_int("data_bits") + device_get_config_int("stop_bits");
/* Return our private data to the I/O layer. */
return dev;
}
const char *serpt_mode_names[SERPT_MODES_MAX] = {
[SERPT_MODE_VCON] = "vcon",
[SERPT_MODE_TCPSRV] = "tcpsrv",
[SERPT_MODE_TCPCLNT] = "tcpclnt",
[SERPT_MODE_HOSTSER] = "hostser",
};
// clang-format off
static const device_config_t serial_passthrough_config[] = {
{
.name = "mode",
.description = "Passthrough Mode",
.type = CONFIG_SELECTION,
.default_string = "",
.default_int = 0,
.file_filter = "",
.spinner = { 0 },
.selection = {
#ifdef _WIN32
{
.description = "Named Pipe (Server)",
.value = SERPT_MODE_VCON
},
#if 0 /* TODO */
{
.description = "Named Pipe (Client)",
.value = SERPT_MODE_VCON
},
#endif
#else
{
.description = "Pseudo Terminal/Virtual Console",
.value = SERPT_MODE_VCON
},
#endif
#if 0 /* TODO */
{
.description = "TCP Server",
.value = SERPT_MODE_TCPSRV
},
{
.description = "TCP Client",
.value = SERPT_MODE_TCPCLNT
},
#endif
{
.description = "Host Serial Passthrough",
.value = SERPT_MODE_HOSTSER
},
{
.description = ""
}
}
},
{
.name = "host_serial_path",
.description = "Host Serial Device",
.type = CONFIG_SERPORT,
.default_string = "",
.file_filter = NULL,
.spinner = {},
.selection = {}
},
{
.name = "data_bits",
.description = "Data bits",
.type = CONFIG_SELECTION,
.default_string = "8",
.default_int = 8,
.file_filter = NULL,
.spinner = { 0 },
.selection = {
#if 0 /* Mentioned by WFW 3.1x, not supported, atleast on Linux */
{ .description = "4", .value = 4 },
#endif
{ .description = "5", .value = 5 },
{ .description = "6", .value = 6 },
{ .description = "7", .value = 7 },
{ .description = "8", .value = 8 }
}
},
{
.name = "stop_bits",
.description = "Stop bits",
.type = CONFIG_SELECTION,
.default_string = "1",
.default_int = 1,
.file_filter = NULL,
.spinner = { 0 },
.selection = {
{ .description = "1", .value = 1 },
#if 0
{ .description = "1.5", .value = 1.5 },
#endif
{ .description = "2", .value = 2 }
}
},
{
.name = "baudrate",
.description = "Baud Rate of Passthrough",
.type = CONFIG_SELECTION,
.default_string = "",
.default_int = 115200,
.file_filter = NULL,
.spinner = { 0 },
.selection = {
#if 0
{ .description = "256000", .value = 256000 },
{ .description = "128000", .value = 128000 },
#endif
{ .description = "115200", .value = 115200 },
{ .description = "57600", .value = 57600 },
{ .description = "56000", .value = 56000 },
{ .description = "38400", .value = 38400 },
{ .description = "19200", .value = 19200 },
{ .description = "14400", .value = 14400 },
{ .description = "9600", .value = 9600 },
{ .description = "7200", .value = 7200 },
{ .description = "4800", .value = 4800 },
{ .description = "2400", .value = 2400 },
{ .description = "1800", .value = 1800 },
{ .description = "1200", .value = 1200 },
{ .description = "600", .value = 600 },
{ .description = "300", .value = 300 },
{ .description = "150", .value = 150 },
#if 0
{ .description = "134.5", .value = 134.5 },
#endif
{ .description = "110", .value = 110 },
{ .description = "75", .value = 75 }
}
},
{ .name = "", .description = "", .type = CONFIG_END }
};
// clang-format on
const device_t serial_passthrough_device = {
.name = "Serial Passthrough Device",
.flags = 0,
.local = 0,
.init = serial_passthrough_dev_init,
.close = serial_passthrough_dev_close,
.reset = NULL,
{ .poll = NULL },
.speed_changed = serial_passthrough_speed_changed,
.force_redraw = NULL,
.config = serial_passthrough_config
};

View File

@@ -17,6 +17,8 @@
* Copyright 2017-2019 Fred N. van Kempen. * Copyright 2017-2019 Fred N. van Kempen.
* Copyright 2016-2019 Miran Grca. * Copyright 2016-2019 Miran Grca.
* Copyright 2008-2019 Sarah Walker. * Copyright 2008-2019 Sarah Walker.
* Copyright 2021 Andreas J. Reichel.
* Copyright 2021-2022 Jasmine Iwanek.
* *
* This program is free software; you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by
@@ -52,6 +54,7 @@
#define CONFIG_MAC 9 #define CONFIG_MAC 9
#define CONFIG_MIDI_IN 10 #define CONFIG_MIDI_IN 10
#define CONFIG_BIOS 11 #define CONFIG_BIOS 11
#define CONFIG_SERPORT 12
enum { enum {
DEVICE_PCJR = 2, /* requires an IBM PCjr */ DEVICE_PCJR = 2, /* requires an IBM PCjr */
@@ -107,7 +110,7 @@ typedef struct {
int default_int; int default_int;
const char *file_filter; const char *file_filter;
const device_config_spinner_t spinner; const device_config_spinner_t spinner;
const device_config_selection_t selection[16]; const device_config_selection_t selection[32];
const device_config_bios_t bios[32]; const device_config_bios_t bios[32];
} device_config_t; } device_config_t;
@@ -134,6 +137,7 @@ typedef struct _device_ {
typedef struct { typedef struct {
const device_t *dev; const device_t *dev;
char name[2048]; char name[2048];
int instance;
} device_context_t; } device_context_t;
#ifdef __cplusplus #ifdef __cplusplus
@@ -178,6 +182,7 @@ extern void device_set_config_hex16(const char *s, int val);
extern void device_set_config_hex20(const char *s, int val); extern void device_set_config_hex20(const char *s, int val);
extern void device_set_config_mac(const char *s, int val); extern void device_set_config_mac(const char *s, int val);
extern const char *device_get_config_string(const char *name); extern const char *device_get_config_string(const char *name);
extern const int device_get_instance(void);
#define device_get_config_bios device_get_config_string #define device_get_config_bios device_get_config_string
extern char *device_get_internal_name(const device_t *d); extern char *device_get_internal_name(const device_t *d);

View File

@@ -0,0 +1,38 @@
/*
* 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.
*
* Definitions for platform specific serial to host passthrough.
*
*
* Authors: Andreas J. Reichel <webmaster@6th-dimension.com>,
* Jasmine Iwanek <jasmine@iwanek.co.uk>
*
* Copyright 2021 Andreas J. Reichel.
* Copyright 2021-2022 Jasmine Iwanek.
*/
#ifndef PLAT_SERIAL_PASSTHROUGH_H
#define PLAT_SERIAL_PASSTHROUGH_H
#include <stdint.h>
#ifdef __cplusplus
extern "C" {
#endif
extern void plat_serpt_write(void *p, uint8_t data);
extern int plat_serpt_read(void *p, uint8_t *data);
extern int plat_serpt_open_device(void *p);
extern void plat_serpt_close(void *p);
extern void plat_serpt_set_params(void *p);
#ifdef __cplusplus
}
#endif
#endif

View File

@@ -247,6 +247,10 @@
#define IDC_CHECK_PARALLEL2 1089 #define IDC_CHECK_PARALLEL2 1089
#define IDC_CHECK_PARALLEL3 1090 #define IDC_CHECK_PARALLEL3 1090
#define IDC_CHECK_PARALLEL4 1091 #define IDC_CHECK_PARALLEL4 1091
#define IDC_CHECK_SERIAL_PASS1 1092
#define IDC_CHECK_SERIAL_PASS2 1093
#define IDC_CHECK_SERIAL_PASS3 1094
#define IDC_CHECK_SERIAL_PASS4 1095
#define IDC_OTHER_PERIPH 1110 /* storage controllers config */ #define IDC_OTHER_PERIPH 1110 /* storage controllers config */
#define IDC_COMBO_HDC 1111 #define IDC_COMBO_HDC 1111
@@ -364,6 +368,10 @@
#define IDC_CONFIGURE_NET4 1321 #define IDC_CONFIGURE_NET4 1321
#define IDC_CONFIGURE_MIDI_OUT 1322 #define IDC_CONFIGURE_MIDI_OUT 1322
#define IDC_CONFIGURE_MIDI_IN 1323 #define IDC_CONFIGURE_MIDI_IN 1323
#define IDC_CONFIGURE_SERIAL_PASS1 1324
#define IDC_CONFIGURE_SERIAL_PASS2 1325
#define IDC_CONFIGURE_SERIAL_PASS3 1326
#define IDC_CONFIGURE_SERIAL_PASS4 1327
#define IDC_JOY1 1330 #define IDC_JOY1 1330
#define IDC_JOY2 1331 #define IDC_JOY2 1331
#define IDC_JOY3 1332 #define IDC_JOY3 1332

View File

@@ -53,7 +53,7 @@ typedef struct serial_s {
dat, int_status, scratch, fcr, dat, int_status, scratch, fcr,
irq, type, inst, transmit_enabled, irq, type, inst, transmit_enabled,
fifo_enabled, rcvr_fifo_len, bits, data_bits, fifo_enabled, rcvr_fifo_len, bits, data_bits,
baud_cycles, rcvr_fifo_full, txsr, pad; baud_cycles, rcvr_fifo_full, txsr, pad, msr_set;
uint16_t dlab, base_address; uint16_t dlab, base_address;
@@ -70,6 +70,8 @@ typedef struct serial_s {
typedef struct serial_device_s { typedef struct serial_device_s {
void (*rcr_callback)(struct serial_s *serial, void *p); void (*rcr_callback)(struct serial_s *serial, void *p);
void (*dev_write)(struct serial_s *serial, void *p, uint8_t data); void (*dev_write)(struct serial_s *serial, void *p, uint8_t data);
void (*lcr_callback)(struct serial_s *serial, void *p, uint8_t lcr);
void (*transmit_period_callback)(struct serial_s *serial, void *p, double transmit_period);
void *priv; void *priv;
serial_t *serial; serial_t *serial;
} serial_device_t; } serial_device_t;
@@ -84,6 +86,12 @@ extern serial_t *serial_attach(int port,
void (*rcr_callback)(struct serial_s *serial, void *p), void (*rcr_callback)(struct serial_s *serial, void *p),
void (*dev_write)(struct serial_s *serial, void *p, uint8_t data), void (*dev_write)(struct serial_s *serial, void *p, uint8_t data),
void *priv); void *priv);
extern serial_t *serial_attach_ex(int port,
void (*rcr_callback)(struct serial_s *serial, void *p),
void (*dev_write)(struct serial_s *serial, void *p, uint8_t data),
void (*transmit_period_callback)(struct serial_s *serial, void *p, double transmit_period),
void (*lcr_callback)(struct serial_s *serial, void *p, uint8_t data_bits),
void *priv);
extern void serial_remove(serial_t *dev); extern void serial_remove(serial_t *dev);
extern void serial_set_type(serial_t *dev, int type); extern void serial_set_type(serial_t *dev, int type);
extern void serial_setup(serial_t *dev, uint16_t addr, uint8_t irq); extern void serial_setup(serial_t *dev, uint16_t addr, uint8_t irq);
@@ -93,6 +101,11 @@ extern void serial_set_next_inst(int ni);
extern void serial_standalone_init(void); extern void serial_standalone_init(void);
extern void serial_set_clock_src(serial_t *dev, double clock_src); extern void serial_set_clock_src(serial_t *dev, double clock_src);
extern void serial_reset_port(serial_t *dev); extern void serial_reset_port(serial_t *dev);
extern void serial_device_timeout(void *priv);
extern void serial_set_cts(serial_t *dev, uint8_t enabled);
extern void serial_set_dsr(serial_t *dev, uint8_t enabled);
extern void serial_set_dcd(serial_t *dev, uint8_t enabled);
extern const device_t ns8250_device; extern const device_t ns8250_device;
extern const device_t ns8250_pcjr_device; extern const device_t ns8250_pcjr_device;

View File

@@ -0,0 +1,61 @@
/*
* 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.
*
* Definition of Serial passthrough device.
*
*
* Authors: Andreas J. Reichel <webmaster@6th-dimension.com>,
* Jasmine Iwanek <jasmine@iwanek.co.uk>
*
* Copyright 2021 Andreas J. Reichel.
* Copyright 2021-2022 Jasmine Iwanek.
*/
#ifndef SERIAL_PASSTHROUGH_H
#define SERIAL_PASSTHROUGH_H
#include <stdint.h>
#include <stdbool.h>
#include <86box/86box.h>
#include <86box/device.h>
#include <86box/timer.h>
#include <86box/serial.h>
enum serial_passthrough_mode {
SERPT_MODE_VCON, /*Named Pipe (Server) / Pseudo Terminal/Virtual Console */
SERPT_MODE_TCPSRV, /* TCP Server (TODO) */
SERPT_MODE_TCPCLNT, /* TCP Client (TODO) */
SERPT_MODE_HOSTSER, /* Host Serial Passthrough */
SERPT_MODES_MAX,
};
extern const char *serpt_mode_names[SERPT_MODES_MAX];
typedef struct serial_passthrough_s {
enum serial_passthrough_mode mode;
pc_timer_t host_to_serial_timer;
pc_timer_t serial_to_host_timer;
serial_t *serial;
double baudrate;
uint8_t bits, data_bits;
uint8_t port;
uint8_t data;
char slave_pt[32]; /* used for pseudo term name of slave side */
intptr_t master_fd; /* file desc for master pseudo terminal or
* socket or alike */
char host_serial_path[1024]; /* Path to TTY/host serial port on the host */
void *backend_priv; /* Private platform backend data */
} serial_passthrough_t;
extern bool serial_passthrough_enabled[SERIAL_MAX];
extern const device_t serial_passthrough_device;
extern void serial_passthrough_init(void);
#endif

View File

@@ -17,7 +17,7 @@
#define WIN_OPENGL_H #define WIN_OPENGL_H
#define UNICODE #define UNICODE
#include <Windows.h> #include <windows.h>
extern int opengl_init(HWND hwnd); extern int opengl_init(HWND hwnd);
extern int opengl_pause(void); extern int opengl_pause(void);

View File

@@ -9,7 +9,7 @@
#define _DISCORD_GAME_SDK_H_ #define _DISCORD_GAME_SDK_H_
#ifdef _WIN32 #ifdef _WIN32
#include <Windows.h> #include <windows.h>
#include <dxgi.h> #include <dxgi.h>
#endif #endif

View File

@@ -221,6 +221,12 @@ if(WIN32 AND NOT MINGW)
target_sources(plat PRIVATE ../win/win_opendir.c) target_sources(plat PRIVATE ../win/win_opendir.c)
endif() endif()
if(WIN32)
target_sources(plat PRIVATE ../win/win_serial_passthrough.c)
else()
target_sources(plat PRIVATE ../unix/unix_serial_passthrough.c)
endif()
if (APPLE) if (APPLE)
target_sources(ui PRIVATE macos_event_filter.mm) target_sources(ui PRIVATE macos_event_filter.mm)
if(MOLTENVK) if(MOLTENVK)

View File

@@ -27,6 +27,8 @@
#include <QCheckBox> #include <QCheckBox>
#include <QFrame> #include <QFrame>
#include <QLabel> #include <QLabel>
#include <QDir>
#include <QSettings>
extern "C" { extern "C" {
#include <86box/86box.h> #include <86box/86box.h>
@@ -40,6 +42,10 @@ extern "C" {
#include "qt_filefield.hpp" #include "qt_filefield.hpp"
#include "qt_models_common.hpp" #include "qt_models_common.hpp"
#ifdef Q_OS_LINUX
# include <sys/stat.h>
# include <sys/sysmacros.h>
#endif
DeviceConfig::DeviceConfig(QWidget *parent) DeviceConfig::DeviceConfig(QWidget *parent)
: QDialog(parent) : QDialog(parent)
@@ -53,6 +59,40 @@ DeviceConfig::~DeviceConfig()
delete ui; delete ui;
} }
static QStringList
EnumerateSerialDevices()
{
QStringList serialDevices, ttyEntries;
QByteArray devstr(1024, 0);
#ifdef Q_OS_LINUX
QDir class_dir("/sys/class/tty/");
QDir dev_dir("/dev/");
ttyEntries = class_dir.entryList(QDir::Dirs | QDir::NoDotAndDotDot | QDir::System, QDir::SortFlag::Name);
for (int i = 0; i < ttyEntries.size(); i++) {
if (class_dir.exists(ttyEntries[i] + "/device/driver/") && dev_dir.exists(ttyEntries[i])
&& QFileInfo(dev_dir.canonicalPath() + '/' + ttyEntries[i]).isReadable()
&& QFileInfo(dev_dir.canonicalPath() + '/' + ttyEntries[i]).isWritable()) {
serialDevices.push_back("/dev/" + ttyEntries[i]);
}
}
#endif
#ifdef Q_OS_WINDOWS
QSettings comPorts("HKEY_LOCAL_MACHINE\\HARDWARE\\DEVICEMAP\\SERIALCOMM", QSettings::NativeFormat, nullptr);
for (int i = 0; i < comPorts.childKeys().length(); i++) {
serialDevices.push_back(QString("\\\\.\\") + comPorts.value(comPorts.childKeys()[i]).toString());
}
#endif
#ifdef Q_OS_MACOS
QDir dev_dir("/dev/");
dev_dir.setNameFilters({ "tty.*", "cu.*" });
QDir::Filters serial_dev_flags = QDir::Files | QDir::NoSymLinks | QDir::Readable | QDir::Writable | QDir::NoDotAndDotDot | QDir::System;
for (const auto &device : dev_dir.entryInfoList(serial_dev_flags, QDir::SortFlag::Name)) {
serialDevices.push_back(device.canonicalFilePath());
}
#endif
return serialDevices;
}
void void
DeviceConfig::ConfigureDevice(const _device_ *device, int instance, Settings *settings) DeviceConfig::ConfigureDevice(const _device_ *device, int instance, Settings *settings)
{ {
@@ -205,6 +245,27 @@ DeviceConfig::ConfigureDevice(const _device_ *device, int instance, Settings *se
dc.ui->formLayout->addRow(config->description, fileField); dc.ui->formLayout->addRow(config->description, fileField);
break; break;
} }
case CONFIG_SERPORT:
{
auto *cbox = new QComboBox();
cbox->setObjectName(config->name);
auto *model = cbox->model();
int currentIndex = 0;
auto serialDevices = EnumerateSerialDevices();
char *selected = config_get_string(device_context.name, const_cast<char *>(config->name), const_cast<char *>(config->default_string));
Models::AddEntry(model, "None", -1);
for (int i = 0; i < serialDevices.size(); i++) {
int row = Models::AddEntry(model, serialDevices[i], i);
if (selected == serialDevices[i]) {
currentIndex = row;
}
}
dc.ui->formLayout->addRow(config->description, cbox);
cbox->setCurrentIndex(currentIndex);
break;
}
} }
++config; ++config;
} }
@@ -236,6 +297,15 @@ DeviceConfig::ConfigureDevice(const _device_ *device, int instance, Settings *se
config_set_string(device_context.name, const_cast<char *>(config->name), const_cast<char *>(config->bios[idx].internal_name)); config_set_string(device_context.name, const_cast<char *>(config->name), const_cast<char *>(config->bios[idx].internal_name));
break; break;
} }
case CONFIG_SERPORT:
{
auto *cbox = dc.findChild<QComboBox *>(config->name);
auto path = cbox->currentText().toUtf8();
if (path == "None")
path = "";
config_set_string(device_context.name, const_cast<char *>(config->name), path);
break;
}
case CONFIG_HEX16: case CONFIG_HEX16:
{ {
auto *cbox = dc.findChild<QComboBox *>(config->name); auto *cbox = dc.findChild<QComboBox *>(config->name);

View File

@@ -43,7 +43,7 @@ Q_IMPORT_PLUGIN(QWindowsVistaStylePlugin)
# include "qt_winrawinputfilter.hpp" # include "qt_winrawinputfilter.hpp"
# include "qt_winmanagerfilter.hpp" # include "qt_winmanagerfilter.hpp"
# include <86box/win.h> # include <86box/win.h>
# include <Shobjidl.h> # include <shobjidl.h>
#endif #endif
extern "C" { extern "C" {

View File

@@ -27,6 +27,7 @@ extern "C" {
#include <86box/machine.h> #include <86box/machine.h>
#include <86box/lpt.h> #include <86box/lpt.h>
#include <86box/serial.h> #include <86box/serial.h>
#include <86box/serial_passthrough.h>
} }
#include "qt_deviceconfig.hpp" #include "qt_deviceconfig.hpp"
@@ -66,6 +67,15 @@ SettingsPorts::SettingsPorts(QWidget *parent)
auto *checkBox = findChild<QCheckBox *>(QString("checkBoxSerial%1").arg(i + 1)); auto *checkBox = findChild<QCheckBox *>(QString("checkBoxSerial%1").arg(i + 1));
checkBox->setChecked(com_ports[i].enabled > 0); checkBox->setChecked(com_ports[i].enabled > 0);
} }
ui->checkBoxSerialPassThru1->setChecked(serial_passthrough_enabled[0]);
ui->pushButtonSerialPassThru1->setEnabled(serial_passthrough_enabled[0]);
ui->checkBoxSerialPassThru2->setChecked(serial_passthrough_enabled[1]);
ui->pushButtonSerialPassThru2->setEnabled(serial_passthrough_enabled[1]);
ui->checkBoxSerialPassThru3->setChecked(serial_passthrough_enabled[2]);
ui->pushButtonSerialPassThru3->setEnabled(serial_passthrough_enabled[2]);
ui->checkBoxSerialPassThru4->setChecked(serial_passthrough_enabled[3]);
ui->pushButtonSerialPassThru4->setEnabled(serial_passthrough_enabled[3]);
} }
SettingsPorts::~SettingsPorts() SettingsPorts::~SettingsPorts()
@@ -87,6 +97,11 @@ SettingsPorts::save()
auto *checkBox = findChild<QCheckBox *>(QString("checkBoxSerial%1").arg(i + 1)); auto *checkBox = findChild<QCheckBox *>(QString("checkBoxSerial%1").arg(i + 1));
com_ports[i].enabled = checkBox->isChecked() ? 1 : 0; com_ports[i].enabled = checkBox->isChecked() ? 1 : 0;
} }
serial_passthrough_enabled[0] = ui->checkBoxSerialPassThru1->isChecked();
serial_passthrough_enabled[1] = ui->checkBoxSerialPassThru2->isChecked();
serial_passthrough_enabled[2] = ui->checkBoxSerialPassThru3->isChecked();
serial_passthrough_enabled[3] = ui->checkBoxSerialPassThru4->isChecked();
} }
void void
@@ -112,3 +127,51 @@ SettingsPorts::on_checkBoxParallel4_stateChanged(int state)
{ {
ui->comboBoxLpt4->setEnabled(state == Qt::Checked); ui->comboBoxLpt4->setEnabled(state == Qt::Checked);
} }
void
SettingsPorts::on_pushButtonSerialPassThru1_clicked()
{
DeviceConfig::ConfigureDevice(&serial_passthrough_device, 1, qobject_cast<Settings *>(Settings::settings));
}
void
SettingsPorts::on_pushButtonSerialPassThru2_clicked()
{
DeviceConfig::ConfigureDevice(&serial_passthrough_device, 2, qobject_cast<Settings *>(Settings::settings));
}
void
SettingsPorts::on_pushButtonSerialPassThru3_clicked()
{
DeviceConfig::ConfigureDevice(&serial_passthrough_device, 3, qobject_cast<Settings *>(Settings::settings));
}
void
SettingsPorts::on_pushButtonSerialPassThru4_clicked()
{
DeviceConfig::ConfigureDevice(&serial_passthrough_device, 4, qobject_cast<Settings *>(Settings::settings));
}
void
SettingsPorts::on_checkBoxSerialPassThru1_clicked(bool checked)
{
ui->pushButtonSerialPassThru1->setEnabled(checked);
}
void
SettingsPorts::on_checkBoxSerialPassThru2_clicked(bool checked)
{
ui->pushButtonSerialPassThru2->setEnabled(checked);
}
void
SettingsPorts::on_checkBoxSerialPassThru3_clicked(bool checked)
{
ui->pushButtonSerialPassThru3->setEnabled(checked);
}
void
SettingsPorts::on_checkBoxSerialPassThru4_clicked(bool checked)
{
ui->pushButtonSerialPassThru4->setEnabled(checked);
}

View File

@@ -15,6 +15,30 @@ public:
~SettingsPorts(); ~SettingsPorts();
void save(); void save();
private slots:
void on_checkBoxSerialPassThru4_clicked(bool checked);
private slots:
void on_checkBoxSerialPassThru3_clicked(bool checked);
private slots:
void on_checkBoxSerialPassThru2_clicked(bool checked);
private slots:
void on_pushButtonSerialPassThru4_clicked();
private slots:
void on_pushButtonSerialPassThru3_clicked();
private slots:
void on_pushButtonSerialPassThru2_clicked();
private slots:
void on_pushButtonSerialPassThru1_clicked();
private slots:
void on_checkBoxSerialPassThru1_clicked(bool checked);
private slots: private slots:
void on_checkBoxParallel3_stateChanged(int arg1); void on_checkBoxParallel3_stateChanged(int arg1);
void on_checkBoxParallel2_stateChanged(int arg1); void on_checkBoxParallel2_stateChanged(int arg1);

View File

@@ -13,7 +13,7 @@
<property name="windowTitle"> <property name="windowTitle">
<string>Form</string> <string>Form</string>
</property> </property>
<layout class="QVBoxLayout" name="verticalLayout"> <layout class="QGridLayout" name="gridLayout_4">
<property name="leftMargin"> <property name="leftMargin">
<number>0</number> <number>0</number>
</property> </property>
@@ -26,7 +26,7 @@
<property name="bottomMargin"> <property name="bottomMargin">
<number>0</number> <number>0</number>
</property> </property>
<item> <item row="0" column="0">
<layout class="QFormLayout" name="formLayout"> <layout class="QFormLayout" name="formLayout">
<item row="0" column="0"> <item row="0" column="0">
<widget class="QLabel" name="label"> <widget class="QLabel" name="label">
@@ -70,29 +70,8 @@
</item> </item>
</layout> </layout>
</item> </item>
<item>
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="0">
<widget class="QCheckBox" name="checkBoxSerial1">
<property name="text">
<string>Serial port 1</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QCheckBox" name="checkBoxParallel1">
<property name="text">
<string>Parallel port 1</string>
</property>
</widget>
</item>
<item row="1" column="0"> <item row="1" column="0">
<widget class="QCheckBox" name="checkBoxSerial2"> <layout class="QGridLayout" name="gridLayout">
<property name="text">
<string>Serial port 2</string>
</property>
</widget>
</item>
<item row="1" column="1"> <item row="1" column="1">
<widget class="QCheckBox" name="checkBoxParallel2"> <widget class="QCheckBox" name="checkBoxParallel2">
<property name="text"> <property name="text">
@@ -100,13 +79,6 @@
</property> </property>
</widget> </widget>
</item> </item>
<item row="2" column="0">
<widget class="QCheckBox" name="checkBoxSerial3">
<property name="text">
<string>Serial port 3</string>
</property>
</widget>
</item>
<item row="2" column="1"> <item row="2" column="1">
<widget class="QCheckBox" name="checkBoxParallel3"> <widget class="QCheckBox" name="checkBoxParallel3">
<property name="text"> <property name="text">
@@ -114,10 +86,17 @@
</property> </property>
</widget> </widget>
</item> </item>
<item row="3" column="0"> <item row="2" column="0">
<widget class="QCheckBox" name="checkBoxSerial4"> <widget class="QCheckBox" name="checkBoxSerial3">
<property name="text"> <property name="text">
<string>Serial port 4</string> <string>Serial port 3</string>
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="QCheckBox" name="checkBoxSerial1">
<property name="text">
<string>Serial port 1</string>
</property> </property>
</widget> </widget>
</item> </item>
@@ -128,9 +107,55 @@
</property> </property>
</widget> </widget>
</item> </item>
<item row="1" column="0">
<widget class="QCheckBox" name="checkBoxSerial2">
<property name="text">
<string>Serial port 2</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QCheckBox" name="checkBoxParallel1">
<property name="text">
<string>Parallel port 1</string>
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="QCheckBox" name="checkBoxSerial4">
<property name="text">
<string>Serial port 4</string>
</property>
</widget>
</item>
</layout> </layout>
</item> </item>
<item> <item row="3" column="0">
<layout class="QGridLayout" name="gridLayout_5">
<property name="sizeConstraint">
<enum>QLayout::SetDefaultConstraint</enum>
</property>
<item row="4" column="0">
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item row="2" column="0">
<widget class="QCheckBox" name="checkBoxSerialPassThru3">
<property name="text">
<string>Serial port passthrough 3</string>
</property>
</widget>
</item>
<item row="5" column="0" colspan="2">
<spacer name="verticalSpacer"> <spacer name="verticalSpacer">
<property name="orientation"> <property name="orientation">
<enum>Qt::Vertical</enum> <enum>Qt::Vertical</enum>
@@ -143,6 +168,57 @@
</property> </property>
</spacer> </spacer>
</item> </item>
<item row="0" column="1">
<widget class="QPushButton" name="pushButtonSerialPassThru1">
<property name="text">
<string>Configure</string>
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="QCheckBox" name="checkBoxSerialPassThru1">
<property name="text">
<string>Serial port passthrough 1</string>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QCheckBox" name="checkBoxSerialPassThru2">
<property name="text">
<string>Serial port passthrough 2</string>
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="QCheckBox" name="checkBoxSerialPassThru4">
<property name="text">
<string>Serial port passthrough 4</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QPushButton" name="pushButtonSerialPassThru2">
<property name="text">
<string>Configure</string>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QPushButton" name="pushButtonSerialPassThru3">
<property name="text">
<string>Configure</string>
</property>
</widget>
</item>
<item row="3" column="1">
<widget class="QPushButton" name="pushButtonSerialPassThru4">
<property name="text">
<string>Configure</string>
</property>
</widget>
</item>
</layout>
</item>
</layout> </layout>
</widget> </widget>
<resources/> <resources/>

View File

@@ -17,7 +17,7 @@
#include "qt_winmanagerfilter.hpp" #include "qt_winmanagerfilter.hpp"
#include <Windows.h> #include <windows.h>
#include <86box/win.h> #include <86box/win.h>
bool bool

View File

@@ -35,7 +35,7 @@
#include <QMenuBar> #include <QMenuBar>
#include <Windows.h> #include <windows.h>
#include <86box/keyboard.h> #include <86box/keyboard.h>
#include <86box/mouse.h> #include <86box/mouse.h>

View File

@@ -37,7 +37,7 @@
#include <QAbstractNativeEventFilter> #include <QAbstractNativeEventFilter>
#include <QByteArray> #include <QByteArray>
#include <Windows.h> #include <windows.h>
#include <memory> #include <memory>

View File

@@ -13,9 +13,11 @@
# #
# Copyright 2021 Cacodemon345. # Copyright 2021 Cacodemon345.
# Copyright 2021 David Hrdlička. # Copyright 2021 David Hrdlička.
# Copyright 2021 Andreas J. Reichel.
# Copyright 2021-2022 Jasmine Iwanek.
# #
add_library(plat OBJECT unix.c) add_library(plat OBJECT unix.c unix_serial_passthrough.c)
if (NOT CPPTHREADS) if (NOT CPPTHREADS)
target_sources(plat PRIVATE unix_thread.c) target_sources(plat PRIVATE unix_thread.c)

View File

@@ -0,0 +1,314 @@
/*
* 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.
*
* Definitions for platform specific serial to host passthrough
*
*
* Authors: Andreas J. Reichel <webmaster@6th-dimension.com>,
* Jasmine Iwanek <jasmine@iwanek.co.uk>
*
* Copyright 2021 Andreas J. Reichel.
* Copyright 2021-2022 Jasmine Iwanek.
*/
#ifndef __APPLE__
# define _XOPEN_SOURCE 500
# define _DEFAULT_SOURCE 1
# define _BSD_SOURCE 1
#endif
#include <stdio.h>
#include <fcntl.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/select.h>
#include <stdint.h>
#include <sys/select.h>
#include <86box/86box.h>
#include <86box/log.h>
#include <86box/plat.h>
#include <86box/device.h>
#include <86box/serial_passthrough.h>
#include <86box/plat_serial_passthrough.h>
#include <termios.h>
#include <errno.h>
#define LOG_PREFIX "serial_passthrough: "
int
plat_serpt_read(void *p, uint8_t *data)
{
serial_passthrough_t *dev = (serial_passthrough_t *) p;
int res;
struct timeval tv;
fd_set rdfds;
switch (dev->mode) {
case SERPT_MODE_VCON:
case SERPT_MODE_HOSTSER:
FD_ZERO(&rdfds);
FD_SET(dev->master_fd, &rdfds);
tv.tv_sec = 0;
tv.tv_usec = 0;
res = select(dev->master_fd + 1, &rdfds, NULL, NULL, &tv);
if (res <= 0 || !FD_ISSET(dev->master_fd, &rdfds)) {
return 0;
}
if (read(dev->master_fd, data, 1) > 0) {
return 1;
}
break;
default:
break;
}
return 0;
}
void
plat_serpt_close(void *p)
{
serial_passthrough_t *dev = (serial_passthrough_t *) p;
if (dev->mode == SERPT_MODE_HOSTSER) {
tcsetattr(dev->master_fd, TCSANOW, (struct termios *) dev->backend_priv);
free(dev->backend_priv);
}
close(dev->master_fd);
}
static void
plat_serpt_write_vcon(serial_passthrough_t *dev, uint8_t data)
{
/* fd_set wrfds;
* int res;
*/
/* We cannot use select here, this would block the hypervisor! */
/* FD_ZERO(&wrfds);
FD_SET(ctx->master_fd, &wrfds);
res = select(ctx->master_fd + 1, NULL, &wrfds, NULL, NULL);
if (res <= 0) {
return;
}
*/
/* just write it out */
if (dev->mode == SERPT_MODE_HOSTSER) {
int res = 0;
do {
res = write(dev->master_fd, &data, 1);
} while (res == 0 || (res == -1 && (errno == EAGAIN || res == EWOULDBLOCK)));
} else
write(dev->master_fd, &data, 1);
}
void
plat_serpt_set_params(void *p)
{
serial_passthrough_t *dev = (serial_passthrough_t *) p;
if (dev->mode == SERPT_MODE_HOSTSER) {
struct termios term_attr;
tcgetattr(dev->master_fd, &term_attr);
#define BAUDRATE_RANGE(baud_rate, min, max, val) \
if (baud_rate >= min && baud_rate < max) { \
cfsetispeed(&term_attr, val); \
cfsetospeed(&term_attr, val); \
}
BAUDRATE_RANGE(dev->baudrate, 50, 75, B50);
BAUDRATE_RANGE(dev->baudrate, 75, 110, B75);
BAUDRATE_RANGE(dev->baudrate, 110, 134, B110);
BAUDRATE_RANGE(dev->baudrate, 134, 150, B134);
BAUDRATE_RANGE(dev->baudrate, 150, 200, B150);
BAUDRATE_RANGE(dev->baudrate, 200, 300, B200);
BAUDRATE_RANGE(dev->baudrate, 300, 600, B300);
BAUDRATE_RANGE(dev->baudrate, 600, 1200, B600);
BAUDRATE_RANGE(dev->baudrate, 1200, 1800, B1200);
BAUDRATE_RANGE(dev->baudrate, 1800, 2400, B1800);
BAUDRATE_RANGE(dev->baudrate, 2400, 4800, B2400);
BAUDRATE_RANGE(dev->baudrate, 4800, 9600, B4800);
BAUDRATE_RANGE(dev->baudrate, 9600, 19200, B9600);
BAUDRATE_RANGE(dev->baudrate, 19200, 38400, B19200);
BAUDRATE_RANGE(dev->baudrate, 38400, 57600, B38400);
BAUDRATE_RANGE(dev->baudrate, 57600, 115200, B57600);
BAUDRATE_RANGE(dev->baudrate, 115200, 0xFFFFFFFF, B115200);
term_attr.c_cflag &= CSIZE;
switch (dev->data_bits) {
case 8:
default:
term_attr.c_cflag |= CS8;
break;
case 7:
term_attr.c_cflag |= CS7;
break;
case 6:
term_attr.c_cflag |= CS6;
break;
case 5:
term_attr.c_cflag |= CS5;
break;
}
term_attr.c_cflag &= CSTOPB;
if (dev->serial->lcr & 0x04)
term_attr.c_cflag |= CSTOPB;
#ifdef __APPLE__
term_attr.c_cflag &= PARENB | PARODD;
#else
term_attr.c_cflag &= PARENB | PARODD | CMSPAR;
#endif
if (dev->serial->lcr & 0x08) {
term_attr.c_cflag |= PARENB;
if (!(dev->serial->lcr & 0x10))
term_attr.c_cflag |= PARODD;
#ifndef __APPLE__
if ((dev->serial->lcr & 0x20))
term_attr.c_cflag |= CMSPAR;
#endif
}
tcsetattr(dev->master_fd, TCSANOW, &term_attr);
#undef BAUDRATE_RANGE
}
}
void
plat_serpt_write(void *p, uint8_t data)
{
serial_passthrough_t *dev = (serial_passthrough_t *) p;
switch (dev->mode) {
case SERPT_MODE_VCON:
case SERPT_MODE_HOSTSER:
plat_serpt_write_vcon(dev, data);
break;
default:
break;
}
}
static int
open_pseudo_terminal(serial_passthrough_t *dev)
{
int master_fd = open("/dev/ptmx", O_RDWR | O_NONBLOCK);
char *ptname;
struct termios term_attr_raw;
if (!master_fd) {
return 0;
}
/* get name of slave device */
if (!(ptname = ptsname(master_fd))) {
pclog(LOG_PREFIX "could not get name of slave pseudo terminal");
close(master_fd);
return 0;
}
memset(dev->slave_pt, 0, sizeof(dev->slave_pt));
strncpy(dev->slave_pt, ptname, sizeof(dev->slave_pt) - 1);
fprintf(stderr, LOG_PREFIX "Slave side is %s\n", dev->slave_pt);
if (grantpt(master_fd)) {
pclog(LOG_PREFIX "error in grantpt()\n");
close(master_fd);
return 0;
}
if (unlockpt(master_fd)) {
pclog(LOG_PREFIX "error in unlockpt()\n");
close(master_fd);
return 0;
}
tcgetattr(master_fd, &term_attr_raw);
cfmakeraw(&term_attr_raw);
tcsetattr(master_fd, TCSANOW, &term_attr_raw);
dev->master_fd = master_fd;
return master_fd;
}
static int
open_host_serial_port(serial_passthrough_t *dev)
{
struct termios *term_attr = NULL;
struct termios term_attr_raw = {};
int fd = open(dev->host_serial_path, O_RDWR | O_NOCTTY | O_NONBLOCK);
if (fd == -1) {
return 0;
}
if (!isatty(fd)) {
return 0;
}
term_attr = calloc(1, sizeof(struct termios));
if (!term_attr) {
close(fd);
return 0;
}
if (tcgetattr(fd, term_attr) == -1) {
free(term_attr);
close(fd);
return 0;
}
term_attr_raw = *term_attr;
/* "Raw" mode. */
cfmakeraw(&term_attr_raw);
term_attr_raw.c_cflag &= CSIZE;
switch (dev->data_bits) {
case 8:
default:
term_attr_raw.c_cflag |= CS8;
break;
case 7:
term_attr_raw.c_cflag |= CS7;
break;
case 6:
term_attr_raw.c_cflag |= CS6;
break;
case 5:
term_attr_raw.c_cflag |= CS5;
break;
}
tcsetattr(fd, TCSANOW, &term_attr_raw);
dev->backend_priv = term_attr;
dev->master_fd = fd;
pclog(LOG_PREFIX "Opened host TTY/serial port %s\n", dev->host_serial_path);
return 1;
}
int
plat_serpt_open_device(void *p)
{
serial_passthrough_t *dev = (serial_passthrough_t *) p;
switch (dev->mode) {
case SERPT_MODE_VCON:
if (!open_pseudo_terminal(dev)) {
return 1;
}
break;
case SERPT_MODE_HOSTSER:
if (!open_host_serial_port(dev)) {
return 1;
}
break;
default:
break;
}
return 0;
}

View File

@@ -10,13 +10,14 @@
# #
# Authors: David Hrdlička, <hrdlickadavid@outlook.com> # Authors: David Hrdlička, <hrdlickadavid@outlook.com>
# #
# Copyright 2020-2021 David Hrdlička. # Copyright 2020,2021 David Hrdlička.
# Copyright 2021-2022 Jasmine Iwanek.
# #
enable_language(RC) enable_language(RC)
add_library(plat OBJECT win.c win_dynld.c win_cdrom.c win_keyboard.c add_library(plat OBJECT win.c win_dynld.c win_cdrom.c win_keyboard.c
win_mouse.c) win_mouse.c win_serial_passthrough.c)
add_library(ui OBJECT win_ui.c win_icon.c win_stbar.c win_sdl.c win_dialog.c win_about.c add_library(ui OBJECT win_ui.c win_icon.c win_stbar.c win_sdl.c win_dialog.c win_about.c
win_settings.c win_devconf.c win_snd_gain.c win_specify_dim.c win_new_floppy.c win_settings.c win_devconf.c win_snd_gain.c win_specify_dim.c win_new_floppy.c

View File

@@ -596,7 +596,7 @@ DEVOBJ := bugger.o cartridge.o cassette.o hasp.o hwm.o hwm_lm75.o hwm_lm78.o hwm
mouse.o \ mouse.o \
mouse_bus.o \ mouse_bus.o \
mouse_serial.o mouse_ps2.o \ mouse_serial.o mouse_ps2.o \
phoenix_486_jumper.o phoenix_486_jumper.o serial_passthrough.o
SIOOBJ := sio_acc3221.o sio_ali5123.o \ SIOOBJ := sio_acc3221.o sio_ali5123.o \
sio_f82c710.o sio_82091aa.o sio_fdc37c6xx.o \ sio_f82c710.o sio_82091aa.o sio_fdc37c6xx.o \
@@ -749,7 +749,7 @@ VOODOOOBJ := vid_voodoo.o vid_voodoo_banshee.o \
PLATOBJ := win.o \ PLATOBJ := win.o \
win_dynld.o \ win_dynld.o \
win_cdrom.o win_keyboard.o \ win_cdrom.o win_keyboard.o \
win_mouse.o win_mouse.o win_serial_passthrough.o
UIOBJ := win_ui.o win_icon.o win_stbar.o discord.o \ UIOBJ := win_ui.o win_icon.o win_stbar.o discord.o \
win_sdl.o win_opengl.o win_opengl_glslp.o glad.o \ win_sdl.o win_opengl.o win_opengl_glslp.o glad.o \

View File

@@ -328,6 +328,10 @@ END
#define STR_PARALLEL2 "Povolit port LPT2" #define STR_PARALLEL2 "Povolit port LPT2"
#define STR_PARALLEL3 "Povolit port LPT3" #define STR_PARALLEL3 "Povolit port LPT3"
#define STR_PARALLEL4 "Povolit port LPT4" #define STR_PARALLEL4 "Povolit port LPT4"
#define STR_SERIAL_PASS1 "Serial port passthrough 1"
#define STR_SERIAL_PASS2 "Serial port passthrough 2"
#define STR_SERIAL_PASS3 "Serial port passthrough 3"
#define STR_SERIAL_PASS4 "Serial port passthrough 4"
#define STR_HDC "Řadič disku:" #define STR_HDC "Řadič disku:"
#define STR_FDC "Disketový řadič:" #define STR_FDC "Disketový řadič:"

View File

@@ -328,6 +328,10 @@ END
#define STR_PARALLEL2 "Parallelport 2" #define STR_PARALLEL2 "Parallelport 2"
#define STR_PARALLEL3 "Parallelport 3" #define STR_PARALLEL3 "Parallelport 3"
#define STR_PARALLEL4 "Parallelport 4" #define STR_PARALLEL4 "Parallelport 4"
#define STR_SERIAL_PASS1 "Serial port passthrough 1"
#define STR_SERIAL_PASS2 "Serial port passthrough 2"
#define STR_SERIAL_PASS3 "Serial port passthrough 3"
#define STR_SERIAL_PASS4 "Serial port passthrough 4"
#define STR_HDC "HDD-Controller:" #define STR_HDC "HDD-Controller:"
#define STR_FDC "FD-Controller:" #define STR_FDC "FD-Controller:"

View File

@@ -453,54 +453,78 @@ BEGIN
CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
LTEXT STR_LPT2, IDT_LPT2, LTEXT STR_LPT2, IDT_LPT2,
CFG_HMARGIN, 28, CFG_PANE_LTEXT_PRI_WIDTH, CFG_PANE_LTEXT_HEIGHT CFG_HMARGIN, 24, CFG_PANE_LTEXT_PRI_WIDTH, CFG_PANE_LTEXT_HEIGHT
COMBOBOX IDC_COMBO_LPT2, COMBOBOX IDC_COMBO_LPT2,
CFG_COMBO_BOX_LEFT, 26, CFG_COMBO_NOBTN_WIDTH, CFG_COMBO_HEIGHT, CFG_COMBO_BOX_LEFT, 22, CFG_COMBO_NOBTN_WIDTH, CFG_COMBO_HEIGHT,
CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
LTEXT STR_LPT3, IDT_LPT3, LTEXT STR_LPT3, IDT_LPT3,
CFG_HMARGIN, 47, CFG_PANE_LTEXT_PRI_WIDTH, CFG_PANE_LTEXT_HEIGHT CFG_HMARGIN, 39, CFG_PANE_LTEXT_PRI_WIDTH, CFG_PANE_LTEXT_HEIGHT
COMBOBOX IDC_COMBO_LPT3, COMBOBOX IDC_COMBO_LPT3,
CFG_COMBO_BOX_LEFT, 45, CFG_COMBO_NOBTN_WIDTH, CFG_COMBO_HEIGHT, CFG_COMBO_BOX_LEFT, 37, CFG_COMBO_NOBTN_WIDTH, CFG_COMBO_HEIGHT,
CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
LTEXT STR_LPT4, IDT_LPT4, LTEXT STR_LPT4, IDT_LPT4,
CFG_HMARGIN, 66, CFG_PANE_LTEXT_PRI_WIDTH, CFG_PANE_LTEXT_HEIGHT CFG_HMARGIN, 54, CFG_PANE_LTEXT_PRI_WIDTH, CFG_PANE_LTEXT_HEIGHT
COMBOBOX IDC_COMBO_LPT4, COMBOBOX IDC_COMBO_LPT4,
CFG_COMBO_BOX_LEFT, 64, CFG_COMBO_NOBTN_WIDTH, CFG_COMBO_HEIGHT, CFG_COMBO_BOX_LEFT, 52, CFG_COMBO_NOBTN_WIDTH, CFG_COMBO_HEIGHT,
CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
CONTROL STR_SERIAL1, IDC_CHECK_SERIAL1, CONTROL STR_SERIAL1, IDC_CHECK_SERIAL1,
"Button", BS_AUTOCHECKBOX | WS_TABSTOP, "Button", BS_AUTOCHECKBOX | WS_TABSTOP,
CFG_HMARGIN, 83, CFG_CHECKBOX_PRI_WIDTH, CFG_CHECKBOX_HEIGHT CFG_HMARGIN, 71, CFG_CHECKBOX_PRI_WIDTH, CFG_CHECKBOX_HEIGHT
CONTROL STR_SERIAL2, IDC_CHECK_SERIAL2, CONTROL STR_SERIAL2, IDC_CHECK_SERIAL2,
"Button", BS_AUTOCHECKBOX | WS_TABSTOP, "Button", BS_AUTOCHECKBOX | WS_TABSTOP,
CFG_HMARGIN, 102, CFG_CHECKBOX_PRI_WIDTH, CFG_CHECKBOX_HEIGHT CFG_HMARGIN, 86, CFG_CHECKBOX_PRI_WIDTH, CFG_CHECKBOX_HEIGHT
CONTROL STR_SERIAL3, IDC_CHECK_SERIAL3, CONTROL STR_SERIAL3, IDC_CHECK_SERIAL3,
"Button", BS_AUTOCHECKBOX | WS_TABSTOP, "Button", BS_AUTOCHECKBOX | WS_TABSTOP,
CFG_HMARGIN, 121, CFG_CHECKBOX_PRI_WIDTH, CFG_CHECKBOX_HEIGHT CFG_HMARGIN, 101, CFG_CHECKBOX_PRI_WIDTH, CFG_CHECKBOX_HEIGHT
CONTROL STR_SERIAL4, IDC_CHECK_SERIAL4, CONTROL STR_SERIAL4, IDC_CHECK_SERIAL4,
"Button", BS_AUTOCHECKBOX | WS_TABSTOP, "Button", BS_AUTOCHECKBOX | WS_TABSTOP,
CFG_HMARGIN, 140, CFG_CHECKBOX_PRI_WIDTH, CFG_CHECKBOX_HEIGHT CFG_HMARGIN, 116, CFG_CHECKBOX_PRI_WIDTH, CFG_CHECKBOX_HEIGHT
CONTROL STR_PARALLEL1, IDC_CHECK_PARALLEL1, CONTROL STR_PARALLEL1, IDC_CHECK_PARALLEL1,
"Button", BS_AUTOCHECKBOX | WS_TABSTOP, "Button", BS_AUTOCHECKBOX | WS_TABSTOP,
167, 83, CFG_CHECKBOX_PRI_WIDTH, CFG_CHECKBOX_HEIGHT 167, 71, CFG_CHECKBOX_PRI_WIDTH, CFG_CHECKBOX_HEIGHT
CONTROL STR_PARALLEL2, IDC_CHECK_PARALLEL2, CONTROL STR_PARALLEL2, IDC_CHECK_PARALLEL2,
"Button", BS_AUTOCHECKBOX | WS_TABSTOP, "Button", BS_AUTOCHECKBOX | WS_TABSTOP,
167, 102, CFG_CHECKBOX_PRI_WIDTH, CFG_CHECKBOX_HEIGHT 167, 86, CFG_CHECKBOX_PRI_WIDTH, CFG_CHECKBOX_HEIGHT
CONTROL STR_PARALLEL3, IDC_CHECK_PARALLEL3, CONTROL STR_PARALLEL3, IDC_CHECK_PARALLEL3,
"Button", BS_AUTOCHECKBOX | WS_TABSTOP, "Button", BS_AUTOCHECKBOX | WS_TABSTOP,
167, 121, CFG_CHECKBOX_PRI_WIDTH, CFG_CHECKBOX_HEIGHT 167, 101, CFG_CHECKBOX_PRI_WIDTH, CFG_CHECKBOX_HEIGHT
CONTROL STR_PARALLEL4, IDC_CHECK_PARALLEL4, CONTROL STR_PARALLEL4, IDC_CHECK_PARALLEL4,
"Button", BS_AUTOCHECKBOX | WS_TABSTOP, "Button", BS_AUTOCHECKBOX | WS_TABSTOP,
167, 140, CFG_CHECKBOX_PRI_WIDTH, CFG_CHECKBOX_HEIGHT 167, 116, CFG_CHECKBOX_PRI_WIDTH, CFG_CHECKBOX_HEIGHT
CONTROL STR_SERIAL_PASS1, IDC_CHECK_SERIAL_PASS1,
"Button", BS_AUTOCHECKBOX | WS_TABSTOP,
CFG_HMARGIN, 134, CFG_CHECKBOX_PRI_WIDTH, CFG_CHECKBOX_HEIGHT
PUSHBUTTON STR_CONFIGURE, IDC_CONFIGURE_SERIAL_PASS1,
CFG_COMBO_BTN_LEFT, 131, CFG_BTN_WIDTH, CFG_BTN_HEIGHT
CONTROL STR_SERIAL_PASS2, IDC_CHECK_SERIAL_PASS2,
"Button", BS_AUTOCHECKBOX | WS_TABSTOP,
CFG_HMARGIN, 150, CFG_CHECKBOX_PRI_WIDTH, CFG_CHECKBOX_HEIGHT
PUSHBUTTON STR_CONFIGURE, IDC_CONFIGURE_SERIAL_PASS2,
CFG_COMBO_BTN_LEFT, 147, CFG_BTN_WIDTH, CFG_BTN_HEIGHT
CONTROL STR_SERIAL_PASS3, IDC_CHECK_SERIAL_PASS3,
"Button", BS_AUTOCHECKBOX | WS_TABSTOP,
CFG_HMARGIN, 165, CFG_CHECKBOX_PRI_WIDTH, CFG_CHECKBOX_HEIGHT
PUSHBUTTON STR_CONFIGURE, IDC_CONFIGURE_SERIAL_PASS3,
CFG_COMBO_BTN_LEFT, 162, CFG_BTN_WIDTH, CFG_BTN_HEIGHT
CONTROL STR_SERIAL_PASS4, IDC_CHECK_SERIAL_PASS4,
"Button", BS_AUTOCHECKBOX | WS_TABSTOP,
CFG_HMARGIN, 180, CFG_CHECKBOX_PRI_WIDTH, CFG_CHECKBOX_HEIGHT
PUSHBUTTON STR_CONFIGURE, IDC_CONFIGURE_SERIAL_PASS4,
CFG_COMBO_BTN_LEFT, 177, CFG_BTN_WIDTH, CFG_BTN_HEIGHT
END END
DLG_CFG_STORAGE DIALOG DISCARDABLE CFG_PANE_LEFT, CFG_PANE_TOP, CFG_PANE_WIDTH, CFG_PANE_HEIGHT DLG_CFG_STORAGE DIALOG DISCARDABLE CFG_PANE_LEFT, CFG_PANE_TOP, CFG_PANE_WIDTH, CFG_PANE_HEIGHT
@@ -996,6 +1020,10 @@ END
#undef STR_PARALLEL2 #undef STR_PARALLEL2
#undef STR_PARALLEL3 #undef STR_PARALLEL3
#undef STR_PARALLEL4 #undef STR_PARALLEL4
#undef STR_SERIAL_PASS1
#undef STR_SERIAL_PASS2
#undef STR_SERIAL_PASS3
#undef STR_SERIAL_PASS4
#undef STR_HDC #undef STR_HDC
#undef STR_FDC #undef STR_FDC

View File

@@ -328,6 +328,10 @@ END
#define STR_PARALLEL2 "Parallel port 2" #define STR_PARALLEL2 "Parallel port 2"
#define STR_PARALLEL3 "Parallel port 3" #define STR_PARALLEL3 "Parallel port 3"
#define STR_PARALLEL4 "Parallel port 4" #define STR_PARALLEL4 "Parallel port 4"
#define STR_SERIAL_PASS1 "Serial port passthrough 1"
#define STR_SERIAL_PASS2 "Serial port passthrough 2"
#define STR_SERIAL_PASS3 "Serial port passthrough 3"
#define STR_SERIAL_PASS4 "Serial port passthrough 4"
#define STR_HDC "HD Controller:" #define STR_HDC "HD Controller:"
#define STR_FDC "FD Controller:" #define STR_FDC "FD Controller:"

View File

@@ -328,6 +328,10 @@ END
#define STR_PARALLEL2 "Parallel port 2" #define STR_PARALLEL2 "Parallel port 2"
#define STR_PARALLEL3 "Parallel port 3" #define STR_PARALLEL3 "Parallel port 3"
#define STR_PARALLEL4 "Parallel port 4" #define STR_PARALLEL4 "Parallel port 4"
#define STR_SERIAL_PASS1 "Serial port passthrough 1"
#define STR_SERIAL_PASS2 "Serial port passthrough 2"
#define STR_SERIAL_PASS3 "Serial port passthrough 3"
#define STR_SERIAL_PASS4 "Serial port passthrough 4"
#define STR_HDC "HD Controller:" #define STR_HDC "HD Controller:"
#define STR_FDC "FD Controller:" #define STR_FDC "FD Controller:"

View File

@@ -328,6 +328,10 @@ END
#define STR_PARALLEL2 "Puerto paralelo 2" #define STR_PARALLEL2 "Puerto paralelo 2"
#define STR_PARALLEL3 "Puerto paralelo 3" #define STR_PARALLEL3 "Puerto paralelo 3"
#define STR_PARALLEL4 "Puerto paralelo 4" #define STR_PARALLEL4 "Puerto paralelo 4"
#define STR_SERIAL_PASS1 "Serial port passthrough 1"
#define STR_SERIAL_PASS2 "Serial port passthrough 2"
#define STR_SERIAL_PASS3 "Serial port passthrough 3"
#define STR_SERIAL_PASS4 "Serial port passthrough 4"
#define STR_HDC "Controladora HD:" #define STR_HDC "Controladora HD:"
#define STR_FDC "Controladora FD:" #define STR_FDC "Controladora FD:"

View File

@@ -328,6 +328,10 @@ END
#define STR_PARALLEL2 "Rinnakkaisportti 2" #define STR_PARALLEL2 "Rinnakkaisportti 2"
#define STR_PARALLEL3 "Rinnakkaisportti 3" #define STR_PARALLEL3 "Rinnakkaisportti 3"
#define STR_PARALLEL4 "Rinnakkaisportti 4" #define STR_PARALLEL4 "Rinnakkaisportti 4"
#define STR_SERIAL_PASS1 "Serial port passthrough 1"
#define STR_SERIAL_PASS2 "Serial port passthrough 2"
#define STR_SERIAL_PASS3 "Serial port passthrough 3"
#define STR_SERIAL_PASS4 "Serial port passthrough 4"
#define STR_HDC "Kiintolevyohjain:" #define STR_HDC "Kiintolevyohjain:"
#define STR_FDC "Levykeohjain:" #define STR_FDC "Levykeohjain:"

View File

@@ -328,6 +328,10 @@ END
#define STR_PARALLEL2 "Port parallèle 2" #define STR_PARALLEL2 "Port parallèle 2"
#define STR_PARALLEL3 "Port parallèle 3" #define STR_PARALLEL3 "Port parallèle 3"
#define STR_PARALLEL4 "Port parallèle 4" #define STR_PARALLEL4 "Port parallèle 4"
#define STR_SERIAL_PASS1 "Serial port passthrough 1"
#define STR_SERIAL_PASS2 "Serial port passthrough 2"
#define STR_SERIAL_PASS3 "Serial port passthrough 3"
#define STR_SERIAL_PASS4 "Serial port passthrough 4"
#define STR_HDC "Contrôleur HD:" #define STR_HDC "Contrôleur HD:"
#define STR_FDC "Contrôleur FD:" #define STR_FDC "Contrôleur FD:"

View File

@@ -328,6 +328,10 @@ END
#define STR_PARALLEL2 "Paralelna vrata 2" #define STR_PARALLEL2 "Paralelna vrata 2"
#define STR_PARALLEL3 "Paralelna vrata 3" #define STR_PARALLEL3 "Paralelna vrata 3"
#define STR_PARALLEL4 "Paralelna vrata 4" #define STR_PARALLEL4 "Paralelna vrata 4"
#define STR_SERIAL_PASS1 "Serial port passthrough 1"
#define STR_SERIAL_PASS2 "Serial port passthrough 2"
#define STR_SERIAL_PASS3 "Serial port passthrough 3"
#define STR_SERIAL_PASS4 "Serial port passthrough 4"
#define STR_HDC "Kontroler tvrdog diska:" #define STR_HDC "Kontroler tvrdog diska:"
#define STR_FDC "Kontroler diskete:" #define STR_FDC "Kontroler diskete:"

View File

@@ -333,6 +333,10 @@ END
#define STR_PARALLEL2 "Párhuzamos port 2" #define STR_PARALLEL2 "Párhuzamos port 2"
#define STR_PARALLEL3 "Párhuzamos port 3" #define STR_PARALLEL3 "Párhuzamos port 3"
#define STR_PARALLEL4 "Párhuzamos port 4" #define STR_PARALLEL4 "Párhuzamos port 4"
#define STR_SERIAL_PASS1 "Serial port passthrough 1"
#define STR_SERIAL_PASS2 "Serial port passthrough 2"
#define STR_SERIAL_PASS3 "Serial port passthrough 3"
#define STR_SERIAL_PASS4 "Serial port passthrough 4"
#define STR_HDC "Merevl.-vezérlő:" #define STR_HDC "Merevl.-vezérlő:"
#define STR_FDC "Floppy-vezérlő:" #define STR_FDC "Floppy-vezérlő:"

View File

@@ -329,6 +329,10 @@ END
#define STR_PARALLEL2 "Porta parallela 2" #define STR_PARALLEL2 "Porta parallela 2"
#define STR_PARALLEL3 "Porta parallela 3" #define STR_PARALLEL3 "Porta parallela 3"
#define STR_PARALLEL4 "Porta parallela 4" #define STR_PARALLEL4 "Porta parallela 4"
#define STR_SERIAL_PASS1 "Serial port passthrough 1"
#define STR_SERIAL_PASS2 "Serial port passthrough 2"
#define STR_SERIAL_PASS3 "Serial port passthrough 3"
#define STR_SERIAL_PASS4 "Serial port passthrough 4"
#define STR_HDC "Controller HD:" #define STR_HDC "Controller HD:"
#define STR_FDC "Controller FD:" #define STR_FDC "Controller FD:"

View File

@@ -328,6 +328,10 @@ END
#define STR_PARALLEL2 "パラレルポート2" #define STR_PARALLEL2 "パラレルポート2"
#define STR_PARALLEL3 "パラレルポート3" #define STR_PARALLEL3 "パラレルポート3"
#define STR_PARALLEL4 "パラレルポート4" #define STR_PARALLEL4 "パラレルポート4"
#define STR_SERIAL_PASS1 "Serial port passthrough 1"
#define STR_SERIAL_PASS2 "Serial port passthrough 2"
#define STR_SERIAL_PASS3 "Serial port passthrough 3"
#define STR_SERIAL_PASS4 "Serial port passthrough 4"
#define STR_HDC "HDコントローラー:" #define STR_HDC "HDコントローラー:"
#define STR_FDC "FDコントローラー:" #define STR_FDC "FDコントローラー:"

View File

@@ -328,6 +328,10 @@ END
#define STR_PARALLEL2 "병렬 포트 2" #define STR_PARALLEL2 "병렬 포트 2"
#define STR_PARALLEL3 "병렬 포트 3" #define STR_PARALLEL3 "병렬 포트 3"
#define STR_PARALLEL4 "병렬 포트 4" #define STR_PARALLEL4 "병렬 포트 4"
#define STR_SERIAL_PASS1 "Serial port passthrough 1"
#define STR_SERIAL_PASS2 "Serial port passthrough 2"
#define STR_SERIAL_PASS3 "Serial port passthrough 3"
#define STR_SERIAL_PASS4 "Serial port passthrough 4"
#define STR_HDC "HD 컨트롤러:" #define STR_HDC "HD 컨트롤러:"
#define STR_FDC "FD 컨트롤러:" #define STR_FDC "FD 컨트롤러:"

View File

@@ -328,6 +328,10 @@ END
#define STR_PARALLEL2 "Port równoległy 2" #define STR_PARALLEL2 "Port równoległy 2"
#define STR_PARALLEL3 "Port równoległy 3" #define STR_PARALLEL3 "Port równoległy 3"
#define STR_PARALLEL4 "Port równoległy 4" #define STR_PARALLEL4 "Port równoległy 4"
#define STR_SERIAL_PASS1 "Serial port passthrough 1"
#define STR_SERIAL_PASS2 "Serial port passthrough 2"
#define STR_SERIAL_PASS3 "Serial port passthrough 3"
#define STR_SERIAL_PASS4 "Serial port passthrough 4"
#define STR_HDC "Kontroler dysku twardego:" #define STR_HDC "Kontroler dysku twardego:"
#define STR_FDC "Kontroler dyskietek:" #define STR_FDC "Kontroler dyskietek:"

View File

@@ -331,6 +331,10 @@ END
#define STR_PARALLEL2 "Porta paralela 2" #define STR_PARALLEL2 "Porta paralela 2"
#define STR_PARALLEL3 "Porta paralela 3" #define STR_PARALLEL3 "Porta paralela 3"
#define STR_PARALLEL4 "Porta paralela 4" #define STR_PARALLEL4 "Porta paralela 4"
#define STR_SERIAL_PASS1 "Serial port passthrough 1"
#define STR_SERIAL_PASS2 "Serial port passthrough 2"
#define STR_SERIAL_PASS3 "Serial port passthrough 3"
#define STR_SERIAL_PASS4 "Serial port passthrough 4"
#define STR_HDC "Controlador HD:" #define STR_HDC "Controlador HD:"
#define STR_FDC "Controlador FD:" #define STR_FDC "Controlador FD:"

View File

@@ -328,6 +328,10 @@ END
#define STR_PARALLEL2 "Porta paralela 2" #define STR_PARALLEL2 "Porta paralela 2"
#define STR_PARALLEL3 "Porta paralela 3" #define STR_PARALLEL3 "Porta paralela 3"
#define STR_PARALLEL4 "Porta paralela 4" #define STR_PARALLEL4 "Porta paralela 4"
#define STR_SERIAL_PASS1 "Serial port passthrough 1"
#define STR_SERIAL_PASS2 "Serial port passthrough 2"
#define STR_SERIAL_PASS3 "Serial port passthrough 3"
#define STR_SERIAL_PASS4 "Serial port passthrough 4"
#define STR_HDC "Controlador HD:" #define STR_HDC "Controlador HD:"
#define STR_FDC "Controlador FD:" #define STR_FDC "Controlador FD:"

View File

@@ -328,6 +328,10 @@ END
#define STR_PARALLEL2 "Параллельный порт LPT2" #define STR_PARALLEL2 "Параллельный порт LPT2"
#define STR_PARALLEL3 "Параллельный порт LPT3" #define STR_PARALLEL3 "Параллельный порт LPT3"
#define STR_PARALLEL4 "Параллельный порт LPT4" #define STR_PARALLEL4 "Параллельный порт LPT4"
#define STR_SERIAL_PASS1 "Serial port passthrough 1"
#define STR_SERIAL_PASS2 "Serial port passthrough 2"
#define STR_SERIAL_PASS3 "Serial port passthrough 3"
#define STR_SERIAL_PASS4 "Serial port passthrough 4"
#define STR_HDC "Контроллер HD:" #define STR_HDC "Контроллер HD:"
#define STR_FDC "Контроллер FD:" #define STR_FDC "Контроллер FD:"

View File

@@ -328,6 +328,10 @@ END
#define STR_PARALLEL2 "Paralelna vrata 2" #define STR_PARALLEL2 "Paralelna vrata 2"
#define STR_PARALLEL3 "Paralelna vrata 3" #define STR_PARALLEL3 "Paralelna vrata 3"
#define STR_PARALLEL4 "Paralelna vrata 4" #define STR_PARALLEL4 "Paralelna vrata 4"
#define STR_SERIAL_PASS1 "Serial port passthrough 1"
#define STR_SERIAL_PASS2 "Serial port passthrough 2"
#define STR_SERIAL_PASS3 "Serial port passthrough 3"
#define STR_SERIAL_PASS4 "Serial port passthrough 4"
#define STR_HDC "Krmilnik trdega diska:" #define STR_HDC "Krmilnik trdega diska:"
#define STR_FDC "Krmilnik disketnika:" #define STR_FDC "Krmilnik disketnika:"

View File

@@ -328,6 +328,10 @@ END
#define STR_PARALLEL2 "Paralel port 2" #define STR_PARALLEL2 "Paralel port 2"
#define STR_PARALLEL3 "Paralel port 3" #define STR_PARALLEL3 "Paralel port 3"
#define STR_PARALLEL4 "Paralel port 4" #define STR_PARALLEL4 "Paralel port 4"
#define STR_SERIAL_PASS1 "Serial port passthrough 1"
#define STR_SERIAL_PASS2 "Serial port passthrough 2"
#define STR_SERIAL_PASS3 "Serial port passthrough 3"
#define STR_SERIAL_PASS4 "Serial port passthrough 4"
#define STR_HDC "HD Kontrolcüsü:" #define STR_HDC "HD Kontrolcüsü:"
#define STR_FDC "FD Kontrolcüsü:" #define STR_FDC "FD Kontrolcüsü:"

View File

@@ -328,6 +328,10 @@ END
#define STR_PARALLEL2 "Паралельний порт LPT2" #define STR_PARALLEL2 "Паралельний порт LPT2"
#define STR_PARALLEL3 "Паралельний порт LPT3" #define STR_PARALLEL3 "Паралельний порт LPT3"
#define STR_PARALLEL4 "Паралельний порт LPT4" #define STR_PARALLEL4 "Паралельний порт LPT4"
#define STR_SERIAL_PASS1 "Serial port passthrough 1"
#define STR_SERIAL_PASS2 "Serial port passthrough 2"
#define STR_SERIAL_PASS3 "Serial port passthrough 3"
#define STR_SERIAL_PASS4 "Serial port passthrough 4"
#define STR_HDC "Контролер HD:" #define STR_HDC "Контролер HD:"
#define STR_FDC "Контролер FD:" #define STR_FDC "Контролер FD:"

View File

@@ -328,6 +328,10 @@ END
#define STR_PARALLEL2 "并口 2" #define STR_PARALLEL2 "并口 2"
#define STR_PARALLEL3 "并口 3" #define STR_PARALLEL3 "并口 3"
#define STR_PARALLEL4 "并口 4" #define STR_PARALLEL4 "并口 4"
#define STR_SERIAL_PASS1 "Serial port passthrough 1"
#define STR_SERIAL_PASS2 "Serial port passthrough 2"
#define STR_SERIAL_PASS3 "Serial port passthrough 3"
#define STR_SERIAL_PASS4 "Serial port passthrough 4"
#define STR_HDC "硬盘控制器:" #define STR_HDC "硬盘控制器:"
#define STR_FDC "软盘控制器:" #define STR_FDC "软盘控制器:"

View File

@@ -328,6 +328,10 @@ END
#define STR_PARALLEL2 "並列埠 2" #define STR_PARALLEL2 "並列埠 2"
#define STR_PARALLEL3 "並列埠 3" #define STR_PARALLEL3 "並列埠 3"
#define STR_PARALLEL4 "並列埠 4" #define STR_PARALLEL4 "並列埠 4"
#define STR_SERIAL_PASS1 "Serial port passthrough 1"
#define STR_SERIAL_PASS2 "Serial port passthrough 2"
#define STR_SERIAL_PASS3 "Serial port passthrough 3"
#define STR_SERIAL_PASS4 "Serial port passthrough 4"
#define STR_HDC "硬碟控制器:" #define STR_HDC "硬碟控制器:"
#define STR_FDC "軟碟控制器:" #define STR_FDC "軟碟控制器:"

View File

@@ -36,7 +36,7 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/ */
#define UNICODE #define UNICODE
#include <Windows.h> #include <windows.h>
#include <process.h> #include <process.h>
#include <SDL2/SDL.h> #include <SDL2/SDL.h>
#include <SDL2/SDL_syswm.h> #include <SDL2/SDL_syswm.h>

View File

@@ -0,0 +1,223 @@
/*
* 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.
*
* Definitions for platform specific serial to host passthrough
*
*
* Authors: Andreas J. Reichel <webmaster@6th-dimension.com>,
* Jasmine Iwanek <jasmine@iwanek.co.uk>
*
* Copyright 2021 Andreas J. Reichel
* Copyright 2021-2022 Jasmine Iwanek
*/
#define _XOPEN_SOURCE 500
#include <stdio.h>
#include <fcntl.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include <86box/86box.h>
#include <86box/log.h>
#include <86box/timer.h>
#include <86box/plat.h>
#include <86box/device.h>
#include <86box/serial_passthrough.h>
#include <86box/plat_serial_passthrough.h>
#include <windows.h>
#define LOG_PREFIX "serial_passthrough: "
void
plat_serpt_close(void *p)
{
serial_passthrough_t *dev = (serial_passthrough_t *) p;
// fclose(dev->master_fd);
FlushFileBuffers((HANDLE) dev->master_fd);
if (dev->mode == SERPT_MODE_VCON)
DisconnectNamedPipe((HANDLE) dev->master_fd);
if (dev->mode == SERPT_MODE_HOSTSER) {
SetCommState((HANDLE)dev->master_fd, (DCB*)dev->backend_priv);
free(dev->backend_priv);
}
CloseHandle((HANDLE) dev->master_fd);
}
static void
plat_serpt_write_vcon(serial_passthrough_t *dev, uint8_t data)
{
/* fd_set wrfds;
* int res;
*/
/* We cannot use select here, this would block the hypervisor! */
/* FD_ZERO(&wrfds);
FD_SET(ctx->master_fd, &wrfds);
res = select(ctx->master_fd + 1, NULL, &wrfds, NULL, NULL);
if (res <= 0) {
return;
}
*/
/* just write it out */
// fwrite(dev->master_fd, &data, 1);
DWORD bytesWritten = 0;
WriteFile((HANDLE) dev->master_fd, &data, 1, &bytesWritten, NULL);
if (bytesWritten == 0) {
fatal("serial_passthrough: WriteFile pipe write-buffer full!");
}
}
void
plat_serpt_set_params(void *p)
{
serial_passthrough_t *dev = (serial_passthrough_t *)p;
if (dev->mode == SERPT_MODE_HOSTSER) {
DCB serialattr = {};
GetCommState((HANDLE)dev->master_fd, &serialattr);
#define BAUDRATE_RANGE(baud_rate, min, max) if (baud_rate >= min && baud_rate < max) { serialattr.BaudRate = min; }
BAUDRATE_RANGE(dev->baudrate, 110, 300);
BAUDRATE_RANGE(dev->baudrate, 300, 600);
BAUDRATE_RANGE(dev->baudrate, 600, 1200);
BAUDRATE_RANGE(dev->baudrate, 1200, 2400);
BAUDRATE_RANGE(dev->baudrate, 2400, 4800);
BAUDRATE_RANGE(dev->baudrate, 4800, 9600);
BAUDRATE_RANGE(dev->baudrate, 9600, 14400);
BAUDRATE_RANGE(dev->baudrate, 14400, 19200);
BAUDRATE_RANGE(dev->baudrate, 19200, 38400);
BAUDRATE_RANGE(dev->baudrate, 38400, 57600);
BAUDRATE_RANGE(dev->baudrate, 57600, 115200);
BAUDRATE_RANGE(dev->baudrate, 115200, 0xFFFFFFFF);
serialattr.ByteSize = dev->data_bits;
serialattr.StopBits = (dev->serial->lcr & 0x04) ? TWOSTOPBITS : ONESTOPBIT;
if (!(dev->serial->lcr & 0x08)) {
serialattr.fParity = 0;
serialattr.Parity = NOPARITY;
} else {
serialattr.fParity = 1;
if (dev->serial->lcr & 0x20) {
serialattr.Parity = (MARKPARITY) + !!(dev->serial->lcr & 0x10);
} else {
serialattr.Parity = (ODDPARITY) + !!(dev->serial->lcr & 0x10);
}
}
SetCommState((HANDLE)dev->master_fd, &serialattr);
#undef BAUDRATE_RANGE
}
}
void
plat_serpt_write(void *p, uint8_t data)
{
serial_passthrough_t *dev = (serial_passthrough_t *) p;
switch (dev->mode) {
case SERPT_MODE_VCON:
case SERPT_MODE_HOSTSER:
plat_serpt_write_vcon(dev, data);
break;
default:
break;
}
}
uint8_t
plat_serpt_read_vcon(serial_passthrough_t *dev, uint8_t *data)
{
DWORD bytesRead = 0;
ReadFile((HANDLE) dev->master_fd, data, 1, &bytesRead, NULL);
return !!bytesRead;
}
int
plat_serpt_read(void *p, uint8_t *data)
{
serial_passthrough_t *dev = (serial_passthrough_t *) p;
int res = 0;
switch (dev->mode) {
case SERPT_MODE_VCON:
case SERPT_MODE_HOSTSER:
res = plat_serpt_read_vcon(dev, data);
break;
default:
break;
}
return res;
}
static int
open_pseudo_terminal(serial_passthrough_t *dev)
{
char ascii_pipe_name[1024] = { 0 };
snprintf(ascii_pipe_name, sizeof(ascii_pipe_name), "\\\\.\\pipe\\86Box\\%s", vm_name);
dev->master_fd = (intptr_t) CreateNamedPipeA(ascii_pipe_name, PIPE_ACCESS_DUPLEX, PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_NOWAIT, 32, 65536, 65536, NMPWAIT_USE_DEFAULT_WAIT, NULL);
if (dev->master_fd == (intptr_t) INVALID_HANDLE_VALUE) {
return 0;
}
pclog("Named Pipe @ %s\n", ascii_pipe_name);
return 1;
}
static int
open_host_serial_port(serial_passthrough_t *dev)
{
COMMTIMEOUTS timeouts = {
.ReadIntervalTimeout = MAXDWORD,
.ReadTotalTimeoutConstant = 0,
.ReadTotalTimeoutMultiplier = 0,
.WriteTotalTimeoutMultiplier = 0,
.WriteTotalTimeoutConstant = 1000
};
DCB* serialattr = calloc(1, sizeof(DCB));
if (!serialattr) return 0;
dev->master_fd = (intptr_t) CreateFileA(dev->host_serial_path, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL);
if (dev->master_fd == (intptr_t) INVALID_HANDLE_VALUE) {
free(serialattr);
return 0;
}
if (!SetCommTimeouts((HANDLE) dev->master_fd, &timeouts)) {
pclog(LOG_PREFIX "error setting COM port timeouts.\n");
CloseHandle((HANDLE) dev->master_fd);
free(serialattr);
return 0;
}
GetCommState((HANDLE)dev->master_fd, serialattr);
dev->backend_priv = serialattr;
return 1;
}
int
plat_serpt_open_device(void *p)
{
serial_passthrough_t *dev = (serial_passthrough_t *) p;
switch (dev->mode) {
case SERPT_MODE_VCON:
if (open_pseudo_terminal(dev)) {
return 0;
}
break;
case SERPT_MODE_HOSTSER:
if (open_host_serial_port(dev)) {
return 0;
}
default:
break;
}
return 1;
}

View File

@@ -71,6 +71,7 @@
#include <86box/plat.h> #include <86box/plat.h>
#include <86box/ui.h> #include <86box/ui.h>
#include <86box/win.h> #include <86box/win.h>
#include <86box/serial_passthrough.h>
#include "../disk/minivhd/minivhd.h" #include "../disk/minivhd/minivhd.h"
#include "../disk/minivhd/minivhd_util.h" #include "../disk/minivhd/minivhd_util.h"
@@ -111,6 +112,7 @@ static char temp_pcap_dev[NET_CARD_MAX][128];
/* Ports category */ /* Ports category */
static int temp_lpt_devices[PARALLEL_MAX]; static int temp_lpt_devices[PARALLEL_MAX];
static int temp_serial[SERIAL_MAX], temp_lpt[PARALLEL_MAX]; static int temp_serial[SERIAL_MAX], temp_lpt[PARALLEL_MAX];
static int temp_serial_passthrough_enabled[SERIAL_MAX];
/* Other peripherals category */ /* Other peripherals category */
static int temp_fdc_card, temp_hdc, temp_ide_ter, temp_ide_qua, temp_cassette; static int temp_fdc_card, temp_hdc, temp_ide_ter, temp_ide_qua, temp_cassette;
@@ -361,8 +363,10 @@ win_settings_init(void)
temp_lpt_devices[i] = lpt_ports[i].device; temp_lpt_devices[i] = lpt_ports[i].device;
temp_lpt[i] = lpt_ports[i].enabled; temp_lpt[i] = lpt_ports[i].enabled;
} }
for (i = 0; i < SERIAL_MAX; i++) for (i = 0; i < SERIAL_MAX; i++) {
temp_serial[i] = com_ports[i].enabled; temp_serial[i] = com_ports[i].enabled;
temp_serial_passthrough_enabled[i] = serial_passthrough_enabled[i];
}
/* Storage devices category */ /* Storage devices category */
for (i = 0; i < SCSI_BUS_MAX; i++) for (i = 0; i < SCSI_BUS_MAX; i++)
@@ -484,8 +488,10 @@ win_settings_changed(void)
i = i || (temp_lpt_devices[j] != lpt_ports[j].device); i = i || (temp_lpt_devices[j] != lpt_ports[j].device);
i = i || (temp_lpt[j] != lpt_ports[j].enabled); i = i || (temp_lpt[j] != lpt_ports[j].enabled);
} }
for (j = 0; j < SERIAL_MAX; j++) for (j = 0; j < SERIAL_MAX; j++) {
i = i || (temp_serial[j] != com_ports[j].enabled); i = i || (temp_serial[j] != com_ports[j].enabled);
i = i || (temp_serial_passthrough_enabled[i] != serial_passthrough_enabled[i]);
}
/* Storage devices category */ /* Storage devices category */
for (j = 0; j < SCSI_BUS_MAX; j++) for (j = 0; j < SCSI_BUS_MAX; j++)
@@ -578,8 +584,10 @@ win_settings_save(void)
lpt_ports[i].device = temp_lpt_devices[i]; lpt_ports[i].device = temp_lpt_devices[i];
lpt_ports[i].enabled = temp_lpt[i]; lpt_ports[i].enabled = temp_lpt[i];
} }
for (i = 0; i < SERIAL_MAX; i++) for (i = 0; i < SERIAL_MAX; i++) {
com_ports[i].enabled = temp_serial[i]; com_ports[i].enabled = temp_serial[i];
serial_passthrough_enabled[i] = temp_serial_passthrough_enabled[i];
}
/* Storage devices category */ /* Storage devices category */
for (i = 0; i < SCSI_BUS_MAX; i++) for (i = 0; i < SCSI_BUS_MAX; i++)
@@ -1764,8 +1772,10 @@ win_settings_ports_proc(HWND hdlg, UINT message, WPARAM wParam, LPARAM lParam)
settings_enable_window(hdlg, IDC_COMBO_LPT1 + i, temp_lpt[i]); settings_enable_window(hdlg, IDC_COMBO_LPT1 + i, temp_lpt[i]);
} }
for (i = 0; i < SERIAL_MAX; i++) for (i = 0; i < SERIAL_MAX; i++) {
settings_set_check(hdlg, IDC_CHECK_SERIAL1 + i, temp_serial[i]); settings_set_check(hdlg, IDC_CHECK_SERIAL1 + i, temp_serial[i]);
settings_set_check(hdlg, IDC_CHECK_SERIAL_PASS1 + i, temp_serial_passthrough_enabled[i]);
}
free(lptsTemp); free(lptsTemp);
@@ -1790,8 +1800,10 @@ win_settings_ports_proc(HWND hdlg, UINT message, WPARAM wParam, LPARAM lParam)
temp_lpt[i] = settings_get_check(hdlg, IDC_CHECK_PARALLEL1 + i); temp_lpt[i] = settings_get_check(hdlg, IDC_CHECK_PARALLEL1 + i);
} }
for (i = 0; i < SERIAL_MAX; i++) for (i = 0; i < SERIAL_MAX; i++) {
temp_serial[i] = settings_get_check(hdlg, IDC_CHECK_SERIAL1 + i); temp_serial[i] = settings_get_check(hdlg, IDC_CHECK_SERIAL1 + i);
temp_serial_passthrough_enabled[i] = settings_get_check(hdlg, IDC_CHECK_SERIAL_PASS1 + i);
}
default: default:
return FALSE; return FALSE;

View File

@@ -2,8 +2,8 @@
#include <stdint.h> #include <stdint.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <Windows.h> #include <windows.h>
#include <CommCtrl.h> #include <commctrl.h>
#include <86box/86box.h> #include <86box/86box.h>
#include <86box/plat.h> #include <86box/plat.h>
#include <86box/resource.h> #include <86box/resource.h>