Merge branch '86Box:master' into master

This commit is contained in:
Akamaki
2026-02-26 17:17:10 +09:00
committed by GitHub
53 changed files with 6456 additions and 271 deletions

View File

@@ -1870,6 +1870,27 @@ update_mouse_msg(void)
(mouse_get_buttons() > 2) ? plat_get_string(STRING_MOUSE_RELEASE) : plat_get_string(STRING_MOUSE_RELEASE_MMB));
swprintf(mouse_msg[2], sizeof_w(mouse_msg[2]), L"%ls v%ls - %%i%%%% - %ls - %ls/%ls",
EMU_NAME_W, EMU_VERSION_FULL_W, wmachine, wcpufamily, wcpu);
#else
#ifdef __APPLE__
/*
* On macOS, BSD swprintf fails (returns -1) when the format string
* or a %ls argument contains non-ASCII wide characters (e.g. the
* native key symbols ⌘ U+2318, ⌫ U+232B) and the C locale is
* active. Store just the message suffixes here; the title update
* path in pc_render_monitor_dispatch() builds the full string
* without swprintf.
*/
wcsncpy(mouse_msg[0], plat_get_string(STRING_MOUSE_CAPTURE), sizeof_w(mouse_msg[0]) - 1);
mouse_msg[0][sizeof_w(mouse_msg[0]) - 1] = L'\0';
{
wchar_t *rel = (mouse_get_buttons() > 2) ? plat_get_string(STRING_MOUSE_RELEASE)
: plat_get_string(STRING_MOUSE_RELEASE_MMB);
wcsncpy(mouse_msg[1], rel, sizeof_w(mouse_msg[1]) - 1);
mouse_msg[1][sizeof_w(mouse_msg[1]) - 1] = L'\0';
}
mouse_msg[2][0] = L'\0';
#else
swprintf(mouse_msg[0], sizeof_w(mouse_msg[0]), L"%%i%%%% - %ls",
plat_get_string(STRING_MOUSE_CAPTURE));
@@ -1877,6 +1898,7 @@ update_mouse_msg(void)
(mouse_get_buttons() > 2) ? plat_get_string(STRING_MOUSE_RELEASE) : plat_get_string(STRING_MOUSE_RELEASE_MMB));
wcsncpy(mouse_msg[2], L"%i%%", sizeof_w(mouse_msg[2]));
#endif
#endif
}
void
@@ -2009,11 +2031,20 @@ pc_run(void)
else
fps = ((fps + 20) / 50) * 50;
#endif
swprintf(temp, sizeof_w(temp), mouse_msg[mouse_msg_idx], fps / (force_10ms ? 1 : 10));
#ifdef __APPLE__
/*
* mouse_msg[] stores suffixes only on macOS (see update_mouse_msg).
* Build the title without passing non-ASCII chars through swprintf.
*/
swprintf(temp, sizeof_w(temp), L"%i%%", fps / (force_10ms ? 1 : 10));
if (mouse_msg[mouse_msg_idx][0]) {
wcsncat(temp, L" - ", sizeof_w(temp) - wcslen(temp) - 1);
wcsncat(temp, mouse_msg[mouse_msg_idx], sizeof_w(temp) - wcslen(temp) - 1);
}
/* Needed due to modifying the UI on the non-main thread is a big no-no. */
dispatch_async_f(dispatch_get_main_queue(), wcsdup((const wchar_t *) temp), _ui_window_title);
#else
swprintf(temp, sizeof_w(temp), mouse_msg[mouse_msg_idx], fps / (force_10ms ? 1 : 10));
ui_window_title(temp);
#endif
title_update = 0;

View File

@@ -84,7 +84,10 @@ opti499_recalc(opti499_t *dev)
base = 0xd0000 + (i << 14);
if ((dev->regs[0x22] & ((base >= 0xe0000) ? 0x20 : 0x40)) && (dev->regs[0x23] & (1 << i))) {
shflags = MEM_READ_INTERNAL;
if (dev->regs[0x2d] & (1 << ((i >> 1) + 2)))
shflags = MEM_READ_EXTANY;
else
shflags = MEM_READ_INTERNAL;
shflags |= (dev->regs[0x22] & ((base >= 0xe0000) ? 0x08 : 0x10)) ? MEM_WRITE_DISABLED : MEM_WRITE_INTERNAL;
} else {
if (dev->regs[0x2d] & (1 << ((i >> 1) + 2)))

View File

@@ -12,11 +12,17 @@
*
* Copyright 2020 Miran Grca.
*/
#ifdef ENABLE_VL82C48X_LOG
#include <stdarg.h>
#endif
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <wchar.h>
#define HAVE_STDARG_H
#include <86box/86box.h>
#include "cpu.h"
#include <86box/timer.h>
@@ -27,11 +33,31 @@
#include <86box/nmi.h>
#include <86box/port_92.h>
#include <86box/chipset.h>
#include <86box/log.h>
#ifdef ENABLE_VL82C48X_LOG
int vl82c48x_do_log = ENABLE_VL82C48X_LOG;
static void
vl82c48x_log(void *priv, const char *fmt, ...)
{
if (vl82c48x_do_log) {
va_list ap;
va_start(ap, fmt);
log_out(priv, fmt, ap);
va_end(ap);
}
}
#else
# define vl82c48x_log(fmt, ...)
#endif
typedef struct vl82c480_t {
uint8_t idx;
uint8_t regs[256];
uint32_t banks[4];
void * log; // New logging system
} vl82c480_t;
static int
@@ -77,6 +103,14 @@ vl82c480_recalc_shadow(vl82c480_t *dev)
}
}
/* Implement ROMCS# disable portion of ROMMOV behavior */
if ((dev->regs[0x11] == 0x00) && ((dev->regs[0x0c] & 0x20) || (dev->regs[0x0c] & 0x10)))
mem_set_mem_state(0xe0000, 0x10000, MEM_READ_EXTERNAL | MEM_WRITE_EXTERNAL);
if (!(dev->regs[0x0f] & 0x0f) && !(dev->regs[0x0c] & 0x20))
mem_set_mem_state(0xc0000, 0x8000, MEM_READ_EXTERNAL | MEM_WRITE_EXTERNAL);
if (!(dev->regs[0x0f] & 0xf0) && !((dev->regs[0x0c] & 0x30) == 0x30))
mem_set_mem_state(0xc8000, 0x8000, MEM_READ_EXTERNAL | MEM_WRITE_EXTERNAL);
flushmmucache();
}
@@ -116,6 +150,8 @@ vl82c480_write(uint16_t addr, uint8_t val, void *priv)
{
vl82c480_t *dev = (vl82c480_t *) priv;
vl82c48x_log(dev->log, "[%04X:%08X] VL82c48x: [W] %04X = %02X\n", CS, cpu_state.pc, addr, val);
switch (addr) {
case 0xec:
dev->idx = val;
@@ -146,6 +182,10 @@ vl82c480_write(uint16_t addr, uint8_t val, void *priv)
case 0x07:
dev->regs[dev->idx] = (dev->regs[dev->idx] & 0x40) | (val & 0xbf);
break;
case 0x0c:
dev->regs[dev->idx] = val;
vl82c480_recalc_shadow(dev);
break;
case 0x0d ... 0x12:
dev->regs[dev->idx] = val;
vl82c480_recalc_shadow(dev);
@@ -195,6 +235,8 @@ vl82c480_read(uint16_t addr, void *priv)
break;
}
vl82c48x_log(dev->log, "[%04X:%08X] VL82c48x: [R] %04X = %02X\n", CS, cpu_state.pc, addr, ret);
return ret;
}
@@ -203,6 +245,11 @@ vl82c480_close(void *priv)
{
vl82c480_t *dev = (vl82c480_t *) priv;
if (dev->log != NULL) {
log_close(dev->log);
dev->log = NULL;
}
free(dev);
}
@@ -217,6 +264,8 @@ vl82c480_init(const device_t *info)
uint8_t min_j = (machines[machine].init == machine_at_monsoon_init) ? 2 : 2;
uint8_t max_j = (machines[machine].init == machine_at_monsoon_init) ? 7 : 7;
dev->log = log_open("VL82c48x");
dev->regs[0x00] = info->local;
dev->regs[0x01] = 0xff;
dev->regs[0x02] = 0x8a;

View File

@@ -12,7 +12,7 @@
* win2kgamer
*
* Copyright 2020-2025 Miran Grca.
* Copyright 2025 win2kgamer
* Copyright 2025-2026 win2kgamer
*/
#ifdef ENABLE_VL82C59X_LOG
#include <stdarg.h>
@@ -80,6 +80,9 @@ typedef struct vl82c59x_t {
port_92_t *port_92;
nvr_t *nvr;
uint32_t banks[4];
uint8_t bankcfg[4];
void * log; /* New logging system */
} vl82c59x_t;
@@ -207,6 +210,52 @@ vl82c59x_set_pm_io(void *priv)
}
void
vl82c59x_recalc_banks(vl82c59x_t *dev)
{
uint32_t sizes[8] = { 2048, 4096, 8192, 16384, 32768, 65536, 131072, 262144 };
uint8_t shifts[4] = { 0, 4, 0, 4 };
uint8_t regs[4] = { 0x58, 0x58, 0x59, 0x59 };
uint32_t total = 0;
for (uint8_t i = 0; i < 4; i++) {
uint8_t shift = shifts[i];
uint8_t reg = regs[i];
uint8_t cfg = (dev->pci_conf[reg] >> shift) & 0x03; /* Module types */
uint8_t dbl = ((dev->pci_conf[reg] >> shift) & 0x08) ? 1 : 0; /* Single/double sided */
uint8_t conf = (cfg << 1) | (dbl & 0x01);
uint32_t size = sizes[conf];
vl82c59x_log(dev->log, "VL82c59x DRAM recalc: bank %i, cfg = %02X, dbl = %i, conf = %02X, size = %i, RAMCTL0 = %02X\n", i, cfg, dbl, conf, size, dev->pci_conf[0x5c]);
vl82c59x_log(dev->log, "VL82c59x DRAM recalc: bank %i size = %i\n", i, dev->banks[i]);
/* Handle case where the BIOS programs RAMCFGx for dual-sided/ranked memory when single-sided memory is installed */
if (((dev->bankcfg[i] & 0x08) == 0x00) && dbl == 1) {
size = sizes[conf - 1];
vl82c59x_log(dev->log, "VL82c59x DRAM recalc: bank %i mismatch, bankcfg = %02X, reg = %02X\n", dev->bankcfg[i], dev->pci_conf[reg]);
}
if (!(dev->pci_conf[0x5c] & (1 << i)))
size = 0;
total += MIN(dev->banks[i], size);
vl82c59x_log(dev->log, "VL82c59x DRAM recalc: bank %i, total = %i\n", i, total);
}
if (total > 1024) {
mem_mapping_set_addr(&ram_low_mapping, 0x00000000, 0x000a0000);
mem_mapping_set_addr(&ram_high_mapping, 0x00100000, (total - 1024) << 10);
} else {
if (total >= 1024)
mem_mapping_set_addr(&ram_low_mapping, 0x00000000, 0x000a0000);
else
mem_mapping_disable(&ram_low_mapping);
mem_mapping_disable(&ram_high_mapping);
}
flushmmucache();
}
static void
vl82c59x_write(int func, int addr, UNUSED(int len), uint8_t val, void *priv)
{
@@ -231,12 +280,21 @@ vl82c59x_write(int func, int addr, UNUSED(int len), uint8_t val, void *priv)
case 0x58: /* RAMCFG0 */
case 0x59: /* RAMCFG1 */
dev->pci_conf[addr] = val;
vl82c59x_log(dev->log, "VL82c59x: RAMCFGx write, RAMCFG0 = %02X, RAMCFG1 = %02X\n", dev->pci_conf[0x58], dev->pci_conf[0x59]);
if (machines[machine].init == machine_at_bravoms586_init)
vl82c59x_recalc_banks(dev);
break;
case 0x5a: /* Wildcat EDO RAM control */
if (dev->type == 0x01)
dev->pci_conf[addr] = val;
break;
case 0x5c ... 0x5e: /* RAMCTL0-RAMCTL2 */
case 0x5c: /* RAMCTL0 */
vl82c59x_log(dev->log, "VL82c59x: RAMCTL0 write\n");
dev->pci_conf[addr] = val;
if (machines[machine].init == machine_at_bravoms586_init)
vl82c59x_recalc_banks(dev);
break;
case 0x5d ... 0x5e: /* RAMCTL1-RAMCTL2 */
case 0x5f ... 0x60:
case 0x62:
/* Apricot XEN-PC Ruby/Jade BIOS requires bit 2 to be set or */
@@ -483,6 +541,47 @@ vl82c59x_reset(void *priv)
cpu_cache_int_enabled = 1;
cpu_cache_ext_enabled = 1;
cpu_update_waitstates();
/* Init DRAM bank registers */
uint32_t sizes[8] = { 2048, 4096, 8192, 16384, 32768, 65536, 131072, 262144 };
uint8_t reg_vals[8] = { 0x00, 0x08, 0x01, 0x09, 0x02, 0x0a, 0x03, 0x0b };
uint32_t ms = mem_size;
dev->pci_conf[0x58] = 0x00; /* RAMCFG0 */
dev->pci_conf[0x59] = 0x00; /* RAMCFG1 */
dev->pci_conf[0x5c] = 0x00; /* RAMCTL0 */
if (ms > 0) for (uint8_t i = 0; i < 4; i++ ) {
for (uint8_t j = 0; j < 8; j++ ) {
if (ms >= sizes[j] ) {
dev->banks[i] = sizes[j];
dev->bankcfg[i] = reg_vals[j];
dev->pci_conf[0x5c] |= (1 << i);
} else
break;
}
ms -= dev->banks[i];
if ((ms == 0 || dev->banks[i] == 0))
break;
}
for (uint8_t i = 0; i < 4; i++ ) {
if (dev->banks[0] != 0)
dev->pci_conf[0x58] = (dev->bankcfg[0] & 0x0f);
if (dev->banks[1] != 0)
dev->pci_conf[0x58] |= ((dev->bankcfg[1] & 0x0f) << 4);
if (dev->banks[2] != 0)
dev->pci_conf[0x59] = (dev->bankcfg[2] & 0x0f);
if (dev->banks[3] != 0)
dev->pci_conf[0x59] |= ((dev->bankcfg[3] & 0x0f) << 4);
}
vl82c59x_log(dev->log, "VL82c59x: DRAM bank init, RAMCFG0 = %02X, RAMCFG1 = %02X, RAMCTL0 = %02X\n", dev->pci_conf[0x58], dev->pci_conf[0x59], dev->pci_conf[0x5c]);
vl82c59x_log(dev->log, "VL82c59x: DRAM bank vals: %i, %i, %i, %i\n", dev->banks[0], dev->banks[1], dev->banks[2], dev->banks[3]);
}
static void

View File

