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 2021 Laci bá'
* Copyright 2021 dob205
* Copyright 2021 Andreas J. Reichel.
* Copyright 2021-2022 Jasmine Iwanek.
*/
#include <inttypes.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdint.h>
#include <stdbool.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
@@ -68,6 +71,7 @@
#include <86box/isartc.h>
#include <86box/lpt.h>
#include <86box/serial.h>
#include <86box/serial_passthrough.h>
#include <86box/keyboard.h>
#include <86box/mouse.h>
#include <86box/gameport.h>
@@ -162,6 +166,7 @@ int video_filter_method = 1; /* (C) video */
int video_vsync = 0; /* (C) video */
int video_framerate = -1; /* (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 postcard_enabled = 0; /* (C) enable POST card */
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. */
serial_standalone_init();
serial_passthrough_init();
/* Reset and reconfigure the Sound Card layer. */
sound_card_reset();

View File

@@ -20,6 +20,8 @@
* Copyright 2016-2019 Miran Grca.
* Copyright 2017-2019 Fred N. van Kempen.
* 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
* it on Windows XP, and possibly also Vista. Use the
@@ -54,6 +56,8 @@
#include <86box/fdc.h>
#include <86box/fdc_ext.h>
#include <86box/gameport.h>
#include <86box/serial.h>
#include <86box/serial_passthrough.h>
#include <86box/machine.h>
#include <86box/mouse.h>
#include <86box/thread.h>
@@ -81,6 +85,7 @@ static ini_t config;
static int backwards_compat = 0;
static int backwards_compat2 = 0;
#define ENABLE_CONFIG_LOG 1
#ifdef ENABLE_CONFIG_LOG
int config_do_log = ENABLE_CONFIG_LOG;
@@ -834,6 +839,8 @@ load_ports(void)
char temp[512];
int c, d;
memset(temp, 0, sizeof(temp));
for (c = 0; c < SERIAL_MAX; c++) {
sprintf(temp, "serial%d_enabled", c + 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");
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++) {
@@ -2458,6 +2471,12 @@ save_ports(void)
ini_section_set_string(cat, temp,
(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++) {

View File

@@ -18,6 +18,8 @@
* Copyright 2017-2019 Fred N. van Kempen.
* Copyright 2016-2019 Miran Grca.
* 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
* 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));
c->dev = d;
c->instance = inst;
if (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 *
device_get_config_string(const char *s)
{

View File

@@ -11,13 +11,16 @@
# Authors: David Hrdlička, <hrdlickadavid@outlook.com>
#
# 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
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
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)
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. */
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
@@ -161,7 +163,7 @@ write_fifo(serial_t *dev, uint8_t dat)
dev->lsr |= 0x01;
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++;
else
dev->rcvr_fifo_full = 1;
@@ -175,6 +177,8 @@ write_fifo(serial_t *dev, uint8_t dat)
dev->dat = dat;
dev->lsr |= 0x01;
dev->int_status |= SERIAL_INT_RECEIVE;
if (dev->lsr & 0x02)
dev->int_status |= SERIAL_INT_LSR;
serial_update_ints(dev);
}
}
@@ -311,6 +315,22 @@ serial_timeout_timer(void *priv)
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
serial_update_speed(serial_t *dev)
{
@@ -331,6 +351,63 @@ serial_reset_fifo(serial_t *dev)
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
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:
old = dev->lcr;
dev->lcr = val;
if ((old ^ val) & 0x0f) {
if ((old ^ val) & 0x3f) {
/* Data bits + start bit. */
dev->bits = ((dev->lcr & 0x03) + 5) + 1;
/* Stop bits. */
@@ -444,11 +521,14 @@ serial_write(uint16_t addr, uint8_t val, void *p)
serial_transmit_period(dev);
serial_update_speed(dev);
if (dev->sd && dev->sd->lcr_callback)
dev->sd->lcr_callback(dev, dev->sd->priv, dev->lcr);
}
break;
case 4:
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);
}
if (!(val & 8) && (dev->mctrl & 8))
@@ -487,7 +567,7 @@ serial_write(uint16_t addr, uint8_t val, void *p)
serial_update_ints(dev);
break;
case 6:
dev->msr = val;
dev->msr = (val & 0xF0) | (dev->msr & 0x0F);
if (dev->msr & 0x0f)
dev->int_status |= SERIAL_INT_MSR;
serial_update_ints(dev);
@@ -521,11 +601,15 @@ serial_read(uint16_t addr, void *p)
ret = dev->rcvr_fifo[0];
dev->rcvr_fifo_full = 0;
for (i = 1; i < 16; i++)
dev->rcvr_fifo[i - 1] = dev->rcvr_fifo[i];
dev->rcvr_fifo_pos--;
if (dev->rcvr_fifo_pos > 0) {
for (i = 1; i < 16; 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--;
/* At least one byte remains to be read, start the timeout
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);
@@ -571,7 +655,7 @@ serial_read(uint16_t addr, void *p)
serial_update_ints(dev);
break;
case 6:
ret = dev->msr;
ret = dev->msr | dev->msr_set;
dev->msr &= ~0x0f;
dev->int_status &= ~SERIAL_INT_MSR;
serial_update_ints(dev);
@@ -630,9 +714,30 @@ serial_attach(int port,
{
serial_device_t *sd = &serial_devices[port];
sd->rcr_callback = rcr_callback;
sd->dev_write = dev_write;
sd->priv = priv;
sd->rcr_callback = rcr_callback;
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;
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 2016-2019 Miran Grca.
* 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
* it under the terms of the GNU General Public License as published by
@@ -52,6 +54,7 @@
#define CONFIG_MAC 9
#define CONFIG_MIDI_IN 10
#define CONFIG_BIOS 11
#define CONFIG_SERPORT 12
enum {
DEVICE_PCJR = 2, /* requires an IBM PCjr */
@@ -107,7 +110,7 @@ typedef struct {
int default_int;
const char *file_filter;
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];
} device_config_t;
@@ -134,6 +137,7 @@ typedef struct _device_ {
typedef struct {
const device_t *dev;
char name[2048];
int instance;
} device_context_t;
#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_mac(const char *s, int val);
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
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_PARALLEL3 1090
#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_COMBO_HDC 1111
@@ -364,6 +368,10 @@
#define IDC_CONFIGURE_NET4 1321
#define IDC_CONFIGURE_MIDI_OUT 1322
#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_JOY2 1331
#define IDC_JOY3 1332

View File

@@ -53,7 +53,7 @@ typedef struct serial_s {
dat, int_status, scratch, fcr,
irq, type, inst, transmit_enabled,
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;
@@ -70,6 +70,8 @@ typedef struct serial_s {
typedef struct serial_device_s {
void (*rcr_callback)(struct serial_s *serial, void *p);
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;
serial_t *serial;
} serial_device_t;
@@ -84,6 +86,12 @@ extern serial_t *serial_attach(int port,
void (*rcr_callback)(struct serial_s *serial, void *p),
void (*dev_write)(struct serial_s *serial, void *p, uint8_t data),
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_set_type(serial_t *dev, int type);
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_set_clock_src(serial_t *dev, double clock_src);
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_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 UNICODE
#include <Windows.h>
#include <windows.h>
extern int opengl_init(HWND hwnd);
extern int opengl_pause(void);

View File

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

View File

@@ -221,6 +221,12 @@ if(WIN32 AND NOT MINGW)
target_sources(plat PRIVATE ../win/win_opendir.c)
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)
target_sources(ui PRIVATE macos_event_filter.mm)
if(MOLTENVK)

View File

@@ -27,6 +27,8 @@
#include <QCheckBox>
#include <QFrame>
#include <QLabel>
#include <QDir>
#include <QSettings>
extern "C" {
#include <86box/86box.h>
@@ -40,6 +42,10 @@ extern "C" {
#include "qt_filefield.hpp"
#include "qt_models_common.hpp"
#ifdef Q_OS_LINUX
# include <sys/stat.h>
# include <sys/sysmacros.h>
#endif
DeviceConfig::DeviceConfig(QWidget *parent)
: QDialog(parent)
@@ -53,6 +59,40 @@ DeviceConfig::~DeviceConfig()
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
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);
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;
}
@@ -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));
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:
{
auto *cbox = dc.findChild<QComboBox *>(config->name);

View File

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

View File

@@ -27,6 +27,7 @@ extern "C" {
#include <86box/machine.h>
#include <86box/lpt.h>
#include <86box/serial.h>
#include <86box/serial_passthrough.h>
}
#include "qt_deviceconfig.hpp"
@@ -66,6 +67,15 @@ SettingsPorts::SettingsPorts(QWidget *parent)
auto *checkBox = findChild<QCheckBox *>(QString("checkBoxSerial%1").arg(i + 1));
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()
@@ -87,6 +97,11 @@ SettingsPorts::save()
auto *checkBox = findChild<QCheckBox *>(QString("checkBoxSerial%1").arg(i + 1));
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
@@ -112,3 +127,51 @@ SettingsPorts::on_checkBoxParallel4_stateChanged(int state)
{
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();
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:
void on_checkBoxParallel3_stateChanged(int arg1);
void on_checkBoxParallel2_stateChanged(int arg1);

View File

@@ -13,7 +13,7 @@
<property name="windowTitle">
<string>Form</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<layout class="QGridLayout" name="gridLayout_4">
<property name="leftMargin">
<number>0</number>
</property>
@@ -26,7 +26,7 @@
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<item row="0" column="0">
<layout class="QFormLayout" name="formLayout">
<item row="0" column="0">
<widget class="QLabel" name="label">
@@ -70,29 +70,8 @@
</item>
</layout>
</item>
<item>
<item row="1" column="0">
<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">
<widget class="QCheckBox" name="checkBoxSerial2">
<property name="text">
<string>Serial port 2</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QCheckBox" name="checkBoxParallel2">
<property name="text">
@@ -100,13 +79,6 @@
</property>
</widget>
</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">
<widget class="QCheckBox" name="checkBoxParallel3">
<property name="text">
@@ -114,10 +86,17 @@
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="QCheckBox" name="checkBoxSerial4">
<item row="2" column="0">
<widget class="QCheckBox" name="checkBoxSerial3">
<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>
</widget>
</item>
@@ -128,20 +107,117 @@
</property>
</widget>
</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>
</item>
<item>
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
<item row="3" column="0">
<layout class="QGridLayout" name="gridLayout_5">
<property name="sizeConstraint">
<enum>QLayout::SetDefaultConstraint</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
<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">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</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>
</widget>

View File

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

View File

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

View File

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

View File

@@ -13,9 +13,11 @@
#
# Copyright 2021 Cacodemon345.
# 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)
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>
#
# Copyright 2020-2021 David Hrdlička.
# Copyright 2020,2021 David Hrdlička.
# Copyright 2021-2022 Jasmine Iwanek.
#
enable_language(RC)
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
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_bus.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 \
sio_f82c710.o sio_82091aa.o sio_fdc37c6xx.o \
@@ -749,7 +749,7 @@ VOODOOOBJ := vid_voodoo.o vid_voodoo_banshee.o \
PLATOBJ := win.o \
win_dynld.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 \
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_PARALLEL3 "Povolit port LPT3"
#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_FDC "Disketový řadič:"

View File

@@ -328,6 +328,10 @@ END
#define STR_PARALLEL2 "Parallelport 2"
#define STR_PARALLEL3 "Parallelport 3"
#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_FDC "FD-Controller:"

View File

@@ -453,54 +453,78 @@ BEGIN
CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
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,
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
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,
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
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,
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
CONTROL STR_SERIAL1, IDC_CHECK_SERIAL1,
"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,
"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,
"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,
"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,
"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,
"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,
"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,
"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
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_PARALLEL3
#undef STR_PARALLEL4
#undef STR_SERIAL_PASS1
#undef STR_SERIAL_PASS2
#undef STR_SERIAL_PASS3
#undef STR_SERIAL_PASS4
#undef STR_HDC
#undef STR_FDC

View File

@@ -328,6 +328,10 @@ END
#define STR_PARALLEL2 "Parallel port 2"
#define STR_PARALLEL3 "Parallel port 3"
#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_FDC "FD Controller:"

View File

@@ -328,6 +328,10 @@ END
#define STR_PARALLEL2 "Parallel port 2"
#define STR_PARALLEL3 "Parallel port 3"
#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_FDC "FD Controller:"

View File

@@ -328,6 +328,10 @@ END
#define STR_PARALLEL2 "Puerto paralelo 2"
#define STR_PARALLEL3 "Puerto paralelo 3"
#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_FDC "Controladora FD:"

View File

@@ -328,6 +328,10 @@ END
#define STR_PARALLEL2 "Rinnakkaisportti 2"
#define STR_PARALLEL3 "Rinnakkaisportti 3"
#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_FDC "Levykeohjain:"

View File

@@ -328,6 +328,10 @@ END
#define STR_PARALLEL2 "Port parallèle 2"
#define STR_PARALLEL3 "Port parallèle 3"
#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_FDC "Contrôleur FD:"

View File

@@ -328,6 +328,10 @@ END
#define STR_PARALLEL2 "Paralelna vrata 2"
#define STR_PARALLEL3 "Paralelna vrata 3"
#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_FDC "Kontroler diskete:"

View File

@@ -333,6 +333,10 @@ END
#define STR_PARALLEL2 "Párhuzamos port 2"
#define STR_PARALLEL3 "Párhuzamos port 3"
#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_FDC "Floppy-vezérlő:"

View File

@@ -329,6 +329,10 @@ END
#define STR_PARALLEL2 "Porta parallela 2"
#define STR_PARALLEL3 "Porta parallela 3"
#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_FDC "Controller FD:"

View File

@@ -328,6 +328,10 @@ END
#define STR_PARALLEL2 "パラレルポート2"
#define STR_PARALLEL3 "パラレルポート3"
#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_FDC "FDコントローラー:"

View File

@@ -328,6 +328,10 @@ END
#define STR_PARALLEL2 "병렬 포트 2"
#define STR_PARALLEL3 "병렬 포트 3"
#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_FDC "FD 컨트롤러:"

View File

@@ -328,6 +328,10 @@ END
#define STR_PARALLEL2 "Port równoległy 2"
#define STR_PARALLEL3 "Port równoległy 3"
#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_FDC "Kontroler dyskietek:"

View File

@@ -331,6 +331,10 @@ END
#define STR_PARALLEL2 "Porta paralela 2"
#define STR_PARALLEL3 "Porta paralela 3"
#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_FDC "Controlador FD:"

View File

@@ -328,6 +328,10 @@ END
#define STR_PARALLEL2 "Porta paralela 2"
#define STR_PARALLEL3 "Porta paralela 3"
#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_FDC "Controlador FD:"

View File

@@ -328,6 +328,10 @@ END
#define STR_PARALLEL2 "Параллельный порт LPT2"
#define STR_PARALLEL3 "Параллельный порт LPT3"
#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_FDC "Контроллер FD:"

View File

@@ -328,6 +328,10 @@ END
#define STR_PARALLEL2 "Paralelna vrata 2"
#define STR_PARALLEL3 "Paralelna vrata 3"
#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_FDC "Krmilnik disketnika:"

View File

@@ -328,6 +328,10 @@ END
#define STR_PARALLEL2 "Paralel port 2"
#define STR_PARALLEL3 "Paralel port 3"
#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_FDC "FD Kontrolcüsü:"

View File

@@ -328,6 +328,10 @@ END
#define STR_PARALLEL2 "Паралельний порт LPT2"
#define STR_PARALLEL3 "Паралельний порт LPT3"
#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_FDC "Контролер FD:"

View File

@@ -328,6 +328,10 @@ END
#define STR_PARALLEL2 "并口 2"
#define STR_PARALLEL3 "并口 3"
#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_FDC "软盘控制器:"

View File

@@ -328,6 +328,10 @@ END
#define STR_PARALLEL2 "並列埠 2"
#define STR_PARALLEL3 "並列埠 3"
#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_FDC "軟碟控制器:"

View File

@@ -36,7 +36,7 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#define UNICODE
#include <Windows.h>
#include <windows.h>
#include <process.h>
#include <SDL2/SDL.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/ui.h>
#include <86box/win.h>
#include <86box/serial_passthrough.h>
#include "../disk/minivhd/minivhd.h"
#include "../disk/minivhd/minivhd_util.h"
@@ -111,6 +112,7 @@ static char temp_pcap_dev[NET_CARD_MAX][128];
/* Ports category */
static int temp_lpt_devices[PARALLEL_MAX];
static int temp_serial[SERIAL_MAX], temp_lpt[PARALLEL_MAX];
static int temp_serial_passthrough_enabled[SERIAL_MAX];
/* Other peripherals category */
static int temp_fdc_card, temp_hdc, temp_ide_ter, temp_ide_qua, temp_cassette;
@@ -358,11 +360,13 @@ win_settings_init(void)
/* Ports category */
for (i = 0; i < PARALLEL_MAX; i++) {
temp_lpt_devices[i] = lpt_ports[i].device;
temp_lpt[i] = lpt_ports[i].enabled;
temp_lpt_devices[i] = lpt_ports[i].device;
temp_lpt[i] = lpt_ports[i].enabled;
}
for (i = 0; i < SERIAL_MAX; i++) {
temp_serial[i] = com_ports[i].enabled;
temp_serial_passthrough_enabled[i] = serial_passthrough_enabled[i];
}
for (i = 0; i < SERIAL_MAX; i++)
temp_serial[i] = com_ports[i].enabled;
/* Storage devices category */
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[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_passthrough_enabled[i] != serial_passthrough_enabled[i]);
}
/* Storage devices category */
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].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];
serial_passthrough_enabled[i] = temp_serial_passthrough_enabled[i];
}
/* Storage devices category */
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]);
}
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_SERIAL_PASS1 + i, temp_serial_passthrough_enabled[i]);
}
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);
}
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_passthrough_enabled[i] = settings_get_check(hdlg, IDC_CHECK_SERIAL_PASS1 + i);
}
default:
return FALSE;

View File

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