@@ -1016,27 +1016,37 @@ load_image_file(char *dest, char *p, uint8_t *ui_wp)
int ret = 0;
char *slash = NULL;
char *above = NULL;
char *above2 = NULL;
char *use = NULL;
if ((slash = memrmem(usr_path + strlen(usr_path) - 2, usr_path, "/")) != NULL) {
slash++;
above = (char *) calloc(1, slash - usr_path + 1);
memcpy(above, usr_path, slash - usr_path);
if ((slash = memrmem(above + strlen(above) - 2, above, "/")) != NULL) {
slash++;
above2 = (char *) calloc(1, slash - above + 1);
memcpy(above2, above, slash - above);
}
}
if (strstr(p, "wp://") == p) {
p += 5;
prefix = "wp://";
if (ui_wp != NULL)
*ui_wp = 1;
p += 5;
prefix = "wp://";
if (ui_wp != NULL)
*ui_wp = 1;
} else if ((ui_wp != NULL) && *ui_wp)
prefix = "wp://";
prefix = "wp://";
if (strstr(p, "ioctl://") == p) {
if (strlen(p) > (MAX_IMAGE_PATH_LEN - 11))
ret = 1;
else
snprintf(dest, MAX_IMAGE_PATH_LEN, "%s", p);
if (strlen(p) > (MAX_IMAGE_PATH_LEN - 11))
ret = 1;
else
snprintf(dest, MAX_IMAGE_PATH_LEN, "%s", p);
if (above2 != NULL)
free(above2);
if (above != NULL)
free(above);
@@ -1051,6 +1061,13 @@ load_image_file(char *dest, char *p, uint8_t *ui_wp)
else
snprintf(dest, MAX_IMAGE_PATH_LEN, "%s%s%s%s", prefix, exe_path, path_get_slash(exe_path),
p + strlen("<exe_path>/"));
} else if (memcmp(p, "../../", strlen("../../")) == 0) {
use = (above2 == NULL) ? usr_path : above2;
if ((strlen(prefix) + strlen(use) + strlen(path_get_slash(use)) + strlen(p + strlen("../../"))) >
(MAX_IMAGE_PATH_LEN - 11))
ret = 1;
else
snprintf(dest, MAX_IMAGE_PATH_LEN, "%s%s%s%s", prefix, use, path_get_slash(use), p + strlen("../../"));
} else if (memcmp(p, "../", strlen("../")) == 0) {
use = (above == NULL) ? usr_path : above;
if ((strlen(prefix) + strlen(use) + strlen(path_get_slash(use)) + strlen(p + strlen("../"))) >
@@ -1072,6 +1089,9 @@ load_image_file(char *dest, char *p, uint8_t *ui_wp)
path_normalize(dest);
if (above2 != NULL)
free(above2);
if (above != NULL)
free(above);
@@ -3146,11 +3166,25 @@ save_image_file(char *cat, char *var, char *src)
char *prefix = "";
char *slash = NULL;
char *above = NULL;
char *above2 = NULL;
char *above3 = NULL;
if ((slash = memrmem(usr_path + strlen(usr_path) - 2, usr_path, "/")) != NULL) {
slash++;
above = (char *) calloc(1, slash - usr_path + 1);
memcpy(above, usr_path, slash - usr_path);
if ((slash = memrmem(above + strlen(above) - 2, above, "/")) != NULL) {
slash++;
above2 = (char *) calloc(1, slash - above + 1);
memcpy(above2, above, slash - above);
if ((slash = memrmem(above2 + strlen(above2) - 2, above2, "/")) != NULL) {
slash++;
above3 = (char *) calloc(1, slash - above2 + 1);
memcpy(above3, above2, slash - above2);
}
}
}
path_normalize(src);
@@ -3164,7 +3198,11 @@ save_image_file(char *cat, char *var, char *src)
sprintf(temp, "%s", src);
else if (!strnicmp(src, usr_path, strlen(usr_path)))
sprintf(temp, "%s%s", prefix, &src[strlen(usr_path)]);
else if ((above != NULL) && !strnicmp(src, above, strlen(above)))
/* Do not relativize to root. */
else if ((above2 != NULL) && (above3 != NULL) && !strnicmp(src, above2, strlen(above2)))
sprintf(temp, "../../%s%s", prefix, &src[strlen(above2)]);
/* Do not relativize to root. */
else if ((above != NULL) && (above2 != NULL) && !strnicmp(src, above, strlen(above)))
sprintf(temp, "../%s%s", prefix, &src[strlen(above)]);
else if (!strnicmp(src, exe_path, strlen(exe_path)))
sprintf(temp, "<exe_path>/%s%s", prefix, &src[strlen(exe_path)]);
@@ -3173,6 +3211,12 @@ save_image_file(char *cat, char *var, char *src)
ini_section_set_string(cat, var, temp);
if (above3 != NULL)
free(above3);
if (above2 != NULL)
free(above2);
if (above != NULL)
free(above);
}

View File

@@ -2184,7 +2184,7 @@ read_p1(atkbc_t *dev)
-----------------
IBM PS/1: xxxxxxxx
IBM PS/2 MCA: xxxxx1xx
IBM PS/2 Model 30-286: xxxxx1xx
IBM PS/2 Model 30-286: x0xxx1xx
Intel AMI Pentium BIOS'es with AMI MegaKey KB-5 keyboard controller: x1x1xxxx
Acer: xxxxx0xx
Packard Bell PB450: xxxxx1xx
@@ -2199,7 +2199,8 @@ read_p1(atkbc_t *dev)
Acer: Pull down bit 6 if primary display is MDA.
Pull down bit 2 always (must be so to enable CMOS Setup).
IBM PS/1: Pull down bit 6 if current floppy drive is 3.5".
IBM PS/2 Model 30-286: Pull down bits 5 and 4 based on planar memory size.
IBM PS/2 Model 30-286: Pull down bit 6 always (for 1.44M floppy).
Pull down bits 5 and 4 based on planar memory size.
Epson Action Tower 2600: Pull down bit 3 always (for Epson logo).
NCR: Pull down bit 5 always (power-on default speed = high).
Pull down bit 3 if there is no FPU.
@@ -2215,6 +2216,7 @@ read_p1(atkbc_t *dev)
Bit 6: Mostly, display: 0 = CGA, 1 = MDA, inverted on Xi8088 and Acer KBC's;
Intel AMI MegaKey KB-5: Used for green features, SMM handler expects it to be set;
IBM PS/1 Model 2011: 0 = current FDD is 3.5", 1 = current FDD is 5.25";
IBM PS/2 Model 30-286: 0 = drive A is 1.44M, 1 = drive A is 720k;
Compaq: 0 = Compaq dual-scan display, 1 = non-Compaq display.
Bit 5: Mostly, manufacturing jumper: 0 = installed (infinite loop at POST), 1 = not installed;
NCR: power-on default speed: 0 = high, 1 = low;

View File

@@ -52,6 +52,14 @@
Bit 0 = ????
*/
/*
Intel Monsoon bit meanings:
Bit 5 = Password enable
Bit 4 = Onboard video: 1 = disabled, 0 = enabled
Bit 3 = CMOS Setup enable
Bit 2 = CMOS clear: 1 = normal, 0 = clear CMOS
*/
typedef struct phoenix_486_jumper_t {
uint8_t type;
uint8_t jumper;
@@ -84,7 +92,11 @@ phoenix_486_jumper_write(UNUSED(uint16_t addr), uint8_t val, void *priv)
dev->jumper = val & 0xbf;
else if (dev->type == 2) /* PB600 */
dev->jumper = ((val & 0xbf) | 0x02);
else
else if (dev->type == 3) { /* Intel Monsoon */
dev->jumper = ((val & 0xef) | 0x2c);
if (gfxcard[0] != 0x01)
dev->jumper |= 0x10;
} else
dev->jumper = val;
}
@@ -106,7 +118,11 @@ phoenix_486_jumper_reset(void *priv)
dev->jumper = 0x00;
else if (dev->type == 2) /* PB600 */
dev->jumper = 0x02;
else {
else if (dev->type == 3) { /* Intel Monsoon */
dev->jumper = 0x2c;
if (gfxcard[0] != 0x01)
dev->jumper |= 0x10;
} else {
dev->jumper = 0x9f;
if (gfxcard[0] != 0x01)
dev->jumper |= 0x40;
@@ -176,3 +192,18 @@ const device_t phoenix_486_jumper_pci_pb600_device = {
.force_redraw = NULL,
.config = NULL
};
const device_t phoenix_486_jumper_monsoon_device = {
.name = "Phoenix 486 Jumper Readout (Monsoon)",
.internal_name = "phoenix_486_jumper_monsoon",
.flags = 0,
.local = 3,
.init = phoenix_486_jumper_init,
.close = phoenix_486_jumper_close,
.reset = phoenix_486_jumper_reset,
.available = NULL,
.speed_changed = NULL,
.force_redraw = NULL,
.config = NULL
};

View File

@@ -381,6 +381,7 @@ typedef struct hdc_t {
pc_timer_t timer;
int8_t state; /* controller state */
int8_t reset; /* reset state counter */
int8_t ready; /* ready state counter */
/* Data transfer. */
int16_t buf_idx; /* buffer index and pointer */
@@ -723,6 +724,15 @@ hdc_callback(void *priv)
uint8_t cmd = ccb->cmd & 0x0f;
#endif
/* If we are returning from a RESET, handle this first. */
if (dev->reset) {
ps1_hdc_log("XTA reset.\n");
dev->status &= ~ASR_BUSY;
dev->reset = 0;
do_finish(dev);
return;
}
/* Clear the SSB error bits. */
dev->ssb.track_0 = 0;
dev->ssb.cylinder_err = 0;
@@ -754,6 +764,12 @@ hdc_callback(void *priv)
return;
}
if (!(dev->ready | no_data)) {
/* Delay a bit, transfer not ready. */
timer_advance_u64(&dev->timer, HDC_TIME);
return;
}
switch (dev->state) {
case STATE_IDLE:
/* Seek to cylinder if requested. */
@@ -937,9 +953,6 @@ do_send:
break;
case CMD_WRITE_VERIFY:
no_data = 1;
fallthrough;
case CMD_WRITE_SECTORS:
if (!drive->present) {
dev->ssb.not_ready = 1;
@@ -947,6 +960,12 @@ do_send:
return;
}
if (!(dev->ready | no_data)) {
/* Delay a bit, transfer not ready. */
timer_advance_u64(&dev->timer, HDC_TIME);
return;
}
switch (dev->state) {
case STATE_IDLE:
/* Seek to cylinder if requested. */
@@ -1231,24 +1250,21 @@ hdc_write(uint16_t port, uint8_t val, void *priv)
if (val & ACR_INT_EN)
set_intr(dev, 0); /* clear IRQ */
if (dev->reset != 0) {
if (++dev->reset == 3) {
dev->reset = 0;
set_intr(dev, 1);
}
break;
if (val & ACR_RESET) {
dev->reset = 1;
dev->status |= ASR_BUSY;
/* Schedule command execution. */
timer_set_delay_u64(&dev->timer, HDC_TIME);
}
if (val & ACR_RESET)
dev->reset = 1;
break;
case 4: /* ATTN */
dev->status &= ~ASR_INT_REQ;
if (val & ATT_DATA) {
/* Dunno. Start PIO/DMA now? */
}
if (val & ATT_DATA)
dev->ready = 1;
else
dev->ready = 0;
if (val & ATT_SSB) {
if (dev->attn & ATT_CCB) {

View File

@@ -234,6 +234,7 @@ extern const device_t nec_mate_unk_device;
extern const device_t phoenix_486_jumper_device;
extern const device_t phoenix_486_jumper_pci_device;
extern const device_t phoenix_486_jumper_pci_pb600_device;
extern const device_t phoenix_486_jumper_monsoon_device;
extern const device_t ast_readout_device;
extern const device_t ast_nvr_device;

View File

@@ -31,6 +31,43 @@
#define PCI_REG_LATENCY_TIMER 0x0d
#define PCI_REG_HEADER_TYPE 0x0e
#define PCI_REG_BIST 0x0f
#define PCI_REG_BAR0_BYTE0 0x10
#define PCI_REG_BAR0_BYTE1 0x11
#define PCI_REG_BAR0_BYTE2 0x12
#define PCI_REG_BAR0_BYTE3 0x13
#define PCI_REG_BAR1_BYTE0 0x14
#define PCI_REG_BAR1_BYTE1 0x15
#define PCI_REG_BAR1_BYTE2 0x16
#define PCI_REG_BAR1_BYTE3 0x17
#define PCI_REG_BAR2_BYTE0 0x18
#define PCI_REG_BAR2_BYTE1 0x19
#define PCI_REG_BAR2_BYTE2 0x1a
#define PCI_REG_BAR2_BYTE3 0x1b
#define PCI_REG_BAR3_BYTE0 0x1c
#define PCI_REG_BAR3_BYTE1 0x1d
#define PCI_REG_BAR3_BYTE2 0x1e
#define PCI_REG_BAR3_BYTE3 0x1e
#define PCI_REG_BAR4_BYTE0 0x20
#define PCI_REG_BAR4_BYTE1 0x21
#define PCI_REG_BAR4_BYTE2 0x22
#define PCI_REG_BAR4_BYTE3 0x23
#define PCI_REG_BAR5_BYTE0 0x24
#define PCI_REG_BAR5_BYTE1 0x25
#define PCI_REG_BAR5_BYTE2 0x26
#define PCI_REG_BAR5_BYTE3 0x27
#define PCI_REG_SUBVEN_ID_L 0x2c
#define PCI_REG_SUBVEN_ID_H 0x2d
#define PCI_REG_SUBSYS_ID_L 0x2e
#define PCI_REG_SUBSYS_ID_H 0x2f
#define PCI_REG_ROM_BAR_BYTE0 0x30
#define PCI_REG_ROM_BAR_BYTE1 0x31
#define PCI_REG_ROM_BAR_BYTE2 0x32
#define PCI_REG_ROM_BAR_BYTE3 0x33
#define PCI_REG_CAPS_PTR 0x34
#define PCI_REG_INT_LINE 0x3c
#define PCI_REG_INT_PIN 0x3d
#define PCI_REG_MIN_GRANT 0x3e
#define PCI_REG_MAX_LAT 0x3f
#define PCI_COMMAND_L_IO 0x01
#define PCI_COMMAND_L_MEM 0x02

View File

@@ -84,6 +84,7 @@ typedef struct ncr_t {
int (*dma_send_ext)(void *priv, void *ext_priv);
int (*dma_initiator_receive_ext)(void *priv, void *ext_priv);
void (*timer)(void *ext_priv, double period);
int (*irq_ena)(void *priv, void *ext_priv, int state);
scsi_bus_t scsibus;
} ncr_t;

View File

@@ -0,0 +1,19 @@
/*
* 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.
*
* Emulation of QLogic QLA1x40/QLA1x80/QLA1x160 SCSI HBA.
*
* Authors: Dmitry Borisov, <di.sean@protonmail.com>
*
* Copyright 2026 Dmitry Borisov
*/
#pragma once
extern const device_t qla1040b_device;
extern const device_t qla1080_device;
extern const device_t qla1240_device;
extern const device_t qla1280_device;
extern const device_t qla12160a_device;

View File

@@ -15,7 +15,7 @@
*
* Copyright 2008-2018 Sarah Walker.
* Copyright 2016-2018 Miran Grca.
* Copyright 2024-2025 Jasmine Iwanek.
* Copyright 2024-2026 Jasmine Iwanek.
*/
#ifndef SOUND_SND_SB_H
#define SOUND_SND_SB_H
@@ -28,12 +28,14 @@
enum {
SADLIB = 1, /* No DSP */
SB_DSP_105, /* DSP v1.05, Original CT1320 (Also known as CT1310) */
SB_DSP_103, /* DSP v1.03, "killer card" prototype (Also known as CT1310) */
SB_DSP_105, /* DSP v1.05, Original CT1320 */
SB_DSP_200, /* DSP v2.00 */
SB_DSP_201, /* DSP v2.01 - needed for high-speed DMA, Seen on CT1350B with CT1336 */
SB_DSP_202, /* DSP v2.02 - Seen on CT1350B with CT1336A */
SBPRO_DSP_300, /* DSP v3.00 */
SBPRO2_DSP_302, /* DSP v3.02 + OPL3 */
SBPRO_DSP_301, /* DSP v3.01 */
SBPRO_DSP_302, /* DSP v3.02 */
SB16_DSP_404, /* DSP v4.05 + OPL3 */
SB16_DSP_405, /* DSP v4.05 + OPL3 */
SB16_DSP_406, /* DSP v4.06 + OPL3 */

View File

@@ -9,8 +9,9 @@
#define SB_SUBTYPE_CLONE_AZT1605_0X0C 2 /* Aztech Sound Galaxy Nova 16 Extra /
Packard Bell Forte 16, DSP 2.1 - SBPRO2 clone */
#define SB_SUBTYPE_CLONE_AZTPR16_0X09 3 /* Aztech Sound Galaxy Pro 16 Extra */
#define SB_SUBTYPE_ESS_ES688 4 /* ESS Technology ES688 */
#define SB_SUBTYPE_ESS_ES1688 5 /* ESS Technology ES1688 */
#define SB_SUBTYPE_MVD201 4 /* Mediavision MVD201, found on the thunderboard and PAS16 */
#define SB_SUBTYPE_ESS_ES688 5 /* ESS Technology ES688 */
#define SB_SUBTYPE_ESS_ES1688 6 /* ESS Technology ES1688 */
/* ESS-related */
#define IS_ESS(dsp) ((dsp)->sb_subtype >= SB_SUBTYPE_ESS_ES688) /* Check for future ESS cards here */
@@ -20,6 +21,9 @@
#define IS_AZTECH(dsp) ((dsp)->sb_subtype == SB_SUBTYPE_CLONE_AZT2316A_0X11 || (dsp)->sb_subtype == SB_SUBTYPE_CLONE_AZT1605_0X0C || (dsp)->sb_subtype == SB_SUBTYPE_CLONE_AZTPR16_0X09) /* check for future AZT cards here */
#define AZTECH_EEPROM_SIZE 36
/* MediaVision related */
#define IS_MV201(dsp) ((dsp)->sb_subtype >= SB_SUBTYPE_MVD201)
typedef struct sb_dsp_t {
int sb_type;
int sb_subtype; /* which clone */
@@ -102,6 +106,7 @@ typedef struct sb_dsp_t {
int sbreset;
uint8_t sbreaddat;
uint8_t sb_command;
uint8_t sb_last_command;
uint8_t sb_test;
int sb_timei;
int sb_timeo;

View File

@@ -228,6 +228,9 @@ extern const device_t entertainer_device;
/* Mindscape Music Board */
extern const device_t mmb_device;
/* MediaVision ThunderBoard */
extern const device_t thunderboard_device;
/* OPTi 82c93x */
extern const device_t acermagic_s20_device;
extern const device_t mirosound_pcm10_device;

View File

@@ -65,6 +65,7 @@ typedef union {
typedef struct ibm8514_t {
rom_t bios_rom;
rom_t bios_rom2;
uint8_t *rom1;
uint8_t *rom2;
hwcursor8514_t hwcursor;
@@ -187,6 +188,7 @@ typedef struct ibm8514_t {
uint32_t dst_ge_offset;
uint16_t src_pitch;
uint16_t dst_pitch;
uint16_t read_pixel;
int64_t cur_x_24bpp;
int64_t cur_y_24bpp;
int64_t dest_x_24bpp;

View File

@@ -1300,7 +1300,7 @@ voodoo_generate(uint8_t *code_block, voodoo_t *voodoo, voodoo_params_t *params,
addbyte(0x35); /*XOR EAX, 0xff*/
addlong(0xff);
}
addbyte(0x8e); /*ADD EAX, 1*/
addbyte(0x83); /*ADD EAX, 1*/
addbyte(0xc0);
addbyte(1);
addbyte(0x0f); /*IMUL EAX, EBX*/
@@ -2327,7 +2327,7 @@ voodoo_generate(uint8_t *code_block, voodoo_t *voodoo, voodoo_params_t *params,
addlong(offsetof(voodoo_state_t, z));
addbyte(0xc1); /*SHR EAX, 12*/
addbyte(0xe8);
addbyte(12);
addbyte(20);
addbyte(0x25); /*AND EAX, 0xff*/
addlong(0xff);
#if 0

View File

@@ -375,6 +375,7 @@ extern const device_t gd5401_isa_device;
extern const device_t gd5401_onboard_device;
extern const device_t gd5402_isa_device;
extern const device_t gd5402_onboard_device;
extern const device_t gd5402_onboard_commodore_device;
extern const device_t gd5420_isa_device;
extern const device_t gd5420_onboard_device;
extern const device_t gd5422_isa_device;
@@ -383,9 +384,11 @@ extern const device_t gd5424_onboard_device;
extern const device_t gd5426_isa_device;
extern const device_t gd5426_diamond_speedstar_pro_a1_isa_device;
extern const device_t gd5426_vlb_device;
extern const device_t gd5426_onboard_isa_device;
extern const device_t gd5426_onboard_device;
extern const device_t gd5428_isa_device;
extern const device_t gd5428_vlb_onboard_device;
extern const device_t gd5428_vlb_onboard_tandy_device;
extern const device_t gd5428_vlb_device;
extern const device_t gd5428_diamond_speedstar_pro_b1_vlb_device;
extern const device_t gd5428_boca_isa_device;

View File

@@ -586,7 +586,7 @@ machine_at_cmdsl386sx25_init(const machine_t *model)
return ret;
if (gfxcard[0] == VID_INTERNAL)
device_add(&gd5402_onboard_device);
device_add(&gd5402_onboard_commodore_device);
machine_at_common_init_ex(model, 2);

View File

@@ -294,11 +294,13 @@ machine_at_vect486vl_init(const machine_t *model) // has HDC problems
int ret;
ret = bios_load_linear("roms/machines/vect486vl/aa0500.ami",
0x000e0000, 131072, 0);
0x000c0000, 262144, 0);
if (bios_only || !ret)
return ret;
memcpy(&rom[0x00020000], rom, 131072);
if (gfxcard[0] == VID_INTERNAL)
device_add(machine_get_vid_device(machine));
@@ -311,6 +313,15 @@ machine_at_vect486vl_init(const machine_t *model) // has HDC problems
device_add(&ide_isa_device);
device_add_params(&fdc37c6xx_device, (void *) (FDC37C651 | FDC37C6XX_IDE_PRI));
video_reset(gfxcard[0]);
if (gfxcard[0] != VID_INTERNAL) {
for (uint16_t i = 0; i < 32768; i++)
rom[i] = mem_readb_phys(0x000c0000 + i);
}
mem_mapping_set_addr(&bios_mapping, 0x0c0000, 0x40000);
mem_mapping_set_exec(&bios_mapping, rom);
return ret;
}
@@ -321,11 +332,13 @@ machine_at_d824_init(const machine_t *model)
int ret;
ret = bios_load_linear("roms/machines/d824/fts-biosupdated824noflashbiosepromv320-320334-160.bin",
0x000e0000, 131072, 0);
0x000c0000, 262144, 0);
if (bios_only || !ret)
return ret;
memcpy(&rom[0x00020000], rom, 131072);
if (gfxcard[0] == VID_INTERNAL)
device_add(machine_get_vid_device(machine));
@@ -342,6 +355,15 @@ machine_at_d824_init(const machine_t *model)
device_add(&ide_isa_device);
device_add_params(&fdc37c6xx_device, (void *) FDC37C651);
video_reset(gfxcard[0]);
if (gfxcard[0] != VID_INTERNAL) {
for (uint16_t i = 0; i < 32768; i++)
rom[i] = mem_readb_phys(0x000c0000 + i);
}
mem_mapping_set_addr(&bios_mapping, 0x0c0000, 0x40000);
mem_mapping_set_exec(&bios_mapping, rom);
return ret;
}

View File

@@ -389,6 +389,7 @@ machine_at_monsoon_init(const machine_t *model)
device_add_params(&fdc37c6xx_device, (void *) (FDC37C651 | FDC37C6XX_IDE_PRI));
device_add(&intel_flash_bxt_device);
device_add(&phoenix_486_jumper_monsoon_device);
if (gfxcard[0] == VID_INTERNAL)
device_add(machine_get_vid_device(machine));

View File

@@ -59,12 +59,12 @@ machine_at_p5a_init(const machine_t *model)
pci_register_slot(0x0F, PCI_CARD_SOUTHBRIDGE_IDE, 1, 2, 3, 4);
pci_register_slot(0x03, PCI_CARD_SOUTHBRIDGE_PMU, 1, 2, 3, 4);
pci_register_slot(0x02, PCI_CARD_SOUTHBRIDGE_USB, 1, 2, 3, 4);
pci_register_slot(0x0C, PCI_CARD_NORMAL, 1, 2, 3, 4);
pci_register_slot(0x0B, PCI_CARD_NORMAL, 2, 3, 4, 1);
pci_register_slot(0x0A, PCI_CARD_NORMAL, 3, 4, 1, 2);
pci_register_slot(0x09, PCI_CARD_NORMAL, 4, 1, 2, 3);
pci_register_slot(0x0A, PCI_CARD_NORMAL, 3, 4, 1, 2);
pci_register_slot(0x0B, PCI_CARD_NORMAL, 2, 3, 4, 1);
pci_register_slot(0x0C, PCI_CARD_NORMAL, 1, 2, 3, 4);
pci_register_slot(0x0D, PCI_CARD_NORMAL, 4, 1, 2, 3);
pci_register_slot(0x06, PCI_CARD_NORMAL, 3, 4, 1, 2);
pci_register_slot(0x06, PCI_CARD_SOUND, 3, 4, 1, 2);
device_add(&ali1541_device);
device_add(&ali1543c_device); /* +0 */

View File

@@ -264,18 +264,18 @@ machine_ps2_isa_p1_handler(void)
switch (mem_size / 1024) {
case 0: /*256Kx2*/
mem_p1 = 0xf0;
mem_p1 = 0xb0;
break;
case 1: /*256Kx4*/
mem_p1 = 0xe0;
mem_p1 = 0xa0;
break;
case 2: /*1Mx2*/
case 3:
mem_p1 = 0xd0;
mem_p1 = 0x90;
break;
case 4: /*1Mx4*/
default:
mem_p1 = 0xc0;
mem_p1 = 0x80;
break;
}

View File

@@ -2167,7 +2167,7 @@ const machine_t machines[] = {
.kbd_device = &keyboard_pc_xt_device,
.fdc_device = NULL,
.sio_device = NULL,
.vid_device = &cga_device,
.vid_device = &v6355d_device,
.snd_device = NULL,
.net_device = NULL
},
@@ -5905,7 +5905,7 @@ const machine_t machines[] = {
.kbd_device = NULL,
.fdc_device = NULL,
.sio_device = NULL,
.vid_device = &gd5402_onboard_device,
.vid_device = &gd5402_onboard_commodore_device,
.snd_device = NULL,
.net_device = NULL
},
@@ -7779,7 +7779,7 @@ const machine_t machines[] = {
.kbd_device = NULL,
.fdc_device = NULL,
.sio_device = NULL, /*Has SIO (sorta): VLSI VL82C113A SCAMP Combination I/O*/
.vid_device = &gd5428_onboard_device,
.vid_device = &gd5426_onboard_isa_device,
.snd_device = NULL,
.net_device = NULL
},
@@ -7893,7 +7893,7 @@ const machine_t machines[] = {
.max_multi = 0
},
.bus_flags = MACHINE_PS2,
.flags = MACHINE_IDE | MACHINE_SOUND | MACHINE_GAMEPORT | MACHINE_APM,
.flags = MACHINE_IDE | MACHINE_SOUND | MACHINE_GAMEPORT,
.ram = {
.min = 2048,
.max = 32768,
@@ -8620,7 +8620,7 @@ const machine_t machines[] = {
.kbd_device = NULL,
.fdc_device = NULL,
.sio_device = NULL,
.vid_device = &gd5428_vlb_onboard_device,
.vid_device = &gd5428_onboard_vlb_device,
.snd_device = NULL,
.net_device = NULL
},
@@ -8670,7 +8670,7 @@ const machine_t machines[] = {
},
/* Has a VLSI VL82C113A SCAMP Combination I/O which holds the KBC. */
{
.name = "[VLSI 82C486] Tandy Sensation! II (25-1651)/3100/MMPC",
.name = "[VLSI 82C486] Tandy Sensation! II (25-1651)",
.internal_name = "sensation2",
.type = MACHINE_TYPE_486_S2,
.chipset = MACHINE_CHIPSET_VLSI_VL82C486,
@@ -8690,7 +8690,7 @@ const machine_t machines[] = {
.max_multi = 0
},
.bus_flags = MACHINE_PS2,
.flags = MACHINE_IDE | MACHINE_VIDEO | MACHINE_APM,
.flags = MACHINE_IDE | MACHINE_VIDEO,
.ram = {
.min = 2048,
.max = 65536,
@@ -8708,7 +8708,7 @@ const machine_t machines[] = {
.kbd_device = NULL,
.fdc_device = NULL,
.sio_device = NULL,
.vid_device = &gd5428_vlb_onboard_device,
.vid_device = &gd5428_vlb_onboard_tandy_device,
.snd_device = NULL,
.net_device = NULL
},

View File

@@ -348,8 +348,9 @@ endif()
if(WIN32)
target_sources(plat PRIVATE win_cdrom_ioctl.c)
elseif(UNIX AND NOT APPLE)
target_sources(plat PRIVATE ../unix/linux_cdrom_ioctl.c)
else()
# Replace with proper *nix and mac handler files once they are done.
target_sources(plat PRIVATE dummy_cdrom_ioctl.c)
endif()

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.4 KiB

After

Width:  |  Height:  |  Size: 9.4 KiB

View File

@@ -1006,7 +1006,7 @@ msgid "About %1"
msgstr "À propos de %1"
msgid "An emulator of old computers\n\nAuthors: Miran Grča (OBattler), RichardG867, Jasmine Iwanek, TC1995, coldbrewed, Teemu Korhonen (Manaatti), Joakim L. Gilje, Adrien Moulin (elyosh), Daniel Balsom (gloriouscow), Cacodemon345, Fred N. van Kempen (waltje), Tiseno100, reenigne, and others.\n\nWith previous core contributions from Sarah Walker, leilei, JohnElliott, greatpsycho, and others.\n\nReleased under the GNU General Public License version 2 or later. See LICENSE for more information."
msgstr "Un émulateur d'ordinateurs du passé\n\nAuteurs : Miran Grča (OBattler), RichardG867, Jasmine Iwanek, TC1995, coldbrewed, Teemu Korhonen (Manaatti), Joakim L. Gilje, Adrien Moulin (elyosh), Daniel Balsom (gloriouscow), Cacodemon345, Fred N. van Kempen (waltje), Tiseno100, reenigne, and others.\n\nAvec les contributions de Sarah Walker, leilei, JohnElliott, greatpsycho et d'autres.\n\nLibéré sous la licence GNU General Public License version 2 ou ultérieure. Pour plus d'informations, voir le fichier LICENSE."
msgstr "Un émulateur d'ordinateurs du passé\n\nAuteurs : Miran Grča (OBattler), RichardG867, Jasmine Iwanek, TC1995, coldbrewed, Teemu Korhonen (Manaatti), Joakim L. Gilje, Adrien Moulin (elyosh), Daniel Balsom (gloriouscow), Cacodemon345, Fred N. van Kempen (waltje), Tiseno100, reenigne et d'autres.\n\nAvec les contributions de Sarah Walker, leilei, JohnElliott, greatpsycho et d'autres.\n\nLibéré sous la licence GNU General Public License version 2 ou ultérieure. Pour plus d'informations, voir le fichier LICENSE."
msgid "Hardware not available"
msgstr "Matériel non disponible"

View File

@@ -55,10 +55,10 @@ msgid "&Resizeable window"
msgstr "&Venster met aanpasbare grootte"
msgid "R&emember size && position"
msgstr "&Onthoud grootte && positie"
msgstr "&Onthoud grootte en positie"
msgid "Remember size && position"
msgstr "Onthoud grootte && positie"
msgstr "Onthoud grootte en positie"
msgid "Re&nderer"
msgstr "Re&nderer"
@@ -73,7 +73,7 @@ msgid "&VNC"
msgstr "&VNC"
msgid "Specify &dimensions…"
msgstr "Afmetingen opgeven…"
msgstr "&Afmetingen opgeven…"
msgid "Force &4:3 display ratio"
msgstr "Forceer &4:3 beeldverhouding"
@@ -154,7 +154,7 @@ msgid "VGA screen &type"
msgstr "VGA-scherm &type"
msgid "RGB &Color"
msgstr "RGB &Kleur"
msgstr "RGB &kleur"
msgid "RGB (no brown)"
msgstr "RGN (geen bruin)"
@@ -421,7 +421,7 @@ msgid "IBM 8514/A Graphics"
msgstr "IBM 8514/A-graphics"
msgid "XGA Graphics"
msgstr "XGA Graphics"
msgstr "XGA-graphics"
msgid "IBM PS/55 Display Adapter Graphics"
msgstr "IBM PS/55 Display Adapter Graphics"
@@ -469,13 +469,13 @@ msgid "Sound card #4:"
msgstr "Geluidskaart #4:"
msgid "MIDI Out Device:"
msgstr "MIDI Uitvoerapparaat:"
msgstr "MIDI uitvoerapparaat:"
msgid "MIDI In Device:"
msgstr "MIDI Invoerapparaat:"
msgstr "MIDI invoerapparaat:"
msgid "MIDI Out:"
msgstr "Midi Uit:"
msgstr "Midi uit:"
msgid "Standalone MPU-401"
msgstr "Standalone MPU-401"
@@ -580,7 +580,7 @@ msgid "Hard disks:"
msgstr "Harde schijven:"
msgid "Firmware Version"
msgstr "Firmware Versie"
msgstr "Firmware versie"
msgid "&New…"
msgstr "&Nieuw…"
@@ -673,10 +673,10 @@ msgid "Generic ISA ROM Board"
msgstr "Generieke ISA ROM-kaart"
msgid "Generic Dual ISA ROM Board"
msgstr "Generieke Dubbele ISA ROM-kaart"
msgstr "Generieke dubbele ISA ROM-kaart"
msgid "Generic Quad ISA ROM Board"
msgstr "Generieke Viervoudige ISA ROM-kaart"
msgstr "Generieke viervoudige ISA ROM-kaart"
msgid "ISABugger device"
msgstr "ISABugger-apparaat"
@@ -1006,7 +1006,7 @@ msgid "About %1"
msgstr "Over %1"
msgid "An emulator of old computers\n\nAuthors: Miran Grča (OBattler), RichardG867, Jasmine Iwanek, TC1995, coldbrewed, Teemu Korhonen (Manaatti), Joakim L. Gilje, Adrien Moulin (elyosh), Daniel Balsom (gloriouscow), Cacodemon345, Fred N. van Kempen (waltje), Tiseno100, reenigne, and others.\n\nWith previous core contributions from Sarah Walker, leilei, JohnElliott, greatpsycho, and others.\n\nReleased under the GNU General Public License version 2 or later. See LICENSE for more information."
msgstr "Een emulator van oude computers\n\nAuteurs: Miran Grča (OBattler), RichardG867, Jasmine Iwanek, TC1995, coldbrewed, Teemu Korhonen (Manaatti), Joakim L. Gilje, Adrien Moulin (elyosh), Daniel Balsom (gloriouscow), Cacodemon345, Fred N. van Kempen (waltje), Tiseno100, reenigne, and others.\n\nMet eerdere bijdragen van Sarah Walker, leilei, JohnElliott, greatpsycho en anderen.\n\nUitgebracht onder de GNU General Public License versie 2 of later. Zie LICENSE voor meer informatie."
msgstr "Een emulator van oude computers\n\nAuteurs: Miran Grča (OBattler), RichardG867, Jasmine Iwanek, TC1995, coldbrewed, Teemu Korhonen (Manaatti), Joakim L. Gilje, Adrien Moulin (elyosh), Daniel Balsom (gloriouscow), Cacodemon345, Fred N. van Kempen (waltje), Tiseno100, reenigne, en anderen.\n\nMet eerdere bijdragen van Sarah Walker, leilei, JohnElliott, greatpsycho en anderen.\n\nUitgebracht onder de GNU General Public License versie 2 of later. Zie LICENSE voor meer informatie."
msgid "Hardware not available"
msgstr "Hardware niet beschikbaar"
@@ -1312,7 +1312,7 @@ msgid "An error has occurred while checking for updates: %1"
msgstr "Er is een fout opgetreden tijdens het controleren op updates: %1"
msgid "<b>An update to 86Box is available!</b>"
msgstr "<b> Een update van 86Box is beschikbaar!</b>"
msgstr "<b>Een update van 86Box is beschikbaar!</b>"
msgid "Warning"
msgstr "Waarschuwing"
@@ -2065,7 +2065,7 @@ msgid "Dynamic Sample Loading"
msgstr "Dynamische sample-lading"
msgid "Reverb Output Gain"
msgstr "Reverbuitgang Versterking"
msgstr "Reverbuitgang versterking"
msgid "Reversed stereo"
msgstr "Omgekeerde stereo"
@@ -2362,7 +2362,7 @@ msgid "Always at selected speed"
msgstr "Altijd op geselecteerde snelheid"
msgid "BIOS setting + Hotkeys (off during POST)"
msgstr "BIOS-instelling + Sneltoetsen (niet actief tijdens POST)"
msgstr "BIOS-instelling + sneltoetsen (niet actief tijdens POST)"
msgid "64 KB starting from F0000"
msgstr "64 KB vanaf F0000"
@@ -2401,16 +2401,16 @@ msgid "Wheel"
msgstr "Wiel"
msgid "Five + Wheel"
msgstr "Vijf + Wiel"
msgstr "Vijf + wiel"
msgid "Five + 2 Wheels"
msgstr "Vijf + 2 Wielen"
msgstr "Vijf + 2 wielen"
msgid "A3 - SMT2 Serial / SMT3(R)V"
msgstr "A3 - SMT2 Serieel / SMT3(R)V"
msgstr "A3 - SMT2 serieel / SMT3(R)V"
msgid "Q1 - SMT3(R) Serial"
msgstr "Q1 - SMT3(R) Serieel"
msgstr "Q1 - SMT3(R) serieel"
msgid "8 KB"
msgstr "8 KB"
@@ -2482,7 +2482,7 @@ msgid "Green Monochrome"
msgstr "Groen monochroom"
msgid "Amber Monochrome"
msgstr "Amber Monochroom"
msgstr "Amber monochroom"
msgid "Gray Monochrome"
msgstr "Grijs monochroom"
@@ -2551,7 +2551,7 @@ msgid "Color"
msgstr "Kleur"
msgid "U.S. English"
msgstr "Amerikaans Engels"
msgstr "Amerikaans engels"
msgid "Scandinavian"
msgstr "Scandinavisch"
@@ -2566,16 +2566,16 @@ msgid "Apply overscan deltas"
msgstr "Overscan-deltas toepassen"
msgid "Mono Interlaced"
msgstr "Mono Interlaced"
msgstr "Mono interlaced"
msgid "Mono Non-Interlaced"
msgstr "Mono Niet-Interlaced"
msgstr "Mono niet-interlaced"
msgid "Color Interlaced"
msgstr "Kleur Interlaced"
msgstr "Kleur interlaced"
msgid "Color Non-Interlaced"
msgstr "Kleur Niet-Interlaced"
msgstr "Kleur niet-interlaced"
msgid "3Dfx Voodoo Graphics"
msgstr "3Dfx Voodoo Graphics"
@@ -2635,7 +2635,7 @@ msgid "Passthrough Mode"
msgstr "Doorgeefmodus"
msgid "Host Serial Device"
msgstr "Host Serieel Apparaat"
msgstr "Host serieel apparaat"
msgid "Name of pipe"
msgstr "Naam van de pipe"
@@ -2650,10 +2650,10 @@ msgid "Baud Rate of Passthrough"
msgstr "Baud-snelheid van doorvoer"
msgid "Named Pipe (Server)"
msgstr "Named Pipe (Server)"
msgstr "Genoemd pipe (server)"
msgid "Named Pipe (Client)"
msgstr "Named Pipe (Client)"
msgstr "Genoemd pipe (client)"
msgid "Host Serial Passthrough"
msgstr "Host seriële doorgave"
@@ -2833,10 +2833,10 @@ msgid "SoundFont files"
msgstr "SoundFont-bestanden"
msgid "Local Switch"
msgstr "Lokale Switch"
msgstr "Lokale-switch"
msgid "Remote Switch"
msgstr "Externe Switch"
msgstr "Externe-switch"
msgid "Shared secret:"
msgstr "Gedeeld geheim:"
@@ -2869,16 +2869,16 @@ msgid "An error occurred trying to wipe the NVRAM contents of the virtual machin
msgstr "Fout bij Wissen van NVRAM-inhoud van de virtuele machine \"%1\""
msgid "%1 VM Manager"
msgstr "%1 VM Beheerder"
msgstr "%1 VM-beheerder"
msgid "%n disk(s)"
msgstr "%n schijf/schijven"
msgid "Unknown Status"
msgstr "Onbekende Status"
msgstr "Onbekende status"
msgid "No Machines Found!"
msgstr "Geen Machines Gevonden!"
msgstr "Geen machines gevonden!"
msgid "Check for updates on startup"
msgstr "Controleer op updates bij starten"
@@ -2932,7 +2932,7 @@ msgid "Checking for updates…"
msgstr "Controleren op updates…"
msgid "86Box Update"
msgstr "86Box Update"
msgstr "86Box-update"
msgid "Release notes:"
msgstr "Release-opmerkingen:"

View File

@@ -20,6 +20,7 @@
#include "qt_machinestatus.hpp"
#include <QMenu>
#include <QFile>
#include <QFileDialog>
#include <QMessageBox>
#include <QStringBuilder>
@@ -176,7 +177,15 @@ MediaMenu::refresh(QMenu *parentMenu)
menu->addAction(QIcon(":/settings/qt/icons/cdrom_host.ico"), tr("&Host CD/DVD Drive (%1:)").arg(letter), [this, i, letter] { cdromMount(i, 2, QString(R"(\\.\%1:)").arg(letter)); })->setCheckable(false);
}
menu->addSeparator();
#endif // Q_OS_WINDOWS
#elif defined(Q_OS_LINUX)
/* Enumerate Linux CD/DVD drives (/dev/sr0 .. /dev/sr15). */
for (int sr = 0; sr < 16; sr++) {
QString devPath = QString("/dev/sr%1").arg(sr);
if (QFile::exists(devPath))
menu->addAction(QIcon(":/settings/qt/icons/cdrom_host.ico"), tr("&Host CD/DVD Drive (%1)").arg(devPath), [this, i, devPath] { cdromMount(i, 2, devPath); })->setCheckable(false);
}
menu->addSeparator();
#endif
cdromEjectPos = menu->children().count();
menu->addAction(tr("E&ject"), [this, i]() { cdromEject(i); })->setCheckable(false);
cdromMenus[i] = menu;

View File

@@ -1726,7 +1726,8 @@ OpenGLRenderer::render()
glw.glFinish();
glw.glReadPixels(window_rect.x, window_rect.y, width, height, GL_RGB, GL_UNSIGNED_BYTE, rgb);
QImage image((uchar*)rgb, width, height, width * 3, QImage::Format_RGB888);
int pitch_adj = (4 - ((width * 3) & 3)) & 3;
QImage image((uchar*)rgb, width, height, (width * 3) + pitch_adj, QImage::Format_RGB888);
image.mirrored(false, true).save(path, "png");
monitors[r_monitor_index].mon_screenshots--;
free(rgb);
@@ -1739,7 +1740,8 @@ OpenGLRenderer::render()
glw.glFinish();
glw.glReadPixels(window_rect.x, window_rect.y, width, height, GL_RGB, GL_UNSIGNED_BYTE, rgb);
QImage image((uchar*)rgb, width, height, width * 3, QImage::Format_RGB888);
int pitch_adj = (4 - ((width * 3) & 3)) & 3;
QImage image((uchar*)rgb, width, height, (width * 3) + pitch_adj, QImage::Format_RGB888);
QClipboard *clipboard = QApplication::clipboard();
clipboard->setImage(image.mirrored(false, true), QClipboard::Clipboard);
monitors[r_monitor_index].mon_screenshots_clipboard--;

View File

@@ -28,5 +28,6 @@ add_library(scsi OBJECT
scsi_t128.c
scsi_ncr53c8xx.c
scsi_pcscsi.c
scsi_ql1xxx.c
scsi_spock.c
)

View File

@@ -38,6 +38,7 @@
#include <86box/scsi_ncr5380.h>
#include <86box/scsi_ncr53c8xx.h>
#include <86box/scsi_pcscsi.h>
#include <86box/scsi_qlogic.h>
#include <86box/scsi_spock.h>
int scsi_card_current[SCSI_CARD_MAX] = { 0, 0, 0, 0 };
@@ -91,6 +92,11 @@ static SCSI_CARD scsi_cards[] = {
{ &ncr53c860_pci_device, },
{ &ncr53c875_pci_device, },
{ &dc390_pci_device, },
{ &qla1040b_device, },
{ &qla1080_device, },
{ &qla1240_device, },
{ &qla1280_device, },
{ &qla12160a_device, },
{ NULL, },
// clang-format on
};

View File

@@ -62,13 +62,9 @@ void
ncr5380_irq(ncr_t *ncr, int set_irq)
{
if (set_irq) {
ncr->irq_state = 1;
ncr->isr |= STATUS_INT;
if (ncr->irq != -1)
picint(1 << ncr->irq);
} else {
ncr->irq_state = 0;
ncr->isr &= ~STATUS_INT;
if (ncr->irq != 1)
picintc(1 << ncr->irq);
}
@@ -104,7 +100,12 @@ ncr5380_reset(ncr_t *ncr)
scsi_bus->data = 0;
scsi_bus->command_issued = 0;
ncr5380_irq(ncr, 0);
if (ncr->irq_ena)
ncr->irq_ena(ncr, ncr->priv, 0);
else
ncr5380_irq(ncr, 0);
ncr->isr &= ~STATUS_INT;
}
uint32_t
@@ -164,7 +165,7 @@ ncr5380_write(uint16_t port, uint8_t val, ncr_t *ncr)
if ((val & 0x80) && !(ncr->icr & 0x80)) {
ncr5380_log("Resetting the 5380\n");
ncr5380_reset(ncr);
ncr5380_irq(ncr, 1);
ncr->isr |= STATUS_INT;
}
ncr->icr = val;
ncr5380_log("ICR WaitData=%d, ClearReq=%d.\n", scsi_bus->wait_data, scsi_bus->clear_req);
@@ -301,7 +302,7 @@ ncr5380_read(uint16_t port, ncr_t *ncr)
if (bus & BUS_MSG)
bus_state |= TCR_MSG;
if ((ncr->tcr & 7) != bus_state) {
ncr5380_irq(ncr, 1);
ncr->isr |= STATUS_INT;
ncr5380_log("IRQ issued\n");
}
}
@@ -321,7 +322,12 @@ ncr5380_read(uint16_t port, ncr_t *ncr)
case 7: /* reset Parity/Interrupt */
ncr->isr &= ~(STATUS_BUSY_ERROR | 0x20);
ncr5380_irq(ncr, 0);
if (ncr->irq_ena)
ncr->irq_ena(ncr, ncr->priv, 0);
else
ncr5380_irq(ncr, 0);
ncr->isr &= ~STATUS_INT;
ncr5380_log("Reset Interrupt\n");
break;

View File

@@ -72,6 +72,7 @@ typedef struct ncr53c400_t {
int8_t type;
uint8_t block_count;
uint8_t status_ctrl;
uint8_t irq_config;
int block_count_loaded;
@@ -103,6 +104,23 @@ ncr53c400_log(const char *fmt, ...)
# define ncr53c400_log(fmt, ...)
#endif
static int
ncr53c400_irq_enable(void *priv, void *ext_priv, int state)
{
ncr53c400_t *ncr400 = (ncr53c400_t *) ext_priv;
ncr_t *ncr = (ncr_t *) priv;
if (ncr->irq_state != state) {
ncr->irq_state = state;
ncr400->status_ctrl &= ~0x01;
ncr400->status_ctrl |= (state << 0);
ncr53c400_log("Status Control bit 4=%02x.\n", ncr400->status_ctrl);
if (ncr400->status_ctrl & 0x10)
ncr5380_irq(ncr, state);
}
return 1;
}
static void
ncr53c400_timer_on_auto(void *ext_priv, double period)
{
@@ -263,7 +281,8 @@ ncr53c400_read(uint32_t addr, void *priv)
ncr->isr |= STATUS_END_OF_DMA;
if (ncr->mode & MODE_ENA_EOP_INT) {
ncr53c400_log("NCR read irq\n");
ncr5380_irq(ncr, 1);
ncr53c400_irq_enable(ncr, ncr400, 1);
ncr->isr |= STATUS_INT;
}
} else if (!timer_is_enabled(&ncr400->timer)) {
ncr53c400_log("Timer re-enabled.\n");
@@ -277,15 +296,16 @@ ncr53c400_read(uint32_t addr, void *priv)
case 0x3980:
switch (addr) {
case 0x3980: /* status */
if (ncr400->reset) {
ncr400->reset = 0;
ncr53c400_irq_enable(ncr, ncr400, 1);
}
ret = ncr400->status_ctrl;
ncr53c400_log("NCR status ctrl read=%02x.\n", ncr400->status_ctrl & STATUS_BUFFER_NOT_READY);
if (!ncr400->busy)
ret |= STATUS_5380_ACCESSIBLE;
if (ncr400->reset) {
ncr400->reset = 0;
ret |= 0x01;
}
ncr53c400_log("NCR 53c400 status=%02x.\n", ret);
break;
@@ -295,10 +315,7 @@ ncr53c400_read(uint32_t addr, void *priv)
break;
case 0x3982: /* switch register read */
if (ncr->irq != -1) {
ret = 0xf8;
ret += ncr->irq;
}
ret = ((ncr400->irq_config >> 5) & 7) | 0xf8;
ncr53c400_log("Switches read=%02x.\n", ret);
break;
@@ -519,7 +536,8 @@ ncr53c400_callback(void *priv)
ncr->isr |= STATUS_END_OF_DMA;
if (ncr->mode & MODE_ENA_EOP_INT) {
ncr53c400_log("NCR 53c400 write irq\n");
ncr5380_irq(ncr, 1);
ncr53c400_irq_enable(ncr, ncr400, 1);
ncr->isr |= STATUS_INT;
}
}
break;
@@ -573,7 +591,8 @@ ncr53c400_callback(void *priv)
ncr->isr |= STATUS_END_OF_DMA;
if (ncr->mode & MODE_ENA_EOP_INT) {
ncr53c400_log("NCR read irq\n");
ncr5380_irq(ncr, 1);
ncr53c400_irq_enable(ncr, ncr400, 1);
ncr->isr |= STATUS_INT;
}
} else
timer_on_auto(&ncr400->timer, 1.0);
@@ -675,7 +694,8 @@ ncr53c400_init(const device_t *info)
switch (ncr400->type) {
case ROM_LCS6821N: /* Longshine LCS6821N */
ncr400->rom_addr = device_get_config_hex20("bios_addr");
ncr->irq = device_get_config_int("irq");
ncr400->irq_config = device_get_config_hex16("irq");
ncr->irq = (ncr400->irq_config >> 5) & 7;
rom_init(&ncr400->bios_rom, LCS6821N_ROM,
ncr400->rom_addr, 0x4000, 0x3fff, 0, MEM_MAPPING_EXTERNAL);
@@ -689,7 +709,8 @@ ncr53c400_init(const device_t *info)
case ROM_LS2000: /* Corel LS2000 */
ncr400->rom_addr = device_get_config_hex20("bios_addr");
ncr->irq = device_get_config_int("irq");
ncr400->irq_config = device_get_config_hex16("irq");
ncr->irq = (ncr400->irq_config >> 5) & 7;
rom_init(&ncr400->bios_rom, COREL_LS2000_ROM,
ncr400->rom_addr, 0x4000, 0x3fff, 0, MEM_MAPPING_EXTERNAL);
@@ -702,7 +723,9 @@ ncr53c400_init(const device_t *info)
case ROM_RT1000B: /* Rancho RT1000B/MC */
ncr400->rom_addr = device_get_config_hex20("bios_addr");
ncr->irq = device_get_config_int("irq");
ncr400->irq_config = device_get_config_hex16("irq");
ncr->irq = (ncr400->irq_config >> 5) & 7;
if (info->flags & DEVICE_MCA) {
rom_init(&ncr400->bios_rom, RT1000B_820R_ROM,
0xd8000, 0x4000, 0x3fff, 0, MEM_MAPPING_EXTERNAL);
@@ -729,7 +752,8 @@ ncr53c400_init(const device_t *info)
case ROM_T130B: /* Trantor T130B */
ncr400->rom_addr = device_get_config_hex20("bios_addr");
ncr400->base = device_get_config_hex16("base");
ncr->irq = device_get_config_int("irq");
ncr400->irq_config = device_get_config_hex16("irq");
ncr->irq = (ncr400->irq_config >> 5) & 7;
if (ncr400->rom_addr > 0x00000) {
rom_init(&ncr400->bios_rom, T130B_ROM,
@@ -754,6 +778,7 @@ ncr53c400_init(const device_t *info)
ncr->dma_send_ext = NULL;
ncr->dma_initiator_receive_ext = NULL;
ncr->timer = ncr53c400_timer_on_auto;
ncr->irq_ena = ncr53c400_irq_enable;
scsi_bus->bus_device = ncr->bus;
scsi_bus->timer = ncr->timer;
scsi_bus->priv = ncr->priv;
@@ -839,16 +864,16 @@ static const device_config_t ncr53c400_mmio_config[] = {
{
.name = "irq",
.description = "IRQ",
.type = CONFIG_SELECTION,
.type = CONFIG_HEX16,
.default_string = NULL,
.default_int = 5,
.default_int = 0xa0,
.file_filter = NULL,
.spinner = { 0 },
.selection = {
{ .description = "None", .value = -1 },
{ .description = "IRQ 3", .value = 3 },
{ .description = "IRQ 5", .value = 5 },
{ .description = "IRQ 7", .value = 7 },
{ .description = "IRQ 3", .value = 0x60 },
{ .description = "IRQ 4", .value = 0x80 },
{ .description = "IRQ 5", .value = 0xa0 },
{ .description = "IRQ 7", .value = 0xe0 },
{ .description = "" }
},
.bios = { { 0 } }
@@ -910,16 +935,16 @@ static const device_config_t rt1000b_config[] = {
{
.name = "irq",
.description = "IRQ",
.type = CONFIG_SELECTION,
.type = CONFIG_HEX16,
.default_string = NULL,
.default_int = 5,
.default_int = 0xa0,
.file_filter = NULL,
.spinner = { 0 },
.selection = {
{ .description = "None", .value = -1 },
{ .description = "IRQ 3", .value = 3 },
{ .description = "IRQ 5", .value = 5 },
{ .description = "IRQ 7", .value = 7 },
{ .description = "IRQ 3", .value = 0x60 },
{ .description = "IRQ 4", .value = 0x80 },
{ .description = "IRQ 5", .value = 0xa0 },
{ .description = "IRQ 7", .value = 0xe0 },
{ .description = "" }
},
.bios = { { 0 } }
@@ -931,16 +956,16 @@ static const device_config_t rt1000b_mc_config[] = {
{
.name = "irq",
.description = "IRQ",
.type = CONFIG_SELECTION,
.type = CONFIG_HEX16,
.default_string = NULL,
.default_int = 5,
.default_int = 0xa0,
.file_filter = NULL,
.spinner = { 0 },
.selection = {
{ .description = "None", .value = -1 },
{ .description = "IRQ 3", .value = 3 },
{ .description = "IRQ 5", .value = 5 },
{ .description = "IRQ 7", .value = 7 },
{ .description = "IRQ 3", .value = 0x60 },
{ .description = "IRQ 4", .value = 0x80 },
{ .description = "IRQ 5", .value = 0xa0 },
{ .description = "IRQ 7", .value = 0xe0 },
{ .description = "" }
},
.bios = { { 0 } }
@@ -987,16 +1012,16 @@ static const device_config_t t130b_config[] = {
{
.name = "irq",
.description = "IRQ",
.type = CONFIG_SELECTION,
.type = CONFIG_HEX16,
.default_string = NULL,
.default_int = 5,
.default_int = 0xa0,
.file_filter = NULL,
.spinner = { 0 },
.selection = {
{ .description = "None", .value = -1 },
{ .description = "IRQ 3", .value = 3 },
{ .description = "IRQ 5", .value = 5 },
{ .description = "IRQ 7", .value = 7 },
{ .description = "IRQ 3", .value = 0x60 },
{ .description = "IRQ 4", .value = 0x80 },
{ .description = "IRQ 5", .value = 0xa0 },
{ .description = "IRQ 7", .value = 0xe0 },
{ .description = "" }
},
.bios = { { 0 } }

4580
src/scsi/scsi_ql1xxx.c Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -27,7 +27,6 @@
#define HAVE_STDARG_H
#include <86box/86box.h>
#include <86box/io.h>
#include "cpu.h"
#include <86box/timer.h>
#include <86box/dma.h>
#include <86box/pic.h>
@@ -41,6 +40,7 @@
#include <86box/scsi_device.h>
#include <86box/scsi_ncr5380.h>
#include <86box/scsi_t128.h>
#include "cpu.h"
#define T128_ROM "roms/scsi/ncr5380/trantor_t128_bios_v1.12.bin"
@@ -75,7 +75,7 @@ t128_write(uint32_t addr, uint8_t val, void *priv)
if ((addr >= 0x1800) && (addr < 0x1880))
t128->ext_ram[addr & 0x7f] = val;
else if ((addr >= 0x1c00) && (addr < 0x1c20)) {
t128_log("T128 ctrl write=%02x, mode=%02x.\n", val, ncr->mode & MODE_DMA);
t128_log("T128 ctrl write=%02x, mode=%02x.\n", val & 0x10, ncr->mode & MODE_DMA);
t128->ctrl = val;
} else if ((addr >= 0x1d00) && (addr < 0x1e00))
ncr5380_write((addr - 0x1d00) >> 5, val, ncr);
@@ -141,6 +141,7 @@ t128_read(uint32_t addr, void *priv)
if (ncr->mode & MODE_ENA_EOP_INT) {
t128_log("T128 read irq\n");
ncr5380_irq(ncr, 1);
ncr->isr |= STATUS_INT;
}
scsi_bus->bus_out |= BUS_CD;
scsi_bus->tx_mode = PIO_TX_BUS;
@@ -298,6 +299,7 @@ t128_callback(void *priv)
if (ncr->mode & MODE_ENA_EOP_INT) {
t128_log("T128 write irq\n");
ncr5380_irq(ncr, 1);
ncr->isr |= STATUS_INT;
}
scsi_bus->tx_mode = PIO_TX_BUS;
timer_stop(&t128->timer);
@@ -497,6 +499,7 @@ t128_init(const device_t *info)
ncr->dma_send_ext = t128_dma_send_ext;
ncr->dma_initiator_receive_ext = t128_dma_initiator_receive_ext;
ncr->timer = t128_timer_on_auto;
ncr->irq_ena = NULL;
scsi_bus->bus_device = ncr->bus;
scsi_bus->timer = ncr->timer;
scsi_bus->priv = ncr->priv;
@@ -566,12 +569,13 @@ static const device_config_t t128_config[] = {
.description = "IRQ",
.type = CONFIG_SELECTION,
.default_string = NULL,
.default_int = 5,
.default_int = -1,
.file_filter = NULL,
.spinner = { 0 },
.selection = {
{ .description = "None", .value = -1 },
{ .description = "IRQ 3", .value = 3 },
{ .description = "IRQ 4", .value = 4 },
{ .description = "IRQ 5", .value = 5 },
{ .description = "IRQ 7", .value = 7 },
{ .description = "IRQ 10", .value = 10 },

View File

@@ -819,7 +819,7 @@ ad1816_init(const device_t *info)
ad1816->sb->opl_enabled = 1;
sb_dsp_set_real_opl(&ad1816->sb->dsp, FM_YMF262);
sb_dsp_init(&ad1816->sb->dsp, SBPRO2_DSP_302, SB_SUBTYPE_DEFAULT, ad1816);
sb_dsp_init(&ad1816->sb->dsp, SBPRO_DSP_302, SB_SUBTYPE_DEFAULT, ad1816);
sb_dsp_setaddr(&ad1816->sb->dsp, ad1816->cur_sb_addr);
sb_dsp_setirq(&ad1816->sb->dsp, ad1816->cur_irq);
sb_dsp_setirq(&ad1816->sb->dsp, ad1816->cur_dma);

View File

@@ -1835,7 +1835,7 @@ azt_init(const device_t *info)
fm_driver_get(FM_YMF262, &azt2316a->sb->opl);
sb_dsp_set_real_opl(&azt2316a->sb->dsp, 1);
sb_dsp_init(&azt2316a->sb->dsp, SBPRO2_DSP_302, azt2316a->type, azt2316a);
sb_dsp_init(&azt2316a->sb->dsp, SBPRO_DSP_302, azt2316a->type, azt2316a);
sb_dsp_setaddr(&azt2316a->sb->dsp, azt2316a->cur_addr);
sb_dsp_setirq(&azt2316a->sb->dsp, azt2316a->cur_irq);
sb_dsp_setdma8(&azt2316a->sb->dsp, azt2316a->cur_dma);

View File

@@ -877,7 +877,7 @@ cmi8x38_write(uint16_t addr, uint8_t val, void *priv)
dev->sb->dsp.sbleftright_default = !!(val & 0x02);
/* Enable or disable SB16 mode. */
dev->sb->dsp.sb_type = (val & 0x01) ? SBPRO2_DSP_302 : SB16_DSP_405;
dev->sb->dsp.sb_type = (val & 0x01) ? SBPRO_DSP_302 : SB16_DSP_405;
break;
case 0x22:

View File

@@ -316,7 +316,9 @@ MPU401_Reset(mpu_t *mpu)
mpu->ch_toref[i] = 4; /* Dummy reftable. */
}
MPU401_ClrQueue(mpu);
mpu->state.irq_pending = 0;
MPU401_UpdateIRQ(mpu, 0);
mpu->state.data_onoff = -1;
mpu->state.req_mask = 0;

View File

@@ -1095,7 +1095,7 @@ optimc_init(const device_t *info)
optimc->fm_type = (info->local & OPTIMC_OPL4) ? FM_YMF278B : FM_YMF262;
sb_dsp_set_real_opl(&optimc->sb->dsp, optimc->fm_type != FM_YMF278B);
sb_dsp_init(&optimc->sb->dsp, SBPRO2_DSP_302, SB_SUBTYPE_DEFAULT, optimc);
sb_dsp_init(&optimc->sb->dsp, SBPRO_DSP_302, SB_SUBTYPE_DEFAULT, optimc);
sb_dsp_setaddr(&optimc->sb->dsp, optimc->cur_addr);
sb_dsp_setirq(&optimc->sb->dsp, optimc->cur_irq);
sb_dsp_setdma8(&optimc->sb->dsp, optimc->cur_dma);

View File

@@ -2327,7 +2327,7 @@ pas16_init(const device_t *info)
pas16->has_scsi = (!pas16->type) || (pas16->type == 0x0f);
fm_driver_get(FM_YMF262, &pas16->opl);
sb_dsp_set_real_opl(&pas16->dsp, 1);
sb_dsp_init(&pas16->dsp, SB_DSP_201, SB_SUBTYPE_DEFAULT, pas16);
sb_dsp_init(&pas16->dsp, SB_DSP_200, SB_SUBTYPE_MVD201, pas16);
pas16->mpu = (mpu_t *) calloc(1, sizeof(mpu_t));
mpu401_init(pas16->mpu, 0, 0, M_UART, device_get_config_int("receive_input401"));
sb_dsp_set_mpu(&pas16->dsp, pas16->mpu);

View File

@@ -15,7 +15,7 @@
*
* Copyright 2008-2020 Sarah Walker.
* Copyright 2016-2020 Miran Grca.
* Copyright 2024-2025 Jasmine Iwanek.
* Copyright 2024-2026 Jasmine Iwanek.
*/
#include <stdarg.h>
#include <stdint.h>
@@ -45,9 +45,10 @@
#include <86box/plat_unused.h>
#include <86box/snd_azt2316a.h>
#define SB_1 0
#define SB_15 1
#define SB_2 2
#define SB_1 0
#define SB_15 1
#define SB_2 2
#define THUNDERBOARD 3
#define SB_16_PNP_NOIDE 0
#define SB_16_PNP_IDE 1
@@ -2959,6 +2960,10 @@ sb_init(UNUSED(const device_t *info))
sb->cms_enabled = device_get_config_int("cms");
mixer_addr = device_get_config_int("mixaddr");
break;
case THUNDERBOARD:
model = SB_DSP_200;
sb->cms_enabled = 0;
break;
}
sb->opl_enabled = device_get_config_int("opl");
@@ -3006,7 +3011,7 @@ sb_init(UNUSED(const device_t *info))
&sb->cms);
}
if (mixer_addr > 0x000) {
if (mixer_addr > 0x0000) {
sb->mixer_enabled = 1;
io_sethandler(mixer_addr + 4, 0x0002,
sb_ct1335_mixer_read, NULL, NULL,
@@ -3026,6 +3031,58 @@ sb_init(UNUSED(const device_t *info))
return sb;
}
void *
thunderboard_init(UNUSED(const device_t *info))
{
/* ThunderBoard port mappings, 210h to 260h in 10h steps
2x6, 2xA, 2xC, 2xE -> DSP chip */
sb_t *sb = calloc(1, sizeof(sb_t));
const uint16_t addr = device_get_config_hex16("base");
sb->opl_enabled = device_get_config_int("opl");
if (sb->opl_enabled)
fm_driver_get(FM_YM3812, &sb->opl);
sb_dsp_set_real_opl(&sb->dsp, 0);
sb_dsp_init(&sb->dsp, SB_DSP_200, SB_SUBTYPE_MVD201, sb);
/* DSP I/O handler is activated in sb_dsp_setaddr */
sb_dsp_setaddr(&sb->dsp, addr);
sb_dsp_setirq(&sb->dsp, device_get_config_int("irq"));
sb_dsp_setdma8(&sb->dsp, 1);
if (device_get_config_int("gameport")) {
sb->gameport = gameport_add(&gameport_device);
sb->gameport_addr = 0x200;
gameport_remap(sb->gameport, sb->gameport_addr);
}
/* DSP I/O handler is activated in sb_dsp_setaddr */
if (sb->opl_enabled) {
io_sethandler(addr, 0x0002,
sb->opl.read, NULL, NULL,
sb->opl.write, NULL, NULL,
sb->opl.priv);
io_sethandler(addr + 8, 0x0002,
sb->opl.read, NULL, NULL,
sb->opl.write, NULL, NULL,
sb->opl.priv);
io_sethandler(0x0388, 0x0002,
sb->opl.read, NULL, NULL,
sb->opl.write, NULL, NULL,
sb->opl.priv);
}
sb->cms_enabled = 0;
sb->mixer_enabled = 0;
sound_add_handler(sb_get_buffer_sb2, sb);
if (sb->opl_enabled)
music_add_handler(sb_get_music_buffer_sb2, sb);
sound_set_cd_audio_filter(sb2_filter_cd_audio, sb);
return sb;
}
void *
sb_mcv_init(UNUSED(const device_t *info))
{
@@ -3170,7 +3227,7 @@ sb_pro_v2_init(UNUSED(const device_t *info))
fm_driver_get(FM_YMF262, &sb->opl);
sb_dsp_set_real_opl(&sb->dsp, 1);
sb_dsp_init(&sb->dsp, SBPRO2_DSP_302, SB_SUBTYPE_DEFAULT, sb);
sb_dsp_init(&sb->dsp, SBPRO_DSP_302, SB_SUBTYPE_DEFAULT, sb);
sb_dsp_setaddr(&sb->dsp, addr);
sb_dsp_setirq(&sb->dsp, device_get_config_int("irq"));
sb_dsp_setdma8(&sb->dsp, device_get_config_int("dma"));
@@ -3226,7 +3283,7 @@ sb_pro_mcv_init(UNUSED(const device_t *info))
fm_driver_get(FM_YMF262, &sb->opl);
sb_dsp_set_real_opl(&sb->dsp, 1);
sb_dsp_init(&sb->dsp, SBPRO2_DSP_302, SB_SUBTYPE_DEFAULT, sb);
sb_dsp_init(&sb->dsp, SBPRO_DSP_302, SB_SUBTYPE_DEFAULT, sb);
sb_ct1345_mixer_reset(sb);
sb->mixer_enabled = 1;
@@ -3258,7 +3315,7 @@ sb_pro_compat_init(UNUSED(const device_t *info))
fm_driver_get(FM_YMF262, &sb->opl);
sb_dsp_set_real_opl(&sb->dsp, 1);
sb_dsp_init(&sb->dsp, SBPRO2_DSP_302, SB_SUBTYPE_DEFAULT, sb);
sb_dsp_init(&sb->dsp, SBPRO_DSP_302, SB_SUBTYPE_DEFAULT, sb);
sb_ct1345_mixer_reset(sb);
sb->mixer_enabled = 1;
@@ -3938,7 +3995,7 @@ ess_x688_init(UNUSED(const device_t *info))
fm_driver_get(info->local ? FM_ESFM : FM_YMF262, &ess->opl);
sb_dsp_set_real_opl(&ess->dsp, 1);
sb_dsp_init(&ess->dsp, SBPRO2_DSP_302, info->local ? SB_SUBTYPE_ESS_ES1688 : SB_SUBTYPE_ESS_ES688, ess);
sb_dsp_init(&ess->dsp, SBPRO_DSP_301, info->local ? SB_SUBTYPE_ESS_ES1688 : SB_SUBTYPE_ESS_ES688, ess);
sb_dsp_setaddr(&ess->dsp, addr);
sb_dsp_setirq(&ess->dsp, device_get_config_int("irq"));
sb_dsp_setdma8(&ess->dsp, device_get_config_int("dma"));
@@ -4050,7 +4107,7 @@ ess_x688_pnp_init(UNUSED(const device_t *info))
fm_driver_get(info->local ? FM_ESFM : FM_YMF262, &ess->opl);
sb_dsp_set_real_opl(&ess->dsp, 1);
sb_dsp_init(&ess->dsp, SBPRO2_DSP_302, info->local ? SB_SUBTYPE_ESS_ES1688 : SB_SUBTYPE_ESS_ES688, ess);
sb_dsp_init(&ess->dsp, SBPRO_DSP_301, info->local ? SB_SUBTYPE_ESS_ES1688 : SB_SUBTYPE_ESS_ES688, ess);
sb_dsp_setdma16_supported(&ess->dsp, 0);
ess_mixer_reset(ess);
@@ -4136,7 +4193,7 @@ ess_x688_mca_init(UNUSED(const device_t *info))
fm_driver_get(info->local ? FM_ESFM : FM_YMF262, &ess->opl);
sb_dsp_set_real_opl(&ess->dsp, 1);
sb_dsp_init(&ess->dsp, SBPRO2_DSP_302, info->local ? SB_SUBTYPE_ESS_ES1688 : SB_SUBTYPE_ESS_ES688, ess);
sb_dsp_init(&ess->dsp, SBPRO_DSP_301, info->local ? SB_SUBTYPE_ESS_ES1688 : SB_SUBTYPE_ESS_ES688, ess);
sb_dsp_setdma16_supported(&ess->dsp, 0);
ess_mixer_reset(ess);
@@ -4288,6 +4345,68 @@ static const device_config_t sb_config[] = {
{ .name = "", .description = "", .type = CONFIG_END }
};
static const device_config_t thunderboard_config[] = {
{
.name = "base",
.description = "Address",
.type = CONFIG_HEX16,
.default_string = NULL,
.default_int = 0x220,
.file_filter = NULL,
.spinner = { 0 },
.selection = {
{ .description = "0x210", .value = 0x210 },
{ .description = "0x220", .value = 0x220 },
{ .description = "0x230", .value = 0x230 },
{ .description = "0x240", .value = 0x240 },
{ .description = "0x250", .value = 0x250 },
{ .description = "0x260", .value = 0x260 },
{ .description = "" }
},
.bios = { { 0 } }
},
{
.name = "irq",
.description = "IRQ",
.type = CONFIG_SELECTION,
.default_string = NULL,
.default_int = 7,
.file_filter = NULL,
.spinner = { 0 },
.selection = {
{ .description = "IRQ 2", .value = 2 },
{ .description = "IRQ 3", .value = 3 },
{ .description = "IRQ 5", .value = 5 },
{ .description = "IRQ 7", .value = 7 },
{ .description = "" }
},
.bios = { { 0 } }
},
{
.name = "gameport",
.description = "Enable Game port",
.type = CONFIG_BINARY,
.default_string = NULL,
.default_int = 0,
.file_filter = NULL,
.spinner = { 0 },
.selection = { { 0 } },
.bios = { { 0 } }
},
{
.name = "opl",
.description = "Enable OPL",
.type = CONFIG_BINARY,
.default_string = NULL,
.default_int = 1,
.file_filter = NULL,
.spinner = { 0 },
.selection = { { 0 } },
.bios = { { 0 } }
},
{ .name = "", .description = "", .type = CONFIG_END }
};
static const device_config_t sb15_config[] = {
{
.name = "base",
@@ -5576,6 +5695,20 @@ static const device_config_t ess_1688_pnp_config[] = {
};
// clang-format on
const device_t thunderboard_device = {
.name = "MediaVision ThunderBoard",
.internal_name = "thunderboard",
.flags = DEVICE_ISA,
.local = THUNDERBOARD,
.init = thunderboard_init,
.close = sb_close,
.reset = NULL,
.available = NULL,
.speed_changed = sb_speed_changed,
.force_redraw = NULL,
.config = thunderboard_config
};
const device_t sb_1_device = {
.name = "Sound Blaster v1.0",
.internal_name = "sb",

View File

@@ -85,20 +85,22 @@ char sb202_copyright[] = "COPYRIGHT(C) CREATIVE TECHNOLOGY PTE. LTD. (1991)
char sb16_copyright[] = "COPYRIGHT (C) CREATIVE TECHNOLOGY LTD, 1992.";
uint16_t sb_dsp_versions[] = {
0, /* Pad */
0, /* SADLIB - No DSP */
0, /* SADLIB - No DSP */
0x103, /* SB_DSP_103 - SB "killer card" prototype, DSP v1.03 */
0x105, /* SB_DSP_105 - SB1/1.5, DSP v1.05 */
0x200, /* SB_DSP_200 - SB1.5/2, DSP v2.00 */
0x201, /* SB_DSP_201 - SB1.5/2, DSP v2.01 - needed for high-speed DMA */
0x202, /* SB_DSP_202 - SB2, DSP v2.02 */
0x300, /* SB_PRO_DSP_300 - SB Pro, DSP v3.00 */
0x302, /* SBPRO2_DSP_302 - SB Pro 2, DSP v3.02 + OPL3 */
0x404, /* SB16_DSP_404 - DSP v4.04 + OPL3 */
0x405, /* SB16_405 - DSP v4.05 + OPL3 */
0x406, /* SB16_406 - DSP v4.06 + OPL3 */
0x40b, /* SB16_411 - DSP v4.11 + OPL3 */
0x40c, /* SBAWE32 - DSP v4.12 + OPL3 */
0x40d, /* SBAWE32PNP - DSP v4.13 + OPL3 */
0x410 /* SBAWE64 - DSP v4.16 + OPL3 */
0x300, /* SBPRO_DSP_300 - SB Pro, DSP v3.00 */
0x301, /* SBPRO_DSP_301 - SB Pro/Pro 2, DSP v3.01 */
0x302, /* SBPRO_DSP_302 - SB Pro/Pro 2, DSP v3.02 */
0x404, /* SB16_DSP_404 - DSP v4.04 + OPL3 */
0x405, /* SB16_DSP_405 - DSP v4.05 + OPL3 */
0x406, /* SB16_DSP_406 - DSP v4.06 + OPL3 */
0x40b, /* SB16_DSP_411 - DSP v4.11 + OPL3 */
0x40c, /* SBAWE32_DSP_412 - DSP v4.12 + OPL3 */
0x40d, /* SBAWE32_DSP_413 - DSP v4.13 + OPL3 */
0x410 /* SBAWE64_DSP_416 - DSP v4.16 + OPL3 */
};
/*These tables were 'borrowed' from DOSBox*/
@@ -1614,7 +1616,7 @@ sb_exec_command(sb_dsp_t *dsp)
break;
case 0xA0: /* Set input mode to mono */
case 0xA8: /* Set input mode to stereo */
if ((dsp->sb_type < SBPRO_DSP_300) || (dsp->sb_type > SBPRO2_DSP_302))
if ((dsp->sb_type < SBPRO_DSP_300) || (dsp->sb_type > SBPRO_DSP_302))
break;
/* TODO: Implement. 3.xx-only command. */
break;
@@ -1730,6 +1732,18 @@ sb_exec_command(sb_dsp_t *dsp)
sb_add_data(dsp, ~dsp->sb_data[0]);
break;
case 0xE1: /* Get DSP version */
if (IS_MV201(dsp)) {
if (dsp->sb_last_command == 0xE1) {
sb_add_data(dsp, 0x01);
sb_add_data(dsp, 0x30);
dsp->sb_last_command = 0x00;
} else {
sb_add_data(dsp, 0x02);
sb_add_data(dsp, 0x00);
dsp->sb_last_command = 0xE1;
}
break;
}
if (IS_ESS(dsp)) {
/*
0x03 0x01 (Sound Blaster Pro compatibility) confirmed by both the
@@ -1859,12 +1873,12 @@ sb_exec_command(sb_dsp_t *dsp)
* 059h Fetches the samples and then immediately plays them back. SB???
* 078h Auto-init DMA ADPCM SB2???
* 07Ah 2.6-bit ADPCM SB???
* 0E3h DSP Copyright SBPro2??? (SBPRO2_DSP_302)
* 0F0h Sine Generator SB (SB_DSP_105, DSP20x)
* 0F1h DSP Auxiliary Status (Obsolete) SB-Pro2 (DSP20x, SBPRO2_DSP_302)
* 0F2h IRQ Request, 8-bit SB (SB_DSP_105, DSP20x)
* 0E3h DSP Copyright SBPro2??? (SBPRO_DSP_302)
* 0F0h Sine Generator SB (SB_DSP_105, SB_DSP_20x)
* 0F1h DSP Auxiliary Status (Obsolete) SB-Pro2 (SB_DSP_20x, SBPRO_DSP_302)
* 0F2h IRQ Request, 8-bit SB (SB_DSP_105, SB_DSP_20x)
* 0F3h IRQ Request, 16-bit SB16
* 0F4h Perform ROM checksum SB (SB_DSP_105, DSP20x)
* 0F4h Perform ROM checksum SB (SB_DSP_105, SB_DSP_20x)
* 0FBh DSP Status SB16
* 0FCh DSP Auxiliary Status SB16
* 0FDh DSP Command Status SB16
@@ -2236,7 +2250,7 @@ sb_dsp_init(sb_dsp_t *dsp, int type, int subtype, void *parent)
a set frequency command is sent. */
recalc_sb16_filter(0, 3200 * 2);
}
if (IS_ESS(dsp) || (dsp->sb_type >= SBPRO2_DSP_302)) {
if (IS_ESS(dsp) || (dsp->sb_type >= SBPRO_DSP_302)) {
/* OPL3 or dual OPL2 is stereo. */
if (dsp->sb_has_real_opl)
recalc_opl_filter(FREQ_49716 * 2);

View File

@@ -808,6 +808,7 @@ sensation_visdac_read(uint16_t port, void *priv)
sensation_t *visdac = (sensation_t *) priv;
uint8_t ret;
ret = 0xff;
switch (port & 0xF) {
case 0x00:

View File

@@ -419,7 +419,7 @@ ymf701_init(const device_t *info)
ymf701->sb->opl_enabled = 1;
sb_dsp_set_real_opl(&ymf701->sb->dsp, 1);
sb_dsp_init(&ymf701->sb->dsp, SBPRO2_DSP_302, SB_SUBTYPE_DEFAULT, ymf701);
sb_dsp_init(&ymf701->sb->dsp, SBPRO_DSP_302, SB_SUBTYPE_DEFAULT, ymf701);
sb_dsp_setaddr(&ymf701->sb->dsp, ymf701->cur_sb_addr);
sb_dsp_setirq(&ymf701->sb->dsp, ymf701->cur_sb_irq);
sb_dsp_setdma8(&ymf701->sb->dsp, ymf701->cur_sb_dma);

View File

@@ -712,7 +712,7 @@ ymf71x_init(const device_t *info)
ymf71x->sb->opl_enabled = 1;
sb_dsp_set_real_opl(&ymf71x->sb->dsp, 1);
sb_dsp_init(&ymf71x->sb->dsp, SBPRO2_DSP_302, SB_SUBTYPE_DEFAULT, ymf71x);
sb_dsp_init(&ymf71x->sb->dsp, SBPRO_DSP_302, SB_SUBTYPE_DEFAULT, ymf71x);
sb_ct1345_mixer_reset(ymf71x->sb);
ymf71x->sb->opl_mixer = ymf71x;

View File

@@ -126,6 +126,7 @@ static const SOUND_CARD sound_cards[] = {
#ifdef USE_LIBSERIALPORT /*The following devices required LIBSERIALPORT*/
{ &opl2board_device },
#endif
{ &thunderboard_device },
{ &pasplus_device },
{ &sb_1_device },
{ &sb_15_device },

View File

@@ -47,8 +47,12 @@ add_library(ui OBJECT
unix_sdl.c
unix_osd.c
unix_cdrom.c
dummy_cdrom_ioctl.c
)
if(APPLE)
target_sources(ui PRIVATE dummy_cdrom_ioctl.c)
else()
target_sources(ui PRIVATE linux_cdrom_ioctl.c)
endif()
target_compile_definitions(ui PUBLIC _FILE_OFFSET_BITS=64)
target_link_libraries(ui ${CMAKE_DL_LIBS})

View File

@@ -0,0 +1,875 @@
/*
* 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.
*
* Linux CD-ROM support via IOCTL (SG_IO).
*
* Authors: Miran Grca, <mgrca8@gmail.com>
* TheCollector1995, <mariogplayer@gmail.com>
*
* Copyright 2023 TheCollector1995.
* Copyright 2023 Miran Grca.
* Copyright 2025 86Box contributors.
*/
#include <inttypes.h>
#ifdef ENABLE_IOCTL_LOG
#include <stdarg.h>
#endif
#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include <stdlib.h>
#include <stddef.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <pthread.h>
#include <sys/ioctl.h>
#include <scsi/sg.h>
#include <linux/cdrom.h>
#define HAVE_STDARG_H
#include <86box/86box.h>
#include <86box/cdrom.h>
#include <86box/log.h>
#include <86box/plat_cdrom_ioctl.h>
#include <86box/scsi_device.h>
typedef struct ioctl_t {
cdrom_t *dev;
void *log;
int fd;
int is_dvd;
int has_audio;
int blocks_num;
uint8_t cur_rti[65536];
char path[256];
pthread_t poll_tid;
int poll_active;
} ioctl_t;
static int ioctl_read_dvd_structure(const void *local, uint8_t layer, uint8_t format,
uint8_t *buffer, uint32_t *info);
static int ioctl_is_empty(const void *local);
/*
* Wrapper for the system ioctl() call to avoid naming collisions
* with the local 'ioctl' variable of type ioctl_t*.
*/
static inline int
sys_ioctl(int fd, unsigned long request, void *arg)
{
return ioctl(fd, request, arg);
}
#ifdef ENABLE_IOCTL_LOG
int ioctl_do_log = ENABLE_IOCTL_LOG;
void
ioctl_log(void *priv, const char *fmt, ...)
{
if (ioctl_do_log) {
va_list ap;
va_start(ap, fmt);
log_out(priv, fmt, ap);
va_end(ap);
}
}
#else
# define ioctl_log(priv, fmt, ...)
#endif
/* Internal functions. */
static void
ioctl_close_handle(const ioctl_t *ioctl)
{
if (ioctl->fd >= 0)
close(ioctl->fd);
}
static int
ioctl_open_handle(ioctl_t *ioctl)
{
ioctl_log(ioctl->log, "ioctl->path = \"%s\"\n", ioctl->path);
ioctl->fd = open(ioctl->path, O_RDONLY | O_NONBLOCK);
ioctl_log(ioctl->log, "fd=%d, errno=%d\n", ioctl->fd, errno);
return (ioctl->fd >= 0);
}
/*
* Execute a SCSI command via the Linux SG_IO interface.
* Returns 1 on success, 0 on failure.
* sense_buf should be at least 64 bytes, sense_len receives actual sense length.
*/
static int
sg_io_cmd(int fd, const uint8_t *cdb, int cdb_len,
uint8_t *data_buf, int data_len, int direction,
uint8_t *sense_buf, int *sense_len)
{
sg_io_hdr_t io_hdr;
memset(&io_hdr, 0, sizeof(sg_io_hdr_t));
io_hdr.interface_id = 'S';
io_hdr.cmd_len = cdb_len;
io_hdr.mx_sb_len = 64;
io_hdr.dxfer_direction = direction;
io_hdr.dxfer_len = data_len;
io_hdr.dxferp = data_buf;
io_hdr.cmdp = (unsigned char *) cdb;
io_hdr.sbp = sense_buf;
io_hdr.timeout = 6000; /* 6 seconds, matching Windows */
if (ioctl(fd, SG_IO, &io_hdr) < 0)
return 0;
if (sense_len != NULL)
*sense_len = io_hdr.sb_len_wr;
/* Check for SCSI errors. */
if ((io_hdr.info & SG_INFO_OK_MASK) != SG_INFO_OK) {
if (io_hdr.sb_len_wr > 0) {
if (sense_len != NULL)
*sense_len = io_hdr.sb_len_wr;
return 0;
}
return 0;
}
return 1;
}
static int
ioctl_read_normal_toc(ioctl_t *ioctl, uint8_t *toc_buf, int32_t *tracks_num)
{
struct cdrom_tochdr tochdr;
struct cdrom_tocentry tocentry;
int status;
*tracks_num = 0;
memset(toc_buf, 0x00, 65536);
status = sys_ioctl(ioctl->fd, CDROMREADTOCHDR, &tochdr);
if (status < 0)
return 0;
ioctl_log(ioctl->log, "TOC: first=%d, last=%d\n",
tochdr.cdth_trk0, tochdr.cdth_trk1);
/*
* Build a cooked TOC buffer in the same format as the Windows
* CDROM_TOC structure:
* [0..1] = length (big-endian)
* [2] = first track
* [3] = last track
* [4..] = 8-byte track descriptors
*
* Each track descriptor:
* [0] = reserved
* [1] = Adr/Control
* [2] = track number
* [3] = reserved
* [4..7] = MSF address (0, M, S, F)
*/
toc_buf[2] = tochdr.cdth_trk0;
toc_buf[3] = tochdr.cdth_trk1;
int count = 0;
for (int i = tochdr.cdth_trk0; i <= tochdr.cdth_trk1; i++) {
memset(&tocentry, 0, sizeof(tocentry));
tocentry.cdte_track = i;
tocentry.cdte_format = CDROM_MSF;
if (sys_ioctl(ioctl->fd, CDROMREADTOCENTRY, &tocentry) < 0)
continue;
uint8_t *t = &toc_buf[4 + count * 8];
t[0] = 0;
t[1] = ((tocentry.cdte_adr & 0xf) << 4) | (tocentry.cdte_ctrl & 0xf);
t[2] = i;
t[3] = 0;
t[4] = 0;
t[5] = tocentry.cdte_addr.msf.minute;
t[6] = tocentry.cdte_addr.msf.second;
t[7] = tocentry.cdte_addr.msf.frame;
count++;
}
/* Lead-out (track 0xAA). */
memset(&tocentry, 0, sizeof(tocentry));
tocentry.cdte_track = CDROM_LEADOUT;
tocentry.cdte_format = CDROM_MSF;
if (sys_ioctl(ioctl->fd, CDROMREADTOCENTRY, &tocentry) >= 0) {
uint8_t *t = &toc_buf[4 + count * 8];
t[0] = 0;
t[1] = ((tocentry.cdte_adr & 0xf) << 4) | (tocentry.cdte_ctrl & 0xf);
t[2] = 0xAA;
t[3] = 0;
t[4] = 0;
t[5] = tocentry.cdte_addr.msf.minute;
t[6] = tocentry.cdte_addr.msf.second;
t[7] = tocentry.cdte_addr.msf.frame;
count++;
}
/* Set the length field (big-endian). */
int length = 2 + count * 8;
toc_buf[0] = (length >> 8) & 0xff;
toc_buf[1] = length & 0xff;
*tracks_num = count;
ioctl_log(ioctl->log, "%i tracks\n", *tracks_num);
return 1;
}
static void
ioctl_read_raw_toc(ioctl_t *ioctl)
{
raw_track_info_t *rti = (raw_track_info_t *) ioctl->cur_rti;
uint8_t *buffer = (uint8_t *) calloc(1, 2052);
int status = 0;
ioctl->is_dvd = (ioctl_read_dvd_structure(ioctl, 0, 0, buffer, NULL) > 0);
free(buffer);
ioctl->has_audio = 0;
ioctl->blocks_num = 0;
memset(ioctl->cur_rti, 0x00, 65536);
if (!ioctl->is_dvd) {
/* Try SG_IO with READ TOC command, Format=2 (full/raw TOC). */
uint8_t cdb[12];
uint8_t sense[64];
uint8_t *raw_buf = (uint8_t *) calloc(1, 65536);
int sense_len = 0;
memset(cdb, 0, sizeof(cdb));
cdb[0] = 0x43; /* READ TOC */
cdb[1] = 0x02; /* MSF */
cdb[2] = 0x02; /* Format = Full TOC (raw) */
cdb[6] = 0x01; /* Session = 1 */
cdb[7] = 0xff; /* Allocation length high */
cdb[8] = 0xff; /* Allocation length low */
memset(sense, 0, sizeof(sense));
status = sg_io_cmd(ioctl->fd, cdb, 10, raw_buf, 65535,
SG_DXFER_FROM_DEV, sense, &sense_len);
if (status && sense_len == 0) {
int length = ((raw_buf[0] << 8) | raw_buf[1]) - 2;
ioctl->blocks_num = length / 11;
if (ioctl->blocks_num > 0)
memcpy(ioctl->cur_rti, &raw_buf[4], ioctl->blocks_num * 11);
} else {
status = 0;
}
free(raw_buf);
}
if (status == 0) {
/*
* Raw TOC read failed (or this is a DVD). Fall back to the
* cooked TOC, and construct raw_track_info_t entries from it,
* mirroring the Windows fallback path.
*/
uint8_t cur_toc[65536] = { 0 };
int32_t tracks_num = 0;
status = ioctl_read_normal_toc(ioctl, cur_toc, &tracks_num);
if ((status > 0) && (tracks_num >= 1)) {
/* Last real entry (the lead-out). */
const uint8_t *ct = &cur_toc[4 + (tracks_num - 1) * 8];
rti[0].adr_ctl = ct[1];
rti[0].point = 0xa0;
rti[0].pm = cur_toc[2]; /* FirstTrack */
rti[1].adr_ctl = rti[0].adr_ctl;
rti[1].point = 0xa1;
rti[1].pm = cur_toc[3]; /* LastTrack */
rti[2].adr_ctl = rti[0].adr_ctl;
rti[2].point = 0xa2;
rti[2].pm = ct[5]; /* M */
rti[2].ps = ct[6]; /* S */
rti[2].pf = ct[7]; /* F */
ioctl->blocks_num = 3;
for (int i = 0; i < (tracks_num - 1); i++) {
raw_track_info_t *crt = &(rti[ioctl->blocks_num]);
ct = &cur_toc[4 + i * 8];
crt->adr_ctl = ct[1];
crt->point = ct[2];
crt->pm = ct[5];
crt->ps = ct[6];
crt->pf = ct[7];
ioctl->blocks_num++;
}
} else if (status > 0)
/* Announce that we've had a failure. */
status = 0;
}
if (ioctl->blocks_num) for (int i = 0; i < ioctl->blocks_num; i++) {
const raw_track_info_t *crt = &(rti[i]);
if ((crt->point >= 1) && (crt->point <= 99) && !(crt->adr_ctl & 0x04)) {
ioctl->has_audio = 1;
break;
}
}
#ifdef ENABLE_IOCTL_LOG
ioctl_log(ioctl->log, "%i blocks\n", ioctl->blocks_num);
for (int i = 0; i < ioctl->blocks_num; i++) {
uint8_t *t = (uint8_t *) &rti[i];
ioctl_log(ioctl->log, "Block %03i: %02X %02X %02X %02X %02X %02X %02X %02X "
"%02X %02X %02X\n",
i, t[0], t[1], t[2], t[3], t[4], t[5], t[6], t[7], t[8],
t[9], t[10]);
}
#endif
}
static int
ioctl_get_track(const ioctl_t *ioctl, const uint32_t sector)
{
raw_track_info_t *rti = (raw_track_info_t *) ioctl->cur_rti;
int track = -1;
for (int i = (ioctl->blocks_num - 1); i >= 0; i--) {
const raw_track_info_t *ct = &(rti[i]);
const uint32_t start = (ct->pm * 60 * 75) + (ct->ps * 75) + ct->pf - 150;
ioctl_log(ioctl->log, "ioctl_get_track(): ct: %02X, %08X\n",
ct->point, start);
if ((ct->point >= 1) && (ct->point <= 99) && (sector >= start)) {
track = i;
ioctl_log(ioctl->log, "ioctl_get_track(): found track: %i\n", i);
break;
}
}
return track;
}
static int
ioctl_is_track_audio(const ioctl_t *ioctl, const uint32_t pos)
{
const raw_track_info_t *rti = (const raw_track_info_t *) ioctl->cur_rti;
int ret = 0;
if (ioctl->has_audio && !ioctl->is_dvd) {
const int track = ioctl_get_track(ioctl, pos);
const int control = rti[track].adr_ctl;
ret = !(control & 0x04);
ioctl_log(ioctl->log, "ioctl_is_track_audio(%08X, %02X): %i\n", pos, track, ret);
}
return ret;
}
/* Shared functions (cdrom_ops_t interface). */
static int
ioctl_get_track_info(const void *local, const uint32_t track,
int end, track_info_t *ti)
{
const ioctl_t *ioctl = (const ioctl_t *) local;
const raw_track_info_t *rti = (const raw_track_info_t *) ioctl->cur_rti;
int ret = 1;
int trk = -1;
int next = -1;
if ((track >= 1) && (track < 99))
for (int i = 0; i < ioctl->blocks_num; i++)
if (rti[i].point == track) {
trk = i;
break;
}
if ((track >= 1) && (track < 98))
for (int i = 0; i < ioctl->blocks_num; i++)
if ((rti[i].point == (track + 1)) && (rti[i].session == rti[trk].session)) {
next = i;
break;
}
if ((track >= 1) && (track < 99) && (trk != -1) && (next == -1))
for (int i = 0; i < ioctl->blocks_num; i++)
if ((rti[i].point == 0xa2) && (rti[i].session == rti[trk].session)) {
next = i;
break;
}
if ((track == 0xaa) || (trk == -1)) {
ioctl_log(ioctl->log, "ioctl_get_track_info(%02i)\n", track);
ret = 0;
} else {
if (end) {
if (next != -1) {
ti->m = rti[next].pm;
ti->s = rti[next].ps;
ti->f = rti[next].pf;
}
} else {
ti->m = rti[trk].pm;
ti->s = rti[trk].ps;
ti->f = rti[trk].pf;
}
ti->number = rti[trk].point;
ti->attr = rti[trk].adr_ctl;
ioctl_log(ioctl->log, "ioctl_get_track_info(%02i): %02i:%02i:%02i, %02i, %02X\n",
track, ti->m, ti->s, ti->f, ti->number, ti->attr);
}
return ret;
}
static void
ioctl_get_raw_track_info(const void *local, int *num, uint8_t *rti)
{
const ioctl_t *ioctl = (const ioctl_t *) local;
*num = ioctl->blocks_num;
memcpy(rti, ioctl->cur_rti, ioctl->blocks_num * 11);
}
static int
ioctl_is_track_pre(const void *local, const uint32_t sector)
{
const ioctl_t *ioctl = (const ioctl_t *) local;
const raw_track_info_t *rti = (const raw_track_info_t *) ioctl->cur_rti;
int ret = 0;
if (ioctl->has_audio && !ioctl->is_dvd) {
const int track = ioctl_get_track(ioctl, sector);
const int control = rti[track].adr_ctl;
ret = control & 0x01;
ioctl_log(ioctl->log, "ioctl_is_track_pre(%08X, %02X): %i\n", sector, track, ret);
}
return ret;
}
static int
ioctl_read_sector(const void *local, uint8_t *buffer, uint32_t const sector)
{
const ioctl_t *ioctl = (const ioctl_t *) local;
const raw_track_info_t *rti = (raw_track_info_t *) ioctl->cur_rti;
const int sc_offs = (sector == 0xffffffff) ? 0 : 2352;
int len = (sector == 0xffffffff) ? 16 : 2368;
int m = 0;
int s = 0;
int f = 0;
uint32_t lba = sector;
int ret;
int data_len = 0;
if (ioctl->is_dvd) {
int track;
data_len = 0;
ret = 0;
if (lba == 0xffffffff) {
lba = ioctl->dev->seek_pos;
track = ioctl_get_track(ioctl, lba);
if (track != -1) {
data_len = len;
ret = 1;
}
} else {
len = COOKED_SECTOR_SIZE;
track = ioctl_get_track(ioctl, lba);
if (track != -1) {
ssize_t nread = pread(ioctl->fd, &(buffer[16]),
COOKED_SECTOR_SIZE,
(off_t) lba * COOKED_SECTOR_SIZE);
if (nread > 0) {
data_len = (int) nread;
ret = 1;
}
}
}
if (ret && (data_len >= len) && (track != -1)) {
const raw_track_info_t *ct = &(rti[track]);
const uint32_t start = (ct->pm * 60 * 75) + (ct->ps * 75) + ct->pf;
m = s = f = 0;
/* Construct sector header and sub-header. */
if (sector != 0xffffffff) {
/* Sync bytes. */
buffer[0] = 0x00;
memset(&(buffer[1]), 0xff, 10);
buffer[11] = 0x00;
/* Sector header. */
FRAMES_TO_MSF(lba + 150, &m, &s, &f);
buffer[12] = bin2bcd(m);
buffer[13] = bin2bcd(s);
buffer[14] = bin2bcd(f);
/* Mode 1 data. */
buffer[15] = 0x01;
}
/* Construct Q. */
buffer[sc_offs + 0] = (ct->adr_ctl >> 4) | ((ct->adr_ctl & 0xf) << 4);
buffer[sc_offs + 1] = bin2bcd(ct->point);
buffer[sc_offs + 2] = 1;
FRAMES_TO_MSF((int32_t) (lba + 150 - start), &m, &s, &f);
buffer[sc_offs + 3] = bin2bcd(m);
buffer[sc_offs + 4] = bin2bcd(s);
buffer[sc_offs + 5] = bin2bcd(f);
FRAMES_TO_MSF(lba + 150, &m, &s, &f);
buffer[sc_offs + 7] = bin2bcd(m);
buffer[sc_offs + 8] = bin2bcd(s);
buffer[sc_offs + 9] = bin2bcd(f);
}
} else {
/* CD: use SG_IO with READ CD (0xBE). */
uint8_t cdb[12];
uint8_t sense[64];
int sense_len = 0;
memset(cdb, 0, sizeof(cdb));
cdb[0] = 0xbe; /* READ CD */
cdb[1] = 0x00;
cdb[2] = (sector >> 24) & 0xff;
cdb[3] = (sector >> 16) & 0xff;
cdb[4] = (sector >> 8) & 0xff;
cdb[5] = sector & 0xff; /* Starting LBA */
cdb[6] = 0x00;
cdb[7] = 0x00;
cdb[8] = 0x01; /* Transfer Length = 1 */
/* If sector is FFFFFFFF, only return the subchannel. */
cdb[9] = (sector == 0xffffffff) ? 0x00 : 0xf8;
cdb[10] = 0x02;
cdb[11] = 0x00;
#ifdef ENABLE_IOCTL_LOG
ioctl_log(ioctl->log, "Host CDB: %02X %02X %02X %02X %02X %02X "
"%02X %02X %02X %02X %02X %02X\n",
cdb[0], cdb[1], cdb[2], cdb[3], cdb[4], cdb[5],
cdb[6], cdb[7], cdb[8], cdb[9], cdb[10], cdb[11]);
#endif
memset(sense, 0, sizeof(sense));
ret = sg_io_cmd(ioctl->fd, cdb, 12, buffer, len,
SG_DXFER_FROM_DEV, sense, &sense_len);
ioctl_log(ioctl->log, "ioctl_read_sector: ret = %d, sense_len = %d\n",
ret, sense_len);
if (sense_len >= 16) {
if ((sense[2] == 0x03) && (sense[12] == 0x11))
/* Treat this as an error to correctly indicate CIRC error to the guest. */
ret = 0;
ioctl_log(ioctl->log, "Host sense: %02X %02X %02X %02X %02X %02X %02X %02X\n",
sense[0], sense[1], sense[2], sense[3],
sense[4], sense[5], sense[6], sense[7]);
ioctl_log(ioctl->log, " %02X %02X %02X %02X %02X %02X %02X %02X\n",
sense[8], sense[9], sense[10], sense[11],
sense[12], sense[13], sense[14], sense[15]);
}
ret = ret ? 1 : -1;
data_len = len; /* sg_io_cmd handles this internally */
}
ioctl_log(ioctl->log, "ioctl_read_sector: final ret = %i\n", ret);
/* Construct raw subchannel data from Q only. */
if ((ret > 0) && !ioctl->is_dvd)
for (int i = 11; i >= 0; i--)
for (int j = 7; j >= 0; j--)
buffer[2352 + (i * 8) + j] = ((buffer[sc_offs + i] >> (7 - j)) & 0x01) << 6;
return ret;
}
static uint8_t
ioctl_get_track_type(const void *local, const uint32_t sector)
{
ioctl_t *ioctl = (ioctl_t *) local;
int track = ioctl_get_track(ioctl, sector);
raw_track_info_t *rti = (raw_track_info_t *) ioctl->cur_rti;
const raw_track_info_t *trk = &(rti[track]);
uint8_t ret = 0x00;
if (ioctl_is_track_audio(ioctl, sector))
ret = CD_TRACK_AUDIO;
else if (track != -1) for (int i = 0; i < ioctl->blocks_num; i++) {
const raw_track_info_t *ct = &(rti[i]);
const raw_track_info_t *nt = &(rti[i + 1]);
if (ct->point == 0xa0) {
uint8_t first = ct->pm;
uint8_t last = nt->pm;
if ((trk->point >= first) && (trk->point <= last)) {
ret = ct->ps;
break;
}
}
}
return ret;
}
static uint32_t
ioctl_get_last_block(const void *local)
{
const ioctl_t *ioctl = (const ioctl_t *) local;
raw_track_info_t *rti = (raw_track_info_t *) ioctl->cur_rti;
uint32_t lb = 0;
for (int i = (ioctl->blocks_num - 1); i >= 0; i--)
if (rti[i].point == 0xa2) {
lb = MSFtoLBA(rti[i].pm, rti[i].ps, rti[i].pf) - 151;
break;
}
ioctl_log(ioctl->log, "LBCapacity=%d\n", lb);
return lb;
}
static int
ioctl_read_dvd_structure(const void *local, const uint8_t layer, const uint8_t format,
uint8_t *buffer, uint32_t *info)
{
const ioctl_t *ioctl = (const ioctl_t *) local;
const int len = 2052;
uint8_t cdb[12];
uint8_t sense[64];
int sense_len = 0;
memset(cdb, 0, sizeof(cdb));
cdb[0] = 0xad; /* READ DVD STRUCTURE */
cdb[6] = layer; /* Layer Number */
cdb[7] = format; /* Format */
cdb[8] = 0x08; /* Allocation Length high */
cdb[9] = 0x04; /* Allocation Length low */
#ifdef ENABLE_IOCTL_LOG
ioctl_log(ioctl->log, "Host CDB: %02X %02X %02X %02X %02X %02X "
"%02X %02X %02X %02X %02X %02X\n",
cdb[0], cdb[1], cdb[2], cdb[3], cdb[4], cdb[5],
cdb[6], cdb[7], cdb[8], cdb[9], cdb[10], cdb[11]);
#endif
memset(sense, 0, sizeof(sense));
int ret = sg_io_cmd(ioctl->fd, cdb, 12, buffer, len,
SG_DXFER_FROM_DEV, sense, &sense_len);
ioctl_log(ioctl->log, "ioctl_read_dvd_structure(): ret = %d, sense_len = %d\n",
ret, sense_len);
if (sense_len >= 16) {
/* Return sense to the host as is. */
ret = -((sense[2] << 16) | (sense[12] << 8) | sense[13]);
if (info != NULL)
*info = *(uint32_t *) &(sense[3]);
ioctl_log(ioctl->log, "Host sense: %02X %02X %02X %02X %02X %02X %02X %02X\n",
sense[0], sense[1], sense[2], sense[3],
sense[4], sense[5], sense[6], sense[7]);
ioctl_log(ioctl->log, " %02X %02X %02X %02X %02X %02X %02X %02X\n",
sense[8], sense[9], sense[10], sense[11],
sense[12], sense[13], sense[14], sense[15]);
} else
ret = ret ? 1 : 0;
return ret;
}
static int
ioctl_is_dvd(const void *local)
{
const ioctl_t *ioctl = (const ioctl_t *) local;
return ioctl->is_dvd;
}
static int
ioctl_has_audio(const void *local)
{
const ioctl_t *ioctl = (const ioctl_t *) local;
return ioctl->has_audio;
}
static int
ioctl_is_empty(const void *local)
{
const ioctl_t *ioctl = (const ioctl_t *) local;
uint8_t cdb[12];
uint8_t sense[64];
int sense_len = 0;
/* TEST UNIT READY */
memset(cdb, 0, sizeof(cdb));
cdb[0] = 0x00;
#ifdef ENABLE_IOCTL_LOG
ioctl_log(ioctl->log, "Host CDB: %02X %02X %02X %02X %02X %02X "
"%02X %02X %02X %02X %02X %02X\n",
cdb[0], cdb[1], cdb[2], cdb[3], cdb[4], cdb[5],
cdb[6], cdb[7], cdb[8], cdb[9], cdb[10], cdb[11]);
#endif
memset(sense, 0, sizeof(sense));
int ret = sg_io_cmd(ioctl->fd, cdb, 6, NULL, 0,
SG_DXFER_NONE, sense, &sense_len);
ioctl_log(ioctl->log, "ioctl_is_empty(): ret = %d, sense_len = %d\n",
ret, sense_len);
if (sense_len >= 16) {
/* Check for NOT READY + MEDIUM NOT PRESENT. */
ret = ((sense[2] == SENSE_NOT_READY) && (sense[12] == ASC_MEDIUM_NOT_PRESENT));
ioctl_log(ioctl->log, "Host sense: %02X %02X %02X %02X %02X %02X %02X %02X\n",
sense[0], sense[1], sense[2], sense[3],
sense[4], sense[5], sense[6], sense[7]);
ioctl_log(ioctl->log, " %02X %02X %02X %02X %02X %02X %02X %02X\n",
sense[8], sense[9], sense[10], sense[11],
sense[12], sense[13], sense[14], sense[15]);
} else if (!ret)
ret = 1; /* SG_IO itself failed, assume empty */
else
ret = 0; /* No sense data and command succeeded = media present */
return ret;
}
/* Disc change polling thread. */
static void *
ioctl_poll_thread(void *arg)
{
ioctl_t *ioctl = (ioctl_t *) arg;
int was_empty = ioctl_is_empty(ioctl);
while (ioctl->poll_active) {
sleep(2); /* Poll every 2 seconds. */
if (!ioctl->poll_active)
break;
int now_empty = ioctl_is_empty(ioctl);
if (now_empty != was_empty) {
if (now_empty)
cdrom_set_empty(ioctl->dev);
else
cdrom_update_status(ioctl->dev);
was_empty = now_empty;
}
}
return NULL;
}
static void
ioctl_close(void *local)
{
ioctl_t *ioctl = (ioctl_t *) local;
/* Stop the polling thread. */
if (ioctl->poll_active) {
ioctl->poll_active = 0;
pthread_join(ioctl->poll_tid, NULL);
}
ioctl_close_handle(ioctl);
ioctl->fd = -1;
ioctl_log(ioctl->log, "Log closed\n");
log_close(ioctl->log);
ioctl->log = NULL;
free(ioctl);
}
static void
ioctl_load(const void *local)
{
ioctl_t *ioctl = (ioctl_t *) local;
if ((ioctl->fd >= 0) || ioctl_open_handle(ioctl)) {
/* Try to close the tray. */
(void) sys_ioctl(ioctl->fd, CDROMCLOSETRAY, NULL);
ioctl_read_raw_toc(ioctl);
}
}
static const cdrom_ops_t ioctl_ops = {
ioctl_get_track_info,
ioctl_get_raw_track_info,
ioctl_is_track_pre,
ioctl_read_sector,
ioctl_get_track_type,
ioctl_get_last_block,
ioctl_read_dvd_structure,
ioctl_is_dvd,
ioctl_has_audio,
ioctl_is_empty,
ioctl_close,
ioctl_load
};
/* Public functions. */
void *
ioctl_open(cdrom_t *dev, const char *drv)
{
ioctl_t *ioctl = (ioctl_t *) calloc(1, sizeof(ioctl_t));
if (ioctl != NULL) {
char n[1024] = { 0 };
sprintf(n, "CD-ROM %i IOCtl", dev->id + 1);
ioctl->log = log_open(n);
memset(ioctl->path, 0x00, sizeof(ioctl->path));
ioctl->fd = -1;
/* drv is "ioctl:///dev/sr0", extract the path part. */
snprintf(ioctl->path, sizeof(ioctl->path), "%s", &(drv[8]));
ioctl_log(ioctl->log, "Path is %s\n", ioctl->path);
ioctl->dev = dev;
dev->ops = &ioctl_ops;
ioctl_load(ioctl);
/* Start the disc change polling thread. */
ioctl->poll_active = 1;
if (pthread_create(&ioctl->poll_tid, NULL, ioctl_poll_thread, ioctl) != 0)
ioctl->poll_active = 0;
}
return ioctl;
}

View File

@@ -1121,83 +1121,159 @@ ibm8514_accel_start(int count, int cpu_input, uint32_t mix_dat, uint32_t cpu_dat
if (pixcntl == 1) {
mix_dat = 0;
if (and3 == 3) {
if (dev->accel.multifunc[8] & 0x02)
mix_dat |= 0x08;
if (dev->accel.multifunc[8] & 0x04)
mix_dat |= 0x10;
if (dev->accel.multifunc[8] & 0x08)
mix_dat |= 0x20;
if (dev->accel.multifunc[8] & 0x10)
mix_dat |= 0x40;
if (dev->accel.multifunc[9] & 0x02)
mix_dat |= 0x80;
if (dev->accel.multifunc[9] & 0x04)
mix_dat |= 0x01;
if (dev->accel.multifunc[9] & 0x08)
mix_dat |= 0x02;
if (dev->accel.multifunc[9] & 0x10)
mix_dat |= 0x04;
}
if (and3 == 2) {
if (dev->accel.multifunc[8] & 0x02)
mix_dat |= 0x04;
if (dev->accel.multifunc[8] & 0x04)
mix_dat |= 0x08;
if (dev->accel.multifunc[8] & 0x08)
mix_dat |= 0x10;
if (dev->accel.multifunc[8] & 0x10)
mix_dat |= 0x20;
if (dev->accel.multifunc[9] & 0x02)
mix_dat |= 0x40;
if (dev->accel.multifunc[9] & 0x04)
mix_dat |= 0x80;
if (dev->accel.multifunc[9] & 0x08)
mix_dat |= 0x01;
if (dev->accel.multifunc[9] & 0x10)
mix_dat |= 0x02;
}
if (and3 == 1) {
if (dev->accel.multifunc[8] & 0x02)
mix_dat |= 0x02;
if (dev->accel.multifunc[8] & 0x04)
mix_dat |= 0x04;
if (dev->accel.multifunc[8] & 0x08)
mix_dat |= 0x08;
if (dev->accel.multifunc[8] & 0x10)
mix_dat |= 0x10;
if (dev->accel.multifunc[9] & 0x02)
mix_dat |= 0x20;
if (dev->accel.multifunc[9] & 0x04)
mix_dat |= 0x40;
if (dev->accel.multifunc[9] & 0x08)
mix_dat |= 0x80;
if (dev->accel.multifunc[9] & 0x10)
mix_dat |= 0x01;
}
if (and3 == 0) {
if (dev->accel.multifunc[8] & 0x02)
mix_dat |= 0x01;
if (dev->accel.multifunc[8] & 0x04)
mix_dat |= 0x02;
if (dev->accel.multifunc[8] & 0x08)
mix_dat |= 0x04;
if (dev->accel.multifunc[8] & 0x10)
mix_dat |= 0x08;
if (dev->accel.multifunc[9] & 0x02)
mix_dat |= 0x10;
if (dev->accel.multifunc[9] & 0x04)
mix_dat |= 0x20;
if (dev->accel.multifunc[9] & 0x08)
mix_dat |= 0x40;
if (dev->accel.multifunc[9] & 0x10)
mix_dat |= 0x80;
if (cmd == 6) {
if (and3_blt == 3) {
if (dev->accel.multifunc[8] & 0x02)
mix_dat |= 0x08;
if (dev->accel.multifunc[8] & 0x04)
mix_dat |= 0x10;
if (dev->accel.multifunc[8] & 0x08)
mix_dat |= 0x20;
if (dev->accel.multifunc[8] & 0x10)
mix_dat |= 0x40;
if (dev->accel.multifunc[9] & 0x02)
mix_dat |= 0x80;
if (dev->accel.multifunc[9] & 0x04)
mix_dat |= 0x01;
if (dev->accel.multifunc[9] & 0x08)
mix_dat |= 0x02;
if (dev->accel.multifunc[9] & 0x10)
mix_dat |= 0x04;
}
if (and3_blt == 2) {
if (dev->accel.multifunc[8] & 0x02)
mix_dat |= 0x04;
if (dev->accel.multifunc[8] & 0x04)
mix_dat |= 0x08;
if (dev->accel.multifunc[8] & 0x08)
mix_dat |= 0x10;
if (dev->accel.multifunc[8] & 0x10)
mix_dat |= 0x20;
if (dev->accel.multifunc[9] & 0x02)
mix_dat |= 0x40;
if (dev->accel.multifunc[9] & 0x04)
mix_dat |= 0x80;
if (dev->accel.multifunc[9] & 0x08)
mix_dat |= 0x01;
if (dev->accel.multifunc[9] & 0x10)
mix_dat |= 0x02;
}
if (and3_blt == 1) {
if (dev->accel.multifunc[8] & 0x02)
mix_dat |= 0x02;
if (dev->accel.multifunc[8] & 0x04)
mix_dat |= 0x04;
if (dev->accel.multifunc[8] & 0x08)
mix_dat |= 0x08;
if (dev->accel.multifunc[8] & 0x10)
mix_dat |= 0x10;
if (dev->accel.multifunc[9] & 0x02)
mix_dat |= 0x20;
if (dev->accel.multifunc[9] & 0x04)
mix_dat |= 0x40;
if (dev->accel.multifunc[9] & 0x08)
mix_dat |= 0x80;
if (dev->accel.multifunc[9] & 0x10)
mix_dat |= 0x01;
}
if (and3_blt == 0) {
if (dev->accel.multifunc[8] & 0x02)
mix_dat |= 0x01;
if (dev->accel.multifunc[8] & 0x04)
mix_dat |= 0x02;
if (dev->accel.multifunc[8] & 0x08)
mix_dat |= 0x04;
if (dev->accel.multifunc[8] & 0x10)
mix_dat |= 0x08;
if (dev->accel.multifunc[9] & 0x02)
mix_dat |= 0x10;
if (dev->accel.multifunc[9] & 0x04)
mix_dat |= 0x20;
if (dev->accel.multifunc[9] & 0x08)
mix_dat |= 0x40;
if (dev->accel.multifunc[9] & 0x10)
mix_dat |= 0x80;
}
} else {
if (and3 == 3) {
if (dev->accel.multifunc[8] & 0x02)
mix_dat |= 0x08;
if (dev->accel.multifunc[8] & 0x04)
mix_dat |= 0x10;
if (dev->accel.multifunc[8] & 0x08)
mix_dat |= 0x20;
if (dev->accel.multifunc[8] & 0x10)
mix_dat |= 0x40;
if (dev->accel.multifunc[9] & 0x02)
mix_dat |= 0x80;
if (dev->accel.multifunc[9] & 0x04)
mix_dat |= 0x01;
if (dev->accel.multifunc[9] & 0x08)
mix_dat |= 0x02;
if (dev->accel.multifunc[9] & 0x10)
mix_dat |= 0x04;
}
if (and3 == 2) {
if (dev->accel.multifunc[8] & 0x02)
mix_dat |= 0x04;
if (dev->accel.multifunc[8] & 0x04)
mix_dat |= 0x08;
if (dev->accel.multifunc[8] & 0x08)
mix_dat |= 0x10;
if (dev->accel.multifunc[8] & 0x10)
mix_dat |= 0x20;
if (dev->accel.multifunc[9] & 0x02)
mix_dat |= 0x40;
if (dev->accel.multifunc[9] & 0x04)
mix_dat |= 0x80;
if (dev->accel.multifunc[9] & 0x08)
mix_dat |= 0x01;
if (dev->accel.multifunc[9] & 0x10)
mix_dat |= 0x02;
}
if (and3 == 1) {
if (dev->accel.multifunc[8] & 0x02)
mix_dat |= 0x02;
if (dev->accel.multifunc[8] & 0x04)
mix_dat |= 0x04;
if (dev->accel.multifunc[8] & 0x08)
mix_dat |= 0x08;
if (dev->accel.multifunc[8] & 0x10)
mix_dat |= 0x10;
if (dev->accel.multifunc[9] & 0x02)
mix_dat |= 0x20;
if (dev->accel.multifunc[9] & 0x04)
mix_dat |= 0x40;
if (dev->accel.multifunc[9] & 0x08)
mix_dat |= 0x80;
if (dev->accel.multifunc[9] & 0x10)
mix_dat |= 0x01;
}
if (and3 == 0) {
if (dev->accel.multifunc[8] & 0x02)
mix_dat |= 0x01;
if (dev->accel.multifunc[8] & 0x04)
mix_dat |= 0x02;
if (dev->accel.multifunc[8] & 0x08)
mix_dat |= 0x04;
if (dev->accel.multifunc[8] & 0x10)
mix_dat |= 0x08;
if (dev->accel.multifunc[9] & 0x02)
mix_dat |= 0x10;
if (dev->accel.multifunc[9] & 0x04)
mix_dat |= 0x20;
if (dev->accel.multifunc[9] & 0x08)
mix_dat |= 0x40;
if (dev->accel.multifunc[9] & 0x10)
mix_dat |= 0x80;
}
}
}
old_mix_dat = mix_dat;
ibm8514_log("CMD=%d, full=%04x, pixcntl=%d, filling=%02x, ssvdraw=%02x.\n", cmd, dev->accel.cmd, pixcntl, dev->accel.multifunc[0x0a] & 0x06, dev->accel.ssv_draw);
if (!(dev->accel.cmd & 0x01))
ibm8514_log("CMD=%d, full=%04x, pixcntl=%d, filling=%02x, ssvdraw=%02x.\n", cmd, dev->accel.cmd, pixcntl, dev->accel.multifunc[0x0a] & 0x06, dev->accel.ssv_draw);
/*Bit 4 of the Command register is the draw yes bit, which enables writing to memory/reading from memory when enabled.
When this bit is disabled, no writing to memory/reading from memory is allowed. (This bit is almost meaningless on

View File

@@ -3021,8 +3021,10 @@ ati8514_recalctimings(svga_t *svga)
if (dev->ven_clock & 0x40)
svga->clock_8514 *= 2.0;
if (dev->interlace)
if (dev->interlace) {
dev->dispend >>= 1;
svga->clock_8514 /= 2.0;
}
mach_log("cntl=%d, hv(%d,%d), pitch=%d, rowoffset=%d, gextconfig=%03x, shadow=%x interlace=%d.\n",
dev->accel.advfunc_cntl & 0x04, dev->h_disp, dev->dispend, dev->pitch, dev->rowoffset,
@@ -3183,8 +3185,10 @@ mach_recalctimings(svga_t *svga)
mach_log("8514/A modes=%d, clocksel=%02x, clkselmode=%02x, divide reg ibm=%02x, divide reg vga=%02x, vgainterlace=%x, interlace=%x, htotal=%02x.\n", _8514_modes, mach->accel.clock_sel & 0xfe, mach->accel.clock_sel_mode & 0xfe, mach->accel.clock_sel & 0x40, mach->regs[0xb8] & 0x40, svga->interlace, dev->interlace, dev->htotal);
if (dev->interlace)
if (dev->interlace) {
dev->dispend >>= 1;
svga->clock_8514 /= 2.0;
}
if (ATI_MACH32) {
switch ((mach->shadow_set >> 8) & 0x03) {

View File

@@ -53,6 +53,7 @@
#define BIOS_GD5428_DIAMOND_B1_VLB_PATH "roms/video/cirruslogic/Diamond SpeedStar PRO VLB v3.04.bin"
#define BIOS_GD5428_ISA_PATH "roms/video/cirruslogic/5428.bin"
#define BIOS_GD5428_MCA_PATH "roms/video/cirruslogic/SVGA141.ROM"
#define BIOS_GD5428_ONBOARD_ACER_PATH "roms/machines/acera1g/4alo001.bin"
#define BIOS_GD5428_PATH "roms/video/cirruslogic/vlbusjapan.BIN"
#define BIOS_GD5428_BOCA_ISA_PATH_1 "roms/video/cirruslogic/boca_gd5428_1.30b_1.bin"
#define BIOS_GD5428_BOCA_ISA_PATH_2 "roms/video/cirruslogic/boca_gd5428_1.30b_2.bin"
@@ -1327,7 +1328,10 @@ gd54xx_in(uint16_t addr, void *priv)
/* Scratch Pad 1 (Memory size for 5402/542x) */
ret = svga->seqregs[0x0a] & ~0x1a;
if (svga->crtc[0x27] == CIRRUS_ID_CLGD5402) {
ret |= 0x01; /*512K of memory*/
if ((gd54xx->vram_size >> 10) == 512)
ret |= 0x01; /*512K of memory*/
else
ret &= 0xfe; /*256K of memory*/
} else if (svga->crtc[0x27] > CIRRUS_ID_CLGD5402) {
switch (gd54xx->vram_size >> 10) {
case 512:
@@ -4284,6 +4288,8 @@ gd54xx_init(const device_t *info)
case CIRRUS_ID_CLGD5402:
if (info->local & 0x200)
romfn = NULL;
else if (info->local & 0x100)
romfn = BIOS_GD5402_ONBOARD_PATH;
else
romfn = BIOS_GD5402_PATH;
@@ -4326,7 +4332,10 @@ gd54xx_init(const device_t *info)
case CIRRUS_ID_CLGD5428:
if (info->local & 0x200) {
romfn = NULL;
if (machines[machine].init == machine_at_acera1g_init)
romfn = BIOS_GD5428_ONBOARD_ACER_PATH;
else
romfn = NULL;
gd54xx->has_bios = 0;
} else if (info->local & 0x100)
if (gd54xx->vlb)
@@ -4427,12 +4436,12 @@ gd54xx_init(const device_t *info)
gd54xx->vram_size = vram << 10;
} else {
if (id <= CIRRUS_ID_CLGD5428) {
if ((id == CIRRUS_ID_CLGD5426) && (info->local & 0x200))
if ((id == CIRRUS_ID_CLGD5428) && (info->local & 0x200) && (info->local & 0x1000))
vram = 1024;
else if ((id == CIRRUS_ID_CLGD5426) && (info->local & 0x200) && (info->local & 0x1000))
vram = 1024;
else if (id == CIRRUS_ID_CLGD5401)
vram = 256;
else if (id == CIRRUS_ID_CLGD5402)
vram = 512;
else
vram = device_get_config_int("memory");
@@ -4768,6 +4777,25 @@ gd54xx_force_redraw(void *priv)
}
// clang-format off
static const device_config_t gd5402_config[] = {
{
.name = "memory",
.description = "Memory size",
.type = CONFIG_SELECTION,
.default_string = NULL,
.default_int = 512,
.file_filter = NULL,
.spinner = { 0 },
.selection = {
{ .description = "256 KB", .value = 256 },
{ .description = "512 KB", .value = 512 },
{ .description = "" }
},
.bios = { { 0 } }
},
{ .name = "", .description = "", .type = CONFIG_END }
};
static const device_config_t gd542x_config[] = {
{
.name = "memory",
@@ -5015,7 +5043,7 @@ const device_t gd5402_isa_device = {
.available = gd5402_available,
.speed_changed = gd54xx_speed_changed,
.force_redraw = gd54xx_force_redraw,
.config = NULL,
.config = gd5402_config,
};
const device_t gd5402_onboard_device = {
@@ -5029,7 +5057,21 @@ const device_t gd5402_onboard_device = {
.available = NULL,
.speed_changed = gd54xx_speed_changed,
.force_redraw = gd54xx_force_redraw,
.config = NULL,
.config = gd5402_config,
};
const device_t gd5402_onboard_commodore_device = {
.name = "Cirrus Logic GD5402 (ISA) (ACUMOS AVGA2) (On-Board) (Commodore)",
.internal_name = "cl_gd5402_onboard_commodore",
.flags = DEVICE_ISA16,
.local = CIRRUS_ID_CLGD5402 | 0x100,
.init = gd54xx_init,
.close = gd54xx_close,
.reset = gd54xx_reset,
.available = NULL,
.speed_changed = gd54xx_speed_changed,
.force_redraw = gd54xx_force_redraw,
.config = gd5402_config,
};
const device_t gd5420_isa_device = {
@@ -5145,11 +5187,25 @@ const device_t gd5426_vlb_device = {
.config = gd5426_config
};
const device_t gd5426_onboard_isa_device = {
.name = "Cirrus Logic GD5426 (ISA) (On-Board)",
.internal_name = "cl_gd5426_onboard",
.flags = DEVICE_ISA16,
.local = CIRRUS_ID_CLGD5426 | 0x200,
.init = gd54xx_init,
.close = gd54xx_close,
.reset = gd54xx_reset,
.available = gd5428_isa_available,
.speed_changed = gd54xx_speed_changed,
.force_redraw = gd54xx_force_redraw,
.config = gd542x_config
};
const device_t gd5426_onboard_device = {
.name = "Cirrus Logic GD5426 (VLB) (On-Board)",
.internal_name = "cl_gd5426_onboard",
.flags = DEVICE_VLB,
.local = CIRRUS_ID_CLGD5426 | 0x200,
.local = CIRRUS_ID_CLGD5426 | 0x200 | 0x1000,
.init = gd54xx_init,
.close = gd54xx_close,
.reset = gd54xx_reset,
@@ -5248,21 +5304,21 @@ const device_t gd5428_onboard_device = {
.name = "Cirrus Logic GD5428 (ISA) (On-Board)",
.internal_name = "cl_gd5428_onboard",
.flags = DEVICE_ISA16,
.local = CIRRUS_ID_CLGD5428,
.local = CIRRUS_ID_CLGD5428 | 0x200,
.init = gd54xx_init,
.close = gd54xx_close,
.reset = gd54xx_reset,
.available = gd5428_isa_available,
.speed_changed = gd54xx_speed_changed,
.force_redraw = gd54xx_force_redraw,
.config = gd5426_config
.config = gd542x_config
};
const device_t gd5428_vlb_onboard_device = {
.name = "Cirrus Logic GD5428 (VLB) (On-Board)",
.internal_name = "cl_gd5428_vlb_onboard",
.flags = DEVICE_VLB,
.local = CIRRUS_ID_CLGD5428,
.local = CIRRUS_ID_CLGD5428 | 0x200,
.init = gd54xx_init,
.close = gd54xx_close,
.reset = gd54xx_reset,
@@ -5273,7 +5329,7 @@ const device_t gd5428_vlb_onboard_device = {
};
const device_t gd5428_onboard_vlb_device = {
.name = "Cirrus Logic GD5428 (VLB) (On-Board) (Dell)",
.name = "Cirrus Logic GD5428 (VLB) (On-Board) (1MB)",
.internal_name = "cl_gd5428_onboard_vlb",
.flags = DEVICE_VLB,
.local = CIRRUS_ID_CLGD5428 | 0x200,
@@ -5286,6 +5342,20 @@ const device_t gd5428_onboard_vlb_device = {
.config = gd542x_config
};
const device_t gd5428_vlb_onboard_tandy_device = {
.name = "Cirrus Logic GD5428 (VLB) (On-Board) (Tandy)",
.internal_name = "cl_gd5428_vlb_onboard_tandy",
.flags = DEVICE_VLB,
.local = CIRRUS_ID_CLGD5428 | 0x200 | 0x1000,
.init = gd54xx_init,
.close = gd54xx_close,
.reset = gd54xx_reset,
.available = NULL,
.speed_changed = gd54xx_speed_changed,
.force_redraw = gd54xx_force_redraw,
.config = NULL
};
const device_t gd5429_isa_device = {
.name = "Cirrus Logic GD5429 (ISA)",
.internal_name = "cl_gd5429_isa",